Skip to content

Instantly share code, notes, and snippets.

@61131
Last active June 14, 2023 03:00
Show Gist options
  • Save 61131/7b137d758338ff41e8028aa588631f05 to your computer and use it in GitHub Desktop.
Save 61131/7b137d758338ff41e8028aa588631f05 to your computer and use it in GitHub Desktop.
Build array of all directories under given file location (without recursion!)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <limits.h>
#include <dirent.h>
#include <errno.h>
#include <sys/stat.h>
#include <sys/types.h>
/* See https://gist.github.com/61131/a4d5846dd2fb4aaa22ecf9e05a3b34a1 */
#include <strl.h>
#define IS_DIR_SEP(c) (((c) == '/') || ((c) == '\\'))
static int
_isdir(char const *path) {
struct stat buf;
if (lstat(path, &buf) < 0) {
if (errno == ENOENT) {
return 0;
}
return 0;
}
return (int)(S_ISDIR(buf.st_mode) && !S_ISLNK(buf.st_mode));
}
/*
This function takes an array of canonical absolute directory paths that will
be validated in turn and expanded such that the paths array contains list of
_all_ directory paths under the original directory locations.
*/
int
build_tree(int ndirs, char **dirs) {
char **paths, rpath[PATH_MAX];
DIR *dp;
struct dirent *entry;
char path[PATH_MAX];
int count, index;
count = 0;
paths = NULL;
for (index = 0; index < ndirs; ++index) {
if (!realpath(dirs[index], rpath)) {
return -1;
}
if (!_isdir(rpath)) {
continue;
}
if ((paths = realloc(paths, ++count * sizeof(char *))) == NULL) {
return -1;
}
paths[count - 1] = strdup(dirs[index]);
}
for (index = 0; index < count; ++index) {
if ((dp = opendir(paths[index])) == NULL) {
/*
The current array entry either does not appear to be a directory or is
otherwise inaccessible and as such, should be removed from the array.
*/
free(paths[index]);
memmove(&paths[index], &paths[index + 1], (count - index) * sizeof(char *));
if ((paths = realloc(paths, --count * sizeof(char *))) == NULL) {
return -1;
}
--index;
continue;
}
while ((entry = readdir(dp)) != NULL) {
if ((strcmp(entry->d_name, ".") == 0) ||
(strcmp(entry->d_name, "..") == 0)) {
continue;
}
strlcpy(path, paths[index], PATH_MAX);
if (!IS_DIR_SEP(path[strlen(path) - 1])) {
strlcat(path, "/", PATH_MAX);
}
strlcat(path, entry->d_name, PATH_MAX);
if (!realpath(path, rpath) ||
!_isdir(rpath)) {
continue;
}
if ((paths = realloc(paths, ++count * sizeof(char *))) == NULL) {
return -1;
}
/*
Depth-first: if (index < (count - 2)) {
memmove(&paths[index + 2], &paths[index + 1], (count - index - 2) * sizeof(char *));
}
paths[index + 1] = strdup(rpath);
Breadth-first: paths[count - 1] = strdup(rpath);
*/
if (index < (count - 2)) {
memmove(&paths[index + 2], &paths[index + 1], (count - index - 2) * sizeof(char *));
}
paths[index + 1] = strdup(rpath);
}
closedir(dp);
}
/*
Now do something with paths, which has count elements ...
qsort(paths, count, sizeof(paths[0]), _strcmp);
for (index = 0; index < count; ++index) {
printf("%s\n", paths[index]);
}
*/
return 0;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment