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 {
14 int max; /* how many folders we currently can hold in the array
15 * `folders', increased by CRAWL_NUMFOLDERS at a time */
16 int total; /* how many `folders' actually has */
17 char **folders; /* the array of folders */
23 * Add the folder name into the
24 * list in a sorted fashion.
28 add_folder (char *fold, struct crawl_context *crawl)
32 /* if necessary, reallocate the space for folder names */
33 if (crawl->foldp >= crawl->max) {
34 crawl->max += CRAWL_NUMFOLDERS;
35 crawl->folders = mh_xrealloc (crawl->folders,
36 crawl->max * sizeof(char *));
39 for (i = crawl->start; i < crawl->foldp; i++)
40 if (strcmp (fold, crawl->folders[i]) < 0) {
41 for (j = crawl->foldp - 1; j >= i; j--)
42 crawl->folders[j + 1] = crawl->folders[j];
44 crawl->folders[i] = fold;
49 crawl->folders[crawl->foldp++] = fold;
53 add_children (char *name, struct crawl_context *crawl)
61 if (!(dd = opendir (name))) {
62 admonish (name, "unable to read directory ");
66 if (strcmp (name, ".") == 0) {
69 prefix = concat (name, "/", (void *)NULL);
72 while ((dp = readdir (dd))) {
73 /* If the system supports it, try to skip processing of
74 * children we know are not directories or symlinks. */
76 #if defined(HAVE_STRUCT_DIRENT_D_TYPE)
77 if (dp->d_type == DT_DIR) {
79 } else if (dp->d_type != DT_LNK && dp->d_type != DT_UNKNOWN) {
83 if (!strcmp (dp->d_name, ".") || !strcmp (dp->d_name, "..")) {
86 child = concat (prefix, dp->d_name, (void *)NULL);
87 /* If we have no d_type or d_type is DT_LNK or DT_UNKNOWN, stat the
88 * child to see what it is. */
89 if (child_is_folder == -1) {
90 child_is_folder = (stat (child, &st) != -1 && S_ISDIR(st.st_mode));
92 if (child_is_folder) {
93 /* add_folder saves child in the list, don't free it */
94 add_folder (child, crawl);
105 crawl_folders_body (struct crawl_context *crawl, char *dir,
106 crawl_callback_t *callback, void *baton)
109 int os = crawl->start;
110 int of = crawl->foldp;
112 crawl->start = crawl->foldp;
114 add_children (dir, crawl);
116 for (i = crawl->start; i < crawl->foldp; i++) {
117 char *fold = crawl->folders[i];
118 int crawl_children = 1;
120 if (callback != NULL) {
121 crawl_children = callback (fold, baton);
124 if (crawl_children) {
125 crawl_folders_body (crawl, fold, callback, baton);
134 crawl_folders (char *dir, crawl_callback_t *callback, void *baton)
136 struct crawl_context *crawl = mh_xmalloc (sizeof(*crawl));
137 crawl->max = CRAWL_NUMFOLDERS;
138 crawl->total = crawl->start = crawl->foldp = 0;
139 crawl->folders = mh_xmalloc (crawl->max * sizeof(*crawl->folders));
141 crawl_folders_body (crawl, dir, callback, baton);
143 /* Note that we "leak" the folder names, on the assumption that the caller
145 free (crawl->folders);