]> diplodocus.org Git - nmh/blobdiff - sbr/m_convert.c
dtimezone(): Explain abs(3) is undefined on INT_MIN.
[nmh] / sbr / m_convert.c
index 56b63233f07281b0080fc17cba31c944843760b7..566b02a5286fdf185f32f7611f46fb024a781d71 100644 (file)
@@ -1,6 +1,4 @@
-
-/*
- * m_convert.c -- parse a message range or sequence and set SELECTED
+/* 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
  *
  * This code is Copyright (c) 2002, by the authors of nmh.  See the
  * COPYRIGHT file in the root directory of the nmh distribution for
@@ -8,6 +6,7 @@
  */
 
 #include <h/mh.h>
  */
 
 #include <h/mh.h>
+#include <h/utils.h>
 
 /*
  * error codes for sequence
 
 /*
  * error codes for sequence
@@ -22,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 */
@@ -37,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 */
@@ -45,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
@@ -62,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"))
@@ -73,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;
     }
 
@@ -85,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;
        }
@@ -117,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;
        }
 
@@ -127,18 +127,23 @@ 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;
        while (isdigit ((unsigned char) *bp))
            bp++;
            goto badlist;
        while (isdigit ((unsigned char) *bp))
            bp++;
@@ -158,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 {
 
@@ -189,8 +202,8 @@ single:
             * limits simply reallocate the folder so it's within range.
             */
            if (first < mp->lowoff || first > mp->hghoff)
             * limits simply reallocate the folder so it's within range.
             */
            if (first < mp->lowoff || first > mp->hghoff)
-               mp = folder_realloc(mp, first < mp->lowoff ? first : mp->lowoff,
-                                   first > mp->hghoff ? first : mp->hghoff);
+                mp = folder_realloc(mp, min(first, mp->lowoff),
+                                    max(first, mp->hghoff));
 
            set_select_empty (mp, first);
        } else {
 
            set_select_empty (mp, first);
        } else {
@@ -198,9 +211,9 @@ single:
                || first < mp->lowmsg
                || !(does_exist (mp, first))) {
                if (!strcmp (name, "cur") || !strcmp (name, "."))
                || 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;
            }
        }
@@ -263,22 +276,16 @@ m_conv (struct msgs *mp, char *str, int call)
 
        if (i <= mp->hghmsg)
            return i;
 
        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 */
     for (bp = buf; (isalpha((unsigned char) *cp) || *cp == '.')
            && (bp - buf < (int) sizeof(buf) - 1); )
     /* doesn't enforce lower case */
     for (bp = buf; (isalpha((unsigned char) *cp) || *cp == '.')
            && (bp - buf < (int) sizeof(buf) - 1); )
-#else
-    for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
-           && (bp - buf < (int) sizeof(buf) - 1); )
-#endif /* LOCALE */
     {
        *bp++ = *cp++;
     }
     {
        *bp++ = *cp++;
     }
@@ -338,17 +345,23 @@ attr (struct msgs *mp, char *cp)
 {
     char *dp;
     char *bp = NULL;
 {
     char *dp;
     char *bp = NULL;
+    char *ep;
+    char op;
     int i, j;
     int found,
        inverted = 0,
     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;
 
     /* 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)) {
@@ -363,7 +376,7 @@ attr (struct msgs *mp, char *cp)
 
     if (*dp == ':') {
        bp = dp++;
 
     if (*dp == ':') {
        bp = dp++;
-       range = 1;
+       count = 1;
 
        /*
         * seq:prev  (or)
 
        /*
         * seq:prev  (or)
@@ -377,81 +390,119 @@ attr (struct msgs *mp, char *cp)
                first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
                        ? mp->curmsg - 1
                        : mp->hghmsg;
                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 ((unsigned char) *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;
 }