-
/*
- * m_convert.c -- parse a message range or sequence and set SELECTED
- *
- * $Id$
- *
- * This code is Copyright (c) 2002, by the authors of nmh. See the
- * COPYRIGHT file in the root directory of the nmh distribution for
- * complete copyright information.
- */
+** m_convert.c -- parse a message range or sequence and set SELECTED
+**
+** This code is Copyright (c) 2002, by the authors of nmh. See the
+** COPYRIGHT file in the root directory of the nmh distribution for
+** complete copyright information.
+*/
+
+
+/* FIXME: This code needs rework! Rewrite as a parser? */
#include <h/mh.h>
+#include <ctype.h>
/*
- * error codes for sequence
- * and message range processing
- */
-#define BADMSG (-2)
-#define BADRNG (-3)
-#define BADNEW (-4)
-#define BADNUM (-5)
-#define BADLST (-6)
+** error codes for sequence
+** and message range processing
+*/
+#define BADMSG (-2)
+#define BADRNG (-3)
+#define BADNEW (-4)
+#define BADNUM (-5)
+#define BADLST (-6)
-#define FIRST 1
-#define LAST 2
+#define FIRST 1
+#define LAST 2
-#define getnew(mp) (mp->hghmsg + 1)
+#define getbeyond(mp) ((mp)->hghmsg + 1)
-static int convdir; /* convert direction */
-static char *delimp;
+static int convdir; /* convert direction */
+static char *delimp; /* delimiter pointer */
/*
- * static prototypes
- */
-static int m_conv (struct msgs *, char *, int);
-static int attr (struct msgs *, char *);
+** static prototypes
+*/
+static int m_conv(struct msgs *, char *, int);
+static int attr(struct msgs *, char *);
+static void
+addtosel(struct msgs *mp, int msg)
+{
+ if (is_selected(mp, msg)) {
+ return; /* dont select twice */
+ }
+ set_selected(mp, msg);
+ mp->numsel++;
+ if (mp->lowsel == 0 || msg < mp->lowsel) {
+ mp->lowsel = msg;
+ }
+ if (msg > mp->hghsel) {
+ mp->hghsel = msg;
+ }
+}
+
int
-m_convert (struct msgs *mp, char *name)
+m_convert(struct msgs *mp, char *name)
{
- int first, last, found, range, err;
- char *bp, *cp;
+ int first, last, found, range, err;
+ unsigned char *bp;
+ char *cp;
- /* check if user defined sequence */
- err = attr (mp, cp = name);
+ /* check if user defined sequence */
+ err = attr(mp, cp = name);
+ if (err == -1)
+ return 0;
+ else if (err < 0)
+ goto badmsg;
+ else if (err > 0) {
+ /* it had been a user-defined sequence: we're finished */
+ return 1;
+ }
+ /*
+ ** else err == 0, so continue
+ ** here we know: it is no user-defined seq
+ */
- if (err == -1)
- return 0;
- else if (err < 0)
- goto badmsg;
- else if (err > 0)
- return 1;
- /*
- * else err == 0, so continue
- */
-
- found = 0;
-
- /*
- * Check for special "new" sequence, which
- * is valid only if ALLOW_NEW is set.
- */
- if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) {
- if ((err = first = getnew (mp)) <= 0)
- goto badmsg;
- else
- goto single;
- }
-
- if (!strcmp (cp, "all"))
- cp = "first-last";
-
- if ((err = first = m_conv (mp, cp, FIRST)) <= 0)
- goto badmsg;
-
- cp = delimp;
- if (*cp != '\0' && *cp != '-' && *cp != ':') {
-badelim:
- advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
- return 0;
- }
+ /*
+ ** Handle the special beyond sequence, which is valid only if
+ ** ALLOW_BEYOND is set, and can appear only on its own.
+ ** Also, it is available in any folder.
+ */
+ if ((mp->msgflags & ALLOW_BEYOND) && strcmp(cp, seq_beyond)==0) {
+ addtosel(mp, getbeyond(mp));
+ return 1;
+ }
+
+ /*
+ ** Handle the special all sequence: replace `a' with `f-l'
+ */
+ if (strcmp(cp, seq_all)==0) {
+ cp = concat(seq_first, "-", seq_last, NULL);
+ }
- if (*cp == '-') {
- cp++;
- if ((err = last = m_conv (mp, cp, LAST)) <= 0) {
+ if ((err = first = m_conv(mp, cp, FIRST)) <= 0)
+ goto badmsg;
+
+ cp = delimp;
+ switch (*cp) {
+ case '-':
+ /* global range */
+ cp++;
+ if ((err = last = m_conv(mp, cp, LAST)) <= 0) {
badmsg:
- switch (err) {
- case BADMSG:
- advise (NULL, "no %s message", cp);
- break;
+ switch (err) {
+ case BADMSG:
+ advise(NULL, "no %s message", cp);
+ break;
- case BADNUM:
- advise (NULL, "message %s doesn't exist", cp);
- break;
+ case BADNUM:
+ advise(NULL, "message %s doesn't exist", cp);
+ break;
- case BADRNG:
- advise (NULL, "message %s out of range 1-%d", cp, mp->hghmsg);
- break;
+ case BADRNG:
+ advise(NULL, "message %s out of range 1-%d",
+ cp, mp->hghmsg);
+ break;
- case BADLST:
+ case BADLST:
badlist:
- advise (NULL, "bad message list %s", name);
+ advise(NULL, "bad message list %s", name);
+ break;
+
+ case BADNEW:
+ advise(NULL, "folder full, no %s message",
+ name);
+ break;
+
+ default:
+ advise(NULL, "no messages match specification");
+ }
+ return 0;
+ }
+
+ if (last < first)
+ goto badlist;
+ if (*delimp)
+ goto badelim;
+ if (first > mp->hghmsg || last < mp->lowmsg) {
+rangerr:
+ advise(NULL, "no messages in range %s", name);
+ return 0;
+ }
+
+ /* tighten the range to search */
+ if (last > mp->hghmsg)
+ last = mp->hghmsg;
+ if (first < mp->lowmsg)
+ first = mp->lowmsg;
break;
- case BADNEW:
- advise (NULL, "folder full, no %s message", name);
+ case ':':
+ /* anchored range */
+ cp++;
+ if (*cp == '-') {
+ convdir = -1;
+ cp++;
+ } else if (*cp == '+') {
+ convdir = 1;
+ cp++;
+ }
+ if ((range = atoi(bp = cp)) == 0)
+ goto badlist;
+ while (isdigit(*bp))
+ bp++;
+ if (*bp)
+ goto badelim;
+ if ((convdir > 0 && first > mp->hghmsg)
+ || (convdir < 0 && first < mp->lowmsg))
+ goto rangerr;
+
+ /* tighten the range to search */
+ if (first < mp->lowmsg)
+ first = mp->lowmsg;
+ if (first > mp->hghmsg)
+ first = mp->hghmsg;
+
+ for (last = first; last >= mp->lowmsg && last <= mp->hghmsg;
+ last += convdir)
+ if (does_exist(mp, last) && (--range <= 0))
+ break;
+ if (last < mp->lowmsg)
+ last = mp->lowmsg;
+ if (last > mp->hghmsg)
+ last = mp->hghmsg;
+ if (last < first) {
+ range = last;
+ last = first;
+ first = range;
+ }
break;
- default:
- advise (NULL, "no messages match specification");
- }
- return 0;
- }
-
- if (last < first)
- goto badlist;
- if (*delimp)
- goto badelim;
- if (first > mp->hghmsg || last < mp->lowmsg) {
-rangerr:
- advise (NULL, "no messages in range %s", name);
- return 0;
- }
-
- /* tighten the range to search */
- if (last > mp->hghmsg)
- last = mp->hghmsg;
- if (first < mp->lowmsg)
- first = mp->lowmsg;
-
- } else if (*cp == ':') {
- cp++;
- if (*cp == '-') {
- convdir = -1;
- cp++;
- } else {
- if (*cp == '+') {
- convdir = 1;
- cp++;
- }
- }
- if ((range = atoi (bp = cp)) == 0)
- goto badlist;
- while (isdigit (*bp))
- bp++;
- if (*bp)
- goto badelim;
- if ((convdir > 0 && first > mp->hghmsg)
- || (convdir < 0 && first < mp->lowmsg))
- goto rangerr;
-
- /* tighten the range to search */
- if (first < mp->lowmsg)
- first = mp->lowmsg;
- if (first > mp->hghmsg)
- first = mp->hghmsg;
-
- for (last = first;
- last >= mp->lowmsg && last <= mp->hghmsg;
- last += convdir)
- if (does_exist (mp, last))
- if (--range <= 0)
- break;
- if (last < mp->lowmsg)
- last = mp->lowmsg;
- if (last > mp->hghmsg)
- last = mp->hghmsg;
- if (last < first) {
- range = last;
- last = first;
- first = range;
- }
- } else {
+ case '\0':
+ /* single name */
+ /*
+ ** AFAICS, the only cases to reach here are:
+ ** f, l, p, n, c, b
+ ** But I'm not sure. --meillo
+ */
+ /*
+ ** Single Message
+ **
+ ** Check if message is in-range and exists.
+ */
+ if (first > mp->hghmsg || first < mp->lowmsg ||
+ !does_exist(mp, first)) {
+ if (strcmp(name, seq_cur)==0)
+ advise(NULL, "no current message");
+ else
+ /* this case seems to never be reached */
+ advise(NULL, "message %d doesn't exist",
+ first);
+ return 0;
+ }
+ last = first; /* range of 1 */
+ break;
-single:
- /*
- * Single Message
- *
- * If ALLOW_NEW is set, then allow selecting of an
- * empty slot. If ALLOW_NEW is not set, then we
- * check if message is in-range and exists.
- */
- if (mp->msgflags & ALLOW_NEW) {
- set_select_empty (mp, first);
- } else {
- if (first > mp->hghmsg
- || first < mp->lowmsg
- || !(does_exist (mp, first))) {
- if (!strcmp (name, "cur") || !strcmp (name, "."))
- advise (NULL, "no %s message", name);
- else
- advise (NULL, "message %d doesn't exist", first);
+ default:
+badelim:
+ advise(NULL, "illegal argument delimiter: `%c'(0%o)",
+ *delimp, *delimp);
return 0;
- }
- }
- last = first; /* range of 1 */
- }
-
- /*
- * Cycle through the range and select the messages
- * that exist. If ALLOW_NEW is set, then we also check
- * if we are selecting an empty slot.
- */
- for (; first <= last; first++) {
- if (does_exist (mp, first) ||
- ((mp->msgflags & ALLOW_NEW) && is_select_empty (mp, first))) {
- if (!is_selected (mp, first)) {
- set_selected (mp, first);
- mp->numsel++;
- if (mp->lowsel == 0 || first < mp->lowsel)
- mp->lowsel = first;
- if (first > mp->hghsel)
- mp->hghsel = first;
- }
- found++;
+ break;
}
- }
- if (!found)
- goto rangerr;
+ /* Cycle through the range and select the messages that exist. */
+ for (found=0; first <= last; first++) {
+ if (does_exist(mp, first)) {
+ addtosel(mp, first);
+ found++;
+ }
+ }
+ if (!found)
+ goto rangerr;
- return 1;
+ return 1;
}
/*
- * Convert the various message names to
- * their numeric values.
- *
- * n (integer)
- * prev
- * next
- * first
- * last
- * cur
- * . (same as cur)
- */
-
+** Convert the various message names to their numeric values.
+**
+** 42 (any integer)
+** p
+** n
+** f
+** l
+** c
+*/
static int
-m_conv (struct msgs *mp, char *str, int call)
+m_conv(struct msgs *mp, char *str, int call)
{
- register int i;
- register char *cp, *bp;
- char buf[16];
-
- convdir = 1;
- cp = bp = str;
- if (isdigit (*cp)) {
- while (isdigit (*bp))
- bp++;
- delimp = bp;
- i = atoi (cp);
-
- if (i <= mp->hghmsg)
- return i;
- else if (*delimp || call == LAST)
- return mp->hghmsg + 1;
- else if (mp->msgflags & ALLOW_NEW)
- return BADRNG;
- else
- return BADNUM;
- }
-
-#ifdef LOCALE
- /* doesn't enforce lower case */
- for (bp = buf; (isalpha(*cp) || *cp == '.')
- && (bp - buf < sizeof(buf) - 1); )
-#else
- for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
- && (bp - buf < sizeof(buf) - 1); )
-#endif /* LOCALE */
- {
- *bp++ = *cp++;
- }
- *bp++ = '\0';
- delimp = cp;
-
- if (!strcmp (buf, "first"))
- return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW)
- ? mp->lowmsg : BADMSG);
-
- if (!strcmp (buf, "last")) {
- convdir = -1;
- return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) ? mp->hghmsg : BADMSG);
- }
-
- if (!strcmp (buf, "cur") || !strcmp (buf, "."))
- return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
-
- if (!strcmp (buf, "prev")) {
- convdir = -1;
- for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg;
- i >= mp->lowmsg; i--) {
- if (does_exist (mp, i))
- return i;
+ int i;
+ unsigned char *cp, *bp;
+ unsigned char buf[16]; /* for reserved sequence name */
+
+ convdir = 1;
+ cp = bp = str;
+
+ /* Handle an integer */
+ if (isdigit(*cp)) {
+ while (isdigit(*bp))
+ bp++;
+ delimp = bp;
+ i = atoi(cp);
+
+ if (i <= mp->hghmsg)
+ return i;
+ else if (*delimp || call == LAST)
+ return mp->hghmsg + 1;
+ else if (mp->msgflags & ALLOW_BEYOND)
+ return BADRNG;
+ else
+ return BADNUM;
}
- return BADMSG;
- }
-
- if (!strcmp (buf, "next")) {
- for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg;
- i <= mp->hghmsg; i++) {
- if (does_exist (mp, i))
- return i;
+
+ for (bp = buf; isalpha(*cp) && (bp - buf < (int)sizeof(buf) - 1); ) {
+ *bp++ = *cp++;
}
- return BADMSG;
- }
+ *bp++ = '\0';
+ delimp = cp;
- return BADLST;
-}
+ /* Which one of the reserved names is it? */
+ if (strcmp(buf, seq_first)==0) {
+ return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ?
+ mp->lowmsg : BADMSG);
-/*
- * Handle user defined sequences.
- * They can take the following forms:
- *
- * seq
- * seq:prev
- * seq:next
- * seq:first
- * seq:last
- * seq:+n
- * seq:-n
- * seq:n
- */
+ } else if (strcmp(buf, seq_last)==0) {
+ convdir = -1;
+ return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ?
+ mp->hghmsg : BADMSG);
-static int
-attr (struct msgs *mp, char *cp)
-{
- register char *dp;
- char *bp = NULL;
- register int i, j;
- int found,
- inverted = 0,
- range = 0, /* no range */
- first = 0;
-
- /* hack for "cur-name", "cur-n", etc. */
- if (!strcmp (cp, "cur"))
- return 0;
- if (ssequal ("cur:", cp)) /* this code need to be rewritten... */
- return 0;
-
- /* Check for sequence negation */
- if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) {
- inverted = 1;
- cp += strlen (dp);
- }
-
- convdir = 1; /* convert direction */
-
- for (dp = cp; *dp && isalnum(*dp); dp++)
- continue;
-
- if (*dp == ':') {
- bp = dp++;
- range = 1;
+ } else if (strcmp(buf, seq_cur)==0) {
+ return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
- /*
- * seq:prev (or)
- * seq:next (or)
- * seq:first (or)
- * seq:last
- */
- if (isalpha (*dp)) {
- if (!strcmp (dp, "prev")) {
+ } else if (strcmp(buf, seq_prev)==0) {
convdir = -1;
- first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
- ? mp->curmsg - 1
- : mp->hghmsg;
- }
- else if (!strcmp (dp, "next")) {
- convdir = 1;
- first = (mp->curmsg >= mp->lowmsg)
- ? mp->curmsg + 1
- : mp->lowmsg;
- }
- else if (!strcmp (dp, "first")) {
- convdir = 1;
- }
- else if (!strcmp (dp, "last")) {
- convdir = -1;
- }
- else
- return BADLST;
+ for (i = (mp->curmsg <= mp->hghmsg) ?
+ mp->curmsg - 1 : mp->hghmsg;
+ i >= mp->lowmsg; i--) {
+ if (does_exist(mp, i))
+ return i;
+ }
+ return BADMSG;
+
+ } else if (strcmp(buf, seq_next)==0) {
+ for (i = (mp->curmsg >= mp->lowmsg) ?
+ mp->curmsg + 1 : mp->lowmsg;
+ i <= mp->hghmsg; i++) {
+ if (does_exist(mp, i))
+ return i;
+ }
+ return BADMSG;
+
} else {
- /*
- * seq:n (or)
- * seq:+n (or)
- * seq:-n
- */
- if (*dp == '+')
- dp++;
- else if (*dp == '-') {
- dp++;
- convdir = -1;
- }
- if ((range = atoi(dp)) == 0)
- return BADLST;
- while (isdigit (*dp))
- dp++;
- if (*dp)
return BADLST;
}
+}
- *bp = '\0'; /* temporarily terminate sequence name */
- }
-
- i = seq_getnum (mp, cp); /* get index of sequence */
-
- if (bp)
- *bp = ':'; /* restore sequence name */
- if (i == -1)
- return 0;
-
- found = 0; /* count the number we select for this argument */
-
- for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
- j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
- if (does_exist (mp, j)
- && inverted ? !in_sequence (mp, i, j) : in_sequence (mp, i, j)) {
- if (!is_selected (mp, j)) {
- set_selected (mp, j);
- mp->numsel++;
- if (mp->lowsel == 0 || j < mp->lowsel)
- mp->lowsel = j;
- if (j > mp->hghsel)
- mp->hghsel = j;
- }
- found++;
-
- /*
- * If we have a range, then break out
- * once we've found enough.
- */
- if (range && found >= range)
- break;
+/*
+** Handle user defined sequences.
+** They can take the following forms:
+**
+** seq
+** seq:p
+** seq:n
+** seq:f
+** seq:l
+** seq:+42
+** seq:-42
+** seq:42
+**
+** (`42' being an arbitrary integer)
+*/
+static int
+attr(struct msgs *mp, char *cp)
+{
+ unsigned char *dp;
+ char *bp = NULL;
+ int i, j;
+ int found;
+ int inverted = 0;
+ int range = 0; /* no range */
+ int first = 0;
+
+ /* hack for "c-..." */
+ if (strcmp(cp, seq_cur)==0)
+ return 0;
+ /* "c:..." -- this code need to be rewritten... */
+ if (strncmp(seq_cur, cp, strlen(seq_cur))==0 &&
+ cp[strlen(seq_cur)] == ':') {
+ return 0;
+ }
+
+ /* Check for sequence negation */
+ if (!(dp = context_find(nsequence))) {
+ dp = seq_neg; /* use default */
+ }
+ if (*dp && strncmp(cp, dp, strlen(dp))==0) {
+ inverted = 1;
+ cp += strlen(dp);
+ }
+
+ convdir = 1; /* convert direction */
+
+ for (dp = cp; *dp && isalnum(*dp); dp++)
+ continue;
+
+ if (*dp == ':') {
+ bp = dp++;
+ range = 1;
+
+ /*
+ ** seq:p (or)
+ ** seq:n (or)
+ ** seq:f (or)
+ ** seq:l
+ */
+ if (isalpha(*dp)) {
+ if (strcmp(dp, seq_prev)==0) {
+ convdir = -1;
+ first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
+ ? mp->curmsg - 1 : mp->hghmsg;
+ } else if (strcmp(dp, seq_next)==0) {
+ convdir = 1;
+ first = (mp->curmsg >= mp->lowmsg)
+ ? mp->curmsg + 1 : mp->lowmsg;
+ } else if (strcmp(dp, seq_first)==0) {
+ convdir = 1;
+ } else if (strcmp(dp, seq_last)==0) {
+ convdir = -1;
+ } else
+ return BADLST;
+ } else {
+ /*
+ ** seq:42 (or)
+ ** seq:+42 (or)
+ ** seq:-42
+ */
+ if (*dp == '+')
+ dp++;
+ else if (*dp == '-') {
+ dp++;
+ convdir = -1;
+ }
+ if ((range = atoi(dp)) == 0)
+ return BADLST;
+ while (isdigit(*dp))
+ dp++;
+ if (*dp)
+ return BADLST;
+ }
+
+ *bp = '\0'; /* temporarily terminate sequence name */
+ }
+
+ i = seq_getnum(mp, cp); /* get index of sequence */
+
+ if (bp)
+ *bp = ':'; /* restore sequence name */
+ if (i == -1)
+ return 0;
+
+ found = 0; /* count the number we select for this argument */
+
+ for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
+ j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
+ if (does_exist(mp, j)
+ && inverted ? !in_sequence(mp, i, j) :
+ in_sequence(mp, i, j)) {
+ addtosel(mp, j);
+ found++;
+
+ /*
+ ** If we have a range, then break out
+ ** once we've found enough.
+ */
+ if (range && found >= range)
+ break;
+ }
}
- }
- if (found > 0)
- return found;
+ if (found)
+ return found;
- if (first)
- return BADMSG;
- advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
- return -1;
+ if (first)
+ return BADMSG;
+ advise(NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
+ return -1;
}