Home > Enterprise >  How can I sort the files read from a directory?
How can I sort the files read from a directory?

Time:12-15

I am trying to write a program that implements somehow the "dir" command that you can use in the Unix shell but I have encountered the following problem. I managed to read the current directory as I will show in the code but I don't know exactly how I am supposed to sort it in order to make it like the dir function which sorts the files from the directory

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


void dirfunction()
{

    DIR* directory=opendir(".");
    if(directory==NULL)
    {
        perror("Directory does not exist");
        exit(1);
    }
    struct dirent* p;
    p=readdir(directory);
    int i=0;
    while(p!=NULL)
    {

        if(strcmp(p->d_name,".")!=0 && strcmp(p->d_name,"..")!=0)
        {
            printf("%s ",p->d_name);
           
           i  ;
        }
        

        p=readdir(directory);
        
    }
    printf("\n");
    closedir(directory);


}
int main(int argc,char** argv[])
{
    dirfunction();

}

Should I basically do the normal sorting for an array of character, like adding all file names in an array of string and sort it with selection sort or another sort method? I don't really get how dir command sorts the files before printing them to the terminal.

CodePudding user response:

Because readdir reuses the same buffer for the returned entry, we need a dynamic [growing] array to save/store the struct dirent entries.

Then, we need to sort the stored entries (e.g. use qsort).

Side note: int main(int argc,char **argv[]) is incorrect. It should be: int main(int argc,char **argv) There was one too many levels of indirection.

Below is the updated code with some enhancements. It is annotated:

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

// dynamic array of dirent structs
struct dirlist {
    size_t count;                       // number of entries
    struct dirent *base;                // pointer to list start
};

// dirload -- load up directory
// RETURNS: directory list
struct dirlist *
dirload(const char *path)
{
    size_t capacity = 0;
    struct dirlist *list = calloc(1,sizeof(*list));

    DIR *directory = opendir(path);
    if (directory == NULL) {
        perror("Directory does not exist");
        exit(1);
    }

    struct dirent *p;

    while (1) {
        // get next entry
        // this is overwritten, so we need to copy/save it below
        p = readdir(directory);
        if (p == NULL)
            break;

        // skip over "." and ".."
        if (p->d_name[0] == '.') {
            if (p->d_name[1] == 0)
                continue;
            if ((p->d_name[1] == '.') && (p->d_name[2] == 0))
                continue;
        }

        // enlarge array
        if (list->count >= capacity) {
            capacity  = 10;
            list->base = realloc(list->base,sizeof(*list->base) * capacity);
            if (list->base == NULL) {
                perror("realloc");
                exit(1);
            }
        }

        // save dirent entry
        list->base[list->count  ] = *p;
    }

    closedir(directory);

    // trim list to actual size
    list->base = realloc(list->base,sizeof(*list->base) * list->count);
    if (list->base == NULL) {
        perror("realloc");
        exit(1);
    }

    return list;
}

// dircmp -- compare dirent structs
int
dircmp(const void *lhsp,const void *rhsp)
{
    const struct dirent *lhs = lhsp;
    const struct dirent *rhs = rhsp;
    int cmp;

    cmp = strcmp(lhs->d_name,rhs->d_name);

    return cmp;
}

// dirsort -- sort directory list
void
dirsort(struct dirlist *list)
{

    if (list->count > 0)
        qsort(list->base,list->count,sizeof(*list->base),dircmp);
}

// dirprint -- print directory list
void
dirprint(const struct dirlist *list)
{
    const struct dirent *p = list->base;

    for (size_t idx = 0;  idx < list->count;    idx,   p)
        printf("%s\n",p->d_name);
}

// dirdestroy -- destroy directory list
void
dirdestroy(struct dirlist *list)
{

    if (list != NULL)
        free(list->base);
    free(list);
}

int
main(int argc, char **argv)
{

    --argc;
      argv;

    const char *dir;
    if (argc > 0)
        dir = *argv;
    else
        dir = ".";

    struct dirlist *list = dirload(dir);

    // sort the list
    dirsort(list);

    // print the list
    dirprint(list);

    // destroy the list
    dirdestroy(list);

    return 0;
}
  • Related