POSIX C libraries provide nftw(), which makes directory tree traversals much easier.
However, BSD C libraries (since 4.4BSD, about 1994 or thereabouts) and GNU C libraries (since 1999) have long provided fts() to help programmers implement exactly this kind of code efficiently. You need sixty lines, including comments, to write a full program that searches for and lists all regular files ending in .c in all directories specified on the command line:
Code:
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fts.h>
#include <stdio.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[])
{
FTS *tree;
FTSENT *item;
if (argc < 2 || !strcmp(argv[1], "-h") || !strcmp(argv[1], "--help")) {
fprintf(stderr, "\n");
fprintf(stderr, "Usage: %s [ -h | --help ]\n", argv[0]);
fprintf(stderr, " %s FILES-OR-DIRECTORIES...\n", argv[0]);
fprintf(stderr, "\n");
return EXIT_FAILURE;
}
tree = fts_open(argv, FTS_LOGICAL | FTS_COMFOLLOW, NULL);
if (!tree) {
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
while (1) {
errno = 0;
item = fts_read(tree);
if (!item)
break;
/* Only consider regular files. */
if (item->fts_info != FTS_F)
continue;
/* Require .c suffix. */
if (item->fts_namelen < 3 ||
item->fts_name[item->fts_namelen - 2] != '.' ||
item->fts_name[item->fts_namelen - 1] != 'c')
continue;
/* Print the access path, and file size. */
printf("%s (%.0f bytes)\n", item->fts_accpath, (double)item->fts_statp->st_size);
}
if (errno) {
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
if (fts_close(tree)) {
fprintf(stderr, "%s.\n", strerror(errno));
return EXIT_FAILURE;
}
return EXIT_SUCCESS;
}
You might find the Walk a directory/Recursively, C at Rosetta Code interesting.