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.
12 ** error codes for sequence
13 ** and message range processing
24 #define getnew(mp) (mp->hghmsg + 1)
26 static int convdir; /* convert direction */
32 static int m_conv(struct msgs *, char *, int);
33 static int attr(struct msgs *, char *);
37 m_convert(struct msgs *mp, char *name)
39 int first, last, found, range, err;
43 /* check if user defined sequence */
44 err = attr(mp, cp = name);
53 ** else err == 0, so continue
59 ** Check for special "new" sequence, which
60 ** is valid only if ALLOW_NEW is set.
62 if ((mp->msgflags & ALLOW_NEW) && !strcmp(cp, "new")) {
63 if ((err = first = getnew(mp)) <= 0)
69 if (!strcmp(cp, "all"))
72 if ((err = first = m_conv(mp, cp, FIRST)) <= 0)
76 if (*cp != '\0' && *cp != '-' && *cp != ':') {
78 advise(NULL, "illegal argument delimiter: `%c'(0%o)",
85 if ((err = last = m_conv(mp, cp, LAST)) <= 0) {
89 advise(NULL, "no %s message", cp);
93 advise(NULL, "message %s doesn't exist", cp);
97 advise(NULL, "message %s out of range 1-%d",
103 advise(NULL, "bad message list %s", name);
107 advise(NULL, "folder full, no %s message",
112 advise(NULL, "no messages match specification");
121 if (first > mp->hghmsg || last < mp->lowmsg) {
123 advise(NULL, "no messages in range %s", name);
127 /* tighten the range to search */
128 if (last > mp->hghmsg)
130 if (first < mp->lowmsg)
133 } else if (*cp == ':') {
138 } else if (*cp == '+') {
142 if ((range = atoi(bp = cp)) == 0)
148 if ((convdir > 0 && first > mp->hghmsg)
149 || (convdir < 0 && first < mp->lowmsg))
152 /* tighten the range to search */
153 if (first < mp->lowmsg)
155 if (first > mp->hghmsg)
158 for (last = first; last >= mp->lowmsg && last <= mp->hghmsg;
160 if (does_exist(mp, last))
163 if (last < mp->lowmsg)
165 if (last > mp->hghmsg)
178 ** If ALLOW_NEW is set, then allow selecting of an
179 ** empty slot. If ALLOW_NEW is not set, then we
180 ** check if message is in-range and exists.
182 if (mp->msgflags & ALLOW_NEW) {
183 set_select_empty(mp, first);
185 if (first > mp->hghmsg
186 || first < mp->lowmsg
187 || !(does_exist(mp, first))) {
188 if (!strcmp(name, "cur") || !strcmp(name, "."))
189 advise(NULL, "no %s message", name);
191 advise(NULL, "message %d doesn't exist", first);
195 last = first; /* range of 1 */
199 ** Cycle through the range and select the messages
200 ** that exist. If ALLOW_NEW is set, then we also check
201 ** if we are selecting an empty slot.
203 for (; first <= last; first++) {
204 if (does_exist(mp, first) ||
205 ((mp->msgflags & ALLOW_NEW) && is_select_empty(mp, first))) {
206 if (!is_selected(mp, first)) {
207 set_selected(mp, first);
209 if (mp->lowsel == 0 || first < mp->lowsel)
211 if (first > mp->hghsel)
225 ** Convert the various message names to
226 ** their numeric values.
238 m_conv(struct msgs *mp, char *str, int call)
241 register unsigned char *cp, *bp;
242 unsigned char buf[16];
254 else if (*delimp || call == LAST)
255 return mp->hghmsg + 1;
256 else if (mp->msgflags & ALLOW_NEW)
263 /* doesn't enforce lower case */
264 for (bp = buf; (isalpha(*cp) || *cp == '.')
265 && (bp - buf < sizeof(buf) - 1); )
267 for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
268 && (bp - buf < sizeof(buf) - 1); )
276 if (!strcmp(buf, "first"))
277 return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW)
278 ? mp->lowmsg : BADMSG);
280 if (!strcmp(buf, "last")) {
282 return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) ? mp->hghmsg : BADMSG);
285 if (!strcmp(buf, "cur") || !strcmp(buf, "."))
286 return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
288 if (!strcmp(buf, "prev")) {
290 for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg;
291 i >= mp->lowmsg; i--) {
292 if (does_exist(mp, i))
298 if (!strcmp(buf, "next")) {
299 for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg;
300 i <= mp->hghmsg; i++) {
301 if (does_exist(mp, i))
311 ** Handle user defined sequences.
312 ** They can take the following forms:
325 attr(struct msgs *mp, char *cp)
327 register unsigned char *dp;
332 int range = 0; /* no range */
335 /* hack for "cur-name", "cur-n", etc. */
336 if (!strcmp(cp, "cur"))
338 if (isprefix("cur:", cp)) /* this code need to be rewritten... */
341 /* Check for sequence negation */
342 if ((dp = context_find(nsequence)) && *dp != '\0' &&
348 convdir = 1; /* convert direction */
350 for (dp = cp; *dp && isalnum(*dp); dp++)
364 if (!strcmp(dp, "prev")) {
366 first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
367 ? mp->curmsg - 1 : mp->hghmsg;
368 } else if (!strcmp(dp, "next")) {
370 first = (mp->curmsg >= mp->lowmsg)
371 ? mp->curmsg + 1 : mp->lowmsg;
372 } else if (!strcmp(dp, "first")) {
374 } else if (!strcmp(dp, "last")) {
386 else if (*dp == '-') {
390 if ((range = atoi(dp)) == 0)
398 *bp = '\0'; /* temporarily terminate sequence name */
401 i = seq_getnum(mp, cp); /* get index of sequence */
404 *bp = ':'; /* restore sequence name */
408 found = 0; /* count the number we select for this argument */
410 for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
411 j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
412 if (does_exist(mp, j)
413 && inverted ? !in_sequence(mp, i, j) : in_sequence(mp, i, j)) {
414 if (!is_selected(mp, j)) {
417 if (mp->lowsel == 0 || j < mp->lowsel)
425 ** If we have a range, then break out
426 ** once we've found enough.
428 if (range && found >= range)
438 advise(NULL, "sequence %s %s", cp, inverted ? "full" : "empty");