1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149
|
/*
* crawl_folders.c -- crawl folder hierarchy
*
* This code is Copyright (c) 2008, by the authors of nmh. See the
* COPYRIGHT file in the root directory of the nmh distribution for
* complete copyright information.
*/
#include <h/mh.h>
#include <h/crawl_folders.h>
#include <h/utils.h>
struct crawl_context {
int max; /* how many folders we currently can hold in
* the array `folders', increased by
* CRAWL_NUMFOLDERS at a time */
int total; /* how many `folders' actually has */
char **folders; /* the array of folders */
int start;
int foldp;
};
/*
* Add the folder name into the
* list in a sorted fashion.
*/
static void
add_folder (char *fold, struct crawl_context *crawl)
{
register int i, j;
/* if necessary, reallocate the space for folder names */
if (crawl->foldp >= crawl->max) {
crawl->max += CRAWL_NUMFOLDERS;
crawl->folders = mh_xrealloc (crawl->folders,
crawl->max * sizeof(char *));
}
for (i = crawl->start; i < crawl->foldp; i++)
if (strcmp (fold, crawl->folders[i]) < 0) {
for (j = crawl->foldp - 1; j >= i; j--)
crawl->folders[j + 1] = crawl->folders[j];
crawl->foldp++;
crawl->folders[i] = fold;
return;
}
crawl->total++;
crawl->folders[crawl->foldp++] = fold;
}
static void
add_children (char *name, struct crawl_context *crawl)
{
char *prefix, *child;
struct stat st;
struct dirent *dp;
DIR * dd;
int child_is_folder;
if (!(dd = opendir (name))) {
admonish (name, "unable to read directory ");
return;
}
if (strcmp (name, ".") == 0) {
prefix = getcpy ("");
} else {
prefix = concat (name, "/", (void *)NULL);
}
while ((dp = readdir (dd))) {
/* If the system supports it, try to skip processing of children we
* know are not directories or symlinks. */
child_is_folder = -1;
#if defined(HAVE_STRUCT_DIRENT_D_TYPE)
if (dp->d_type == DT_DIR) {
child_is_folder = 1;
} else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) {
continue;
}
#endif
if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) {
continue;
}
child = concat (prefix, dp->d_name, (void *)NULL);
/* If we have no d_type or d_type is DT_LNK or DT_UNKNOWN, stat the
* child to see what it is. */
if (child_is_folder == -1) {
child_is_folder = (stat (child, &st) != -1 && S_ISDIR(st.st_mode));
}
if (child_is_folder) {
/* add_folder saves child in the list, don't free it */
add_folder (child, crawl);
} else {
free (child);
}
}
closedir (dd);
free(prefix);
}
static void
crawl_folders_body (struct crawl_context *crawl,
char *dir, crawl_callback_t *callback, void *baton)
{
int i;
int os = crawl->start;
int of = crawl->foldp;
crawl->start = crawl->foldp;
add_children (dir, crawl);
for (i = crawl->start; i < crawl->foldp; i++) {
char *fold = crawl->folders[i];
int crawl_children = 1;
if (callback != NULL) {
crawl_children = callback (fold, baton);
}
if (crawl_children) {
crawl_folders_body (crawl, fold, callback, baton);
}
}
crawl->start = os;
crawl->foldp = of;
}
void
crawl_folders (char *dir, crawl_callback_t *callback, void *baton)
{
struct crawl_context *crawl = mh_xmalloc (sizeof(*crawl));
crawl->max = CRAWL_NUMFOLDERS;
crawl->total = crawl->start = crawl->foldp = 0;
crawl->folders = mh_xmalloc (crawl->max * sizeof(*crawl->folders));
crawl_folders_body (crawl, dir, callback, baton);
/* Note that we "leak" the folder names, on the assumption that the caller
* is using them. */
free (crawl->folders);
free (crawl);
}
|