source: trunk/third/nmh/sbr/m_convert.c @ 12455

Revision 12455, 8.6 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * m_convert.c -- parse a message range or sequence and set SELECTED
4 *
5 * $Id: m_convert.c,v 1.1.1.1 1999-02-07 18:14:09 danw Exp $
6 */
7
8#include <h/mh.h>
9
10/*
11 * error codes for sequence
12 * and message range processing
13 */
14#define BADMSG  (-2)
15#define BADRNG  (-3)
16#define BADNEW  (-4)
17#define BADNUM  (-5)
18#define BADLST  (-6)
19
20#define FIRST   1
21#define LAST    2
22
23#define getnew(mp) (mp->hghmsg + 1)
24
25static int convdir;     /* convert direction */
26static char *delimp;
27
28/*
29 * static prototypes
30 */
31static int m_conv (struct msgs *, char *, int);
32static int attr (struct msgs *, char *);
33
34
35int
36m_convert (struct msgs *mp, char *name)
37{
38    int first, last, found, range, err;
39    char *bp, *cp;
40
41    /* check if user defined sequence */
42    err = attr (mp, cp = name);
43
44    if (err == -1)
45        return 0;
46    else if (err < 0)
47        goto badmsg;
48    else if (err > 0)
49        return 1;
50    /*
51     * else err == 0, so continue
52     */
53
54    found = 0;
55
56    /*
57     * Check for special "new" sequence, which
58     * is valid only if ALLOW_NEW is set.
59     */
60    if ((mp->msgflags & ALLOW_NEW) && !strcmp (cp, "new")) {
61        if ((err = first = getnew (mp)) <= 0)
62            goto badmsg;
63        else
64            goto single;
65    }
66
67    if (!strcmp (cp, "all"))
68        cp = "first-last";
69
70    if ((err = first = m_conv (mp, cp, FIRST)) <= 0)
71        goto badmsg;
72
73    cp = delimp;
74    if (*cp != '\0' && *cp != '-' && *cp != ':') {
75badelim:
76        advise (NULL, "illegal argument delimiter: `%c'(0%o)", *delimp, *delimp);
77        return 0;
78    }
79
80    if (*cp == '-') {
81        cp++;
82        if ((err = last = m_conv (mp, cp, LAST)) <= 0) {
83badmsg:
84            switch (err) {
85            case BADMSG:
86                advise (NULL, "no %s message", cp);
87                break;
88
89            case BADNUM:
90                advise (NULL, "message %s doesn't exist", cp);
91                break;
92
93            case BADRNG:
94                advise (NULL, "message %s out of range 1-%d", cp, mp->hghmsg);
95                break;
96
97            case BADLST:
98badlist:
99                advise (NULL, "bad message list %s", name);
100                break;
101
102            case BADNEW:
103                advise (NULL, "folder full, no %s message", name);
104                break;
105
106            default:
107                advise (NULL, "no messages match specification");
108            }
109            return 0;
110        }
111
112        if (last < first)
113            goto badlist;
114        if (*delimp)
115            goto badelim;
116        if (first > mp->hghmsg || last < mp->lowmsg) {
117rangerr:
118            advise (NULL, "no messages in range %s", name);
119            return 0;
120        }
121
122        /* tighten the range to search */
123        if (last > mp->hghmsg)
124            last = mp->hghmsg;
125        if (first < mp->lowmsg)
126            first = mp->lowmsg;
127
128    } else if (*cp == ':') {
129        cp++;
130        if (*cp == '-') {
131            convdir = -1;
132            cp++;
133        } else {
134            if (*cp == '+') {
135                convdir = 1;
136                cp++;
137            }
138        }
139        if ((range = atoi (bp = cp)) == 0)
140            goto badlist;
141        while (isdigit (*bp))
142            bp++;
143        if (*bp)
144            goto badelim;
145        if ((convdir > 0 && first > mp->hghmsg)
146            || (convdir < 0 && first < mp->lowmsg))
147            goto rangerr;
148
149        /* tighten the range to search */
150        if (first < mp->lowmsg)
151            first = mp->lowmsg;
152        if (first > mp->hghmsg)
153            first = mp->hghmsg;
154
155        for (last = first;
156             last >= mp->lowmsg && last <= mp->hghmsg;
157             last += convdir)
158            if (does_exist (mp, last))
159                if (--range <= 0)
160                    break;
161        if (last < mp->lowmsg)
162            last = mp->lowmsg;
163        if (last > mp->hghmsg)
164            last = mp->hghmsg;
165        if (last < first) {
166            range = last;
167            last = first;
168            first = range;
169        }
170    } else {
171
172single:
173        /*
174         * Single Message
175         *
176         * If ALLOW_NEW is set, then allow selecting of an
177         * empty slot.  If ALLOW_NEW is not set, then we
178         * check if message is in-range and exists.
179         */
180        if (mp->msgflags & ALLOW_NEW) {
181            set_select_empty (mp, first);
182        } else {
183            if (first > mp->hghmsg
184                || first < mp->lowmsg
185                || !(does_exist (mp, first))) {
186                if (!strcmp (name, "cur") || !strcmp (name, "."))
187                    advise (NULL, "no %s message", name);
188                else
189                    advise (NULL, "message %d doesn't exist", first);
190                return 0;
191            }
192        }
193        last = first;   /* range of 1 */
194    }
195
196    /*
197     * Cycle through the range and select the messages
198     * that exist.  If ALLOW_NEW is set, then we also check
199     * if we are selecting an empty slot.
200     */
201    for (; first <= last; first++) {
202        if (does_exist (mp, first) ||
203            ((mp->msgflags & ALLOW_NEW) && is_select_empty (mp, first))) {
204            if (!is_selected (mp, first)) {
205                set_selected (mp, first);
206                mp->numsel++;
207                if (mp->lowsel == 0 || first < mp->lowsel)
208                    mp->lowsel = first;
209                if (first > mp->hghsel)
210                    mp->hghsel = first;
211            }
212            found++;
213        }
214    }
215
216    if (!found)
217        goto rangerr;
218
219    return 1;
220}
221
222/*
223 * Convert the various message names to
224 * there numeric value.
225 *
226 * n     (integer)
227 * prev
228 * next
229 * first
230 * last
231 * cur
232 * .     (same as cur)
233 */
234
235static int
236m_conv (struct msgs *mp, char *str, int call)
237{
238    register int i;
239    register char *cp, *bp;
240    char buf[16];
241
242    convdir = 1;
243    cp = bp = str;
244    if (isdigit (*cp)) {
245        while (isdigit (*bp))
246            bp++;
247        delimp = bp;
248        i = atoi (cp);
249
250        if (i <= mp->hghmsg)
251            return i;
252        else if (*delimp || call == LAST)
253            return mp->hghmsg + 1;
254        else if (mp->msgflags & ALLOW_NEW)
255            return BADRNG;
256        else
257            return BADNUM;
258    }
259
260#ifdef LOCALE
261    /* doesn't enforce lower case */
262    for (bp = buf; (isalpha(*cp) || *cp == '.')
263                && (bp - buf < sizeof(buf) - 1); )
264#else
265    for (bp = buf; ((*cp >= 'a' && *cp <= 'z') || *cp == '.')
266                && (bp - buf < sizeof(buf) - 1); )
267#endif /* LOCALE */
268    {
269        *bp++ = *cp++;
270    }
271    *bp++ = '\0';
272    delimp = cp;
273
274    if (!strcmp (buf, "first"))
275        return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW)
276                ? mp->lowmsg : BADMSG);
277
278    if (!strcmp (buf, "last")) {
279        convdir = -1;
280        return (mp->hghmsg || !(mp->msgflags & ALLOW_NEW) ? mp->hghmsg : BADMSG);
281    }
282
283    if (!strcmp (buf, "cur") || !strcmp (buf, "."))
284        return (mp->curmsg > 0 ? mp->curmsg : BADMSG);
285
286    if (!strcmp (buf, "prev")) {
287        convdir = -1;
288        for (i = (mp->curmsg <= mp->hghmsg) ? mp->curmsg - 1 : mp->hghmsg;
289                i >= mp->lowmsg; i--) {
290            if (does_exist (mp, i))
291                return i;
292        }
293        return BADMSG;
294    }
295
296    if (!strcmp (buf, "next")) {
297        for (i = (mp->curmsg >= mp->lowmsg) ? mp->curmsg + 1 : mp->lowmsg;
298                i <= mp->hghmsg; i++) {
299            if (does_exist (mp, i))
300                return i;
301        }
302        return BADMSG;
303    }
304
305    return BADLST;
306}
307
308/*
309 * Handle user defined sequences.
310 * They can take the following forms:
311 *
312 * seq
313 * seq:prev
314 * seq:next
315 * seq:first
316 * seq:last
317 * seq:+n
318 * seq:-n
319 * seq:n
320 */
321
322static int
323attr (struct msgs *mp, char *cp)
324{
325    register char *dp;
326    char *bp = NULL;
327    register int i, j;
328    int found,
329        inverted = 0,
330        range = 0,              /* no range */
331        first = 0;
332
333    /* hack for "cur-name", "cur-n", etc. */
334    if (!strcmp (cp, "cur"))
335        return 0;
336    if (ssequal ("cur:", cp))   /* this code need to be rewritten... */
337        return 0;
338
339    /* Check for sequence negation */
340    if ((dp = context_find (nsequence)) && *dp != '\0' && ssequal (dp, cp)) {
341        inverted = 1;
342        cp += strlen (dp);
343    }
344
345    convdir = 1;        /* convert direction */
346
347    for (dp = cp; *dp && isalnum(*dp); dp++)
348        continue;
349
350    if (*dp == ':') {
351        bp = dp++;
352        range = 1;
353
354        /*
355         * seq:prev  (or)
356         * seq:next  (or)
357         * seq:first (or)
358         * seq:last
359         */
360        if (isalpha (*dp)) {
361            if (!strcmp (dp, "prev")) {
362                convdir = -1;
363                first = (mp->curmsg > 0) && (mp->curmsg <= mp->hghmsg)
364                        ? mp->curmsg - 1
365                        : mp->hghmsg;
366            }
367            else if (!strcmp (dp, "next")) {
368                convdir = 1;
369                first = (mp->curmsg >= mp->lowmsg)
370                            ? mp->curmsg + 1
371                            : mp->lowmsg;
372            }
373            else if (!strcmp (dp, "first")) {
374                convdir = 1;
375            }
376            else if (!strcmp (dp, "last")) {
377                convdir = -1;
378            }
379            else
380                return BADLST;
381        } else {
382            /*
383             * seq:n  (or)
384             * seq:+n (or)
385             * seq:-n
386             */
387            if (*dp == '+')
388                dp++;
389            else if (*dp == '-') {
390                dp++;
391                convdir = -1;
392            }
393            if ((range = atoi(dp)) == 0)
394                return BADLST;
395            while (isdigit (*dp))
396                dp++;
397            if (*dp)
398                return BADLST;
399        }
400
401        *bp = '\0';     /* temporarily terminate sequence name */
402    }
403
404    i = seq_getnum (mp, cp);    /* get index of sequence */
405
406    if (bp)
407        *bp = ':';              /* restore sequence name */
408    if (i == -1)
409        return 0;
410
411    found = 0;  /* count the number we select for this argument */
412
413    for (j = first ? first : (convdir > 0) ? mp->lowmsg : mp->hghmsg;
414                j >= mp->lowmsg && j <= mp->hghmsg; j += convdir) {
415        if (does_exist (mp, j)
416                && inverted ? !in_sequence (mp, i, j) : in_sequence (mp, i, j)) {
417            if (!is_selected (mp, j)) {
418                set_selected (mp, j);
419                mp->numsel++;
420                if (mp->lowsel == 0 || j < mp->lowsel)
421                    mp->lowsel = j;
422                if (j > mp->hghsel)
423                    mp->hghsel = j;
424            }
425            found++;
426
427            /*
428             * If we have a range, then break out
429             * once we've found enough.
430             */
431            if (range && found >= range)
432                break;
433        }
434    }
435
436    if (found > 0)
437        return found;
438
439    if (first)
440        return BADMSG;
441    advise (NULL, "sequence %s %s", cp, inverted ? "full" : "empty");
442    return -1;
443}
Note: See TracBrowser for help on using the repository browser.