Added test of -nosequence to test-pick.
[mmh] / docs / historical / mh-6.8.5 / sbr / m_convert.c
1 /* m_convert.c - parse a message sequence and set SELECTED */
2 #ifndef lint
3 static char ident[] = "@(#)$Id: m_convert.c,v 1.10 1992/12/15 00:20:22 jromine Exp $";
4 #endif  /* lint */
5
6 #include "../h/mh.h"
7 #include <stdio.h>
8 #include <ctype.h>
9
10 #define BADMSG  (-2)
11 #define BADRNG  (-3)
12 #define BADNEW  (-4)
13 #define BADNUM  (-5)
14 #define BADLST  (-6)
15
16 #define FIRST   1
17 #define LAST    2
18
19 #define getnew(mp)      (mp -> hghmsg + 1)
20
21 static int  convdir;
22 static char *delimp;
23
24 static m_conv(), attr();
25 /* \f */
26
27 m_convert (mp, name)
28 register struct msgs *mp;
29 register char   *name;
30 {
31     register int    first,
32                     last;
33     register char  *bp,
34                    *cp;
35     int     found,
36             range,
37             err,
38             flags;
39
40     switch (err = attr (mp, cp = name)) {
41         case NOTOK: 
42             return 0;
43
44         case OK: 
45             break;
46
47         default: 
48             if (err < 0)
49                 goto badmsg;
50             return 1;
51     }
52
53     found = 0;
54     flags = mp -> msgflags & MHPATH ? EXISTS | SELECT_EMPTY : EXISTS;
55
56     if ((mp -> msgflags & MHPATH) && strcmp (cp, "new") == 0)
57         if ((err = first = getnew (mp)) <= 0)
58             goto badmsg;
59         else
60             goto single;
61     if (strcmp (cp, "all") == 0)
62         cp = "first-last";
63     if ((err = first = m_conv (mp, cp, FIRST)) <= 0)
64         goto badmsg;
65     if (*(cp = delimp) && *cp != '-' && *cp != ':') {
66 badelim: ;
67         advise (NULLCP, "illegal argument delimiter: `%c'(0%o)",
68                 *delimp, *delimp);
69         return 0;
70     }
71     if (*cp == '-') {
72         cp++;
73         if ((err = last = m_conv (mp, cp, LAST)) <= 0) {
74     badmsg: ;
75             switch (err) {
76                 case BADMSG: 
77                     advise (NULLCP, "no %s message", cp);
78                     break;
79
80                 case BADNUM: 
81                     advise (NULLCP, "message %s doesn't exist", cp);
82                     break;
83
84                 case BADRNG: 
85                     advise (NULLCP, "message %s out of range 1-%d",
86                             cp, mp -> hghmsg);
87                     break;
88
89                 case BADLST: 
90             badlist: ;
91                     advise (NULLCP, "bad message list %s", name);
92                     break;
93
94                 case BADNEW:
95                     advise (NULLCP, "folder full, no %s message", name);
96                     break;
97
98                 default: 
99                     advise (NULLCP, "no messages match specification");
100             }
101             return 0;
102         }
103         if (last < first)
104             goto badlist;
105         if (*delimp)
106             goto badelim;
107         if (first > mp -> hghmsg || last < mp -> lowmsg) {
108     rangerr: ;
109             advise (NULLCP, "no messages in range %s", name);
110             return 0;
111         }
112         if (last > mp -> hghmsg)
113             last = mp -> hghmsg;
114         if (first < mp -> lowmsg)
115             first = mp -> lowmsg;
116         }
117     else
118         if (*cp == ':') {
119             cp++;
120             if (*cp == '-') {
121                 convdir = -1;
122                 cp++;
123             }
124             else
125                 if (*cp == '+') {
126                     convdir = 1;
127                     cp++;
128                 }
129             if ((range = atoi (bp = cp)) == 0)
130                 goto badlist;
131             while (isdigit (*bp))
132                 bp++;
133             if (*bp)
134                 goto badelim;
135             if ((convdir > 0 && first > mp -> hghmsg)
136                     || (convdir < 0 && first < mp -> lowmsg))
137                 goto rangerr;
138             if (first < mp -> lowmsg)
139                 first = mp -> lowmsg;
140             if (first > mp -> hghmsg)
141                 first = mp -> hghmsg;
142             for (last = first;
143                     last >= mp -> lowmsg && last <= mp -> hghmsg;
144                     last += convdir)
145                 if (mp -> msgstats[last] & EXISTS)
146                     if (--range <= 0)
147                         break;
148             if (last < mp -> lowmsg)
149                 last = mp -> lowmsg;
150             if (last > mp -> hghmsg)
151                 last = mp -> hghmsg;
152             if (last < first) {
153                 range = last;
154                 last = first;
155                 first = range;
156             }
157         }
158         else {
159             if (!(mp -> msgflags & MHPATH))
160                 if (first > mp -> hghmsg
161                         || first < mp -> lowmsg
162                         || !(mp -> msgstats[first] & EXISTS)) {
163                     if (strcmp (name, "cur") == 0 || strcmp (name, ".") == 0)
164                         advise (NULLCP, "no %s message", name);
165                     else
166                         advise (NULLCP, "message %d doesn't exist", first);
167                     return 0;
168                 }
169     single: ;
170             last = first;
171             if (mp -> msgflags & MHPATH)
172                 mp -> msgstats[first] |= SELECT_EMPTY;
173         }
174     for (; first <= last; first++)
175         if (mp -> msgstats[first] & flags) {
176             if (!(mp -> msgstats[first] & SELECTED)) {
177                 mp -> numsel++;
178                 mp -> msgstats[first] |= SELECTED;
179                 if (mp -> lowsel == 0 || first < mp -> lowsel)
180                     mp -> lowsel = first;
181                 if (first > mp -> hghsel)
182                     mp -> hghsel = first;
183             }
184             found++;
185         }
186     if (!found)
187         goto rangerr;
188
189     return 1;
190 }
191
192 /* \f */
193
194 static  m_conv (mp, str, call)
195 register struct msgs *mp;
196 register char   *str;
197 register int     call;
198 {
199     register int    i;
200     register char  *cp,
201                    *bp;
202     char    buf[16];
203
204     convdir = 1;
205     cp = bp = str;
206     if (isdigit (*cp)) {
207         while (isdigit (*bp))
208             bp++;
209         delimp = bp;
210         return ((i = atoi (cp)) <= mp -> hghmsg ? i
211                 : *delimp || call == LAST ? mp -> hghmsg + 1
212                 : mp -> msgflags & MHPATH ? BADRNG : BADNUM);
213     }
214
215     bp = buf;
216 #ifndef LOCALE
217     while ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
218 #else
219     while (isalpha(*cp) || *cp == '.')  /* doesn't enforce lower case */
220 #endif /* LOCALE */
221         *bp++ = *cp++;
222     *bp++ = 0;
223     delimp = cp;
224
225     if (strcmp (buf, "first") == 0)
226         return (mp -> hghmsg || !(mp -> msgflags & MHPATH)
227                 ? mp -> lowmsg : BADMSG);
228
229     if (strcmp (buf, "last") == 0) {
230         convdir = -1;
231         return (mp -> hghmsg || !(mp -> msgflags & MHPATH)
232                 ? mp -> hghmsg : BADMSG);
233     }
234
235     if (strcmp (buf, "cur") == 0 || strcmp (buf, ".") == 0)
236         return (mp -> curmsg > 0 ? mp -> curmsg : BADMSG);
237
238     if (strcmp (buf, "prev") == 0) {
239         convdir = -1;
240         for (i = (mp -> curmsg <= mp -> hghmsg) ? mp -> curmsg - 1 : mp -> hghmsg;
241                 i >= mp -> lowmsg; i--) {
242             if (mp -> msgstats[i] & EXISTS)
243                 return i;
244         }
245         return BADMSG;
246     }
247
248     if (strcmp (buf, "next") == 0) {
249         for (i = (mp -> curmsg >= mp -> lowmsg) ? mp -> curmsg + 1 : mp -> lowmsg;
250                 i <= mp -> hghmsg; i++) {
251             if (mp -> msgstats[i] & EXISTS)
252                 return i;
253         }
254         return BADMSG;
255     }
256
257     return BADLST;
258 }
259
260 /* \f */
261
262 static  attr (mp, cp)
263 register struct msgs *mp;
264 register char   *cp;
265 {
266     char   *bp = (char *)NULL;
267     int     bits,
268             found,
269             inverted,
270             range = 0,          /* no range */
271             first = 0;
272     register int    i,
273                     j;
274     register char  *dp;
275
276     if (strcmp (cp, "cur") == 0)/* hack for "cur-xyz", etc. */
277         return OK;
278     if (ssequal ("cur:", cp))   /* this code need to be rewritten... */
279         return OK;
280
281     if (inverted = (dp = m_find (nsequence)) && *dp && ssequal (dp, cp))
282         cp += strlen (dp);
283
284     convdir = 1;
285     for (dp = cp; *dp && isalnum(*dp); dp++)
286         continue;
287     if (*dp == ':') {
288         bp = dp++;
289
290         range = 1;
291         if (isalpha (*dp)) {    /* optimize? */
292             if (strcmp (dp, "prev") == 0) {
293                 convdir = -1;
294                 first = (mp -> curmsg > 0) && (mp -> curmsg <= mp -> hghmsg)
295                         ? mp -> curmsg - 1
296                         : mp -> hghmsg;
297             }
298             else if (strcmp (dp, "next") == 0) {
299                 convdir = 1;
300                 first = (mp -> curmsg >= mp -> lowmsg)
301                             ? mp -> curmsg + 1
302                             : mp -> lowmsg;
303             }
304             else if (strcmp (dp, "first") == 0) {
305                 convdir = 1;
306             }
307             else if (strcmp (dp, "last") == 0) {
308                 convdir = -1;
309             }
310             else
311                 return BADLST;
312         }
313         else {                  /* a numeric range */
314             if (*dp == '+')
315                 dp++;
316             else if (*dp == '-') {
317                 dp++;
318                 convdir = -1;
319             }
320             if ((range = atoi(dp)) == 0)
321                 return BADLST;
322             while (isdigit (*dp))
323                 dp++;
324             if (*dp)
325                 return BADLST;
326         }
327
328         *bp = '\0';             /* terminate sequence name */
329     }
330
331
332     bits = FFATTRSLOT;
333     for (i = 0; mp -> msgattrs[i]; i++)
334         if (strcmp (mp -> msgattrs[i], cp) == 0)
335             break;
336     if (bp)
337         *bp = ':';              /* restore sequence name */
338     if (mp -> msgattrs[i] == NULL)
339         return OK;
340
341     found = 0;
342     for (j = first ? first : (convdir > 0) ? mp -> lowmsg : mp -> hghmsg;
343                 j >= mp -> lowmsg && j <= mp -> hghmsg; j += convdir)
344         if ((mp -> msgstats[j] & EXISTS)
345                 && inverted ? !(mp -> msgstats[j] & (1 << (bits + i)))
346                 : mp -> msgstats[j] & (1 << (bits + i))) {
347             if (!(mp -> msgstats[j] & SELECTED)) {
348                 mp -> numsel++;
349                 mp -> msgstats[j] |= SELECTED;
350                 if (mp -> lowsel == 0 || j < mp -> lowsel)
351                     mp -> lowsel = j;
352                 if (j > mp -> hghsel)
353                     mp -> hghsel = j;
354             }
355             found++;
356             if (range && found >= range)
357                 break;          /* we've done enough */
358         }
359     if (found > 0)
360         return found;
361
362     if (first)
363         return BADMSG;
364     advise (NULLCP, "sequence %s %s", cp, inverted ? "full" : "empty");
365     return NOTOK;
366 }