Remove not used code (JLR define)
[mmh] / sbr / m_convert.c
1 /*
2 ** m_convert.c -- parse a message range or sequence and set SELECTED
3 **
4 ** This code is Copyright (c) 2002, by the authors of nmh.  See the
5 ** COPYRIGHT file in the root directory of the nmh distribution for
6 ** complete copyright information.
7 */
8
9
10 /* FIXME: This code needs rework! Rewrite as a parser? */
11
12 #include <h/mh.h>
13 #include <ctype.h>
14
15 /*
16 ** error codes for sequence
17 ** and message range processing
18 */
19 #define BADMSG (-2)
20 #define BADRNG (-3)
21 #define BADNEW (-4)
22 #define BADNUM (-5)
23 #define BADLST (-6)
24
25 #define FIRST 1
26 #define LAST 2
27
28 #define getbeyond(mp) ((mp)->hghmsg + 1)
29
30 static int convdir;  /* convert direction */
31 static char *delimp;  /* delimiter pointer */
32
33 /*
34 ** static prototypes
35 */
36 static int m_conv(struct msgs *, char *, int);
37 static int attr(struct msgs *, char *);
38
39 int
40 m_convert(struct msgs *mp, char *name)
41 {
42         int first, last, found, range, err;
43         unsigned char *bp;
44         char *cp;
45
46         /* check if user defined sequence */
47         err = attr(mp, cp = name);
48         if (err == -1)
49                 return 0;
50         else if (err < 0)
51                 goto badmsg;
52         else if (err > 0) {
53                 /* it had been a user-defined sequence: we're finished */
54                 return 1;
55         }
56         /*
57         ** else err == 0, so continue
58         ** here we know: it is no user-defined seq
59         */
60
61         /*
62         ** Handle the special beyond sequence, which is valid only if
63         ** ALLOW_BEYOND is set, and can appear only on its own.
64         ** Also, it is available in any folder.
65         */
66         if ((mp->msgflags & ALLOW_BEYOND) && strcmp(cp, seq_beyond)==0) {
67                 set_selected(mp, getbeyond(mp));
68                 return 1;
69         }
70
71         /*
72         ** Handle the special all sequence: replace `a' with `f-l'
73         */
74         if (strcmp(cp, seq_all)==0) {
75                 cp = concat(seq_first, "-", seq_last, NULL);
76         }
77
78         if ((err = first = m_conv(mp, cp, FIRST)) <= 0)
79                 goto badmsg;
80
81         cp = delimp;
82         switch (*cp) {
83         case '-':
84                 /* global range */
85                 cp++;
86                 if ((err = last = m_conv(mp, cp, LAST)) <= 0) {
87 badmsg:
88                         switch (err) {
89                         case BADMSG:
90                                 advise(NULL, "no %s message", cp);
91                                 break;
92
93                         case BADNUM:
94                                 advise(NULL, "message %s doesn't exist", cp);
95                                 break;
96
97                         case BADRNG:
98                                 advise(NULL, "message %s out of range 1-%d",
99                                                 cp, mp->hghmsg);
100                                 break;
101
102                         case BADLST:
103 badlist:
104                                 advise(NULL, "bad message list %s", name);
105                                 break;
106
107                         case BADNEW:
108                                 advise(NULL, "folder full, no %s message",
109                                                 name);
110                                 break;
111
112                         default:
113                                 advise(NULL, "no messages match specification");
114                         }
115                         return 0;
116                 }
117
118                 if (last < first)
119                         goto badlist;
120                 if (*delimp)
121                         goto badelim;
122                 if (first > mp->hghmsg || last < mp->lowmsg) {
123 rangerr:
124                         advise(NULL, "no messages in range %s", name);
125                         return 0;
126                 }
127
128                 /* tighten the range to search */
129                 if (last > mp->hghmsg)
130                         last = mp->hghmsg;
131                 if (first < mp->lowmsg)
132                         first = mp->lowmsg;
133                 break;
134
135         case ':':
136                 /* anchored range */
137                 cp++;
138                 if (*cp == '-') {
139                         convdir = -1;
140                         cp++;
141                 } else if (*cp == '+') {
142                         convdir = 1;
143                         cp++;
144                 }
145                 if ((range = atoi(bp = cp)) == 0)
146                         goto badlist;
147                 while (isdigit(*bp))
148                         bp++;
149                 if (*bp)
150                         goto badelim;
151                 if ((convdir > 0 && first > mp->hghmsg)
152                                 || (convdir < 0 && first < mp->lowmsg))
153                         goto rangerr;
154
155                 /* tighten the range to search */
156                 if (first < mp->lowmsg)
157                         first = mp->lowmsg;
158                 if (first > mp->hghmsg)
159                         first = mp->hghmsg;
160
161                 for (last = first; last >= mp->lowmsg && last <= mp->hghmsg;
162                                 last += convdir)
163                         if (does_exist(mp, last) && (--range <= 0))
164                                 break;
165                 if (last < mp->lowmsg)
166                         last = mp->lowmsg;
167                 if (last > mp->hghmsg)
168                         last = mp->hghmsg;
169                 if (last < first) {
170                         range = last;
171                         last = first;
172                         first = range;
173                 }
174                 break;
175
176         case '\0':
177                 /* single name */
178                 /*
179                 ** AFAICS, the only cases to reach here are:
180                 **     f, l, p, n, c, b
181                 ** But I'm not sure.  --meillo
182                 */
183                 /*
184                 ** Single Message
185                 **
186                 ** Check if message is in-range and exists.
187                 */
188                 if (first > mp->hghmsg || first < mp->lowmsg ||
189                                 !does_exist(mp, first)) {
190                         if (strcmp(name, seq_cur)==0)
191                                 advise(NULL, "no current message");
192                         else
193                                 /* this case seems to never be reached */
194                                 advise(NULL, "message %d doesn't exist",
195                                                 first);
196                         return 0;
197                 }
198                 last = first;  /* range of 1 */
199                 break;
200
201         default:
202 badelim:
203                 advise(NULL, "illegal argument delimiter: `%c'(0%o)",
204                                 *delimp, *delimp);
205                 return 0;
206                 break;
207         }
208
209         /* Cycle through the range and select the messages that exist. */
210         for (found=0; first <= last; first++) {
211                 if (does_exist(mp, first)) {
212                         set_selected(mp, first);
213                         found++;
214                 }
215         }
216         if (!found)
217                 goto rangerr;
218
219         return 1;
220 }
221
222 /*
223 ** Convert the various message names to their numeric values.
224 **
225 ** 42  (any integer)
226 ** p
227 ** n
228 ** f
229 ** l
230 ** c
231 */
232 static int
233 m_conv(struct msgs *mp, char *str, int call)
234 {
235         int i;
236         unsigned char *cp, *bp;
237         unsigned char buf[16];  /* for reserved sequence name */
238
239         convdir = 1;
240         cp = bp = str;
241
242         /* Handle an integer */
243         if (isdigit(*cp)) {
244                 while (isdigit(*bp))
245                         bp++;
246                 delimp = bp;
247                 i = atoi(cp);
248
249                 if (i <= mp->hghmsg)
250                         return i;
251                 else if (*delimp || call == LAST)
252                         return mp->hghmsg + 1;
253                 else if (mp->msgflags & ALLOW_BEYOND)
254                         return BADRNG;
255                 else
256                         return BADNUM;
257         }
258
259         for (bp = buf; isalpha(*cp) && (bp - buf < (int)sizeof(buf) - 1); ) {
260                 *bp++ = *cp++;
261         }
262         *bp++ = '\0';
263         delimp = cp;
264
265         /* Which one of the reserved names is it? */
266         if (strcmp(buf, seq_first)==0) {
267                 return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ?
268                                 mp->lowmsg : BADMSG);
269
270         } else if (strcmp(buf, seq_last)==0) {
271                 convdir = -1;
272                 return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ?
273                                 mp->hghmsg : BADMSG);
274
275         } else if (strcmp(buf, seq_cur)==0) {
276                 return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
277
278         } else if (strcmp(buf, seq_prev)==0) {
279                 convdir = -1;
280                 for (i = (mp->curmsg <= mp->hghmsg) ?
281                                 mp->curmsg - 1 : mp->hghmsg;
282                                 i >= mp->lowmsg; i--) {
283                         if (does_exist(mp, i))
284                                 return i;
285                 }
286                 return BADMSG;
287
288         } else if (strcmp(buf, seq_next)==0) {
289                 for (i = (mp->curmsg >= mp->lowmsg) ?
290                                 mp->curmsg + 1 : mp->lowmsg;
291                                 i <= mp->hghmsg; i++) {
292                         if (does_exist(mp, i))
293                                 return i;
294                 }
295                 return BADMSG;
296
297         } else {
298                 return BADLST;
299         }
300 }
301
302 /*
303 ** Handle user defined sequences.
304 ** They can take the following forms:
305 **
306 ** seq
307 ** seq:p
308 ** seq:n
309 ** seq:f
310 ** seq:l
311 ** seq:+42
312 ** seq:-42
313 ** seq:42
314 **
315 ** (`42' being an arbitrary integer)
316 */
317 static int
318 attr(struct msgs *mp, char *cp)
319 {
320         unsigned char *dp;
321         char *bp = NULL;
322         int i, j;
323         int found;
324         int inverted = 0;
325         int range = 0;  /* no range */
326         int first = 0;
327
328         /* hack for "c-..." */
329         if (strcmp(cp, seq_cur)==0)
330                 return 0;
331         /* "c:..." -- this code need to be rewritten... */
332         if (strncmp(seq_cur, cp, strlen(seq_cur))==0 &&
333                         cp[strlen(seq_cur)] == ':') {
334                 return 0;
335         }
336
337         /* Check for sequence negation */
338         if (!(dp = context_find(nsequence))) {
339                 dp = seq_neg;  /* use default */
340         }
341         if (*dp && strncmp(cp, dp, strlen(dp))==0) {
342                 inverted = 1;
343                 cp += strlen(dp);
344         }
345
346         convdir = 1;  /* convert direction */
347
348         for (dp = cp; *dp && isalnum(*dp); dp++)
349                 continue;
350
351         if (*dp == ':') {
352                 bp = dp++;
353                 range = 1;
354
355                 /*
356                 ** seq:p  (or)
357                 ** seq:n  (or)
358                 ** seq:f  (or)
359                 ** seq:l
360                 */
361                 if (isalpha(*dp)) {
362                         if (strcmp(dp, seq_prev)==0) {
363                                 convdir = -1;
364                                 first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
365                                         ? mp->curmsg - 1 : mp->hghmsg;
366                         } else if (strcmp(dp, seq_next)==0) {
367                                 convdir = 1;
368                                 first = (mp->curmsg >= mp->lowmsg)
369                                         ? mp->curmsg + 1 : mp->lowmsg;
370                         } else if (strcmp(dp, seq_first)==0) {
371                                 convdir = 1;
372                         } else if (strcmp(dp, seq_last)==0) {
373                                 convdir = -1;
374                         } else
375                                 return BADLST;
376                 } else {
377                         /*
378                         ** seq:42  (or)
379                         ** seq:+42 (or)
380                         ** seq:-42
381                         */
382                         if (*dp == '+')
383                                 dp++;
384                         else if (*dp == '-') {
385                                 dp++;
386                                 convdir = -1;
387                         }
388                         if ((range = atoi(dp)) == 0)
389                                 return BADLST;
390                         while (isdigit(*dp))
391                                 dp++;
392                         if (*dp)
393                                 return BADLST;
394                 }
395
396                 *bp = '\0';  /* temporarily terminate sequence name */
397         }
398
399         i = seq_getnum(mp, cp);  /* get index of sequence */
400
401         if (bp)
402                 *bp = ':';  /* restore sequence name */
403         if (i == -1)
404                 return 0;
405
406         found = 0;  /* count the number we select for this argument */
407
408         for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
409                         j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
410                 if (does_exist(mp, j)
411                                 && inverted ? !in_sequence(mp, i, j) :
412                                 in_sequence(mp, i, j)) {
413                         set_selected(mp, j);
414                         found++;
415
416                         /*
417                         ** If we have a range, then break out
418                         ** once we've found enough.
419                         */
420                         if (range && found >= range)
421                                 break;
422                 }
423         }
424
425         if (found)
426                 return found;
427
428         if (first)
429                 return BADMSG;
430         advise(NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
431         return -1;
432 }