for-each-ref: fix off by one read.
[gitweb.git] / builtin-mailsplit.c
index 3bca855aae857cde15f2a249f8e0a5c30b3e7d82..10fa1773401d6474d8e6c88065e3a992690ae0f8 100644 (file)
@@ -6,9 +6,10 @@
  */
 #include "cache.h"
 #include "builtin.h"
+#include "path-list.h"
 
 static const char git_mailsplit_usage[] =
-"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>...";
+"git-mailsplit [-d<prec>] [-f<n>] [-b] -o<directory> <mbox>|<Maildir>...";
 
 static int is_from_line(const char *line, int len)
 {
@@ -96,44 +97,113 @@ static int split_one(FILE *mbox, const char *name, int allow_bare)
        exit(1);
 }
 
-int split_mbox(const char **mbox, const char *dir, int allow_bare, int nr_prec, int skip)
+static int populate_maildir_list(struct path_list *list, const char *path)
 {
-       char *name = xmalloc(strlen(dir) + 2 + 3 * sizeof(skip));
+       DIR *dir;
+       struct dirent *dent;
+       char name[PATH_MAX];
+       char *subs[] = { "cur", "new", NULL };
+       char **sub;
+
+       for (sub = subs; *sub; ++sub) {
+               snprintf(name, sizeof(name), "%s/%s", path, *sub);
+               if ((dir = opendir(name)) == NULL) {
+                       if (errno == ENOENT)
+                               continue;
+                       error("cannot opendir %s (%s)", name, strerror(errno));
+                       return -1;
+               }
+
+               while ((dent = readdir(dir)) != NULL) {
+                       if (dent->d_name[0] == '.')
+                               continue;
+                       snprintf(name, sizeof(name), "%s/%s", *sub, dent->d_name);
+                       path_list_insert(name, list);
+               }
+
+               closedir(dir);
+       }
+
+       return 0;
+}
+
+static int split_maildir(const char *maildir, const char *dir,
+       int nr_prec, int skip)
+{
+       char file[PATH_MAX];
+       char name[PATH_MAX];
        int ret = -1;
+       int i;
+       struct path_list list = {NULL, 0, 0, 1};
 
-       while (*mbox) {
-               const char *file = *mbox++;
-               FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
-               int file_done = 0;
+       if (populate_maildir_list(&list, maildir) < 0)
+               goto out;
 
-               if ( !f ) {
-                       error("cannot open mbox %s", file);
+       for (i = 0; i < list.nr; i++) {
+               FILE *f;
+               snprintf(file, sizeof(file), "%s/%s", maildir, list.items[i].path);
+               f = fopen(file, "r");
+               if (!f) {
+                       error("cannot open mail %s (%s)", file, strerror(errno));
                        goto out;
                }
 
                if (fgets(buf, sizeof(buf), f) == NULL) {
-                       if (f == stdin)
-                               break; /* empty stdin is OK */
-                       error("cannot read mbox %s", file);
+                       error("cannot read mail %s (%s)", file, strerror(errno));
                        goto out;
                }
 
-               while (!file_done) {
-                       sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
-                       file_done = split_one(f, name, allow_bare);
+               sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+               split_one(f, name, 1);
+
+               fclose(f);
+       }
+
+       ret = skip;
+out:
+       path_list_clear(&list, 1);
+       return ret;
+}
+
+static int split_mbox(const char *file, const char *dir, int allow_bare,
+                     int nr_prec, int skip)
+{
+       char name[PATH_MAX];
+       int ret = -1;
+
+       FILE *f = !strcmp(file, "-") ? stdin : fopen(file, "r");
+       int file_done = 0;
+
+       if (!f) {
+               error("cannot open mbox %s", file);
+               goto out;
+       }
+
+       if (fgets(buf, sizeof(buf), f) == NULL) {
+               /* empty stdin is OK */
+               if (f != stdin) {
+                       error("cannot read mbox %s", file);
+                       goto out;
                }
+               file_done = 1;
+       }
 
-               if (f != stdin)
-                       fclose(f);
+       while (!file_done) {
+               sprintf(name, "%s/%0*d", dir, nr_prec, ++skip);
+               file_done = split_one(f, name, allow_bare);
        }
+
+       if (f != stdin)
+               fclose(f);
+
        ret = skip;
 out:
-       free(name);
        return ret;
 }
+
 int cmd_mailsplit(int argc, const char **argv, const char *prefix)
 {
-       int nr = 0, nr_prec = 4, ret;
+       int nr = 0, nr_prec = 4, num = 0;
        int allow_bare = 0;
        const char *dir = NULL;
        const char **argp;
@@ -186,9 +256,41 @@ int cmd_mailsplit(int argc, const char **argv, const char *prefix)
                        argp = stdin_only;
        }
 
-       ret = split_mbox(argp, dir, allow_bare, nr_prec, nr);
-       if (ret != -1)
-               printf("%d\n", ret);
+       while (*argp) {
+               const char *arg = *argp++;
+               struct stat argstat;
+               int ret = 0;
+
+               if (arg[0] == '-' && arg[1] == 0) {
+                       ret = split_mbox(arg, dir, allow_bare, nr_prec, nr);
+                       if (ret < 0) {
+                               error("cannot split patches from stdin");
+                               return 1;
+                       }
+                       num += (ret - nr);
+                       nr = ret;
+                       continue;
+               }
+
+               if (stat(arg, &argstat) == -1) {
+                       error("cannot stat %s (%s)", arg, strerror(errno));
+                       return 1;
+               }
+
+               if (S_ISDIR(argstat.st_mode))
+                       ret = split_maildir(arg, dir, nr_prec, nr);
+               else
+                       ret = split_mbox(arg, dir, allow_bare, nr_prec, nr);
+
+               if (ret < 0) {
+                       error("cannot split patches from %s", arg);
+                       return 1;
+               }
+               num += (ret - nr);
+               nr = ret;
+       }
+
+       printf("%d\n", num);
 
-       return ret == -1;
+       return 0;
 }