]> diplodocus.org Git - nmh/commitdiff
Removed limit on maximum number of sequences in a folder.
authorDavid Levine <levinedl@acm.org>
Sun, 31 Mar 2013 16:45:09 +0000 (11:45 -0500)
committerDavid Levine <levinedl@acm.org>
Sun, 31 Mar 2013 16:45:09 +0000 (11:45 -0500)
Dynamically sized vectors in sbr/vector.c were added to support
this.  Their sizes are limited only by virtual memory.

29 files changed:
Makefile.am
docs/TODO
docs/pending-release-notes
h/mh.h
h/msh.h
man/mark.man
sbr/folder_free.c
sbr/folder_read.c
sbr/folder_realloc.c
sbr/seq_add.c
sbr/seq_bits.c
sbr/seq_del.c
sbr/seq_getnum.c
sbr/seq_print.c
sbr/seq_read.c
sbr/seq_save.c
sbr/vector.c [new file with mode: 0644]
test/sequences/test-mark
uip/flist.c
uip/fmttest.c
uip/mark.c
uip/msh.c
uip/mshcmds.c
uip/new.c
uip/pick.c
uip/rcvstore.c
uip/refile.c
uip/scan.c
uip/sortm.c

index 338bba3..d4d8faa 100644 (file)
@@ -547,8 +547,8 @@ sbr_libmh_a_SOURCES = sbr/addrsbr.c sbr/ambigsw.c sbr/atooi.c sbr/arglist.c \
                      sbr/snprintb.c sbr/ssequal.c \
                      sbr/strindex.c sbr/trimcpy.c sbr/uprf.c sbr/vfgets.c \
                      sbr/fmt_def.c sbr/mf.c sbr/utils.c sbr/ctype-checked.c \
-                     sbr/m_mktemp.c sbr/getansreadline.c config/config.c \
-                     config/version.c
+                     sbr/m_mktemp.c sbr/getansreadline.c sbr/vector.c \
+                     config/config.c config/version.c
 
 ##
 ## Because these files use the definitions in the libmh rule below,
index 75379cd..32173c2 100644 (file)
--- a/docs/TODO
+++ b/docs/TODO
@@ -39,9 +39,6 @@ MAN PAGES
 
 SEQUENCES
 ---------
-* Change so you can have more than 26 sequences.  Unfortunately,
-  given the way that the bit flags for sequences work, this is
-  not easy.
 * Maybe add option gracefully handle empty sequences (-force).
 
 ENVIRONMENT/PROFILE
index db5f13f..a0f5abc 100644 (file)
@@ -51,7 +51,7 @@ NEW FEATURES
 - Added support for Content-Disposition header (RFC 2183) to mhstore(1)
   and mhn(1) when used with -auto.
 - All nmh commands now support transactional locking for sequence files.
-- The per-folder maximum number of sequences is now 59 on LP64 systems.
+- There is no longer a per-folder maximum number of sequences.
 
 ----------------------------
 OBSOLETE/DEPRECATED FEATURES
diff --git a/h/mh.h b/h/mh.h
index c92543c..f5fd66b 100644 (file)
--- a/h/mh.h
+++ b/h/mh.h
@@ -131,35 +131,58 @@ extern struct swit anoyes[];      /* standard yes/no switches */
 
 #define        FBITS "\020\01READONLY\02SEQMOD\03ALLOW_NEW\04OTHERS\05MODIFIED"
 
-/*
- * type for holding the sequence set of a message
- */
-typedef unsigned long seqset_t;
-
 /*
  * first free slot for user defined sequences
  * and attributes
  */
 #define        FFATTRSLOT  5
 
-/*
- * Determine the number of user defined sequences we
- * can have.  The first FFATTRSLOT sequence flags are for
- * internal nmh message flags.
- */
-#define        NUMATTRS  ((sizeof(seqset_t) * Nbby) - FFATTRSLOT)
-
 /*
  * internal messages attributes (sequences)
  */
-#define EXISTS        (1<<0)   /* exists            */
-#define DELETED       (1<<1)   /* deleted           */
-#define SELECTED      (1<<2)   /* selected for use  */
-#define SELECT_EMPTY  (1<<3)   /* "new" message     */
-#define        SELECT_UNSEEN (1<<4)    /* inc/show "unseen" */
+#define EXISTS        (0)      /* exists            */
+#define DELETED       (1)      /* deleted           */
+#define SELECTED      (2)      /* selected for use  */
+#define SELECT_EMPTY  (3)      /* "new" message     */
+#define        SELECT_UNSEEN (4)       /* inc/show "unseen" */
 
 #define        MBITS "\020\01EXISTS\02DELETED\03SELECTED\04NEW\05UNSEEN"
 
+/*
+ * type for holding the sequence set of a message
+ */
+typedef struct bvector *bvector_t;
+
+bvector_t bvector_create (size_t /* initial size in bits, can be 0 */);
+void bvector_copy (bvector_t, bvector_t);
+void bvector_free (bvector_t);
+void bvector_clear (bvector_t, size_t);
+void bvector_clear_all (bvector_t);
+void bvector_set (bvector_t, size_t);
+unsigned int bvector_at (bvector_t, size_t);
+const unsigned long *bvector_bits (bvector_t);
+size_t bvector_maxsize (bvector_t);
+
+struct svector;
+typedef struct svector *svector_t;
+
+svector_t svector_create (size_t);
+void svector_free (svector_t);
+char *svector_push_back (svector_t, char *);
+char *svector_at (svector_t, size_t);
+char **svector_strs (svector_t);
+size_t svector_size (svector_t);
+
+struct ivector;
+typedef struct ivector *ivector_t;
+
+ivector_t ivector_create (size_t);
+void ivector_free (ivector_t);
+int ivector_push_back (ivector_t, int);
+int ivector_at (ivector_t, size_t);
+int *ivector_atp (ivector_t, size_t);
+size_t ivector_size (ivector_t);
+
 /*
  * Primary structure of folder/message information
  */
@@ -178,16 +201,15 @@ struct msgs {
     char *foldpath;    /* Pathname of folder                */
 
     /*
-     * Name of sequences in this folder.  We add an
-     * extra slot, so we can NULL terminate the list.
+     * Name of sequences in this folder.
      */
-    char *msgattrs[NUMATTRS + 1];
+    svector_t msgattrs;
 
     /*
      * bit flags for whether sequence
      * is public (0), or private (1)
      */
-    seqset_t attrstats;
+    bvector_t attrstats;
 
     /*
      * These represent the lowest and highest possible
@@ -198,13 +220,14 @@ struct msgs {
     int        hghoff;
 
     /*
-     * This is an array of seqset_t which we allocate dynamically.
-     * Each seqset_t is a set of bits flags for a particular message.
+     * This is an array of bvector_t which we allocate dynamically.
+     * Each bvector_t is a set of bits flags for a particular message.
      * These bit flags represent general attributes such as
      * EXISTS, SELECTED, etc. as well as track if message is
      * in a particular sequence.
      */
-    seqset_t *msgstats;                /* msg status */
+    size_t num_msgstats;
+    bvector_t *msgstats;       /* msg status */
 
     /*
      * A FILE handle containing an open filehandle for the sequence file
@@ -221,53 +244,59 @@ struct msgs {
 
 /*
  * Amount of space to allocate for msgstats.  Allocate
- * the array to have space for messages numbers lo to hi.
+ * the array to have space for messages numbered lo to hi.
+ * Use MSGSTATNUM to load mp->num_msgstats first.
  */
-#define MSGSTATSIZE(mp,lo,hi) ((size_t) (((hi) - (lo) + 1) * sizeof(*(mp)->msgstats)))
+#define MSGSTATNUM(lo, hi) ((size_t) ((hi) - (lo) + 1))
+#define MSGSTATSIZE(mp) ((mp)->num_msgstats * sizeof *(mp)->msgstats)
 
 /*
  * macros for message and sequence manipulation
  */
-#define clear_msg_flags(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] = 0)
-#define copy_msg_flags(mp,i,j) \
-       ((mp)->msgstats[(i) - mp->lowoff] = (mp)->msgstats[(j) - mp->lowoff])
-#define get_msg_flags(mp,ptr,msgnum)  (*(ptr) = (mp)->msgstats[(msgnum) - mp->lowoff])
-#define set_msg_flags(mp,ptr,msgnum)  ((mp)->msgstats[(msgnum) - mp->lowoff] = *(ptr))
-
-#define does_exist(mp,msgnum)     ((mp)->msgstats[(msgnum) - mp->lowoff] & EXISTS)
-#define unset_exists(mp,msgnum)   ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~EXISTS)
-#define set_exists(mp,msgnum)     ((mp)->msgstats[(msgnum) - mp->lowoff] |= EXISTS)
-
-#define is_selected(mp,msgnum)    ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECTED)
-#define unset_selected(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~SELECTED)
-#define set_selected(mp,msgnum)   ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECTED)
-
-#define is_select_empty(mp,msgnum) ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECT_EMPTY)
+#define msgstat(mp,n) (mp)->msgstats[(n) - mp->lowoff]
+#define clear_msg_flags(mp,msgnum)   bvector_clear_all (msgstat(mp, msgnum))
+#define copy_msg_flags(mp,i,j)       bvector_copy (msgstat(mp,i), msgstat(mp,j))
+#define get_msg_flags(mp,ptr,msgnum) bvector_copy (ptr, msgstat(mp, msgnum))
+#define set_msg_flags(mp,ptr,msgnum) bvector_copy (msgstat(mp, msgnum), ptr)
+
+#define does_exist(mp,msgnum)     bvector_at (msgstat(mp, msgnum), EXISTS)
+#define unset_exists(mp,msgnum)   bvector_clear (msgstat(mp, msgnum), EXISTS)
+#define set_exists(mp,msgnum)     bvector_set (msgstat(mp, msgnum), EXISTS)
+
+#define is_selected(mp,msgnum)    bvector_at (msgstat(mp, msgnum), SELECTED)
+#define unset_selected(mp,msgnum) bvector_clear (msgstat(mp, msgnum), SELECTED)
+#define set_selected(mp,msgnum)   bvector_set (msgstat(mp, msgnum), SELECTED)
+
+#define is_select_empty(mp,msgnum)  \
+        bvector_at (msgstat(mp, msgnum), SELECT_EMPTY)
 #define set_select_empty(mp,msgnum) \
-       ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECT_EMPTY)
+        bvector_set (msgstat(mp, msgnum), SELECT_EMPTY)
 
-#define is_unseen(mp,msgnum)      ((mp)->msgstats[(msgnum) - mp->lowoff] & SELECT_UNSEEN)
-#define unset_unseen(mp,msgnum)   ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~SELECT_UNSEEN)
-#define set_unseen(mp,msgnum)     ((mp)->msgstats[(msgnum) - mp->lowoff] |= SELECT_UNSEEN)
+#define is_unseen(mp,msgnum) \
+        bvector_at (msgstat(mp, msgnum), SELECT_UNSEEN)
+#define unset_unseen(mp,msgnum) \
+        bvector_clear (msgstat(mp, msgnum), SELECT_UNSEEN)
+#define set_unseen(mp,msgnum) \
+        bvector_set (msgstat(mp, msgnum), SELECT_UNSEEN)
 
 /* for msh only */
-#define set_deleted(mp,msgnum)    ((mp)->msgstats[(msgnum) - mp->lowoff] |= DELETED)
+#define set_deleted(mp,msgnum)     bvector_set (msgstat(mp, msgnum), DELETED)
 
 #define in_sequence(mp,seqnum,msgnum) \
-           ((mp)->msgstats[(msgnum) - mp->lowoff] & ((seqset_t)1 << (FFATTRSLOT + seqnum)))
+        bvector_at (msgstat(mp, msgnum), FFATTRSLOT + seqnum)
 #define clear_sequence(mp,seqnum,msgnum) \
-           ((mp)->msgstats[(msgnum) - mp->lowoff] &= ~((seqset_t)1 << (FFATTRSLOT + seqnum)))
+        bvector_clear (msgstat(mp, msgnum), FFATTRSLOT + seqnum)
 #define add_sequence(mp,seqnum,msgnum) \
-           ((mp)->msgstats[(msgnum) - mp->lowoff] |= ((seqset_t)1 << (FFATTRSLOT + seqnum)))
+        bvector_set (msgstat(mp, msgnum), FFATTRSLOT + seqnum)
 
 #define is_seq_private(mp,seqnum) \
-           ((mp)->attrstats & ((seqset_t)1 << (FFATTRSLOT + seqnum)))
+        bvector_at (mp->attrstats, FFATTRSLOT + seqnum)
 #define make_seq_public(mp,seqnum) \
-           ((mp)->attrstats &= ~((seqset_t)1 << (FFATTRSLOT + seqnum)))
+        bvector_clear (mp->attrstats, FFATTRSLOT + seqnum)
 #define make_seq_private(mp,seqnum) \
-           ((mp)->attrstats |= ((seqset_t)1 << (FFATTRSLOT + seqnum)))
+        bvector_set (mp->attrstats, FFATTRSLOT + seqnum)
 #define make_all_public(mp) \
-           ((mp)->attrstats = 0)
+        mp->attrstats = bvector_create(0); bvector_clear_all (mp->attrstats)
 
 /*
  * macros for folder attributes
diff --git a/h/msh.h b/h/msh.h
index 8111003..4e0314d 100644 (file)
--- a/h/msh.h
+++ b/h/msh.h
@@ -22,7 +22,13 @@ struct Cmd {
 #define        MHNCHK 0x0001   /* did nontext check           */
 #define        MHNYES 0x0002   /* .. and known to be non-text */
 
-#define CUR ((seqset_t)1 << (FFATTRSLOT + NUMATTRS - 1))
+/*
+ * Determine the number of user defined sequences we
+ * can have.  The first FFATTRSLOT sequence flags are for
+ * internal nmh message flags.
+ */
+#define        NUMATTRS  (27)
+#define CUR (FFATTRSLOT + NUMATTRS - 1)
 
 #ifdef BPOP
 # define VIRTUAL SELECT_EMPTY
@@ -37,7 +43,7 @@ struct Msg {
     char *m_scanl;
     struct tws m_tb;
     short m_flags;
-    seqset_t m_stats;
+    bvector_t m_stats;
 };
 
 #define        m_bboard_id  m_drop.d_id
index b786c16..6fa455a 100644 (file)
@@ -1,4 +1,4 @@
-.TH MARK %manext1% "March 25, 2013" "%nmhversion%"
+.TH MARK %manext1% "March 31, 2013" "%nmhversion%"
 .\"
 .\" %nmhwarning%
 .\"
@@ -143,7 +143,7 @@ will be listed.  The
 switch does not affect the operation of
 .BR \-list .
 .PP
-The current restrictions on sequences are:
+The restrictions on sequences are:
 .PP
 .IP \(bu 2
 The name used to denote a message sequence must consist of an alphabetic
@@ -152,12 +152,6 @@ be one of the (reserved) message names \*(lqnew\*(rq, \*(lqfirst\*(rq,
 \*(lqlast\*(rq, \*(lqall\*(rq, \*(lqnext\*(rq, or \*(lqprev\*(rq.
 .PP
 .IP \(bu 2
-Only a certain number of sequences may be defined for a given folder.
-This number is usually limited to 59 (27 on small systems).  (The
-internal implementation relies on bitmasks, with some bits set aside
-for internal use.)
-.PP
-.IP \(bu 2
 Message ranges with user\-defined sequence names are restricted to the
 form \*(lqname:n\*(rq, \*(lqname:+n\*(rq, or \*(lqname:-n\*(rq, and refer
 to the first or last `n' messages of the sequence `name', respectively.
index 7f87ccd..cad86da 100644 (file)
@@ -13,7 +13,8 @@
 void
 folder_free (struct msgs *mp)
 {
-    int i;
+    size_t i;
+    bvector_t *v;
 
     if (!mp)
        return;
@@ -22,8 +23,14 @@ folder_free (struct msgs *mp)
        free (mp->foldpath);
 
     /* free the sequence names */
-    for (i = 0; mp->msgattrs[i]; i++)
-       free (mp->msgattrs[i]);
+    for (i = 0; i < svector_size (mp->msgattrs); i++)
+       free (svector_at (mp->msgattrs, i));
+    svector_free (mp->msgattrs);
+
+    for (i = 0, v = mp->msgstats; i < mp->num_msgstats; ++i, ++v) {
+       bvector_free (*v);
+    }
+    free (mp->msgstats);
 
     /* Close/free the sequence file if it is open */
 
@@ -33,6 +40,6 @@ folder_free (struct msgs *mp)
     if (mp->seqname)
        free (mp->seqname);
 
-    free (mp->msgstats);       /* free message status area   */
+    bvector_free (mp->attrstats);
     free (mp);                 /* free main folder structure */
 }
index 02271bc..170946b 100644 (file)
@@ -30,6 +30,8 @@ folder_read (char *name, int lockflag)
     struct stat st;
     struct dirent *dp;
     DIR *dd;
+    bvector_t *v;
+    size_t i;
 
     name = m_mailpath (name);
     if (!(dd = opendir (name))) {
@@ -131,7 +133,13 @@ folder_read (char *name, int lockflag)
     /*
      * Allocate space for status of each message.
      */
-    mp->msgstats = mh_xmalloc (MSGSTATSIZE(mp, mp->lowoff, mp->hghoff));
+    mp->num_msgstats = MSGSTATNUM (mp->lowoff, mp->hghoff);
+    mp->msgstats = mh_xmalloc (MSGSTATSIZE(mp));
+    for (i = 0, v = mp->msgstats; i < mp->num_msgstats; ++i, ++v) {
+       *v = bvector_create (0);
+    }
+
+    mp->msgattrs = svector_create (0);
 
     /*
      * Clear all the flag bits for all the message
index 6a94a00..0d1f497 100644 (file)
@@ -40,26 +40,47 @@ folder_realloc (struct msgs *mp, int lo, int hi)
        return mp;
 
     if (lo == mp->lowoff) {
+       bvector_t *v;
+       size_t old_size = mp->num_msgstats;
+       size_t new_size = hi - lo + 1;
+       size_t i;
+
        /*
         * We are just extending (or shrinking) the end of message
         * status array.  So we don't have to move anything and can
         * just realloc the message status array.
         */
-       mp->msgstats = mh_xrealloc (mp->msgstats, MSGSTATSIZE(mp, lo, hi));
+
+       for (i = old_size, v = &mp->msgstats[old_size-1]; i > new_size;
+            --i, --v) {
+           bvector_free (*v);
+       }
+       mp->num_msgstats = MSGSTATNUM (lo, hi);
+       mp->msgstats =
+           mh_xrealloc (mp->msgstats, MSGSTATSIZE(mp));
+       for (i = old_size, v = &mp->msgstats[old_size]; i < new_size;
+            ++i, ++v) {
+           *v = bvector_create (0);
+       }
     } else {
        /*
         * We are changing the offset of the message status
         * array.  So we will need to shift everything.
         */
-       seqset_t *tmpstats;
+       bvector_t *tmpstats, *t;
+       size_t i;
 
        /* first allocate the new message status space */
-       tmpstats = mh_xmalloc (MSGSTATSIZE(mp, lo, hi));
+       mp->num_msgstats = MSGSTATNUM (lo, hi);
+       tmpstats = mh_xmalloc (MSGSTATSIZE(mp));
+       for (i = 0, t = tmpstats; i < mp->num_msgstats; ++i, ++t) {
+           *t = bvector_create (0);
+       }
 
        /* then copy messages status array with shift */
        if (mp->nummsg > 0) {
            for (msgnum = mp->lowmsg; msgnum <= mp->hghmsg; msgnum++)
-               tmpstats[msgnum - lo] = mp->msgstats[msgnum - mp->lowoff];
+               bvector_copy (tmpstats[msgnum - lo], msgstat (mp, msgnum));
        }
        free(mp->msgstats);
        mp->msgstats = tmpstats;
index d5109b0..47085f8 100644 (file)
@@ -41,8 +41,8 @@ seq_addsel (struct msgs *mp, char *cp, int public, int zero)
     /*
      * Get the number for this sequence
      */
-    for (i = 0; mp->msgattrs[i]; i++) {
-       if (!strcmp (mp->msgattrs[i], cp)) {
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       if (!strcmp (svector_at (mp->msgattrs, i), cp)) {
            new_seq = 0;
            break;
        }
@@ -52,15 +52,10 @@ seq_addsel (struct msgs *mp, char *cp, int public, int zero)
      * If this is a new sequence, add a slot for it
      */
     if (new_seq) {
-       if (i >= NUMATTRS) {
-           advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp);
-           return 0;
-       }
-       if (!(mp->msgattrs[i] = strdup (cp))) {
+       if (!(svector_push_back (mp->msgattrs, strdup (cp)))) {
            advise (NULL, "strdup failed");
            return 0;
        }
-       mp->msgattrs[i + 1] = NULL;
     }
 
     /*
@@ -133,8 +128,8 @@ seq_addmsg (struct msgs *mp, char *cp, int msgnum, int public, int zero)
     /*
      * Get the number for this sequence
      */
-    for (i = 0; mp->msgattrs[i]; i++) {
-       if (!strcmp (mp->msgattrs[i], cp)) {
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       if (!strcmp (svector_at (mp->msgattrs, i), cp)) {
            new_seq = 0;
            break;
        }
@@ -144,15 +139,10 @@ seq_addmsg (struct msgs *mp, char *cp, int msgnum, int public, int zero)
      * If this is a new sequence, add a slot for it
      */
     if (new_seq) {
-       if (i >= NUMATTRS) {
-           advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp);
-           return 0;
-       }
-       if (!(mp->msgattrs[i] = strdup (cp))) {
+       if (!(svector_push_back (mp->msgattrs, strdup (cp)))) {
            advise (NULL, "strdup failed");
            return 0;
        }
-       mp->msgattrs[i + 1] = NULL;
     }
 
     /*
index 30dd3f5..f27efa9 100644 (file)
 char *
 seq_bits (struct msgs *mp)
 {
-    int i;
+    size_t i;
     size_t len;
     static char buffer[BUFSIZ];
 
     strncpy (buffer, MBITS, sizeof(buffer));
 
-    for (i = 0; mp->msgattrs[i]; i++) {
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
        len = strlen (buffer);
        snprintf (buffer + len, sizeof(buffer) - len,
-               "%c%s", FFATTRSLOT + 1 + i, mp->msgattrs[i]);
+                 "%c%s", FFATTRSLOT + 1 + (int) i,
+                  svector_at (mp->msgattrs, i));
+       /*
+        * seq_bits() is used by seq_printdebug(), which passes an
+        * unsigned int bit vector to snprintb().  So limit the
+        * size of the return value accordingly.   Even worse,
+        * snprintb() only uses characters up through ASCII space
+        * as the delimiter (the %c character above).  So limit
+        * based on that.
+        */
+       if ((int) i == ' ' - FFATTRSLOT - 1) break;
     }
 
     return buffer;
index 97e3578..670872e 100644 (file)
@@ -34,8 +34,8 @@ seq_delsel (struct msgs *mp, char *cp, int public, int zero)
     /*
      * Get the number for this sequence
      */
-    for (i = 0; mp->msgattrs[i]; i++) {
-       if (!strcmp (mp->msgattrs[i], cp)) {
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       if (!strcmp (svector_at (mp->msgattrs, i), cp)) {
            new_seq = 0;
            break;
        }
@@ -50,15 +50,10 @@ seq_delsel (struct msgs *mp, char *cp, int public, int zero)
         * create the sequence, if necessary
         */
        if (new_seq) {
-           if (i >= NUMATTRS) {
-               advise (NULL, "only %d sequences allowed (no room for %s)!", NUMATTRS, cp);
-               return 0;
-           }
-           if (!(mp->msgattrs[i] = strdup (cp))) {
+           if (!(svector_push_back (mp->msgattrs, strdup (cp)))) {
                advise (NULL, "strdup failed");
                return 0;
            }
-           mp->msgattrs[i + 1] = NULL;
        }
        /*
         * now add sequence bit to all existing messages
@@ -121,13 +116,13 @@ seq_delsel (struct msgs *mp, char *cp, int public, int zero)
 int
 seq_delmsg (struct msgs *mp, char *cp, int msgnum)
 {
-    int i;
+    size_t i;
 
     if (!seq_nameok (cp))
        return 0;
 
-    for (i = 0; mp->msgattrs[i]; i++) {
-       if (!strcmp (mp->msgattrs[i], cp)) {
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       if (!strcmp (svector_at (mp->msgattrs, i), cp)) {
            clear_sequence (mp, i, msgnum);
            mp->msgflags |= SEQMOD;
            return 1;
index 251b609..b34a325 100644 (file)
 int
 seq_getnum (struct msgs *mp, char *seqname)
 {
-    int i;
+    size_t i;
 
-    for (i = 0; mp->msgattrs[i]; i++)
-       if (!strcmp (mp->msgattrs[i], seqname))
+    for (i = 0; i < svector_size (mp->msgattrs); i++)
+       if (!strcmp (svector_at (mp->msgattrs, i), seqname))
            return i;
 
     return -1;
index 3d97038..b6d5936 100644 (file)
 void
 seq_printall (struct msgs *mp)
 {
-    int i;
+    size_t i;
     char *list;
 
-    for (i = 0; mp->msgattrs[i]; i++) {
-       list = seq_list (mp, mp->msgattrs[i]);
-       printf ("%s%s: %s\n", mp->msgattrs[i],
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       list = seq_list (mp, svector_at (mp->msgattrs, i));
+       printf ("%s%s: %s\n", svector_at (mp->msgattrs, i),
            is_seq_private (mp, i) ? " (private)" : "", empty(list));
     }
 }
index 831efd2..4b9e815 100644 (file)
@@ -32,8 +32,7 @@ seq_read (struct msgs *mp, int lockflag)
      * Initialize the list of sequence names.  Go ahead and
      * add the "cur" sequence to the list of sequences.
      */
-    mp->msgattrs[0] = getcpy (current);
-    mp->msgattrs[1] = NULL;
+    svector_push_back (mp->msgattrs, getcpy (current));
     make_all_public (mp);      /* initially, make all public */
 
     /* If folder is empty, don't scan for sequence information */
@@ -181,31 +180,22 @@ seq_init (struct msgs *mp, char *name, char *field)
      * then clear the bit for this sequence from all the
      * mesages in this folder.
      */
-    for (i = 0; mp->msgattrs[i]; i++) {
-       if (!strcmp (mp->msgattrs[i], name)) {
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       if (!strcmp (svector_at (mp->msgattrs, i), name)) {
            for (j = mp->lowmsg; j <= mp->hghmsg; j++)
                clear_sequence (mp, i, j);
            break;
        }
     }
 
-    /* Return error, if too many sequences */
-    if (i >= NUMATTRS) {
-       admonish (NULL, "Too many sequences, sequence %s ignored", name);
-       free (name);
-       free (field);
-       return -1;
-    }
-
     /*
      * If we've already seen this sequence name, just free the
      * name string.  Else add it to the list of sequence names.
      */
-    if (mp->msgattrs[i]) {
+    if (svector_at (mp->msgattrs, i)) {
        free (name);
     } else {
-       mp->msgattrs[i] = name;
-       mp->msgattrs[i + 1] = NULL;
+       svector_push_back (mp->msgattrs, name);
     }
 
     /*
index a431804..83753af 100644 (file)
@@ -24,7 +24,7 @@
 void
 seq_save (struct msgs *mp)
 {
-    int i;
+    size_t i;
     char flags, *cp, attr[BUFSIZ], seqfile[PATH_MAX];
     FILE *fp;
     sigset_t set, oset;
@@ -54,11 +54,12 @@ seq_save (struct msgs *mp)
     else
        snprintf (seqfile, sizeof(seqfile), "%s/%s", mp->foldpath, mh_seq);
 
-    for (i = 0; mp->msgattrs[i]; i++) {
-       snprintf (attr, sizeof(attr), "atr-%s-%s", mp->msgattrs[i], mp->foldpath);
+    for (i = 0; i < svector_size (mp->msgattrs); i++) {
+       snprintf (attr, sizeof(attr), "atr-%s-%s",
+                 svector_at (mp->msgattrs, i), mp->foldpath);
 
        /* get space separated list of sequence ranges */
-       if (!(cp = seq_list(mp, mp->msgattrs[i]))) {
+       if (!(cp = seq_list(mp, svector_at (mp->msgattrs, i)))) {
            context_del (attr);                 /* delete sequence from context */
            continue;
        }
@@ -104,7 +105,7 @@ priv:
                sigaddset(&set, SIGTERM);
                sigprocmask (SIG_BLOCK, &set, &oset);
            }
-           fprintf (fp, "%s: %s\n", mp->msgattrs[i], cp);
+           fprintf (fp, "%s: %s\n", svector_at (mp->msgattrs, i), cp);
        }
     }
 
diff --git a/sbr/vector.c b/sbr/vector.c
new file mode 100644 (file)
index 0000000..ca8c894
--- /dev/null
@@ -0,0 +1,257 @@
+/*
+ * vector.c -- dynamically sized vectors
+ *
+ * This code is Copyright (c) 2013, by the authors of nmh.  See the
+ * COPYRIGHT file in the root directory of the nmh distribution for
+ * complete copyright information.
+ */
+
+/*
+ * This file defines several kinds of vectors:
+ *   bvector:  bit vector
+ *   svector:  vector of char arrays
+ *   ivector:  vector of ints
+ *
+ * The interfaces provide only the capabilities needed by nmh.  The
+ * implementations rely on dynamic allocation, so that a vector
+ * can be as large as needed, as long as it fits in (virtual) memory.
+ */
+
+#include <h/mh.h>
+#include <h/utils.h>
+
+#define VEC_INIT_SIZE 256
+
+/*
+ * These try to hide the type of the "bits" member of bvector.  But if
+ * that is changed to a type that's wider than unsigned long, the 1ul
+ * constants in the code below must also be changed to a 1 that's at
+ * least as wide as the new type.
+ */
+#ifndef Nbby
+# define Nbby 8
+#endif
+#define BVEC_WORD(vec, max) ((max) / (sizeof *vec->bits * Nbby))
+#define BVEC_OFFSET(vec, max) ((max) % (sizeof *vec->bits * Nbby))
+#define BVEC_BYTES(vec, n) \
+    ((BVEC_WORD (vec, n) + (BVEC_OFFSET (vec, n) == 0 ? 0 : 1))  * \
+    sizeof *vec->bits)
+
+struct bvector {
+    unsigned long *bits;
+    size_t maxsize;
+};
+
+static void bvector_resize (bvector_t, size_t);
+
+bvector_t
+bvector_create (size_t init_size) {
+    bvector_t vec = mh_xmalloc (sizeof *vec);
+    size_t bytes = BVEC_BYTES (vec, init_size  ?  init_size  :  VEC_INIT_SIZE);
+
+    vec->bits = mh_xmalloc (bytes);
+    memset (vec->bits, 0, bytes);
+    vec->maxsize = bytes * Nbby;
+
+    return vec;
+}
+
+void
+bvector_copy (bvector_t dest, bvector_t src) {
+    size_t bytes = BVEC_BYTES (dest, src->maxsize);
+
+    free (dest->bits);
+    dest->bits = mh_xmalloc (bytes);
+    memcpy (dest->bits, src->bits, bytes);
+    dest->maxsize = src->maxsize;
+}
+
+void
+bvector_free (bvector_t vec) {
+    free (vec->bits);
+    free (vec);
+}
+
+void
+bvector_clear (bvector_t vec, size_t n) {
+    size_t word = BVEC_WORD (vec,n);
+    size_t offset = BVEC_OFFSET (vec, n);
+
+    if (n >= vec->maxsize) bvector_resize (vec, n);
+
+    assert (sizeof *vec->bits <= sizeof 1ul);
+    vec->bits[word] &= ~(1ul << offset);
+}
+
+
+void
+bvector_clear_all (bvector_t vec) {
+    memset (vec->bits, 0, BVEC_BYTES (vec, vec->maxsize));
+}
+
+
+void
+bvector_set (bvector_t vec, size_t n) {
+    size_t word = BVEC_WORD (vec, n);
+    size_t offset = BVEC_OFFSET (vec, n);
+
+    if (n >= vec->maxsize) bvector_resize (vec, n);
+    assert (sizeof *vec->bits <= sizeof 1ul);
+    vec->bits[word] |= 1ul << offset;
+}
+
+unsigned int
+bvector_at (bvector_t vec, size_t i) {
+    size_t word = BVEC_WORD (vec, i);
+    size_t offset = BVEC_OFFSET (vec, i);
+
+    assert (sizeof *vec->bits <= sizeof 1ul);
+    return i < vec->maxsize
+        ?  (vec->bits[word] & (1ul << offset) ? 1 : 0)
+        :  0;
+}
+
+static void
+bvector_resize (bvector_t vec, size_t maxsize) {
+    size_t old_maxsize = vec->maxsize;
+    size_t bytes;
+    size_t i;
+
+    while ((vec->maxsize *= 2) < maxsize) continue;
+    bytes = BVEC_BYTES (vec, vec->maxsize);
+    vec->bits = mh_xrealloc (vec->bits, bytes);
+    for (i = old_maxsize; i < vec->maxsize; ++i) bvector_clear (vec, i);
+}
+
+const unsigned long *
+bvector_bits (bvector_t vec) {
+    return vec->bits;
+}
+
+size_t
+bvector_maxsize (bvector_t vec) {
+    return vec->maxsize;
+}
+
+
+struct svector {
+    char **strs;
+    size_t maxsize;
+    size_t size;
+};
+
+static void svector_resize (svector_t, size_t);
+
+svector_t
+svector_create (size_t init_size) {
+    svector_t vec = mh_xmalloc (sizeof *vec);
+    size_t bytes;
+
+    vec->maxsize = init_size ? init_size : VEC_INIT_SIZE;
+    bytes = vec->maxsize * sizeof (char *);
+    vec->strs = mh_xmalloc (bytes);
+    memset (vec->strs, 0, bytes);
+    vec->size = 0;
+
+    return vec;
+}
+
+void
+svector_free (svector_t vec) {
+    free (vec->strs);
+    free (vec);
+}
+
+char *
+svector_push_back (svector_t vec, char *s) {
+    if (++vec->size >= vec->maxsize) svector_resize (vec, vec->size);
+    return vec->strs[vec->size-1] = s;
+}
+
+char *
+svector_at (svector_t vec, size_t i) {
+    if (i >= vec->maxsize) svector_resize (vec, i);
+    return vec->strs[i];
+}
+
+char **
+svector_strs (svector_t vec) {
+    return vec->strs;
+}
+
+size_t
+svector_size (svector_t vec) {
+    return vec->size;
+}
+
+static void
+svector_resize (svector_t vec, size_t maxsize) {
+    size_t old_maxsize = vec->maxsize;
+    size_t i;
+
+    while ((vec->maxsize *= 2) < maxsize) continue;
+    vec->strs = mh_xrealloc (vec->strs, vec->maxsize * sizeof (char *));
+    for (i = old_maxsize; i < vec->maxsize; ++i) vec->strs[i] = NULL;
+}
+
+
+struct ivector {
+    int *ints;
+    size_t maxsize;
+    size_t size;
+};
+
+static void ivector_resize (ivector_t, size_t);
+
+ivector_t
+ivector_create (size_t init_size) {
+    ivector_t vec = mh_xmalloc (sizeof *vec);
+    size_t bytes;
+
+    vec->maxsize = init_size ? init_size : VEC_INIT_SIZE;
+    bytes = vec->maxsize * sizeof (int);
+    vec->ints = mh_xmalloc (bytes);
+    memset (vec->ints, 0, bytes);
+    vec->size = 0;
+
+    return vec;
+}
+
+void
+ivector_free (ivector_t vec) {
+    free (vec->ints);
+    free (vec);
+}
+
+int
+ivector_push_back (ivector_t vec, int n) {
+    if (++vec->size >= vec->maxsize) ivector_resize (vec, vec->size);
+    return vec->ints[vec->size-1] = n;
+}
+
+int
+ivector_at (ivector_t vec, size_t i) {
+    if (i >= vec->maxsize) ivector_resize (vec, i);
+    return vec->ints[i];
+}
+
+int *
+ivector_atp (ivector_t vec, size_t i) {
+    if (i >= vec->maxsize) ivector_resize (vec, i);
+    return &vec->ints[i];
+}
+
+size_t
+ivector_size (ivector_t vec) {
+    return vec->size;
+}
+
+static void
+ivector_resize (ivector_t vec, size_t maxsize) {
+    size_t old_maxsize = vec->maxsize;
+    size_t i;
+
+    while ((vec->maxsize *= 2) < maxsize) continue;
+    vec->ints = mh_xrealloc (vec->ints, vec->maxsize * sizeof (int));
+    for (i = old_maxsize; i < vec->maxsize; ++i) vec->ints[i] = 0;
+}
index cd3aedf..cdbafc5 100755 (executable)
@@ -56,7 +56,7 @@ No such file or directory"
 
 # Test private sequence creation.
 # Set current message for following tests.
-folder +inbox 1 > /dev/null
+folder +inbox 1 >/dev/null
 run_test 'mark 1 -sequence privateseq -add -nopublic' ''
 run_test 'mark -list' 'cur: 1
 odd: 1 3 5 7 9
@@ -77,11 +77,22 @@ run_test 'mark -sequence privateseq -list' 'privateseq (private): 1-2'
 run_test 'mark -sequence privateseq -list -public' 'privateseq (private): 1-2'
 
 # Test mark on empty folder.
-folder -create +other > /dev/null
+folder -create +other >/dev/null
 run_test 'mark +other -sequence unseen all' 'mark: no messages in other'
 
 # Test removal of indication of cur message.
 mark +inbox -sequence cur -delete all
 run_test 'pick -nolist cur' 'pick: no cur message'
 
+# Check large number of sequences.
+for i in 1 2 3 4 5; do
+  for j in 0 1 2 3 4 5 6 7 8 9; do
+    mark $i -seq seq$i${j}0 -seq seq$i${j}1 -seq seq$i${j}2 -seq seq$i${j}3 \
+            -seq seq$i${j}4 -seq seq$i${j}5 -seq seq$i${j}6 -seq seq$i${j}7 \
+            -seq seq$i${j}8 -seq seq$i${j}9
+    run_test "pick seq$i${j}0 seq$i${j}1 seq$i${j}2 seq$i${j}3 seq$i${j}4 \
+                   seq$i${j}5 seq$i${j}6 seq$i${j}7 seq$i${j}8 seq$i${j}9" $i
+  done
+done
+
 exit $failed
index d0945fc..fe3dceb 100644 (file)
@@ -57,8 +57,8 @@ struct 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;
@@ -74,8 +74,7 @@ static int numfolders;
 static int maxfolders;
 
 /* info on sequences to search for */
-static char *sequencesToDo[NUMATTRS];
-static unsigned int numsequences;
+static svector_t sequencesToDo;
 
 static int all        = FALSE;  /* scan all folders in top level?           */
 static int alphaOrder = FALSE; /* want alphabetical order only             */
@@ -140,7 +139,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++)) {
@@ -165,10 +164,7 @@ main(int argc, char **argv)
                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:
@@ -239,23 +235,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);
            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);
        }
@@ -265,6 +254,7 @@ main(int argc, char **argv)
     ScanFolders();
     qsort(folders, nFolders, sizeof(struct Folder), (qsort_comp) CompareFolders);
     PrintFolders();
+    svector_free (sequencesToDo);
     done (0);
     return 1;
 }
@@ -463,9 +453,10 @@ AddFolder(char *name, int force)
 {
     unsigned int i;
     int msgnum, nonzero;
-    int seqnum[NUMATTRS], nSeq[NUMATTRS];
+    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, 0))) {
@@ -478,27 +469,27 @@ AddFolder(char *name, int force)
        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,16 +501,23 @@ AddFolder(char *name, int force)
        f = &folders[nFolders++];
        f->name = getcpy(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;
 }
@@ -559,26 +557,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);
@@ -592,9 +591,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);
            }
        }
index cbc3459..e18e2cd 100644 (file)
@@ -491,7 +491,8 @@ process_messages(struct format *fmt, struct msgs_array *comps,
                 int bufsize, int outwidth, int *dat, struct fmt_callbacks *cb)
 {
     int i, state, msgnum, msgsize = dat[2], num = dat[0], cur = dat[1];
-    int num_unseen_seq = 0, seqnum[NUMATTRS];
+    int num_unseen_seq = 0;
+    ivector_t seqnum = ivector_create (0);
     char *maildir, *cp, name[NAMESZ], rbuf[BUFSIZ];
     struct msgs *mp;
     struct comp *c;
@@ -534,7 +535,7 @@ process_messages(struct format *fmt, struct msgs_array *comps,
            dp = getcpy(cp);
            ap = brkstring(dp, " ", "\n");
            for (i = 0; ap && *ap; i++, ap++)
-               seqnum[i] = seq_getnum(mp, *ap);
+               ivector_push_back (seqnum, seq_getnum(mp, *ap));
                
            num_unseen_seq = i;
            if (dp)
@@ -576,7 +577,7 @@ process_messages(struct format *fmt, struct msgs_array *comps,
 
            dat[4] = 0;
            for (i = 0; i < num_unseen_seq; i++) {
-               if (in_sequence(mp, seqnum[i], msgnum)) {
+               if (in_sequence(mp, ivector_at (seqnum, i), msgnum)) {
                    dat[4] = 1;
                    break;
                }
@@ -646,6 +647,7 @@ finished:
        }
     }
 
+    ivector_free (seqnum);
     folder_free(mp);
     return;
 }
index cc5a713..f0f3d7a 100644 (file)
@@ -48,7 +48,7 @@ main (int argc, char **argv)
     unsigned int seqp = 0;
     char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
     char **argp, **arguments;
-    char *seqs[NUMATTRS + 1];
+    svector_t seqs = svector_create (0);
     struct msgs_array msgs = { 0, 0, NULL };
     struct msgs *mp;
 
@@ -101,10 +101,8 @@ main (int argc, char **argv)
                if (!(cp = *argp++) || *cp == '-')
                    adios (NULL, "missing argument to %s", argp[-2]);
 
-               /* check if too many sequences specified */
-               if (seqp >= NUMATTRS)
-                   adios (NULL, "too many sequences (more than %d) specified", NUMATTRS);
-               seqs[seqp++] = cp;
+               svector_push_back (seqs, cp);
+               seqp++;
                continue;
 
            case PUBLSW: 
@@ -185,19 +183,18 @@ main (int argc, char **argv)
     if (seqp == 0 && (addsw || deletesw))
        adios (NULL, "-%s requires at least one -sequence argument",
               addsw ? "add" : "delete");
-    seqs[seqp] = NULL;
 
     /* Adding messages to sequences */
     if (addsw) {
-       for (seqp = 0; seqs[seqp]; seqp++)
-           if (!seq_addsel (mp, seqs[seqp], publicsw, zerosw))
+       for (seqp = 0; seqp < svector_size (seqs); seqp++)
+           if (!seq_addsel (mp, svector_at (seqs, seqp), publicsw, zerosw))
                done (1);
     }
 
     /* Deleting messages from sequences */
     if (deletesw) {
-       for (seqp = 0; seqs[seqp]; seqp++)
-           if (!seq_delsel (mp, seqs[seqp], publicsw, zerosw))
+       for (seqp = 0; seqp < svector_size (seqs); seqp++)
+           if (!seq_delsel (mp, svector_at (seqs, seqp), publicsw, zerosw))
                done (1);
     }
 
@@ -205,8 +202,8 @@ main (int argc, char **argv)
     if (listsw) {
        if (seqp) {
            /* print the sequences given */
-           for (seqp = 0; seqs[seqp]; seqp++)
-               seq_print (mp, seqs[seqp]);
+           for (seqp = 0; seqp < svector_size (seqs); seqp++)
+               seq_print (mp, svector_at (seqs, seqp));
        } else {
            /* else print them all */
            seq_printall (mp);
@@ -217,6 +214,7 @@ main (int argc, char **argv)
            seq_printdebug (mp);
     }
 
+    svector_free (seqs);
     seq_save (mp);                     /* synchronize message sequences */
     context_replace (pfolder, folder); /* update current folder         */
     context_save ();                   /* save the context file         */
@@ -254,18 +252,22 @@ print_debug (struct msgs *mp)
 /*
  * Print debugging info about all the SELECTED
  * messages and the sequences they are in.
+ * Due limitattions of snprintb(), only a limited
+ * number of sequences will be printed.  See the
+ * comments in sbr/seq_bits.c.
  */
 static void
 seq_printdebug (struct msgs *mp)
 {
     int msgnum;
-    char buf[100];
+    char buf[BUFSIZ];
 
     printf ("\n");
     for (msgnum = mp->lowsel; msgnum <= mp->hghsel; msgnum++) {
        if (is_selected (mp, msgnum))
            printf ("%*d: %s\n", DMAXFOLDER, msgnum,
-               snprintb (buf, sizeof(buf),
-               (unsigned) mp->msgstats[msgnum - mp->lowoff], seq_bits (mp)));
+                   snprintb (buf, sizeof buf,
+                             (unsigned) *bvector_bits (msgstat (mp, msgnum)),
+                             seq_bits (mp)));
     }
 }
index cdec766..3144a49 100644 (file)
--- a/uip/msh.c
+++ b/uip/msh.c
@@ -682,8 +682,7 @@ setup (char *file)
     }
     m_init ();
 
-    mp->msgattrs[0] = getcpy ("unseen");
-    mp->msgattrs[1] = NULL;
+    svector_push_back (mp->msgattrs, getcpy ("unseen"));
 
     scan_detect_mbox_style (fp);               /* the MAGIC invocation */
     if (fmsh) {
index a6847d5..acd7671 100644 (file)
@@ -1228,8 +1228,9 @@ markcmd (char **args)
                        (long) Msgs[msgnum].m_start,
                        (long) Msgs[msgnum].m_stop,
                        snprintb (buf, sizeof(buf),
-                               (unsigned) mp->msgstats[msgnum - mp->lowoff],
-                               seq_bits (mp)));
+                                 (unsigned) *bvector_bits (msgstat (mp,
+                                                                     msgnum)),
+                                 seq_bits (mp)));
                    if (Msgs[msgnum].m_scanl)
                        printf ("%s", Msgs[msgnum].m_scanl);
                }                           
@@ -2614,9 +2615,10 @@ sortcmd (char **args)
        }
        else                    /* m_scaln is already NULL */
            twscopy (&Msgs[msgnum].m_tb, &tb);
-       Msgs[msgnum].m_stats = mp->msgstats[msgnum - mp->lowoff];
+       Msgs[msgnum].m_stats = bvector_create (0);
+       bvector_copy (Msgs[msgnum].m_stats, msgstat (mp, msgnum));
        if (mp->curmsg == msgnum)
-           Msgs[msgnum].m_stats |= CUR;
+            bvector_set (Msgs[msgnum].m_stats, CUR);
     }
 
     qsort ((char *) &Msgs[mp->lowsel], mp->hghsel - mp->lowsel + 1,
@@ -2627,8 +2629,9 @@ sortcmd (char **args)
            free (Msgs[msgnum].m_scanl);        /* from subjsort */
            Msgs[msgnum].m_scanl = NULL;
        }
-       mp->msgstats[msgnum - mp->lowoff] = Msgs[msgnum].m_stats & ~CUR;
-       if (Msgs[msgnum].m_stats & CUR)
+       bvector_clear (Msgs[msgnum].m_stats, CUR);
+       bvector_copy (msgstat (mp, msgnum), Msgs[msgnum].m_stats);
+       if (bvector_at (Msgs[msgnum].m_stats, CUR))
            seq_setcur (mp, msgnum);
     }
            
index e391ba2..5efdf74 100644 (file)
--- a/uip/new.c
+++ b/uip/new.c
@@ -404,14 +404,11 @@ main(int argc, char **argv)
     char **ap, *cp, **argp, **arguments;
     char help[BUFSIZ];
     char *folders = NULL;
-    char *sequences[NUMATTRS + 1];
+    svector_t sequences = svector_create (0);
     int i = 0;
     char *unseen;
     struct node *folder;
 
-    sequences[0] = NULL;
-    sequences[1] = NULL;
-
 #ifdef LOCALE
     setlocale(LC_ALL, "");
 #endif
@@ -456,9 +453,9 @@ main(int argc, char **argv)
            }
        }
        /* have a sequence argument */
-       if (!seq_in_list(cp, sequences)) {
-           sequences[i++] = cp;
-           sequences[i] = NULL;
+       if (!seq_in_list(cp, svector_strs (sequences))) {
+           svector_push_back (sequences, cp);
+           ++i;
        }
     }
 
@@ -485,12 +482,12 @@ main(int argc, char **argv)
            adios(NULL, "must specify sequences or set %s", usequence);
        }
        for (ap = brkstring(unseen, " ", "\n"); *ap; ap++) {
-           sequences[i++] = *ap;
+           svector_push_back (sequences, *ap);
+           ++i;
        }
     }
-    sequences[i] = NULL;
 
-    folder = doit(context_find(pfolder), folders, sequences);
+    folder = doit(context_find(pfolder), folders, svector_strs (sequences));
     if (folder == NULL) {
         done(0);
         return 1;
@@ -514,6 +511,7 @@ main(int argc, char **argv)
 
     context_save();
 
+    svector_free (sequences);
     done (0);
     return 1;
 }
index 66198ff..5f28024 100644 (file)
@@ -59,7 +59,8 @@ main (int argc, char **argv)
     int msgnum;
     char *maildir, *folder = NULL, buf[100];
     char *cp, **argp, **arguments;
-    char *seqs[NUMATTRS + 1], *vec[MAXARGS];
+    svector_t seqs = svector_create (0);
+    char *vec[MAXARGS];
     struct msgs_array msgs = { 0, 0, NULL };
     struct msgnum_array nums = { 0, 0, NULL };
     struct msgs *mp, *mp2;
@@ -133,14 +134,11 @@ main (int argc, char **argv)
                if (!(cp = *argp++) || *cp == '-')
                    adios (NULL, "missing argument to %s", argp[-2]);
 
-               /* check if too many sequences specified */
-               if (seqp >= NUMATTRS)
-                   adios (NULL, "too many sequences (more than %d) specified", NUMATTRS);
-
                 if (!seq_nameok (cp))
                   done (1);
 
-               seqs[seqp++] = cp;
+               svector_push_back (seqs, cp);
+               seqp++;
                continue;
            case NSEQSW:
                seqp = 0;
@@ -247,8 +245,6 @@ main (int argc, char **argv)
     if (nums.size >= mp->numsel)
        adios (NULL, "no messages match specification");
 
-    seqs[seqp] = NULL;
-
     /*
      * So, what's happening here?
      *
@@ -280,9 +276,11 @@ main (int argc, char **argv)
     /*
      * Add the matching messages to sequences
      */
-    for (seqp = 0; seqs[seqp]; seqp++)
-       if (!seq_addsel (mp2, seqs[seqp], publicsw, zerosw))
-           done (1);
+    if (seqp > 0) {
+       for (seqp = 0; seqp < svector_size (seqs); seqp++)
+           if (!seq_addsel (mp2, svector_at (seqs, seqp), publicsw, zerosw))
+               done (1);
+    }
 
     /*
      * Print total matched if not printing each matched message number.
@@ -291,6 +289,7 @@ main (int argc, char **argv)
        printf ("%d hit%s\n", mp2->numsel, mp2->numsel == 1 ? "" : "s");
     }
 
+    svector_free (seqs);
     context_replace (pfolder, folder); /* update current folder         */
     seq_save (mp2);                    /* synchronize message sequences */
     context_save ();                   /* save the context file         */
index 9a89230..5875c21 100644 (file)
@@ -51,7 +51,8 @@ main (int argc, char **argv)
     int fd, msgnum;
     size_t seqp = 0;
     char *cp, *maildir, *folder = NULL, buf[BUFSIZ];
-    char **argp, **arguments, *seqs[NUMATTRS+1];
+    char **argp, **arguments;
+    svector_t seqs = svector_create (0);
     struct msgs *mp;
     struct stat st;
 
@@ -92,10 +93,8 @@ main (int argc, char **argv)
                if (!(cp = *argp++) || *cp == '-')
                    adios (NULL, "missing argument name to %s", argp[-2]);
 
-               /* check if too many sequences specified */
-               if (seqp >= NUMATTRS)
-                   adios (NULL, "too many sequences (more than %d) specified", NUMATTRS);
-               seqs[seqp++] = cp;
+               svector_push_back (seqs, cp);
+               seqp++;
                continue;
 
            case UNSEENSW:
@@ -137,8 +136,6 @@ main (int argc, char **argv)
        }
     }
 
-    seqs[seqp] = NULL; /* NULL terminate list of sequences */
-
     if (!context_find ("path"))
        free (path ("./", TFOLDER));
 
@@ -207,11 +204,17 @@ main (int argc, char **argv)
      * Add the message to any extra sequences
      * that have been specified.
      */
-    for (seqp = 0; seqs[seqp]; seqp++) {
-       if (!seq_addmsg (mp, seqs[seqp], msgnum, publicsw, zerosw))
-           done (1);
+    if (seqp) {
+       /* The only reason that seqp was checked to be non-zero is in
+          case a -nosequence switch is added. */
+       for (seqp = 0; seqp < svector_size (seqs); seqp++) {
+           if (!seq_addmsg (mp, svector_at (seqs, seqp), msgnum, publicsw,
+                            zerosw))
+               done (1);
+       }
     }
 
+    svector_free (seqs);
     seq_setunseen (mp, 0);     /* synchronize any Unseen-Sequence's      */
     seq_save (mp);             /* synchronize and save message sequences */
     folder_free (mp);          /* free folder/message structure          */
index 205041e..9b6361c 100644 (file)
@@ -385,11 +385,13 @@ static void
 copy_seqs (struct msgs *oldmp, int oldmsgnum, struct msgs *newmp, int newmsgnum)
 {
     char **seq;
-    int seqnum;
+    size_t seqnum;
 
-    for (seq = oldmp->msgattrs, seqnum = 0; *seq; ++seq, ++seqnum) {
+    for (seq = svector_strs (oldmp->msgattrs), seqnum = 0;
+        *seq && seqnum < svector_size (oldmp->msgattrs);
+        ++seq, ++seqnum) {
        if (strcmp (current, *seq)) {
-           assert (seqnum == seq_getnum (oldmp, *seq));
+           assert ((int) seqnum == seq_getnum (oldmp, *seq));
            if (in_sequence (oldmp, seqnum, oldmsgnum)) {
                seq_addmsg (newmp, *seq, newmsgnum,
                            is_seq_private (oldmp, seqnum) ? 0 : 1, 0);
index 2996a2b..932ffda 100644 (file)
@@ -50,7 +50,8 @@ main (int argc, char **argv)
     int clearflag = 0, hdrflag = 0, ontty;
     int width = 0, revflag = 0;
     int i, state, msgnum;
-    int seqnum[NUMATTRS], unseen, num_unseen_seq = 0;
+    ivector_t seqnum = ivector_create (0);
+    int unseen, num_unseen_seq = 0;
     char *cp, *maildir, *file = NULL, *folder = NULL;
     char *form = NULL, *format = NULL, buf[BUFSIZ];
     char **argp, *nfs, **arguments;
@@ -228,7 +229,7 @@ main (int argc, char **argv)
        dp = getcpy(cp);
        ap = brkstring (dp, " ", "\n");
        for (i = 0; ap && *ap; i++, ap++)
-           seqnum[i] = seq_getnum (mp, *ap);
+           ivector_push_back (seqnum, seq_getnum (mp, *ap));
 
        num_unseen_seq = i;
        if (dp)
@@ -256,7 +257,7 @@ main (int argc, char **argv)
             */
            unseen = 0;
            for (i = 0; i < num_unseen_seq; i++) {
-               if (in_sequence(mp, seqnum[i], msgnum)) {
+               if (in_sequence(mp, ivector_at (seqnum, i), msgnum)) {
                    unseen = 1;
                    break;
                }
@@ -285,6 +286,7 @@ main (int argc, char **argv)
        }
     }
 
+    ivector_free (seqnum);
     folder_free (mp);  /* free folder/message structure */
     if (clearflag)
        clear_screen ();
index 452b774..72fe065 100644 (file)
@@ -565,7 +565,7 @@ static void
 rename_msgs (struct msgs *mp, struct smsg **mlist)
 {
     int i, j, old, new;
-    seqset_t tmpset;
+    bvector_t tmpset = bvector_create (0);
     char f1[BUFSIZ], tmpfil[BUFSIZ];
     char newbuf[PATH_MAX + 1];
     struct smsg *sp;
@@ -605,7 +605,7 @@ rename_msgs (struct msgs *mp, struct smsg **mlist)
        if (rename (f1, tmpfil) == NOTOK)
            adios (tmpfil, "unable to rename %s to ", f1);
 
-       get_msg_flags (mp, &tmpset, old);
+       get_msg_flags (mp, tmpset, old);
 
        rename_chain (mp, mlist, j, i);
 
@@ -620,7 +620,9 @@ rename_msgs (struct msgs *mp, struct smsg **mlist)
        if (rename (tmpfil, m_name(new)) == NOTOK)
            adios (m_name(new), "unable to rename %s to", tmpfil);
 
-       set_msg_flags (mp, &tmpset, new);
+       set_msg_flags (mp, tmpset, new);
        mp->msgflags |= SEQMOD;
     }
+
+    bvector_free (tmpset);
 }