X-Git-Url: https://diplodocus.org/git/nmh/blobdiff_plain/0cebd8284370988c8b1807ef2544bd80804d074e..63621a81d16ab743de6b57d47578a9a2c670ad22:/uip/flist.c diff --git a/uip/flist.c b/uip/flist.c index 36be1ed2..f40f010d 100644 --- a/uip/flist.c +++ b/uip/flist.c @@ -1,5 +1,4 @@ -/* - * flist.c -- list nmh folders containing messages +/* flist.c -- list nmh folders containing messages * -- in a given sequence * * originally by @@ -12,15 +11,11 @@ * control laws. This software is made available AS IS, and Xerox Corporation * makes no warranty about the software, its performance or its conformity to * any specification. - * - * $Id$ */ #include #include - -#define FALSE 0 -#define TRUE 1 +#include "sbr/m_maildir.h" /* * We allocate space to record the names of folders @@ -29,54 +24,45 @@ #define MAXFOLDERS 100 -static struct swit switches[] = { -#define SEQSW 0 - { "sequence name", 0 }, -#define ALLSW 1 - { "all", 0 }, -#define NOALLSW 2 - { "noall", 0 }, -#define RECURSE 3 - { "recurse", 0 }, -#define NORECURSE 4 - { "norecurse", 0 }, -#define SHOWZERO 5 - { "showzero", 0 }, -#define NOSHOWZERO 6 - { "noshowzero", 0 }, -#define ALPHASW 7 - { "alpha", 0 }, -#define NOALPHASW 8 - { "noalpha", 0 }, -#define FASTSW 9 - { "fast", 0 }, -#define NOFASTSW 10 - { "nofast", 0 }, -#define TOTALSW 11 - { "total", -5 }, -#define NOTOTALSW 12 - { "nototal", -7 }, -#define VERSIONSW 13 - { "version", 0 }, -#define HELPSW 14 - { "help", 0 }, - { NULL, 0 } -}; +#define FLIST_SWITCHES \ + X("sequence name", 0, SEQSW) \ + X("all", 0, ALLSW) \ + X("noall", 0, NOALLSW) \ + X("recurse", 0, RECURSE) \ + X("norecurse", 0, NORECURSE) \ + X("showzero", 0, SHOWZERO) \ + X("noshowzero", 0, NOSHOWZERO) \ + X("alpha", 0, ALPHASW) \ + X("noalpha", 0, NOALPHASW) \ + X("fast", 0, FASTSW) \ + X("nofast", 0, NOFASTSW) \ + X("total", -5, TOTALSW) \ + X("nototal", -7, NOTOTALSW) \ + X("version", 0, VERSIONSW) \ + X("help", 0, HELPSW) \ + +#define X(sw, minchars, id) id, +DEFINE_SWITCH_ENUM(FLIST); +#undef X + +#define X(sw, minchars, id) { sw, minchars, id }, +DEFINE_SWITCH_ARRAY(FLIST, switches); +#undef X struct Folder { char *name; /* name of folder */ int priority; int error; /* error == 1 for unreadable folder */ int nMsgs; /* number of messages in folder */ - int nSeq[NUMATTRS]; /* number of messages in each sequence */ - int private[NUMATTRS]; /* is given sequence, public or private */ + ivector_t nSeq; /* number of messages in each sequence */ + ivector_t private; /* is given sequence, public or private */ }; static struct Folder *orders = NULL; static int nOrders = 0; static int nOrdersAlloced = 0; static struct Folder *folders = NULL; -static int nFolders = 0; +static unsigned int nFolders = 0; static int nFoldersAlloced = 0; /* info on folders to search */ @@ -85,14 +71,13 @@ static int numfolders; static int maxfolders; /* info on sequences to search for */ -static char *sequencesToDo[NUMATTRS]; -static int numsequences; - -static int all = FALSE; /* scan all folders in top level? */ -static int alphaOrder = FALSE; /* want alphabetical order only */ -static int recurse = FALSE; /* show nested folders? */ -static int showzero = TRUE; /* show folders even if no messages in seq? */ -static int Total = TRUE; /* display info on number of messages in * +static svector_t sequencesToDo; + +static bool all; /* scan all folders in top level? */ +static bool alphaOrder; /* want alphabetical order only */ +static bool recurse; /* show nested folders? */ +static bool showzero = true; /* show folders even if no messages in seq? */ +static bool Total = true; /* display info on number of messages in * sequence found, and total num messages */ static char curfolder[BUFSIZ]; /* name of the current folder */ @@ -105,17 +90,17 @@ static char *nmhdir; /* base nmh mail directory */ typedef int (*qsort_comp) (const void *, const void *); /* - * prototypes + * static prototypes */ -int CompareFolders(struct Folder *, struct Folder *); -void GetFolderOrder(void); -void ScanFolders(void); -int AddFolder(char *, int); -void BuildFolderList(char *, int); -void BuildFolderListRecurse(char *, struct stat *, int); -void PrintFolders(void); -void AllocFolders(struct Folder **, int *, int); -int AssignPriority(char *); +static int CompareFolders(struct Folder *, struct Folder *); +static void GetFolderOrder(void); +static void ScanFolders(void); +static int AddFolder(char *, int); +static void BuildFolderList(char *, int); +static void BuildFolderListRecurse(char *, struct stat *, int); +static void PrintFolders(void); +static void AllocFolders(struct Folder **, int *, int); +static int AssignPriority(char *); static void do_readonly_folders(void); @@ -127,20 +112,13 @@ main(int argc, char **argv) char **arguments; char buf[BUFSIZ]; -#ifdef LOCALE - setlocale(LC_ALL, ""); -#endif - invo_name = r1bindex(argv[0], '/'); - - /* read user profile/context */ - context_read(); + if (nmh_init(argv[0], 1)) { return 1; } /* * If program was invoked with name ending * in `s', then add switch `-all'. */ - if (argv[0][strlen (argv[0]) - 1] == 's') - all = TRUE; + all = has_suffix_c(argv[0], 's'); arguments = getarguments (invo_name, argc, argv, 1); argp = arguments; @@ -151,7 +129,7 @@ main(int argc, char **argv) foldersToDo = (char **) mh_xmalloc ((size_t) (maxfolders * sizeof(*foldersToDo))); /* no sequences yet */ - numsequences = 0; + sequencesToDo = svector_create (0); /* parse arguments */ while ((cp = *argp++)) { @@ -167,57 +145,54 @@ main(int argc, char **argv) snprintf(buf, sizeof(buf), "%s [+folder1 [+folder2 ...]][switches]", invo_name); print_help(buf, switches, 1); - done(1); + done(0); case VERSIONSW: print_version(invo_name); - done (1); + done (0); case SEQSW: if (!(cp = *argp++) || *cp == '-') adios (NULL, "missing argument to %s", argp[-2]); - /* check if too many sequences specified */ - if (numsequences >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) specified", NUMATTRS); - sequencesToDo[numsequences++] = cp; + svector_push_back (sequencesToDo, cp); break; case ALLSW: - all = TRUE; + all = true; break; case NOALLSW: - all = FALSE; + all = false; break; case SHOWZERO: - showzero = TRUE; + showzero = true; break; case NOSHOWZERO: - showzero = FALSE; + showzero = false; break; case ALPHASW: - alphaOrder = TRUE; + alphaOrder = true; break; case NOALPHASW: - alphaOrder = FALSE; + alphaOrder = false; break; case NOFASTSW: case TOTALSW: - Total = TRUE; + Total = true; break; case FASTSW: case NOTOTALSW: - Total = FALSE; + Total = false; break; case RECURSE: - recurse = TRUE; + recurse = true; break; case NORECURSE: - recurse = FALSE; + recurse = false; break; } } else { @@ -232,7 +207,7 @@ main(int argc, char **argv) } if (*cp == '+' || *cp == '@') { foldersToDo[numfolders++] = - path (cp + 1, *cp == '+' ? TFOLDER : TSUBCWF); + pluspath (cp); } else foldersToDo[numfolders++] = cp; } @@ -250,23 +225,16 @@ main(int argc, char **argv) /* * If we didn't specify any sequences, we search * for the "Unseen-Sequence" profile entry and use - * all the sequences defined there. We check to - * make sure that the Unseen-Sequence entry doesn't - * contain more than NUMATTRS sequences. + * all the sequences defined there. */ - if (numsequences == 0) { + if (svector_size (sequencesToDo) == 0) { if ((cp = context_find(usequence)) && *cp) { char **ap, *dp; - dp = getcpy(cp); + dp = mh_xstrdup(cp); ap = brkstring (dp, " ", "\n"); - for (; ap && *ap; ap++) { - if (numsequences >= NUMATTRS) - adios (NULL, "too many sequences (more than %d) in %s profile entry", - NUMATTRS, usequence); - else - sequencesToDo[numsequences++] = *ap; - } + for (; ap && *ap; ap++) + svector_push_back (sequencesToDo, *ap); } else { adios (NULL, "no sequence specified or %s profile entry found", usequence); } @@ -276,7 +244,9 @@ main(int argc, char **argv) ScanFolders(); qsort(folders, nFolders, sizeof(struct Folder), (qsort_comp) CompareFolders); PrintFolders(); - return done (0); + svector_free (sequencesToDo); + done (0); + return 1; } /* @@ -284,7 +254,7 @@ main(int argc, char **argv) * how to sort folders for output. */ -void +static void GetFolderOrder(void) { char *p, *s; @@ -294,10 +264,10 @@ GetFolderOrder(void) if (!(p = context_find("Flist-Order"))) return; for (;;) { - while (isspace(*p)) + while (isspace((unsigned char) *p)) ++p; s = p; - while (*p && !isspace(*p)) + while (*p && !isspace((unsigned char) *p)) ++p; if (p != s) { /* Found one. */ @@ -316,7 +286,7 @@ GetFolderOrder(void) * Scan all the necessary folders */ -void +static void ScanFolders(void) { int i; @@ -365,7 +335,7 @@ ScanFolders(void) * the top of our search tree. */ -void +static void BuildFolderList(char *dirName, int searchdepth) { struct stat st; @@ -396,10 +366,11 @@ BuildFolderList(char *dirName, int searchdepth) * Recursive building of folder list */ -void +static void BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) { - char *base, *n, name[PATH_MAX]; + char *base, name[PATH_MAX]; + char *n; int nlinks; DIR *dir; struct dirent *dp; @@ -413,6 +384,12 @@ BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) * stat them. But that shouldn't generally be a problem. */ nlinks = s->st_nlink; + if (nlinks == 1) { + /* Disable the optimization under conditions where st_nlink + is set to 1. That happens on Cygwin, for example: + http://cygwin.com/ml/cygwin-apps/2008-08/msg00264.html */ + nlinks = INT_MAX; + } if (!(dir = opendir(dirName))) adios(dirName, "can't open directory"); @@ -433,7 +410,7 @@ BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) /* Check to see if the name of the file is a number * if it is, we assume it's a mail file and skip it */ - for (n = dp->d_name; *n && isdigit(*n); n++); + for (n = dp->d_name; isdigit((unsigned char)*n); n++); if (!*n) continue; strncpy (name, base, sizeof(name) - 2); @@ -461,46 +438,48 @@ BuildFolderListRecurse(char *dirName, struct stat *s, int searchdepth) * messages and the number of messages in each sequence. */ -int +static int AddFolder(char *name, int force) { - int i, msgnum, nonzero; - int seqnum[NUMATTRS], nSeq[NUMATTRS]; + unsigned int i; + int msgnum, nonzero; + ivector_t seqnum = ivector_create (0), nSeq = ivector_create (0); struct Folder *f; struct msgs *mp; + char *cp; /* Read folder and create message structure */ - if (!(mp = folder_read (name))) { + if (!(mp = folder_read (name, 0))) { /* Oops, error occurred. Record it and continue. */ AllocFolders(&folders, &nFoldersAlloced, nFolders + 1); f = &folders[nFolders++]; - f->name = getcpy(name); + f->name = mh_xstrdup(name); f->error = 1; f->priority = AssignPriority(f->name); return 0; } - for (i = 0; i < numsequences; i++) { + for (i = 0; i < svector_size (sequencesToDo); i++) { /* Convert sequences to their sequence numbers */ - if (sequencesToDo[i]) - seqnum[i] = seq_getnum(mp, sequencesToDo[i]); + if ((cp = svector_at (sequencesToDo, i))) + ivector_push_back (seqnum, seq_getnum(mp, cp)); else - seqnum[i] = -1; + ivector_push_back (seqnum, -1); /* Now count messages in this sequence */ - nSeq[i] = 0; - if (mp->nummsg > 0 && seqnum[i] != -1) { + ivector_push_back (nSeq, 0); + if (mp->nummsg > 0 && ivector_at (seqnum, i) != -1) { for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++) { - if (in_sequence(mp, seqnum[i], msgnum)) - nSeq[i]++; + if (in_sequence(mp, ivector_at (seqnum, i), msgnum)) + (*ivector_atp (nSeq, i))++; } } } /* Check if any of the sequence checks were nonzero */ nonzero = 0; - for (i = 0; i < numsequences; i++) { - if (nSeq[i] > 0) { + for (i = 0; i < svector_size (sequencesToDo); i++) { + if (ivector_at (nSeq, i) > 0) { nonzero = 1; break; } @@ -510,18 +489,25 @@ AddFolder(char *name, int force) /* save general folder information */ AllocFolders(&folders, &nFoldersAlloced, nFolders + 1); f = &folders[nFolders++]; - f->name = getcpy(name); + f->name = mh_xstrdup(name); f->nMsgs = mp->nummsg; + f->nSeq = ivector_create (0); + f->private = ivector_create (0); f->error = 0; f->priority = AssignPriority(f->name); /* record the sequence information */ - for (i = 0; i < numsequences; i++) { - f->nSeq[i] = nSeq[i]; - f->private[i] = (seqnum[i] != -1) ? is_seq_private(mp, seqnum[i]) : 0; + for (i = 0; i < svector_size (sequencesToDo); i++) { + *ivector_atp (f->nSeq, i) = ivector_at (nSeq, i); + ivector_push_back (f->private, + ivector_at (seqnum, i) != -1 + ? is_seq_private(mp, ivector_at (seqnum, i)) + : 0); } } + ivector_free (nSeq); + ivector_free (seqnum); folder_free (mp); /* free folder/message structure */ return 1; } @@ -530,17 +516,17 @@ AddFolder(char *name, int force) * Print the folder/sequence information */ -void +static void PrintFolders(void) { char tmpname[BUFSIZ]; - int i, j, len, has_private = 0; - int maxfolderlen = 0, maxseqlen = 0; + unsigned int i, j, len, has_private = 0; + unsigned int maxfolderlen = 0, maxseqlen = 0; int maxnum = 0, maxseq = 0; if (!Total) { for (i = 0; i < nFolders; i++) - printf("%s\n", folders[i].name); + puts(folders[i].name); return; } @@ -561,26 +547,27 @@ PrintFolders(void) if (folders[i].nMsgs > maxnum) maxnum = folders[i].nMsgs; - for (j = 0; j < numsequences; j++) { + for (j = 0; j < svector_size (sequencesToDo); j++) { /* find maximum width of sequence name */ - len = strlen (sequencesToDo[j]); - if ((folders[i].nSeq[j] > 0 || showzero) && (len > maxseqlen)) + len = strlen (svector_at (sequencesToDo, j)); + if ((ivector_at (folders[i].nSeq, j) > 0 || showzero) && + (len > maxseqlen)) maxseqlen = len; /* find the maximum number of messages in sequence */ - if (folders[i].nSeq[j] > maxseq) - maxseq = folders[i].nSeq[j]; + if (ivector_at (folders[i].nSeq, j) > maxseq) + maxseq = ivector_at (folders[i].nSeq, j); /* check if this sequence is private in any of the folders */ - if (folders[i].private[j]) + if (ivector_at (folders[i].private, j)) has_private = 1; } } /* Now print all the folder/sequence information */ for (i = 0; i < nFolders; i++) { - for (j = 0; j < numsequences; j++) { - if (folders[i].nSeq[j] > 0 || showzero) { + for (j = 0; j < svector_size (sequencesToDo); j++) { + if (ivector_at (folders[i].nSeq, j) > 0 || showzero) { /* Add `+' to end of name of current folder */ if (strcmp(curfolder, folders[i].name)) snprintf(tmpname, sizeof(tmpname), "%s", folders[i].name); @@ -594,9 +581,10 @@ PrintFolders(void) printf("%-*s has %*d in sequence %-*s%s; out of %*d\n", maxfolderlen+1, tmpname, - num_digits(maxseq), folders[i].nSeq[j], - maxseqlen, sequencesToDo[j], - !has_private ? "" : folders[i].private[j] ? " (private)" : " ", + num_digits(maxseq), ivector_at (folders[i].nSeq, j), + maxseqlen, svector_at (sequencesToDo, j), + !has_private ? "" : ivector_at (folders[i].private, j) + ? " (private)" : " ", num_digits(maxnum), folders[i].nMsgs); } } @@ -607,20 +595,19 @@ PrintFolders(void) * Put them in priority order. */ -int +static int CompareFolders(struct Folder *f1, struct Folder *f2) { if (!alphaOrder && f1->priority != f2->priority) return f1->priority - f2->priority; - else - return strcmp(f1->name, f2->name); + return strcmp(f1->name, f2->name); } /* * Make sure we have at least n folders allocated. */ -void +static void AllocFolders(struct Folder **f, int *nfa, int n) { if (n <= *nfa) @@ -638,7 +625,7 @@ AllocFolders(struct Folder **f, int *nfa, int n) * Return the priority for a name. The highest comes from an exact match. * After that, the longest match (then first) assigns the priority. */ -int +static int AssignPriority(char *name) { int i, ol, nl; @@ -676,7 +663,7 @@ do_readonly_folders (void) { int atrlen; char atrcur[BUFSIZ]; - register struct node *np; + struct node *np; snprintf (atrcur, sizeof(atrcur), "atr-%s-", current); atrlen = strlen (atrcur);