-
-/*
- * m_convert.c -- parse a message range or sequence and set SELECTED
- *
- * $Id$
+/* 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
*/
#include <h/mh.h>
+#include <h/utils.h>
/*
* error codes for sequence
#define FIRST 1
#define LAST 2
+
#define getnew(mp) (mp->hghmsg + 1)
static int convdir; /* convert direction */
int
m_convert (struct msgs *mp, char *name)
{
- int first, last, found, range, err;
- unsigned char *bp;
- char *cp;
+ int first, last, found, count, is_range, err;
+ char *bp, *cp;
/* check if user defined sequence */
err = attr (mp, cp = name);
if (err == -1)
return 0;
- else if (err < 0)
+ if (err < 0)
goto badmsg;
- else if (err > 0)
+ if (err > 0)
return 1;
/*
* else err == 0, so continue
*/
found = 0;
+ is_range = 1;
/*
* Check for special "new" sequence, which
if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) {
if ((err = first = getnew (mp)) <= 0)
goto badmsg;
- else
- goto single;
+ goto single;
}
if (!strcmp (cp, "all"))
goto badmsg;
cp = delimp;
- if (*cp != '\0' && *cp != '-' && *cp != ':') {
+ if (*cp != '\0' && *cp != '-' && *cp != ':' && *cp != '=') {
badelim:
- advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
+ inform("illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
return 0;
}
badmsg:
switch (err) {
case BADMSG:
- advise (NULL, "no %s message", cp);
+ inform("no %s message", cp);
break;
case BADNUM:
- advise (NULL, "message %s doesn't exist", cp);
+ inform("message %s doesn't exist", cp);
break;
case BADRNG:
- advise (NULL, "message %s out of range 1-%d", cp, mp->hghmsg);
+ inform("message %s out of range 1-%d", cp, mp->hghmsg);
break;
case BADLST:
badlist:
- advise (NULL, "bad message list %s", name);
+ inform("bad message list %s", name);
break;
case BADNEW:
- advise (NULL, "folder full, no %s message", name);
+ inform("folder full, no %s message", name);
break;
default:
- advise (NULL, "no messages match specification");
+ inform("no messages match specification");
}
return 0;
}
goto badelim;
if (first > mp->hghmsg || last < mp->lowmsg) {
rangerr:
- advise (NULL, "no messages in range %s", name);
+ inform("no messages in range %s", name);
return 0;
}
if (first < mp->lowmsg)
first = mp->lowmsg;
- } else if (*cp == ':') {
+ } else if (*cp == ':' || *cp == '=') {
+
+ if (*cp == '=')
+ is_range = 0;
+
cp++;
+
if (*cp == '-') {
+ /* foo:-3 or foo=-3 */
convdir = -1;
cp++;
- } else {
- if (*cp == '+') {
- convdir = 1;
- cp++;
- }
+ } else if (*cp == '+') {
+ /* foo:+3 or foo=+3 is same as foo:3 or foo=3 */
+ convdir = 1;
+ cp++;
}
- if ((range = atoi (bp = cp)) == 0)
+ if ((count = atoi (bp = cp)) == 0)
goto badlist;
- while (isdigit (*bp))
+ while (isdigit ((unsigned char) *bp))
bp++;
if (*bp)
goto badelim;
last >= mp->lowmsg && last <= mp->hghmsg;
last += convdir)
if (does_exist (mp, last))
- if (--range <= 0)
+ if (--count <= 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;
+ if (is_range) { /* a range includes any messages that exist */
+ if (last < mp->lowmsg)
+ last = mp->lowmsg;
+ if (last > mp->hghmsg)
+ last = mp->hghmsg;
+ if (last < first) {
+ count = last;
+ last = first;
+ first = count;
+ }
+ } else { /* looking for the nth message. if not enough, fail. */
+ if (last < mp->lowmsg || last > mp->hghmsg) {
+ inform("no such message");
+ return 0;
+ }
+ first = last;
}
} else {
* check if message is in-range and exists.
*/
if (mp->msgflags & ALLOW_NEW) {
+ /*
+ * We can get into a case where the "cur" sequence is way out
+ * of range, and because it's allowed to not exist (think
+ * of "rmm; next") it doesn't get checked to make sure it's
+ * within the range of messages in seq_init(). So if our
+ * desired sequence is out of range of the allocated folder
+ * limits simply reallocate the folder so it's within range.
+ */
+ if (first < mp->lowoff || first > mp->hghoff)
+ mp = folder_realloc(mp, min(first, mp->lowoff),
+ max(first, mp->hghoff));
+
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);
+ inform("no %s message", name);
else
- advise (NULL, "message %d doesn't exist", first);
+ inform("message %d doesn't exist", first);
return 0;
}
}
static int
m_conv (struct msgs *mp, char *str, int call)
{
- register int i;
- register unsigned char *cp, *bp;
- unsigned char buf[16];
+ int i;
+ char *cp, *bp;
+ char buf[16];
convdir = 1;
cp = bp = str;
- if (isdigit (*cp)) {
- while (isdigit (*bp))
+ if (isdigit ((unsigned char) *cp)) {
+ while (isdigit ((unsigned char) *bp))
bp++;
delimp = bp;
i = atoi (cp);
if (i <= mp->hghmsg)
return i;
- else if (*delimp || call == LAST)
+ if (*delimp || call == LAST)
return mp->hghmsg + 1;
- else if (mp->msgflags & ALLOW_NEW)
+ if (mp->msgflags & ALLOW_NEW)
return BADRNG;
- else
- return BADNUM;
+ 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 */
+ for (bp = buf; (isalpha((unsigned char) *cp) || *cp == '.')
+ && (bp - buf < (int) sizeof(buf) - 1); )
{
*bp++ = *cp++;
}
static int
attr (struct msgs *mp, char *cp)
{
- register unsigned char *dp;
+ char *dp;
char *bp = NULL;
- register int i, j;
+ char *ep;
+ char op;
+ int i, j;
int found,
inverted = 0,
- range = 0, /* no range */
- first = 0;
+ count = 0, /* range given? else use entire sequence */
+ just_one = 0, /* want entire sequence or range */
+ first = 0,
+ start = 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;
+ if (has_prefix(cp, "cur")) {
+ if (cp[3] == ':' || cp[3] == '=')
+ return 0;
+ }
/* Check for sequence negation */
if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) {
convdir = 1; /* convert direction */
- for (dp = cp; *dp && isalnum(*dp); dp++)
+ for (dp = cp; *dp && isalnum((unsigned char) *dp); dp++)
continue;
if (*dp == ':') {
bp = dp++;
- range = 1;
+ count = 1;
/*
* seq:prev (or)
* seq:first (or)
* seq:last
*/
- if (isalpha (*dp)) {
+ if (isalpha ((unsigned char) *dp)) {
if (!strcmp (dp, "prev")) {
convdir = -1;
first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
? mp->curmsg - 1
: mp->hghmsg;
+ start = first;
}
else if (!strcmp (dp, "next")) {
convdir = 1;
first = (mp->curmsg >= mp->lowmsg)
? mp->curmsg + 1
: mp->lowmsg;
+ start = first;
}
else if (!strcmp (dp, "first")) {
convdir = 1;
+ start = mp->lowmsg;
}
else if (!strcmp (dp, "last")) {
convdir = -1;
+ start = mp->hghmsg;
}
- else
+ else {
return BADLST;
+ }
} else {
/*
* seq:n (or)
* seq:+n (or)
* seq:-n
*/
- if (*dp == '+')
+ if (*dp == '+') {
+ /* foo:+3 is same as foo:3 */
dp++;
- else if (*dp == '-') {
+ convdir = 1;
+ start = mp->lowmsg;
+ } else if (*dp == '-' || *dp == ':') {
+ /* foo:-3 or foo::3 */
dp++;
convdir = -1;
+ start = mp->hghmsg;
}
- if ((range = atoi(dp)) == 0)
- return BADLST;
- while (isdigit (*dp))
- dp++;
- if (*dp)
+ count = strtol(dp,&ep,10);
+ if (count == 0 || *ep) /* 0 illegal */
return BADLST;
}
+ op = *bp;
+ *bp = '\0'; /* temporarily terminate sequence name */
+ } else if (*dp == '=') {
+
+ bp = dp++;
+
+ if (*dp == '+') {
+ /* foo=+3 is same as foo=3 */
+ dp++;
+ convdir = 1;
+ start = mp->lowmsg;
+ } else if (*dp == '-') {
+ /* foo=-3 */
+ dp++;
+ convdir = -1;
+ start = mp->hghmsg;
+ }
+
+ count = strtol(dp,&ep,10); /* 0 illegal */
+ if (count == 0 || *ep)
+ return BADLST;
+
+ just_one = 1;
+
+ op = *bp;
*bp = '\0'; /* temporarily terminate sequence name */
}
i = seq_getnum (mp, cp); /* get index of sequence */
if (bp)
- *bp = ':'; /* restore sequence name */
+ *bp = op; /* 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 (!start)
+ start = mp->lowmsg;
+
+ for (j = start; 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++;
-
+ /* we want all that we find, or just the last in the +/_ case */
+ if (!just_one || found >= count) {
+ 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;
+ }
+ }
/*
- * If we have a range, then break out
+ * If we have any sort of limit, then break out
* once we've found enough.
*/
- if (range && found >= range)
+ if (count && found >= count)
break;
+
}
}
- if (found > 0)
- return found;
+ if (mp->numsel > 0)
+ return mp->numsel;
- if (first)
+ if (first || just_one)
return BADMSG;
- advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
+ inform("sequence %s %s", cp, inverted ? "full" : "empty");
return -1;
}