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? */
16 ** error codes for sequence
17 ** and message range processing
28 #define getbeyond(mp) ((mp)->hghmsg + 1)
30 static int convdir; /* convert direction */
31 static char *delimp; /* delimiter pointer */
36 static int m_conv(struct msgs *, char *, int);
37 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 ** here we know: it is no user-defined seq
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.
66 if ((mp->msgflags & ALLOW_BEYOND) && strcmp(cp, seq_beyond)==0) {
67 set_selected(mp, getbeyond(mp));
72 ** Handle the special all sequence: replace `a' with `f-l'
74 if (strcmp(cp, seq_all)==0) {
75 cp = concat(seq_first, "-", seq_last, NULL);
78 if ((err = first = m_conv(mp, cp, FIRST)) <= 0)
86 if ((err = last = m_conv(mp, cp, LAST)) <= 0) {
90 advise(NULL, "no %s message", cp);
94 advise(NULL, "message %s doesn't exist", cp);
98 advise(NULL, "message %s out of range 1-%d",
104 advise(NULL, "bad message list %s", name);
108 advise(NULL, "folder full, no %s message",
113 advise(NULL, "no messages match specification");
122 if (first > mp->hghmsg || last < mp->lowmsg) {
124 advise(NULL, "no messages in range %s", name);
128 /* tighten the range to search */
129 if (last > mp->hghmsg)
131 if (first < mp->lowmsg)
141 } else if (*cp == '+') {
145 if ((range = atoi(bp = cp)) == 0)
151 if ((convdir > 0 && first > mp->hghmsg)
152 || (convdir < 0 && first < mp->lowmsg))
155 /* tighten the range to search */
156 if (first < mp->lowmsg)
158 if (first > mp->hghmsg)
161 for (last = first; last >= mp->lowmsg && last <= mp->hghmsg;
163 if (does_exist(mp, last) && (--range <= 0))
165 if (last < mp->lowmsg)
167 if (last > mp->hghmsg)
179 ** AFAICS, the only cases to reach here are:
181 ** But I'm not sure. --meillo
186 ** Check if message is in-range and exists.
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");
193 /* this case seems to never be reached */
194 advise(NULL, "message %d doesn't exist",
198 last = first; /* range of 1 */
203 advise(NULL, "illegal argument delimiter: `%c'(0%o)",
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);
223 ** Convert the various message names to their numeric values.
233 m_conv(struct msgs *mp, char *str, int call)
236 unsigned char *cp, *bp;
237 unsigned char buf[16]; /* for reserved sequence name */
242 /* Handle an integer */
251 else if (*delimp || call == LAST)
252 return mp->hghmsg + 1;
253 else if (mp->msgflags & ALLOW_BEYOND)
259 for (bp = buf; isalpha(*cp) && (bp - buf < (int)sizeof(buf) - 1); ) {
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);
270 } else if (strcmp(buf, seq_last)==0) {
272 return (mp->hghmsg || !(mp->msgflags & ALLOW_BEYOND) ?
273 mp->hghmsg : BADMSG);
275 } else if (strcmp(buf, seq_cur)==0) {
276 return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
278 } else if (strcmp(buf, seq_prev)==0) {
280 for (i = (mp->curmsg <= mp->hghmsg) ?
281 mp->curmsg - 1 : mp->hghmsg;
282 i >= mp->lowmsg; i--) {
283 if (does_exist(mp, i))
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))
303 ** Handle user defined sequences.
304 ** They can take the following forms:
315 ** (`42' being an arbitrary integer)
318 attr(struct msgs *mp, char *cp)
325 int range = 0; /* no range */
328 /* hack for "c-..." */
329 if (strcmp(cp, seq_cur)==0)
331 /* "c:..." -- this code need to be rewritten... */
332 if (strncmp(seq_cur, cp, strlen(seq_cur))==0 &&
333 cp[strlen(seq_cur)] == ':') {
337 /* Check for sequence negation */
338 if (!(dp = context_find(nsequence))) {
339 dp = seq_neg; /* use default */
341 if (*dp && strncmp(cp, dp, strlen(dp))==0) {
346 convdir = 1; /* convert direction */
348 for (dp = cp; *dp && isalnum(*dp); dp++)
362 if (strcmp(dp, seq_prev)==0) {
364 first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
365 ? mp->curmsg - 1 : mp->hghmsg;
366 } else if (strcmp(dp, seq_next)==0) {
368 first = (mp->curmsg >= mp->lowmsg)
369 ? mp->curmsg + 1 : mp->lowmsg;
370 } else if (strcmp(dp, seq_first)==0) {
372 } else if (strcmp(dp, seq_last)==0) {
384 else if (*dp == '-') {
388 if ((range = atoi(dp)) == 0)
396 *bp = '\0'; /* temporarily terminate sequence name */
399 i = seq_getnum(mp, cp); /* get index of sequence */
402 *bp = ':'; /* restore sequence name */
406 found = 0; /* count the number we select for this argument */
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)) {
417 ** If we have a range, then break out
418 ** once we've found enough.
420 if (range && found >= range)
430 advise(NULL, "sequence %s %s", cp, inverted ? "full" : "empty");