-1

Writing a program in C that is similar to ls. My program needs to implement the -S flag, meaning it sorts whatever directory is specified (or the current one if not) by the size of its contents in bytes.

Obviously you can easily do an alphabetical sorting with scandir and alphasort (see https://www.cs.cf.ac.uk/Dave/C/node20.html). My question is whether you can use scandir with a comparator function that compares two entries on the size of their contents.

Alternatively, I could just specify NULL for the comparator function, have the unsorted array, and then sort it myself with the qsort() function.

Any advice much appreciated. Any clarifications needed, just say in the comments.

Daniel Soutar
  • 827
  • 1
  • 10
  • 24
  • 1
    Since the declaration is `int scandir(const char *dir, struct dirent ***namelist, int (*sel)(const struct dirent *), int (*compar)(const struct dirent **, const struct dirent **));`, you can write a comparator function that uses `stat` on each of the two pointed at directory entries and compares the sizes in any way you see fit. The difficulty is caching the stat data; there isn't an obvious way to do that, but if you have thousands of files, you probably don't want to be running two stat system calls each time you make a comparison. – Jonathan Leffler Apr 06 '16 at 20:17
  • 1
    what's your question? You already know the answer.. `scandir` takes a comparator function, so yes you can pass the proper comparator. – Eugene Sh. Apr 06 '16 at 20:18
  • Eugene, perhaps I should clarify - the point is that the comparator function accepts two dirent structs. The dirent struct doesn't contain the size of the thing in bytes as far as I am aware. – Daniel Soutar Apr 06 '16 at 21:02
  • @JonathanLeffler I was thinking of that, but then I thought that a lot of work would be done for even a few hundred files. Any suggestions? – Daniel Soutar Apr 06 '16 at 21:03
  • 2
    I'd probably go with a a simple comparator (`alphasort()` perhaps), and then when the data's returned by `scandir()`, create a data structure that can cache the file sizes (and any other data that you want for your comparisons), and then use `qsort()` on the augmented data. – Jonathan Leffler Apr 06 '16 at 21:05
  • @JonathanLeffler I thought that might be the best way to go. Thanks again for your help. – Daniel Soutar Apr 06 '16 at 21:06

1 Answers1

1

Converting comments to an answer.

Since the POSIX declaration of scandir() is

int scandir(const char *dir, struct dirent ***namelist,
            int (*sel)(const struct dirent *),
            int (*compar)(const struct dirent **, const struct dirent **));

you can write a comparator function that uses stat() on each of the two pointed at directory entries and compares the sizes in any way you see fit. The difficulty is caching the stat data; there isn't an obvious way to do that, but if you have thousands of files, you probably don't want to be running two stat() system calls each time you make a comparison — that would be pretty much the ultimate in 'slow compare vs fast swap'.

I was thinking of that, but then I thought that a lot of work would be done for even a few hundred files. Any suggestions?

I'd probably go with a a simple comparator (alphasort() perhaps), and then when the data's returned by scandir(), create an array of a data structure that can cache the file names and sizes (and any other data that you want for your comparisons), and then use qsort() on the array of the data structure.

Jonathan Leffler
  • 730,956
  • 141
  • 904
  • 1,278