Search code examples
csortingscandirsortdirection

How to use scandir() in C for case insensitive?


I'm learning C and I have this implementation to sort the files and folders, but this isn't case insensitive:

#include <dirent.h>
#include <stddef.h>
#include <stdlib.h>
#include <stdio.h>

int main(void) {
    struct dirent **namelist;
    int n;

    n = scandir(".", &namelist, NULL, alphasort);
    if (n < 0)
        perror("scandir");
    else {
        printf("Inside else, n = %d\n", n);
        while (n--) {
            printf("%s\n", namelist[n]->d_name);
            free(namelist[n]);
        }
        free(namelist);
    }
}

And if I have a.txt, b.txt, C.txt and z.txt it will sort in this order: C.txt, a.txt, b.txt, z.txt. I want this to be sorted case insensitive like this: a.txt, b.txt, C.txt, z.txt


Solution

  • scandir is defined with this prototype:

    int scandir(const char *restrict dirp,
                struct dirent ***restrict namelist,
                int (*filter)(const struct dirent *),
                int (*compar)(const struct dirent **,
                              const struct dirent **));
    

    The function alphasort sorts the filenames in lexicographical order, hence case-sensitive order. If you want case insensitive sorting, use a different comparison function:

    int alphasort_no_case(const struct dirent **a, const struct dirent **b) {
        return strcasecmp((*a)->d_name, (*b)->d_name);
    }
    

    Both scandir and strcasecmp are POSIX functions: strcasecmp is highly likely to be available on systems that support scandir and defined in <strings.h>.

    Modifier version:

    #include <dirent.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <strings.h>
    
    int alphasort_no_case(const struct dirent **a, const struct dirent **b) {
        return strcasecmp((*a)->d_name, (*b)->d_name);
    }
    
    int main(void) {
        struct dirent **namelist;
        int n;
    
        n = scandir(".", &namelist, NULL, alphasort_no_case);
        if (n < 0) {
            perror("scandir");
        } else {
            printf("Inside else, n = %d\n", n);
            while (n--) {
                printf("%s\n", namelist[n]->d_name);
                free(namelist[n]);
            }
            free(namelist);
        }
        return 0;
    }