]>
diplodocus.org Git - nmh/blob - sbr/m_convert.c
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
26 #define getnew(mp) (mp->hghmsg + 1)
28 static int convdir
; /* convert direction */
34 static int m_conv (struct msgs
*, char *, int);
35 static int attr (struct msgs
*, char *);
39 m_convert (struct msgs
*mp
, char *name
)
41 int first
, last
, found
, count
, is_range
, err
;
44 /* check if user defined sequence */
45 err
= attr (mp
, cp
= name
);
54 * else err == 0, so continue
61 * Check for special "new" sequence, which
62 * is valid only if ALLOW_NEW is set.
64 if ((mp
->msgflags
& ALLOW_NEW
) && !strcmp (cp
, "new")) {
65 if ((err
= first
= getnew (mp
)) <= 0)
71 if (!strcmp (cp
, "all"))
74 if ((err
= first
= m_conv (mp
, cp
, FIRST
)) <= 0)
78 if (*cp
!= '\0' && *cp
!= '-' && *cp
!= ':' && *cp
!= '=') {
80 advise (NULL
, "illegal argument delimiter: `%c'(0%o)", *delimp
, *delimp
);
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", cp
, mp
->hghmsg
);
103 advise (NULL
, "bad message list %s", name
);
107 advise (NULL
, "folder full, no %s message", name
);
111 advise (NULL
, "no messages match specification");
120 if (first
> mp
->hghmsg
|| last
< mp
->lowmsg
) {
122 advise (NULL
, "no messages in range %s", name
);
126 /* tighten the range to search */
127 if (last
> mp
->hghmsg
)
129 if (first
< mp
->lowmsg
)
132 } else if (*cp
== ':' || *cp
== '=') {
140 /* foo:-3 or foo=-3 */
143 } else if (*cp
== '+') {
144 /* foo:+3 or foo=+3 is same as foo:3 or foo=3 */
148 if ((count
= atoi (bp
= cp
)) == 0)
150 while (isdigit ((unsigned char) *bp
))
154 if ((convdir
> 0 && first
> mp
->hghmsg
)
155 || (convdir
< 0 && first
< mp
->lowmsg
))
158 /* tighten the range to search */
159 if (first
< mp
->lowmsg
)
161 if (first
> mp
->hghmsg
)
165 last
>= mp
->lowmsg
&& last
<= mp
->hghmsg
;
167 if (does_exist (mp
, last
))
170 if (is_range
) { /* a range includes any messages that exist */
171 if (last
< mp
->lowmsg
)
173 if (last
> mp
->hghmsg
)
180 } else { /* looking for the nth message. if not enough, fail. */
181 if (last
< mp
->lowmsg
|| last
> mp
->hghmsg
) {
182 advise (NULL
, "no such message");
193 * If ALLOW_NEW is set, then allow selecting of an
194 * empty slot. If ALLOW_NEW is not set, then we
195 * check if message is in-range and exists.
197 if (mp
->msgflags
& ALLOW_NEW
) {
199 * We can get into a case where the "cur" sequence is way out
200 * of range, and because it's allowed to not exist (think
201 * of "rmm; next") it doesn't get checked to make sure it's
202 * within the range of messages in seq_init(). So if our
203 * desired sequence is out of range of the allocated folder
204 * limits simply reallocate the folder so it's within range.
206 if (first
< mp
->lowoff
|| first
> mp
->hghoff
)
207 mp
= folder_realloc(mp
, first
< mp
->lowoff
? first
: mp
->lowoff
,
208 first
> mp
->hghoff
? first
: mp
->hghoff
);
210 set_select_empty (mp
, first
);
212 if (first
> mp
->hghmsg
213 || first
< mp
->lowmsg
214 || !(does_exist (mp
, first
))) {
215 if (!strcmp (name
, "cur") || !strcmp (name
, "."))
216 advise (NULL
, "no %s message", name
);
218 advise (NULL
, "message %d doesn't exist", first
);
222 last
= first
; /* range of 1 */
226 * Cycle through the range and select the messages
227 * that exist. If ALLOW_NEW is set, then we also check
228 * if we are selecting an empty slot.
230 for (; first
<= last
; first
++) {
231 if (does_exist (mp
, first
) ||
232 ((mp
->msgflags
& ALLOW_NEW
) && is_select_empty (mp
, first
))) {
233 if (!is_selected (mp
, first
)) {
234 set_selected (mp
, first
);
236 if (mp
->lowsel
== 0 || first
< mp
->lowsel
)
238 if (first
> mp
->hghsel
)
252 * Convert the various message names to
253 * their numeric values.
265 m_conv (struct msgs
*mp
, char *str
, int call
)
273 if (isdigit ((unsigned char) *cp
)) {
274 while (isdigit ((unsigned char) *bp
))
281 else if (*delimp
|| call
== LAST
)
282 return mp
->hghmsg
+ 1;
283 else if (mp
->msgflags
& ALLOW_NEW
)
289 /* doesn't enforce lower case */
290 for (bp
= buf
; (isalpha((unsigned char) *cp
) || *cp
== '.')
291 && (bp
- buf
< (int) sizeof(buf
) - 1); )
298 if (!strcmp (buf
, "first"))
299 return (mp
->hghmsg
|| !(mp
->msgflags
& ALLOW_NEW
)
300 ? mp
->lowmsg
: BADMSG
);
302 if (!strcmp (buf
, "last")) {
304 return (mp
->hghmsg
|| !(mp
->msgflags
& ALLOW_NEW
) ? mp
->hghmsg
: BADMSG
);
307 if (!strcmp (buf
, "cur") || !strcmp (buf
, "."))
308 return (mp
->curmsg
> 0 ? mp
->curmsg
: BADMSG
);
310 if (!strcmp (buf
, "prev")) {
312 for (i
= (mp
->curmsg
<= mp
->hghmsg
) ? mp
->curmsg
- 1 : mp
->hghmsg
;
313 i
>= mp
->lowmsg
; i
--) {
314 if (does_exist (mp
, i
))
320 if (!strcmp (buf
, "next")) {
321 for (i
= (mp
->curmsg
>= mp
->lowmsg
) ? mp
->curmsg
+ 1 : mp
->lowmsg
;
322 i
<= mp
->hghmsg
; i
++) {
323 if (does_exist (mp
, i
))
333 * Handle user defined sequences.
334 * They can take the following forms:
347 attr (struct msgs
*mp
, char *cp
)
356 count
= 0, /* range given? else use entire sequence */
357 just_one
= 0, /* want entire sequence or range */
361 /* hack for "cur-name", "cur-n", etc. */
362 if (!strcmp (cp
, "cur"))
364 if (strncmp ("cur", cp
, 3) == 0) {
365 if (cp
[3] == ':' || cp
[3] == '=')
369 /* Check for sequence negation */
370 if ((dp
= context_find (nsequence
)) && *dp
!= '\0' && ssequal (dp
, cp
)) {
375 convdir
= 1; /* convert direction */
377 for (dp
= cp
; *dp
&& isalnum((unsigned char) *dp
); dp
++)
390 if (isalpha ((unsigned char) *dp
)) {
391 if (!strcmp (dp
, "prev")) {
393 first
= (mp
->curmsg
> 0) && (mp
->curmsg
<= mp
->hghmsg
)
398 else if (!strcmp (dp
, "next")) {
400 first
= (mp
->curmsg
>= mp
->lowmsg
)
405 else if (!strcmp (dp
, "first")) {
409 else if (!strcmp (dp
, "last")) {
423 /* foo:+3 is same as foo:3 */
427 } else if (*dp
== '-' || *dp
== ':') {
428 /* foo:-3 or foo::3 */
433 count
= strtol(dp
,&ep
,10);
434 if (count
== 0 || *ep
) /* 0 illegal */
439 *bp
= '\0'; /* temporarily terminate sequence name */
440 } else if (*dp
== '=') {
445 /* foo=+3 is same as foo=3 */
449 } else if (*dp
== '-') {
456 count
= strtol(dp
,&ep
,10); /* 0 illegal */
457 if (count
== 0 || *ep
)
463 *bp
= '\0'; /* temporarily terminate sequence name */
466 i
= seq_getnum (mp
, cp
); /* get index of sequence */
469 *bp
= op
; /* restore sequence name */
473 found
= 0; /* count the number we select for this argument */
478 for (j
= start
; j
>= mp
->lowmsg
&& j
<= mp
->hghmsg
; j
+= convdir
) {
480 if (does_exist (mp
, j
)
481 && inverted
? !in_sequence (mp
, i
, j
) : in_sequence (mp
, i
, j
)) {
483 /* we want all that we find, or just the last in the +/_ case */
484 if (!just_one
|| found
>= count
) {
485 if (!is_selected (mp
, j
)) {
486 set_selected (mp
, j
);
488 if (mp
->lowsel
== 0 || j
< mp
->lowsel
)
495 * If we have any sort of limit, then break out
496 * once we've found enough.
498 if (count
&& found
>= count
)
507 if (first
|| just_one
)
509 advise (NULL
, "sequence %s %s", cp
, inverted
? "full" : "empty");