2 ** m_convert.c -- parse a message range or sequence and set SELECTED
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.
10 /* FIXME: This code needs rework! Rewrite as a parser? */
15 ** error codes for sequence
16 ** and message range processing
27 #define getbeyond(mp) ((mp)->hghmsg + 1)
29 static int convdir; /* convert direction */
30 static char *delimp; /* delimiter pointer */
35 static int m_conv(struct msgs *, char *, int);
36 static int attr(struct msgs *, char *);
40 m_convert(struct msgs *mp, char *name)
42 int first, last, found, range, err;
46 /* check if user defined sequence */
47 err = attr(mp, cp = name);
53 /* it had been a user-defined sequence: we're finished */
57 ** else err == 0, so continue
58 ** (we know here: it is no user-defined seq)
64 ** Check for special beyond sequence, which
65 ** is valid only if ALLOW_BEYOND is set.
66 ** (It can appear only on its own.)
68 if ((mp->msgflags & ALLOW_BEYOND) && !strcmp(cp, seq_beyond)) {
69 if ((err = first = getbeyond(mp)) <= 0)
75 /* replace `a' with `f-l' */
76 if (!strcmp(cp, seq_all))
77 cp = concat(seq_first, "-", seq_last, NULL);
79 if ((err = first = m_conv(mp, cp, FIRST)) <= 0)
87 if ((err = last = m_conv(mp, cp, LAST)) <= 0) {
91 advise(NULL, "no %s message", cp);
95 advise(NULL, "message %s doesn't exist", cp);
99 advise(NULL, "message %s out of range 1-%d",
105 advise(NULL, "bad message list %s", name);
109 advise(NULL, "folder full, no %s message",
114 advise(NULL, "no messages match specification");
123 if (first > mp->hghmsg || last < mp->lowmsg) {
125 advise(NULL, "no messages in range %s", name);
129 /* tighten the range to search */
130 if (last > mp->hghmsg)
132 if (first < mp->lowmsg)
142 } else if (*cp == '+') {
146 if ((range = atoi(bp = cp)) == 0)
152 if ((convdir > 0 && first > mp->hghmsg)
153 || (convdir < 0 && first < mp->lowmsg))
156 /* tighten the range to search */
157 if (first < mp->lowmsg)
159 if (first > mp->hghmsg)
162 for (last = first; last >= mp->lowmsg && last <= mp->hghmsg;
164 if (does_exist(mp, last) && (--range <= 0))
166 if (last < mp->lowmsg)
168 if (last > mp->hghmsg)
181 ** AFAICS, the only cases to reach here are:
183 ** But I'm not sure. --meillo
188 ** If ALLOW_BEYOND is set, then allow selecting of an
189 ** empty slot. If ALLOW_BEYOND is not set, then we
190 ** check if message is in-range and exists.
192 if (mp->msgflags & ALLOW_BEYOND) {
193 set_select_empty(mp, first);
194 } else if (first > mp->hghmsg || first < mp->lowmsg
195 || !does_exist(mp, first)) {
196 if (!strcmp(name, seq_cur))
197 advise(NULL, "no current message");
199 advise(NULL, "message %d doesn't exist",
203 last = first; /* range of 1 */
208 advise(NULL, "illegal argument delimiter: `%c'(0%o)",
215 ** Cycle through the range and select the messages
216 ** that exist. If ALLOW_BEYOND is set, then we also check
217 ** if we are selecting an empty slot.
219 for (; first <= last; first++) {
220 if (does_exist(mp, first) || (
221 (mp->msgflags & ALLOW_BEYOND) &&
222 is_select_empty(mp, first))) {
223 if (!is_selected(mp, first)) {
224 set_selected(mp, first);
226 if (mp->lowsel == 0 || first < mp->lowsel)
228 if (first > mp->hghsel)
242 ** Convert the various message names to their numeric values.
252 m_conv(struct msgs *mp, char *str, int call)
255 register unsigned char *cp, *bp;
256 unsigned char buf[16];
268 else if (*delimp || call == LAST)
269 return mp->hghmsg + 1;
270 else if (mp->msgflags & ALLOW_BEYOND)
277 /* doesn't enforce lower case */
278 for (bp = buf; isalpha(*cp) && (bp - buf < sizeof(buf) - 1); )
280 for (bp = buf; islower(*cp) && (bp - buf < sizeof(buf) - 1); )
288 if (!strcmp(buf, seq_first))
289 return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND)
290 ? mp->lowmsg : BADMSG);
292 if (!strcmp(buf, seq_last)) {
294 return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ? mp->hghmsg : BADMSG);
297 if (!strcmp(buf, seq_cur))
298 return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
300 if (!strcmp(buf, seq_prev)) {
302 for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg;
303 i >= mp->lowmsg; i--) {
304 if (does_exist(mp, i))
310 if (!strcmp(buf, seq_next)) {
311 for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg;
312 i <= mp->hghmsg; i++) {
313 if (does_exist(mp, i))
323 ** Handle user defined sequences.
324 ** They can take the following forms:
335 ** (`42' being an arbitrary integer)
338 attr(struct msgs *mp, char *cp)
340 register unsigned char *dp;
345 int range = 0; /* no range */
348 /* hack for "c-..." */
349 if (!strcmp(cp, seq_cur))
351 /* "c:..." -- this code need to be rewritten... */
352 if (strncmp(seq_cur, cp, strlen(seq_cur))==0 &&
353 cp[strlen(seq_cur)] == ':') {
357 /* Check for sequence negation */
358 if (!(dp = context_find(nsequence))) {
359 dp = seq_neg; /* use default */
361 if (dp && *dp && isprefix(dp, cp)) {
366 convdir = 1; /* convert direction */
368 for (dp = cp; *dp && isalnum(*dp); dp++)
382 if (!strcmp(dp, seq_prev)) {
384 first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
385 ? mp->curmsg - 1 : mp->hghmsg;
386 } else if (!strcmp(dp, seq_next)) {
388 first = (mp->curmsg >= mp->lowmsg)
389 ? mp->curmsg + 1 : mp->lowmsg;
390 } else if (!strcmp(dp, seq_first)) {
392 } else if (!strcmp(dp, seq_last)) {
404 else if (*dp == '-') {
408 if ((range = atoi(dp)) == 0)
416 *bp = '\0'; /* temporarily terminate sequence name */
419 i = seq_getnum(mp, cp); /* get index of sequence */
422 *bp = ':'; /* restore sequence name */
426 found = 0; /* count the number we select for this argument */
428 for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
429 j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
430 if (does_exist(mp, j)
431 && inverted ? !in_sequence(mp, i, j) : in_sequence(mp, i, j)) {
432 if (!is_selected(mp, j)) {
435 if (mp->lowsel == 0 || j < mp->lowsel)
443 ** If we have a range, then break out
444 ** once we've found enough.
446 if (range && found >= range)
456 advise(NULL, "sequence %s %s", cp, inverted ? "full" : "empty");