]> diplodocus.org Git - nmh/blobdiff - sbr/m_convert.c
dtimezone(): Explain abs(3) is undefined on INT_MIN.
[nmh] / sbr / m_convert.c
index e9a5d1887d02adc4d41c20bce1b5a74895e30281..566b02a5286fdf185f32f7611f46fb024a781d71 100644 (file)
@@ -1,11 +1,12 @@
-
-/*
- * m_convert.c -- parse a message range or sequence and set SELECTED
+/* 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.
  */
 
 #include <h/mh.h>
  */
 
 #include <h/mh.h>
+#include <h/utils.h>
 
 /*
  * error codes for sequence
 
 /*
  * error codes for sequence
@@ -20,6 +21,7 @@
 #define        FIRST   1
 #define        LAST    2
 
 #define        FIRST   1
 #define        LAST    2
 
+
 #define        getnew(mp) (mp->hghmsg + 1)
 
 static int convdir;    /* convert direction */
 #define        getnew(mp) (mp->hghmsg + 1)
 
 static int convdir;    /* convert direction */
@@ -35,7 +37,7 @@ static int attr (struct msgs *, char *);
 int
 m_convert (struct msgs *mp, char *name)
 {
 int
 m_convert (struct msgs *mp, char *name)
 {
-    int first, last, found, range, err;
+    int first, last, found, count, is_range, err;
     char *bp, *cp;
 
     /* check if user defined sequence */
     char *bp, *cp;
 
     /* check if user defined sequence */
@@ -43,15 +45,16 @@ m_convert (struct msgs *mp, char *name)
 
     if (err == -1)
        return 0;
 
     if (err == -1)
        return 0;
-    else if (err < 0)
+    if (err < 0)
        goto badmsg;
        goto badmsg;
-    else if (err > 0)
+    if (err > 0)
        return 1;
     /*
      * else err == 0, so continue
      */
 
     found = 0;
        return 1;
     /*
      * else err == 0, so continue
      */
 
     found = 0;
+    is_range = 1;
 
     /*
      * Check for special "new" sequence, which
 
     /*
      * Check for special "new" sequence, which
@@ -60,8 +63,7 @@ m_convert (struct msgs *mp, char *name)
     if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) {
        if ((err = first = getnew (mp)) <= 0)
            goto badmsg;
     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"))
     }
 
     if (!strcmp (cp, "all"))
@@ -71,9 +73,9 @@ m_convert (struct msgs *mp, char *name)
        goto badmsg;
 
     cp = delimp;
        goto badmsg;
 
     cp = delimp;
-    if (*cp != '\0' && *cp != '-' && *cp != ':') {
+    if (*cp != '\0' && *cp != '-' && *cp != ':' && *cp != '=') {
 badelim:
 badelim:
-       advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
+       inform("illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
        return 0;
     }
 
        return 0;
     }
 
@@ -83,28 +85,28 @@ badelim:
 badmsg:
            switch (err) {
            case BADMSG: 
 badmsg:
            switch (err) {
            case BADMSG: 
-               advise (NULL, "no %s message", cp);
+               inform("no %s message", cp);
                break;
 
            case BADNUM: 
                break;
 
            case BADNUM: 
-               advise (NULL, "message %s doesn't exist", cp);
+               inform("message %s doesn't exist", cp);
                break;
 
            case BADRNG: 
                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:
                break;
 
            case BADLST: 
 badlist:
-               advise (NULL, "bad message list %s", name);
+               inform("bad message list %s", name);
                break;
 
            case BADNEW:
                break;
 
            case BADNEW:
-               advise (NULL, "folder full, no %s message", name);
+               inform("folder full, no %s message", name);
                break;
 
            default: 
                break;
 
            default: 
-               advise (NULL, "no messages match specification");
+               inform("no messages match specification");
            }
            return 0;
        }
            }
            return 0;
        }
@@ -115,7 +117,7 @@ badlist:
            goto badelim;
        if (first > mp->hghmsg || last < mp->lowmsg) {
 rangerr:
            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;
        }
 
            return 0;
        }
 
@@ -125,20 +127,25 @@ rangerr:
        if (first < mp->lowmsg)
            first = mp->lowmsg;
 
        if (first < mp->lowmsg)
            first = mp->lowmsg;
 
-    } else if (*cp == ':') {
+    } else if (*cp == ':' || *cp == '=') {
+
+       if (*cp == '=')
+           is_range = 0;
+
        cp++;
        cp++;
+
        if (*cp == '-') {
        if (*cp == '-') {
+           /* foo:-3 or foo=-3 */
            convdir = -1;
            cp++;
            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;
            goto badlist;
-       while (isdigit (*bp))
+       while (isdigit ((unsigned char) *bp))
            bp++;
        if (*bp)
            goto badelim;
            bp++;
        if (*bp)
            goto badelim;
@@ -156,16 +163,24 @@ rangerr:
             last >= mp->lowmsg && last <= mp->hghmsg;
             last += convdir)
            if (does_exist (mp, last))
             last >= mp->lowmsg && last <= mp->hghmsg;
             last += convdir)
            if (does_exist (mp, last))
-               if (--range <= 0)
+               if (--count <= 0)
                    break;
                    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 {
 
        }
     } else {
 
@@ -178,15 +193,27 @@ single:
         * check if message is in-range and exists.
         */
        if (mp->msgflags & ALLOW_NEW) {
         * 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, "."))
            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
                else
-                   advise (NULL, "message %d doesn't exist", first);
+                   inform("message %d doesn't exist", first);
                return 0;
            }
        }
                return 0;
            }
        }
@@ -221,7 +248,7 @@ single:
 
 /*
  * Convert the various message names to
 
 /*
  * Convert the various message names to
- * there numeric value.
+ * their numeric values.
  *
  * n     (integer)
  * prev
  *
  * n     (integer)
  * prev
@@ -235,36 +262,30 @@ single:
 static int
 m_conv (struct msgs *mp, char *str, int call)
 {
 static int
 m_conv (struct msgs *mp, char *str, int call)
 {
-    register int i;
-    register char *cp, *bp;
+    int i;
+    char *cp, *bp;
     char buf[16];
 
     convdir = 1;
     cp = bp = str;
     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;
            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;
            return mp->hghmsg + 1;
-       else if (mp->msgflags & ALLOW_NEW)
+       if (mp->msgflags & ALLOW_NEW)
            return BADRNG;
            return BADRNG;
-       else
-           return BADNUM;
+        return BADNUM;
     }
 
     }
 
-#ifdef LOCALE
     /* doesn't enforce lower case */
     /* 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++;
     }
     {
        *bp++ = *cp++;
     }
@@ -322,19 +343,25 @@ m_conv (struct msgs *mp, char *str, int call)
 static int
 attr (struct msgs *mp, char *cp)
 {
 static int
 attr (struct msgs *mp, char *cp)
 {
-    register char *dp;
+    char *dp;
     char *bp = NULL;
     char *bp = NULL;
-    register int i, j;
+    char *ep;
+    char op;
+    int i, j;
     int found,
        inverted = 0,
     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;
 
     /* 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)) {
 
     /* Check for sequence negation */
     if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) {
@@ -344,12 +371,12 @@ attr (struct msgs *mp, char *cp)
 
     convdir = 1;       /* convert direction */
 
 
     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++;
        continue;
 
     if (*dp == ':') {
        bp = dp++;
-       range = 1;
+       count = 1;
 
        /*
         * seq:prev  (or)
 
        /*
         * seq:prev  (or)
@@ -357,87 +384,125 @@ attr (struct msgs *mp, char *cp)
         * seq:first (or)
         * seq:last
         */
         * 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;
            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;
            }
            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;
            }
            else if (!strcmp (dp, "first")) {
                convdir = 1;
+               start = mp->lowmsg;
            }
            else if (!strcmp (dp, "last")) {
                convdir = -1;
            }
            else if (!strcmp (dp, "last")) {
                convdir = -1;
+               start = mp->hghmsg;
            }
            }
-           else
+           else {
                return BADLST;
                return BADLST;
+           }
        } else {
            /*
             * seq:n  (or)
             * seq:+n (or)
             * seq:-n
              */
        } else {
            /*
             * seq:n  (or)
             * seq:+n (or)
             * seq:-n
              */
-           if (*dp == '+')
+           if (*dp == '+') {
+               /* foo:+3 is same as foo:3 */
                dp++;
                dp++;
-           else if (*dp == '-') {
+               convdir = 1;
+               start = mp->lowmsg;
+           } else if (*dp == '-' || *dp == ':') {
+               /* foo:-3 or foo::3 */
                dp++;
                convdir = -1;
                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;
        }
 
                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 = '\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 */
 
     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 (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++;
            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.
              */
             * once we've found enough.
              */
-           if (range && found >= range)
+           if (count && found >= count)
                break;
                break;
+
        }
     }
 
        }
     }
 
-    if (found > 0)
-       return found;
+    if (mp->numsel > 0)
+       return mp->numsel;
 
 
-    if (first)
+    if (first || just_one)
        return BADMSG;
        return BADMSG;
-    advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
+    inform("sequence %s %s", cp, inverted ? "full" : "empty");
     return -1;
 }
     return -1;
 }