nmh-workers
[Top] [All Lists]

[Nmh-workers] [PATCH] Extract folder crawling from uip/folder.c

2008-08-06 17:51:30
The goal is to call this from new.c as an alternative to the
.folders file.

=== modified file 'ChangeLog'
--- ChangeLog   2008-08-05 23:15:07 +0000
+++ ChangeLog   2008-08-07 00:16:56 +0000
@@ -1,3 +1,13 @@
+2008-08-06  Eric Gillespie  <epg(_at_)pretzelnet(_dot_)org>
+
+       * h/Makefile.in, h/crawl_folders.h, sbr/Makefile.in,
+       sbr/crawl_folders.c, uip/folder.c: Extract the folder crawling
+       code from folder.c into new crawl_folders function, using a
+       callback to assemble the folder info in folder.c.  Drop compare
+       function and use strcmp instead.  Rename addfold and addir to
+       add_folder and add_children (add dir vs. add folder?
+       confusing names).
+
 2008-08-05  Eric Gillespie  <epg(_at_)pretzelnet(_dot_)org>
 
        * uip/folder.c: chdir(nmhdir) in main rather than in dodir, which

=== modified file 'h/Makefile.in'
--- h/Makefile.in       2008-08-05 23:13:06 +0000
+++ h/Makefile.in       2008-08-06 23:29:50 +0000
@@ -10,7 +10,7 @@
 VPATH  = @srcdir@
 
 # header files included in distribution
-HDRS =         addrsbr.h aliasbr.h dropsbr.h fmt_compile.h fmt_scan.h          
\
+HDRS =         addrsbr.h aliasbr.h crawl_folders.h dropsbr.h fmt_compile.h 
fmt_scan.h \
        md5.h mf.h mh.h mhcachesbr.h mhparse.h mime.h msh.h mts.h       \
        netdb.h nmh.h nntp.h picksbr.h popsbr.h prototypes.h rcvmail.h  \
        scansbr.h signals.h tws.h vmhsbr.h utils.h

=== added file 'h/crawl_folders.h'
--- h/crawl_folders.h   1970-01-01 00:00:00 +0000
+++ h/crawl_folders.h   2008-08-06 23:31:05 +0000
@@ -0,0 +1,19 @@
+
+/*
+ * crawl_folders.h -- crawl folder hierarchy
+ *
+ * $Id$
+ */
+
+#define CRAWL_NUMFOLDERS 100
+
+/* Callbacks return non-zero if crawl_folders should crawl the children of
+ * `folder'.  Callbacks need not duplicate folder, as crawl_folders does not
+ * free it. */
+typedef int (crawl_callback_t)(char *folder, void *baton);
+
+/* Crawl the folder hierarchy rooted at the relative path `dir'.  For each
+ * folder, pass `callback' the folder name (as a path relative to the current
+ * directory) and `baton'; the callback may direct crawl_folders not to crawl
+ * its children; see above. */
+void crawl_folders (char *dir, crawl_callback_t *callback, void *baton);

=== modified file 'sbr/Makefile.in'
--- sbr/Makefile.in     2008-08-05 23:13:06 +0000
+++ sbr/Makefile.in     2008-08-06 23:30:15 +0000
@@ -58,7 +58,8 @@
        check_charset.c client.c closefds.c concat.c context_del.c      \
        context_find.c context_foil.c context_read.c                    \
        context_replace.c context_save.c copy.c                         \
-       copyip.c cpydata.c cpydgst.c discard.c done.c dtime.c dtimep.c  \
+       copyip.c cpydata.c cpydgst.c crawl_folders.c                    \
+       discard.c done.c dtime.c dtimep.c                               \
        error.c ext_hook.c fdcompare.c folder_addmsg.c folder_delmsgs.c \
        folder_free.c folder_pack.c folder_read.c                       \
        folder_realloc.c gans.c getans.c getanswer.c                    \

=== added file 'sbr/crawl_folders.c'
--- sbr/crawl_folders.c 1970-01-01 00:00:00 +0000
+++ sbr/crawl_folders.c 2008-08-06 23:41:08 +0000
@@ -0,0 +1,151 @@
+
+/*
+ * crawl_folders.c -- crawl folder hierarchy
+ *
+ * $Id$
+ *
+ * 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);
+}

=== modified file 'uip/folder.c'
--- uip/folder.c        2008-08-05 23:15:07 +0000
+++ uip/folder.c        2008-08-07 00:07:29 +0000
@@ -12,6 +12,7 @@
  */
 
 #include <h/mh.h>
+#include <h/crawl_folders.h>
 #include <h/utils.h>
 #include <errno.h>
 
@@ -78,22 +79,10 @@
 
 static int total_folders = 0;  /* total number of folders                  */
 
-static int start = 0;
-static int foldp = 0;
-
 static char *nmhdir;
 static char *stack = "Folder-Stack";
 static char folder[BUFSIZ];
 
-#define NUMFOLDERS 100
-
-/*
- * This is how many folders we currently can hold in the array
- * `folds'.  We increase this amount by NUMFOLDERS at a time.
- */
-static int maxfolders;
-static char **folds;
-
 /*
  * Structure to hold information about
  * folders as we scan them.
@@ -118,13 +107,10 @@
 /*
  * static prototypes
  */
-static void dodir (char *);
 static int get_folder_info (char *, char *);
+static crawl_callback_t get_folder_info_callback;
 static void print_folders (void);
 static int sfold (struct msgs *, char *);
-static void addir (char *);
-static void addfold (char *);
-static int compare (char *, char *);
 static void readonly_folders (void);
 
 
@@ -350,12 +336,8 @@
            done (0);
     }
 
-    /* Allocate initial space to record folder names */
-    maxfolders = NUMFOLDERS;
-    folds = mh_xmalloc (maxfolders * sizeof(char *));
-
     /* Allocate initial space to record folder information */
-    maxFolderInfo = NUMFOLDERS;
+    maxFolderInfo = CRAWL_NUMFOLDERS;
     fi = mh_xmalloc (maxFolderInfo * sizeof(*fi));
 
     /*
@@ -365,7 +347,7 @@
        /*
         * If no folder is given, do them all
         */
-       /* change directory to base of nmh directory for dodir */
+       /* change directory to base of nmh directory for crawl_folders */
        if (chdir (nmhdir) == NOTOK)
            adios (nmhdir, "unable to change directory to");
        if (!argfolder) {
@@ -373,7 +355,7 @@
                admonish (NULL, "no folder given for message %s", msg);
            readonly_folders (); /* do any readonly folders */
            strncpy (folder, (cp = context_find (pfolder)) ? cp : "", 
sizeof(folder));
-           dodir (".");
+           crawl_folders (".", get_folder_info_callback, NULL);
        } else {
            strncpy (folder, argfolder, sizeof(folder));
            if (get_folder_info (argfolder, msg)) {
@@ -385,7 +367,7 @@
             * we still need to list all level-1 sub-folders.
             */
            if (!frecurse)
-               dodir (folder);
+               crawl_folders (folder, get_folder_info_callback, NULL);
        }
     } else {
        strncpy (folder, argfolder ? argfolder : getfolder (1), sizeof(folder));
@@ -412,32 +394,8 @@
     return 1;
 }
 
-/*
- * Base routine for scanning a folder
- */
-
-static void
-dodir (char *dir)
-{
-    int i;
-    int os = start;
-    int of = foldp;
-
-    start = foldp;
-
-    addir (dir);
-
-    for (i = start; i < foldp; i++) {
-       get_folder_info (folds[i], NULL);
-       fflush (stdout);
-    }
-
-    start = os;
-    foldp = of;
-}
-
 static int
-get_folder_info (char *fold, char *msg)
+get_folder_info_body (char *fold, char *msg, int *crawl_children)
 {
     int        i, retval = 1;
     struct msgs *mp = NULL;
@@ -449,7 +407,7 @@
      * for folder information
      */
     if (total_folders >= maxFolderInfo) {
-       maxFolderInfo += NUMFOLDERS;
+       maxFolderInfo += CRAWL_NUMFOLDERS;
        fi = mh_xrealloc (fi, maxFolderInfo * sizeof(*fi));
     }
 
@@ -493,8 +451,32 @@
        folder_free (mp); /* free folder/message structure */
     }
 
-    if (frecurse && (fshort || fi[i].others) && (fi[i].error == 0))
-       dodir (fold);
+    *crawl_children = (frecurse && (fshort || fi[i].others)
+                      && (fi[i].error == 0));
+    return retval;
+}
+
+static int
+get_folder_info_callback (char *fold, void *baton)
+{
+    int crawl_children;
+    get_folder_info_body (fold, NULL, &crawl_children);
+    fflush (stdout);
+    return crawl_children;
+}
+
+static int
+get_folder_info (char *fold, char *msg)
+{
+    int crawl_children;
+    int retval;
+
+    retval = get_folder_info_body (fold, msg, &crawl_children);
+
+    if (crawl_children) {
+       crawl_folders (fold, get_folder_info_callback, NULL);
+    }
+
     return retval;
 }
 
@@ -654,99 +636,6 @@
 }
 
 
-static void
-addir (char *name)
-{
-    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) {
-           /* addfold saves child in the list, don't free it */
-           addfold (child);
-       } else {
-           free (child);
-       }
-    }
-
-    closedir (dd);
-    free(prefix);
-}
-
-/*
- * Add the folder name into the
- * list in a sorted fashion.
- */
-
-static void
-addfold (char *fold)
-{
-    register int i, j;
-
-    /* if necessary, reallocate the space for folder names */
-    if (foldp >= maxfolders) {
-       maxfolders += NUMFOLDERS;
-       folds = mh_xrealloc (folds, maxfolders * sizeof(char *));
-    }
-
-    for (i = start; i < foldp; i++)
-       if (compare (fold, folds[i]) < 0) {
-           for (j = foldp - 1; j >= i; j--)
-               folds[j + 1] = folds[j];
-           foldp++;
-           folds[i] = fold;
-           return;
-       }
-
-    folds[foldp++] = fold;
-}
-
-
-static int
-compare (char *s1, char *s2)
-{
-    register int i;
-
-    while (*s1 || *s2)
-       if ((i = *s1++ - *s2++))
-           return i;
-
-    return 0;
-}
-
 /*
  * Do the read only folders
  */



_______________________________________________
Nmh-workers mailing list
Nmh-workers(_at_)nongnu(_dot_)org
http://lists.nongnu.org/mailman/listinfo/nmh-workers

<Prev in Thread] Current Thread [Next in Thread>