2 ** crawl_folders.c -- crawl folder hierarchy
4 ** This code is Copyright (c) 2008, by the authors of nmh. See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
10 #include <h/crawl_folders.h>
15 struct crawl_context {
17 ** number of folders we can hold in the folders array;
18 ** increased by CRAWL_NUMFOLDERS at a time
20 int total; /* how many `folders' actually has */
21 char **folders; /* the array of folders */
27 ** Add the folder name into the
28 ** list in a sorted fashion.
32 add_folder(char *fold, struct crawl_context *crawl)
36 /* if necessary, reallocate the space for folder names */
37 if (crawl->foldp >= crawl->max) {
38 crawl->max += CRAWL_NUMFOLDERS;
39 crawl->folders = mh_xrealloc(crawl->folders,
40 crawl->max * sizeof(char *));
43 for (i = crawl->start; i < crawl->foldp; i++)
44 if (strcmp(fold, crawl->folders[i]) < 0) {
45 for (j = crawl->foldp - 1; j >= i; j--)
46 crawl->folders[j + 1] = crawl->folders[j];
48 crawl->folders[i] = fold;
53 crawl->folders[crawl->foldp++] = fold;
57 add_children(char *name, struct crawl_context *crawl)
65 if (!(dd = opendir(name))) {
66 admonish(name, "unable to read directory ");
70 if (strcmp(name, ".") == 0) {
73 prefix = concat(name, "/", (void *)NULL);
76 while ((dp = readdir(dd))) {
78 ** If the system supports it, try to skip processing of
79 ** children we know are not directories or symlinks.
82 #if defined(HAVE_STRUCT_DIRENT_D_TYPE)
83 if (dp->d_type == DT_DIR) {
85 } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) {
89 if (strcmp(dp->d_name, ".")==0 ||
90 strcmp(dp->d_name, "..")==0) {
93 child = concat(prefix, dp->d_name, (void *)NULL);
95 ** If we have no d_type or d_type is DT_LNK or DT_UNKNOWN,
96 ** stat the child to see what it is.
98 if (child_is_folder == -1) {
99 child_is_folder = (stat(child, &st) != -1 && S_ISDIR(st.st_mode));
101 if (child_is_folder) {
102 /* add_folder saves child in the list, don't free it */
103 add_folder(child, crawl);
114 crawl_folders_body(struct crawl_context *crawl, char *dir,
115 crawl_callback_t *callback, void *baton)
118 int os = crawl->start;
119 int of = crawl->foldp;
121 crawl->start = crawl->foldp;
123 add_children(dir, crawl);
125 for (i = crawl->start; i < crawl->foldp; i++) {
126 char *fold = crawl->folders[i];
127 int crawl_children = 1;
129 if (callback != NULL) {
130 crawl_children = callback(fold, baton);
133 if (crawl_children) {
134 crawl_folders_body(crawl, fold, callback, baton);
143 crawl_folders(char *dir, crawl_callback_t *callback, void *baton)
145 struct crawl_context *crawl = mh_xmalloc(sizeof(*crawl));
146 crawl->max = CRAWL_NUMFOLDERS;
147 crawl->total = crawl->start = crawl->foldp = 0;
148 crawl->folders = mh_xmalloc(crawl->max * sizeof(*crawl->folders));
150 crawl_folders_body(crawl, dir, callback, baton);
153 ** Note that we "leak" the folder names, on the assumption that the
154 ** caller is using them.
156 free(crawl->folders);