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>
13 struct crawl_context {
15 ** how many folders we currently can hold in the array
16 ** `folders', increased by CRAWL_NUMFOLDERS at a time
18 int total; /* how many `folders' actually has */
19 char **folders; /* the array of folders */
25 ** Add the folder name into the
26 ** list in a sorted fashion.
30 add_folder(char *fold, struct crawl_context *crawl)
34 /* if necessary, reallocate the space for folder names */
35 if (crawl->foldp >= crawl->max) {
36 crawl->max += CRAWL_NUMFOLDERS;
37 crawl->folders = mh_xrealloc(crawl->folders,
38 crawl->max * sizeof(char *));
41 for (i = crawl->start; i < crawl->foldp; i++)
42 if (strcmp(fold, crawl->folders[i]) < 0) {
43 for (j = crawl->foldp - 1; j >= i; j--)
44 crawl->folders[j + 1] = crawl->folders[j];
46 crawl->folders[i] = fold;
51 crawl->folders[crawl->foldp++] = fold;
55 add_children(char *name, struct crawl_context *crawl)
63 if (!(dd = opendir(name))) {
64 admonish(name, "unable to read directory ");
68 if (strcmp(name, ".") == 0) {
71 prefix = concat(name, "/", (void *)NULL);
74 while ((dp = readdir(dd))) {
76 ** If the system supports it, try to skip processing of
77 ** children we know are not directories or symlinks.
80 #if defined(HAVE_STRUCT_DIRENT_D_TYPE)
81 if (dp->d_type == DT_DIR) {
83 } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) {
87 if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) {
90 child = concat(prefix, dp->d_name, (void *)NULL);
92 ** If we have no d_type or d_type is DT_LNK or DT_UNKNOWN,
93 ** stat the child to see what it is.
95 if (child_is_folder == -1) {
96 child_is_folder = (stat(child, &st) != -1 && S_ISDIR(st.st_mode));
98 if (child_is_folder) {
99 /* add_folder saves child in the list, don't free it */
100 add_folder(child, crawl);
111 crawl_folders_body(struct crawl_context *crawl, char *dir,
112 crawl_callback_t *callback, void *baton)
115 int os = crawl->start;
116 int of = crawl->foldp;
118 crawl->start = crawl->foldp;
120 add_children(dir, crawl);
122 for (i = crawl->start; i < crawl->foldp; i++) {
123 char *fold = crawl->folders[i];
124 int crawl_children = 1;
126 if (callback != NULL) {
127 crawl_children = callback(fold, baton);
130 if (crawl_children) {
131 crawl_folders_body(crawl, fold, callback, baton);
140 crawl_folders(char *dir, crawl_callback_t *callback, void *baton)
142 struct crawl_context *crawl = mh_xmalloc(sizeof(*crawl));
143 crawl->max = CRAWL_NUMFOLDERS;
144 crawl->total = crawl->start = crawl->foldp = 0;
145 crawl->folders = mh_xmalloc(crawl->max * sizeof(*crawl->folders));
147 crawl_folders_body(crawl, dir, callback, baton);
150 ** Note that we "leak" the folder names, on the assumption that the
151 ** caller is using them.
153 free(crawl->folders);