3 * m_convert.c -- parse a message range or sequence and set SELECTED
5 * This code is Copyright (c) 2002, by the authors of nmh. See the
6 * COPYRIGHT file in the root directory of the nmh distribution for
7 * complete copyright information.
13 * error codes for sequence
14 * and message range processing
25 #define getnew(mp) (mp->hghmsg + 1)
27 static int convdir; /* convert direction */
33 static int m_conv (struct msgs *, char *, int);
34 static int attr (struct msgs *, char *);
38 m_convert (struct msgs *mp, char *name)
40 int first, last, found, range, err;
44 /* check if user defined sequence */
45 err = attr (mp, cp = name);
54 * else err == 0, so continue
60 * Check for special "new" sequence, which
61 * is valid only if ALLOW_NEW is set.
63 if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) {
64 if ((err = first = getnew (mp)) <= 0)
70 if (!strcmp (cp, "all"))
73 if ((err = first = m_conv (mp, cp, FIRST)) <= 0)
77 if (*cp != '\0' && *cp != '-' && *cp != ':') {
79 advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
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", cp, mp->hghmsg);
102 advise (NULL, "bad message list %s", name);
106 advise (NULL, "folder full, no %s message", name);
110 advise (NULL, "no messages match specification");
119 if (first > mp->hghmsg || last < mp->lowmsg) {
121 advise (NULL, "no messages in range %s", name);
125 /* tighten the range to search */
126 if (last > mp->hghmsg)
128 if (first < mp->lowmsg)
131 } else if (*cp == ':') {
142 if ((range = atoi (bp = cp)) == 0)
144 while (isdigit (*bp))
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)
159 last >= mp->lowmsg && last <= mp->hghmsg;
161 if (does_exist (mp, last))
164 if (last < mp->lowmsg)
166 if (last > mp->hghmsg)
179 * If ALLOW_NEW is set, then allow selecting of an
180 * empty slot. If ALLOW_NEW is not set, then we
181 * check if message is in-range and exists.
183 if (mp->msgflags & ALLOW_NEW) {
184 set_select_empty (mp, first);
186 if (first > mp->hghmsg
187 || first < mp->lowmsg
188 || !(does_exist (mp, first))) {
189 if (!strcmp (name, "cur") || !strcmp (name, "."))
190 advise (NULL, "no %s message", name);
192 advise (NULL, "message %d doesn't exist", first);
196 last = first; /* range of 1 */
200 * Cycle through the range and select the messages
201 * that exist. If ALLOW_NEW is set, then we also check
202 * if we are selecting an empty slot.
204 for (; first <= last; first++) {
205 if (does_exist (mp, first) ||
206 ((mp->msgflags & ALLOW_NEW) && is_select_empty (mp, first))) {
207 if (!is_selected (mp, first)) {
208 set_selected (mp, first);
210 if (mp->lowsel == 0 || first < mp->lowsel)
212 if (first > mp->hghsel)
226 * Convert the various message names to
227 * their numeric values.
239 m_conv (struct msgs *mp, char *str, int call)
242 register unsigned char *cp, *bp;
243 unsigned char buf[16];
248 while (isdigit (*bp))
255 else if (*delimp || call == LAST)
256 return mp->hghmsg + 1;
257 else if (mp->msgflags & ALLOW_NEW)
264 /* doesn't enforce lower case */
265 for (bp = buf; (isalpha(*cp) || *cp == '.')
266 && (bp - buf < sizeof(buf) - 1); )
268 for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
269 && (bp - buf < sizeof(buf) - 1); )
277 if (!strcmp (buf, "first"))
278 return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW)
279 ? mp->lowmsg : BADMSG);
281 if (!strcmp (buf, "last")) {
283 return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) ? mp->hghmsg : BADMSG);
286 if (!strcmp (buf, "cur") || !strcmp (buf, "."))
287 return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
289 if (!strcmp (buf, "prev")) {
291 for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg;
292 i >= mp->lowmsg; i--) {
293 if (does_exist (mp, i))
299 if (!strcmp (buf, "next")) {
300 for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg;
301 i <= mp->hghmsg; i++) {
302 if (does_exist (mp, i))
312 * Handle user defined sequences.
313 * They can take the following forms:
326 attr (struct msgs *mp, char *cp)
328 register unsigned char *dp;
333 range = 0, /* no range */
336 /* hack for "cur-name", "cur-n", etc. */
337 if (!strcmp (cp, "cur"))
339 if (ssequal ("cur:", cp)) /* this code need to be rewritten... */
342 /* Check for sequence negation */
343 if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) {
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)
370 else if (!strcmp (dp, "next")) {
372 first = (mp->curmsg >= mp->lowmsg)
376 else if (!strcmp (dp, "first")) {
379 else if (!strcmp (dp, "last")) {
392 else if (*dp == '-') {
396 if ((range = atoi(dp)) == 0)
398 while (isdigit (*dp))
404 *bp = '\0'; /* temporarily terminate sequence name */
407 i = seq_getnum (mp, cp); /* get index of sequence */
410 *bp = ':'; /* restore sequence name */
414 found = 0; /* count the number we select for this argument */
416 for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
417 j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
418 if (does_exist (mp, j)
419 && inverted ? !in_sequence (mp, i, j) : in_sequence (mp, i, j)) {
420 if (!is_selected (mp, j)) {
421 set_selected (mp, j);
423 if (mp->lowsel == 0 || j < mp->lowsel)
431 * If we have a range, then break out
432 * once we've found enough.
434 if (range && found >= range)
444 advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty");