From: David Levine Date: Sun, 31 Mar 2013 16:45:09 +0000 (-0500) Subject: Removed limit on maximum number of sequences in a folder. X-Git-Url: https://diplodocus.org/git/nmh/commitdiff_plain/e491542da563673b49c6f6df9948ffaffbeed4fb?ds=sidebyside Removed limit on maximum number of sequences in a folder. Dynamically sized vectors in sbr/vector.c were added to support this. Their sizes are limited only by virtual memory. --- diff --git a/Makefile.am b/Makefile.am index 338bba38..d4d8faa2 100644 --- a/Makefile.am +++ b/Makefile.am @@ -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, diff --git a/docs/TODO b/docs/TODO index 75379cd5..32173c25 100644 --- 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 diff --git a/docs/pending-release-notes b/docs/pending-release-notes index db5f13fe..a0f5abc8 100644 --- a/docs/pending-release-notes +++ b/docs/pending-release-notes @@ -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 c92543c7..f5fd66be 100644 --- 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 8111003f..4e0314de 100644 --- 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 diff --git a/man/mark.man b/man/mark.man index b786c16a..6fa455a4 100644 --- a/man/mark.man +++ b/man/mark.man @@ -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. diff --git a/sbr/folder_free.c b/sbr/folder_free.c index 7f87ccd4..cad86dad 100644 --- a/sbr/folder_free.c +++ b/sbr/folder_free.c @@ -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 */ } diff --git a/sbr/folder_read.c b/sbr/folder_read.c index 02271bc6..170946b4 100644 --- a/sbr/folder_read.c +++ b/sbr/folder_read.c @@ -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 diff --git a/sbr/folder_realloc.c b/sbr/folder_realloc.c index 6a94a007..0d1f4979 100644 --- a/sbr/folder_realloc.c +++ b/sbr/folder_realloc.c @@ -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; diff --git a/sbr/seq_add.c b/sbr/seq_add.c index d5109b0d..47085f88 100644 --- a/sbr/seq_add.c +++ b/sbr/seq_add.c @@ -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; } /* diff --git a/sbr/seq_bits.c b/sbr/seq_bits.c index 30dd3f53..f27efa9f 100644 --- a/sbr/seq_bits.c +++ b/sbr/seq_bits.c @@ -13,16 +13,26 @@ 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; diff --git a/sbr/seq_del.c b/sbr/seq_del.c index 97e35783..670872ef 100644 --- a/sbr/seq_del.c +++ b/sbr/seq_del.c @@ -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; diff --git a/sbr/seq_getnum.c b/sbr/seq_getnum.c index 251b6091..b34a3252 100644 --- a/sbr/seq_getnum.c +++ b/sbr/seq_getnum.c @@ -14,10 +14,10 @@ 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; diff --git a/sbr/seq_print.c b/sbr/seq_print.c index 3d970380..b6d59365 100644 --- a/sbr/seq_print.c +++ b/sbr/seq_print.c @@ -17,12 +17,12 @@ 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)); } } diff --git a/sbr/seq_read.c b/sbr/seq_read.c index 831efd28..4b9e815d 100644 --- a/sbr/seq_read.c +++ b/sbr/seq_read.c @@ -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); } /* diff --git a/sbr/seq_save.c b/sbr/seq_save.c index a431804e..83753afb 100644 --- a/sbr/seq_save.c +++ b/sbr/seq_save.c @@ -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 index 00000000..ca8c894e --- /dev/null +++ b/sbr/vector.c @@ -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 +#include + +#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; +} diff --git a/test/sequences/test-mark b/test/sequences/test-mark index cd3aedf2..cdbafc55 100755 --- a/test/sequences/test-mark +++ b/test/sequences/test-mark @@ -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 diff --git a/uip/flist.c b/uip/flist.c index d0945fce..fe3dcebd 100644 --- a/uip/flist.c +++ b/uip/flist.c @@ -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); } } diff --git a/uip/fmttest.c b/uip/fmttest.c index cbc3459a..e18e2cd5 100644 --- a/uip/fmttest.c +++ b/uip/fmttest.c @@ -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; } diff --git a/uip/mark.c b/uip/mark.c index cc5a7133..f0f3d7a6 100644 --- a/uip/mark.c +++ b/uip/mark.c @@ -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))); } } diff --git a/uip/msh.c b/uip/msh.c index cdec7664..3144a493 100644 --- 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) { diff --git a/uip/mshcmds.c b/uip/mshcmds.c index a6847d51..acd7671f 100644 --- a/uip/mshcmds.c +++ b/uip/mshcmds.c @@ -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); } diff --git a/uip/new.c b/uip/new.c index e391ba20..5efdf74c 100644 --- 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; } diff --git a/uip/pick.c b/uip/pick.c index 66198ff2..5f280243 100644 --- a/uip/pick.c +++ b/uip/pick.c @@ -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 */ diff --git a/uip/rcvstore.c b/uip/rcvstore.c index 9a89230e..5875c21a 100644 --- a/uip/rcvstore.c +++ b/uip/rcvstore.c @@ -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 */ diff --git a/uip/refile.c b/uip/refile.c index 205041e0..9b6361c7 100644 --- a/uip/refile.c +++ b/uip/refile.c @@ -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); diff --git a/uip/scan.c b/uip/scan.c index 2996a2b5..932ffda0 100644 --- a/uip/scan.c +++ b/uip/scan.c @@ -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 (); diff --git a/uip/sortm.c b/uip/sortm.c index 452b774a..72fe0659 100644 --- a/uip/sortm.c +++ b/uip/sortm.c @@ -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); }