list.c revision 1.2 1 1.1 cgd /*
2 1.1 cgd * Copyright (c) 1980 Regents of the University of California.
3 1.1 cgd * All rights reserved.
4 1.1 cgd *
5 1.1 cgd * Redistribution and use in source and binary forms, with or without
6 1.1 cgd * modification, are permitted provided that the following conditions
7 1.1 cgd * are met:
8 1.1 cgd * 1. Redistributions of source code must retain the above copyright
9 1.1 cgd * notice, this list of conditions and the following disclaimer.
10 1.1 cgd * 2. Redistributions in binary form must reproduce the above copyright
11 1.1 cgd * notice, this list of conditions and the following disclaimer in the
12 1.1 cgd * documentation and/or other materials provided with the distribution.
13 1.1 cgd * 3. All advertising materials mentioning features or use of this software
14 1.1 cgd * must display the following acknowledgement:
15 1.1 cgd * This product includes software developed by the University of
16 1.1 cgd * California, Berkeley and its contributors.
17 1.1 cgd * 4. Neither the name of the University nor the names of its contributors
18 1.1 cgd * may be used to endorse or promote products derived from this software
19 1.1 cgd * without specific prior written permission.
20 1.1 cgd *
21 1.1 cgd * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 1.1 cgd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 1.1 cgd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 1.1 cgd * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 1.1 cgd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 1.1 cgd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 1.1 cgd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 1.1 cgd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 1.1 cgd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 1.1 cgd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31 1.1 cgd * SUCH DAMAGE.
32 1.1 cgd */
33 1.1 cgd
34 1.1 cgd #ifndef lint
35 1.2 mycroft /*static char sccsid[] = "from: @(#)list.c 5.14 (Berkeley) 6/1/90";*/
36 1.2 mycroft static char rcsid[] = "$Id: list.c,v 1.2 1993/08/01 18:13:02 mycroft Exp $";
37 1.1 cgd #endif /* not lint */
38 1.1 cgd
39 1.1 cgd #include "rcv.h"
40 1.1 cgd #include <ctype.h>
41 1.1 cgd
42 1.1 cgd /*
43 1.1 cgd * Mail -- a mail program
44 1.1 cgd *
45 1.1 cgd * Message list handling.
46 1.1 cgd */
47 1.1 cgd
48 1.1 cgd /*
49 1.1 cgd * Convert the user string of message numbers and
50 1.1 cgd * store the numbers into vector.
51 1.1 cgd *
52 1.1 cgd * Returns the count of messages picked up or -1 on error.
53 1.1 cgd */
54 1.1 cgd
55 1.1 cgd getmsglist(buf, vector, flags)
56 1.1 cgd char *buf;
57 1.1 cgd int *vector;
58 1.1 cgd {
59 1.1 cgd register int *ip;
60 1.1 cgd register struct message *mp;
61 1.1 cgd
62 1.1 cgd if (msgCount == 0) {
63 1.1 cgd *vector = 0;
64 1.1 cgd return 0;
65 1.1 cgd }
66 1.1 cgd if (markall(buf, flags) < 0)
67 1.1 cgd return(-1);
68 1.1 cgd ip = vector;
69 1.1 cgd for (mp = &message[0]; mp < &message[msgCount]; mp++)
70 1.1 cgd if (mp->m_flag & MMARK)
71 1.1 cgd *ip++ = mp - &message[0] + 1;
72 1.1 cgd *ip = 0;
73 1.1 cgd return(ip - vector);
74 1.1 cgd }
75 1.1 cgd
76 1.1 cgd /*
77 1.1 cgd * Mark all messages that the user wanted from the command
78 1.1 cgd * line in the message structure. Return 0 on success, -1
79 1.1 cgd * on error.
80 1.1 cgd */
81 1.1 cgd
82 1.1 cgd /*
83 1.1 cgd * Bit values for colon modifiers.
84 1.1 cgd */
85 1.1 cgd
86 1.1 cgd #define CMNEW 01 /* New messages */
87 1.1 cgd #define CMOLD 02 /* Old messages */
88 1.1 cgd #define CMUNREAD 04 /* Unread messages */
89 1.1 cgd #define CMDELETED 010 /* Deleted messages */
90 1.1 cgd #define CMREAD 020 /* Read messages */
91 1.1 cgd
92 1.1 cgd /*
93 1.1 cgd * The following table describes the letters which can follow
94 1.1 cgd * the colon and gives the corresponding modifier bit.
95 1.1 cgd */
96 1.1 cgd
97 1.1 cgd struct coltab {
98 1.1 cgd char co_char; /* What to find past : */
99 1.1 cgd int co_bit; /* Associated modifier bit */
100 1.1 cgd int co_mask; /* m_status bits to mask */
101 1.1 cgd int co_equal; /* ... must equal this */
102 1.1 cgd } coltab[] = {
103 1.1 cgd 'n', CMNEW, MNEW, MNEW,
104 1.1 cgd 'o', CMOLD, MNEW, 0,
105 1.1 cgd 'u', CMUNREAD, MREAD, 0,
106 1.1 cgd 'd', CMDELETED, MDELETED, MDELETED,
107 1.1 cgd 'r', CMREAD, MREAD, MREAD,
108 1.1 cgd 0, 0, 0, 0
109 1.1 cgd };
110 1.1 cgd
111 1.1 cgd static int lastcolmod;
112 1.1 cgd
113 1.1 cgd markall(buf, f)
114 1.1 cgd char buf[];
115 1.1 cgd {
116 1.1 cgd register char **np;
117 1.1 cgd register int i;
118 1.1 cgd register struct message *mp;
119 1.1 cgd char *namelist[NMLSIZE], *bufp;
120 1.1 cgd int tok, beg, mc, star, other, valdot, colmod, colresult;
121 1.1 cgd
122 1.1 cgd valdot = dot - &message[0] + 1;
123 1.1 cgd colmod = 0;
124 1.1 cgd for (i = 1; i <= msgCount; i++)
125 1.1 cgd unmark(i);
126 1.1 cgd bufp = buf;
127 1.1 cgd mc = 0;
128 1.1 cgd np = &namelist[0];
129 1.1 cgd scaninit();
130 1.1 cgd tok = scan(&bufp);
131 1.1 cgd star = 0;
132 1.1 cgd other = 0;
133 1.1 cgd beg = 0;
134 1.1 cgd while (tok != TEOL) {
135 1.1 cgd switch (tok) {
136 1.1 cgd case TNUMBER:
137 1.1 cgd number:
138 1.1 cgd if (star) {
139 1.1 cgd printf("No numbers mixed with *\n");
140 1.1 cgd return(-1);
141 1.1 cgd }
142 1.1 cgd mc++;
143 1.1 cgd other++;
144 1.1 cgd if (beg != 0) {
145 1.1 cgd if (check(lexnumber, f))
146 1.1 cgd return(-1);
147 1.1 cgd for (i = beg; i <= lexnumber; i++)
148 1.1 cgd if (f == MDELETED || (message[i - 1].m_flag & MDELETED) == 0)
149 1.1 cgd mark(i);
150 1.1 cgd beg = 0;
151 1.1 cgd break;
152 1.1 cgd }
153 1.1 cgd beg = lexnumber;
154 1.1 cgd if (check(beg, f))
155 1.1 cgd return(-1);
156 1.1 cgd tok = scan(&bufp);
157 1.1 cgd regret(tok);
158 1.1 cgd if (tok != TDASH) {
159 1.1 cgd mark(beg);
160 1.1 cgd beg = 0;
161 1.1 cgd }
162 1.1 cgd break;
163 1.1 cgd
164 1.1 cgd case TPLUS:
165 1.1 cgd if (beg != 0) {
166 1.1 cgd printf("Non-numeric second argument\n");
167 1.1 cgd return(-1);
168 1.1 cgd }
169 1.1 cgd i = valdot;
170 1.1 cgd do {
171 1.1 cgd i++;
172 1.1 cgd if (i > msgCount) {
173 1.1 cgd printf("Referencing beyond EOF\n");
174 1.1 cgd return(-1);
175 1.1 cgd }
176 1.1 cgd } while ((message[i - 1].m_flag & MDELETED) != f);
177 1.1 cgd mark(i);
178 1.1 cgd break;
179 1.1 cgd
180 1.1 cgd case TDASH:
181 1.1 cgd if (beg == 0) {
182 1.1 cgd i = valdot;
183 1.1 cgd do {
184 1.1 cgd i--;
185 1.1 cgd if (i <= 0) {
186 1.1 cgd printf("Referencing before 1\n");
187 1.1 cgd return(-1);
188 1.1 cgd }
189 1.1 cgd } while ((message[i - 1].m_flag & MDELETED) != f);
190 1.1 cgd mark(i);
191 1.1 cgd }
192 1.1 cgd break;
193 1.1 cgd
194 1.1 cgd case TSTRING:
195 1.1 cgd if (beg != 0) {
196 1.1 cgd printf("Non-numeric second argument\n");
197 1.1 cgd return(-1);
198 1.1 cgd }
199 1.1 cgd other++;
200 1.1 cgd if (lexstring[0] == ':') {
201 1.1 cgd colresult = evalcol(lexstring[1]);
202 1.1 cgd if (colresult == 0) {
203 1.1 cgd printf("Unknown colon modifier \"%s\"\n",
204 1.1 cgd lexstring);
205 1.1 cgd return(-1);
206 1.1 cgd }
207 1.1 cgd colmod |= colresult;
208 1.1 cgd }
209 1.1 cgd else
210 1.1 cgd *np++ = savestr(lexstring);
211 1.1 cgd break;
212 1.1 cgd
213 1.1 cgd case TDOLLAR:
214 1.1 cgd case TUP:
215 1.1 cgd case TDOT:
216 1.1 cgd lexnumber = metamess(lexstring[0], f);
217 1.1 cgd if (lexnumber == -1)
218 1.1 cgd return(-1);
219 1.1 cgd goto number;
220 1.1 cgd
221 1.1 cgd case TSTAR:
222 1.1 cgd if (other) {
223 1.1 cgd printf("Can't mix \"*\" with anything\n");
224 1.1 cgd return(-1);
225 1.1 cgd }
226 1.1 cgd star++;
227 1.1 cgd break;
228 1.1 cgd
229 1.1 cgd case TERROR:
230 1.1 cgd return -1;
231 1.1 cgd }
232 1.1 cgd tok = scan(&bufp);
233 1.1 cgd }
234 1.1 cgd lastcolmod = colmod;
235 1.1 cgd *np = NOSTR;
236 1.1 cgd mc = 0;
237 1.1 cgd if (star) {
238 1.1 cgd for (i = 0; i < msgCount; i++)
239 1.1 cgd if ((message[i].m_flag & MDELETED) == f) {
240 1.1 cgd mark(i+1);
241 1.1 cgd mc++;
242 1.1 cgd }
243 1.1 cgd if (mc == 0) {
244 1.1 cgd printf("No applicable messages.\n");
245 1.1 cgd return(-1);
246 1.1 cgd }
247 1.1 cgd return(0);
248 1.1 cgd }
249 1.1 cgd
250 1.1 cgd /*
251 1.1 cgd * If no numbers were given, mark all of the messages,
252 1.1 cgd * so that we can unmark any whose sender was not selected
253 1.1 cgd * if any user names were given.
254 1.1 cgd */
255 1.1 cgd
256 1.1 cgd if ((np > namelist || colmod != 0) && mc == 0)
257 1.1 cgd for (i = 1; i <= msgCount; i++)
258 1.1 cgd if ((message[i-1].m_flag & MDELETED) == f)
259 1.1 cgd mark(i);
260 1.1 cgd
261 1.1 cgd /*
262 1.1 cgd * If any names were given, go through and eliminate any
263 1.1 cgd * messages whose senders were not requested.
264 1.1 cgd */
265 1.1 cgd
266 1.1 cgd if (np > namelist) {
267 1.1 cgd for (i = 1; i <= msgCount; i++) {
268 1.1 cgd for (mc = 0, np = &namelist[0]; *np != NOSTR; np++)
269 1.1 cgd if (**np == '/') {
270 1.1 cgd if (matchsubj(*np, i)) {
271 1.1 cgd mc++;
272 1.1 cgd break;
273 1.1 cgd }
274 1.1 cgd }
275 1.1 cgd else {
276 1.1 cgd if (matchsender(*np, i)) {
277 1.1 cgd mc++;
278 1.1 cgd break;
279 1.1 cgd }
280 1.1 cgd }
281 1.1 cgd if (mc == 0)
282 1.1 cgd unmark(i);
283 1.1 cgd }
284 1.1 cgd
285 1.1 cgd /*
286 1.1 cgd * Make sure we got some decent messages.
287 1.1 cgd */
288 1.1 cgd
289 1.1 cgd mc = 0;
290 1.1 cgd for (i = 1; i <= msgCount; i++)
291 1.1 cgd if (message[i-1].m_flag & MMARK) {
292 1.1 cgd mc++;
293 1.1 cgd break;
294 1.1 cgd }
295 1.1 cgd if (mc == 0) {
296 1.1 cgd printf("No applicable messages from {%s",
297 1.1 cgd namelist[0]);
298 1.1 cgd for (np = &namelist[1]; *np != NOSTR; np++)
299 1.1 cgd printf(", %s", *np);
300 1.1 cgd printf("}\n");
301 1.1 cgd return(-1);
302 1.1 cgd }
303 1.1 cgd }
304 1.1 cgd
305 1.1 cgd /*
306 1.1 cgd * If any colon modifiers were given, go through and
307 1.1 cgd * unmark any messages which do not satisfy the modifiers.
308 1.1 cgd */
309 1.1 cgd
310 1.1 cgd if (colmod != 0) {
311 1.1 cgd for (i = 1; i <= msgCount; i++) {
312 1.1 cgd register struct coltab *colp;
313 1.1 cgd
314 1.1 cgd mp = &message[i - 1];
315 1.1 cgd for (colp = &coltab[0]; colp->co_char; colp++)
316 1.1 cgd if (colp->co_bit & colmod)
317 1.1 cgd if ((mp->m_flag & colp->co_mask)
318 1.1 cgd != colp->co_equal)
319 1.1 cgd unmark(i);
320 1.1 cgd
321 1.1 cgd }
322 1.1 cgd for (mp = &message[0]; mp < &message[msgCount]; mp++)
323 1.1 cgd if (mp->m_flag & MMARK)
324 1.1 cgd break;
325 1.1 cgd if (mp >= &message[msgCount]) {
326 1.1 cgd register struct coltab *colp;
327 1.1 cgd
328 1.1 cgd printf("No messages satisfy");
329 1.1 cgd for (colp = &coltab[0]; colp->co_char; colp++)
330 1.1 cgd if (colp->co_bit & colmod)
331 1.1 cgd printf(" :%c", colp->co_char);
332 1.1 cgd printf("\n");
333 1.1 cgd return(-1);
334 1.1 cgd }
335 1.1 cgd }
336 1.1 cgd return(0);
337 1.1 cgd }
338 1.1 cgd
339 1.1 cgd /*
340 1.1 cgd * Turn the character after a colon modifier into a bit
341 1.1 cgd * value.
342 1.1 cgd */
343 1.1 cgd evalcol(col)
344 1.1 cgd {
345 1.1 cgd register struct coltab *colp;
346 1.1 cgd
347 1.1 cgd if (col == 0)
348 1.1 cgd return(lastcolmod);
349 1.1 cgd for (colp = &coltab[0]; colp->co_char; colp++)
350 1.1 cgd if (colp->co_char == col)
351 1.1 cgd return(colp->co_bit);
352 1.1 cgd return(0);
353 1.1 cgd }
354 1.1 cgd
355 1.1 cgd /*
356 1.1 cgd * Check the passed message number for legality and proper flags.
357 1.1 cgd * If f is MDELETED, then either kind will do. Otherwise, the message
358 1.1 cgd * has to be undeleted.
359 1.1 cgd */
360 1.1 cgd check(mesg, f)
361 1.1 cgd {
362 1.1 cgd register struct message *mp;
363 1.1 cgd
364 1.1 cgd if (mesg < 1 || mesg > msgCount) {
365 1.1 cgd printf("%d: Invalid message number\n", mesg);
366 1.1 cgd return(-1);
367 1.1 cgd }
368 1.1 cgd mp = &message[mesg-1];
369 1.1 cgd if (f != MDELETED && (mp->m_flag & MDELETED) != 0) {
370 1.1 cgd printf("%d: Inappropriate message\n", mesg);
371 1.1 cgd return(-1);
372 1.1 cgd }
373 1.1 cgd return(0);
374 1.1 cgd }
375 1.1 cgd
376 1.1 cgd /*
377 1.1 cgd * Scan out the list of string arguments, shell style
378 1.1 cgd * for a RAWLIST.
379 1.1 cgd */
380 1.1 cgd
381 1.1 cgd getrawlist(line, argv, argc)
382 1.1 cgd char line[];
383 1.1 cgd char **argv;
384 1.1 cgd int argc;
385 1.1 cgd {
386 1.1 cgd register char c, *cp, *cp2, quotec;
387 1.1 cgd int argn;
388 1.1 cgd char linebuf[BUFSIZ];
389 1.1 cgd
390 1.1 cgd argn = 0;
391 1.1 cgd cp = line;
392 1.1 cgd for (;;) {
393 1.1 cgd for (; *cp == ' ' || *cp == '\t'; cp++)
394 1.1 cgd ;
395 1.1 cgd if (*cp == '\0')
396 1.1 cgd break;
397 1.1 cgd if (argn >= argc - 1) {
398 1.1 cgd printf(
399 1.1 cgd "Too many elements in the list; excess discarded.\n");
400 1.1 cgd break;
401 1.1 cgd }
402 1.1 cgd cp2 = linebuf;
403 1.1 cgd quotec = '\0';
404 1.1 cgd while ((c = *cp) != '\0') {
405 1.1 cgd cp++;
406 1.1 cgd if (quotec != '\0') {
407 1.1 cgd if (c == quotec)
408 1.1 cgd quotec = '\0';
409 1.1 cgd else if (c == '\\')
410 1.1 cgd switch (c = *cp++) {
411 1.1 cgd case '\0':
412 1.1 cgd *cp2++ = *--cp;
413 1.1 cgd break;
414 1.1 cgd case '0': case '1': case '2': case '3':
415 1.1 cgd case '4': case '5': case '6': case '7':
416 1.1 cgd c -= '0';
417 1.1 cgd if (*cp >= '0' && *cp <= '7')
418 1.1 cgd c = c * 8 + *cp++ - '0';
419 1.1 cgd if (*cp >= '0' && *cp <= '7')
420 1.1 cgd c = c * 8 + *cp++ - '0';
421 1.1 cgd *cp2++ = c;
422 1.1 cgd break;
423 1.1 cgd case 'b':
424 1.1 cgd *cp2++ = '\b';
425 1.1 cgd break;
426 1.1 cgd case 'f':
427 1.1 cgd *cp2++ = '\f';
428 1.1 cgd break;
429 1.1 cgd case 'n':
430 1.1 cgd *cp2++ = '\n';
431 1.1 cgd break;
432 1.1 cgd case 'r':
433 1.1 cgd *cp2++ = '\r';
434 1.1 cgd break;
435 1.1 cgd case 't':
436 1.1 cgd *cp2++ = '\t';
437 1.1 cgd break;
438 1.1 cgd case 'v':
439 1.1 cgd *cp2++ = '\v';
440 1.1 cgd break;
441 1.1 cgd }
442 1.1 cgd else if (c == '^') {
443 1.1 cgd c = *cp++;
444 1.1 cgd if (c == '?')
445 1.1 cgd *cp2++ = '\177';
446 1.1 cgd /* null doesn't show up anyway */
447 1.1 cgd else if (c >= 'A' && c <= '_' ||
448 1.1 cgd c >= 'a' && c <= 'z')
449 1.1 cgd *cp2++ &= 037;
450 1.1 cgd else
451 1.1 cgd *cp2++ = *--cp;
452 1.1 cgd } else
453 1.1 cgd *cp2++ = c;
454 1.1 cgd } else if (c == '"' || c == '\'')
455 1.1 cgd quotec = c;
456 1.1 cgd else if (c == ' ' || c == '\t')
457 1.1 cgd break;
458 1.1 cgd else
459 1.1 cgd *cp2++ = c;
460 1.1 cgd }
461 1.1 cgd *cp2 = '\0';
462 1.1 cgd argv[argn++] = savestr(linebuf);
463 1.1 cgd }
464 1.1 cgd argv[argn] = NOSTR;
465 1.1 cgd return argn;
466 1.1 cgd }
467 1.1 cgd
468 1.1 cgd /*
469 1.1 cgd * scan out a single lexical item and return its token number,
470 1.1 cgd * updating the string pointer passed **p. Also, store the value
471 1.1 cgd * of the number or string scanned in lexnumber or lexstring as
472 1.1 cgd * appropriate. In any event, store the scanned `thing' in lexstring.
473 1.1 cgd */
474 1.1 cgd
475 1.1 cgd struct lex {
476 1.1 cgd char l_char;
477 1.1 cgd char l_token;
478 1.1 cgd } singles[] = {
479 1.1 cgd '$', TDOLLAR,
480 1.1 cgd '.', TDOT,
481 1.1 cgd '^', TUP,
482 1.1 cgd '*', TSTAR,
483 1.1 cgd '-', TDASH,
484 1.1 cgd '+', TPLUS,
485 1.1 cgd '(', TOPEN,
486 1.1 cgd ')', TCLOSE,
487 1.1 cgd 0, 0
488 1.1 cgd };
489 1.1 cgd
490 1.1 cgd scan(sp)
491 1.1 cgd char **sp;
492 1.1 cgd {
493 1.1 cgd register char *cp, *cp2;
494 1.1 cgd register int c;
495 1.1 cgd register struct lex *lp;
496 1.1 cgd int quotec;
497 1.1 cgd
498 1.1 cgd if (regretp >= 0) {
499 1.1 cgd strcpy(lexstring, string_stack[regretp]);
500 1.1 cgd lexnumber = numberstack[regretp];
501 1.1 cgd return(regretstack[regretp--]);
502 1.1 cgd }
503 1.1 cgd cp = *sp;
504 1.1 cgd cp2 = lexstring;
505 1.1 cgd c = *cp++;
506 1.1 cgd
507 1.1 cgd /*
508 1.1 cgd * strip away leading white space.
509 1.1 cgd */
510 1.1 cgd
511 1.1 cgd while (c == ' ' || c == '\t')
512 1.1 cgd c = *cp++;
513 1.1 cgd
514 1.1 cgd /*
515 1.1 cgd * If no characters remain, we are at end of line,
516 1.1 cgd * so report that.
517 1.1 cgd */
518 1.1 cgd
519 1.1 cgd if (c == '\0') {
520 1.1 cgd *sp = --cp;
521 1.1 cgd return(TEOL);
522 1.1 cgd }
523 1.1 cgd
524 1.1 cgd /*
525 1.1 cgd * If the leading character is a digit, scan
526 1.1 cgd * the number and convert it on the fly.
527 1.1 cgd * Return TNUMBER when done.
528 1.1 cgd */
529 1.1 cgd
530 1.1 cgd if (isdigit(c)) {
531 1.1 cgd lexnumber = 0;
532 1.1 cgd while (isdigit(c)) {
533 1.1 cgd lexnumber = lexnumber*10 + c - '0';
534 1.1 cgd *cp2++ = c;
535 1.1 cgd c = *cp++;
536 1.1 cgd }
537 1.1 cgd *cp2 = '\0';
538 1.1 cgd *sp = --cp;
539 1.1 cgd return(TNUMBER);
540 1.1 cgd }
541 1.1 cgd
542 1.1 cgd /*
543 1.1 cgd * Check for single character tokens; return such
544 1.1 cgd * if found.
545 1.1 cgd */
546 1.1 cgd
547 1.1 cgd for (lp = &singles[0]; lp->l_char != 0; lp++)
548 1.1 cgd if (c == lp->l_char) {
549 1.1 cgd lexstring[0] = c;
550 1.1 cgd lexstring[1] = '\0';
551 1.1 cgd *sp = cp;
552 1.1 cgd return(lp->l_token);
553 1.1 cgd }
554 1.1 cgd
555 1.1 cgd /*
556 1.1 cgd * We've got a string! Copy all the characters
557 1.1 cgd * of the string into lexstring, until we see
558 1.1 cgd * a null, space, or tab.
559 1.1 cgd * If the lead character is a " or ', save it
560 1.1 cgd * and scan until you get another.
561 1.1 cgd */
562 1.1 cgd
563 1.1 cgd quotec = 0;
564 1.1 cgd if (c == '\'' || c == '"') {
565 1.1 cgd quotec = c;
566 1.1 cgd c = *cp++;
567 1.1 cgd }
568 1.1 cgd while (c != '\0') {
569 1.1 cgd if (c == quotec) {
570 1.1 cgd cp++;
571 1.1 cgd break;
572 1.1 cgd }
573 1.1 cgd if (quotec == 0 && (c == ' ' || c == '\t'))
574 1.1 cgd break;
575 1.1 cgd if (cp2 - lexstring < STRINGLEN-1)
576 1.1 cgd *cp2++ = c;
577 1.1 cgd c = *cp++;
578 1.1 cgd }
579 1.1 cgd if (quotec && c == 0) {
580 1.1 cgd fprintf(stderr, "Missing %c\n", quotec);
581 1.1 cgd return TERROR;
582 1.1 cgd }
583 1.1 cgd *sp = --cp;
584 1.1 cgd *cp2 = '\0';
585 1.1 cgd return(TSTRING);
586 1.1 cgd }
587 1.1 cgd
588 1.1 cgd /*
589 1.1 cgd * Unscan the named token by pushing it onto the regret stack.
590 1.1 cgd */
591 1.1 cgd
592 1.1 cgd regret(token)
593 1.1 cgd {
594 1.1 cgd if (++regretp >= REGDEP)
595 1.1 cgd panic("Too many regrets");
596 1.1 cgd regretstack[regretp] = token;
597 1.1 cgd lexstring[STRINGLEN-1] = '\0';
598 1.1 cgd string_stack[regretp] = savestr(lexstring);
599 1.1 cgd numberstack[regretp] = lexnumber;
600 1.1 cgd }
601 1.1 cgd
602 1.1 cgd /*
603 1.1 cgd * Reset all the scanner global variables.
604 1.1 cgd */
605 1.1 cgd
606 1.1 cgd scaninit()
607 1.1 cgd {
608 1.1 cgd regretp = -1;
609 1.1 cgd }
610 1.1 cgd
611 1.1 cgd /*
612 1.1 cgd * Find the first message whose flags & m == f and return
613 1.1 cgd * its message number.
614 1.1 cgd */
615 1.1 cgd
616 1.1 cgd first(f, m)
617 1.1 cgd {
618 1.1 cgd register struct message *mp;
619 1.1 cgd
620 1.1 cgd if (msgCount == 0)
621 1.1 cgd return 0;
622 1.1 cgd f &= MDELETED;
623 1.1 cgd m &= MDELETED;
624 1.1 cgd for (mp = dot; mp < &message[msgCount]; mp++)
625 1.1 cgd if ((mp->m_flag & m) == f)
626 1.1 cgd return mp - message + 1;
627 1.1 cgd for (mp = dot-1; mp >= &message[0]; mp--)
628 1.1 cgd if ((mp->m_flag & m) == f)
629 1.1 cgd return mp - message + 1;
630 1.1 cgd return 0;
631 1.1 cgd }
632 1.1 cgd
633 1.1 cgd /*
634 1.1 cgd * See if the passed name sent the passed message number. Return true
635 1.1 cgd * if so.
636 1.1 cgd */
637 1.1 cgd
638 1.1 cgd matchsender(str, mesg)
639 1.1 cgd char *str;
640 1.1 cgd {
641 1.1 cgd register char *cp, *cp2, *backup;
642 1.1 cgd
643 1.1 cgd if (!*str) /* null string matches nothing instead of everything */
644 1.1 cgd return 0;
645 1.1 cgd backup = cp2 = nameof(&message[mesg - 1], 0);
646 1.1 cgd cp = str;
647 1.1 cgd while (*cp2) {
648 1.1 cgd if (*cp == 0)
649 1.1 cgd return(1);
650 1.1 cgd if (raise(*cp++) != raise(*cp2++)) {
651 1.1 cgd cp2 = ++backup;
652 1.1 cgd cp = str;
653 1.1 cgd }
654 1.1 cgd }
655 1.1 cgd return(*cp == 0);
656 1.1 cgd }
657 1.1 cgd
658 1.1 cgd /*
659 1.1 cgd * See if the given string matches inside the subject field of the
660 1.1 cgd * given message. For the purpose of the scan, we ignore case differences.
661 1.1 cgd * If it does, return true. The string search argument is assumed to
662 1.1 cgd * have the form "/search-string." If it is of the form "/," we use the
663 1.1 cgd * previous search string.
664 1.1 cgd */
665 1.1 cgd
666 1.1 cgd char lastscan[128];
667 1.1 cgd
668 1.1 cgd matchsubj(str, mesg)
669 1.1 cgd char *str;
670 1.1 cgd {
671 1.1 cgd register struct message *mp;
672 1.1 cgd register char *cp, *cp2, *backup;
673 1.1 cgd
674 1.1 cgd str++;
675 1.1 cgd if (strlen(str) == 0)
676 1.1 cgd str = lastscan;
677 1.1 cgd else
678 1.1 cgd strcpy(lastscan, str);
679 1.1 cgd mp = &message[mesg-1];
680 1.1 cgd
681 1.1 cgd /*
682 1.1 cgd * Now look, ignoring case, for the word in the string.
683 1.1 cgd */
684 1.1 cgd
685 1.1 cgd cp = str;
686 1.1 cgd cp2 = hfield("subject", mp);
687 1.1 cgd if (cp2 == NOSTR)
688 1.1 cgd return(0);
689 1.1 cgd backup = cp2;
690 1.1 cgd while (*cp2) {
691 1.1 cgd if (*cp == 0)
692 1.1 cgd return(1);
693 1.1 cgd if (raise(*cp++) != raise(*cp2++)) {
694 1.1 cgd cp2 = ++backup;
695 1.1 cgd cp = str;
696 1.1 cgd }
697 1.1 cgd }
698 1.1 cgd return(*cp == 0);
699 1.1 cgd }
700 1.1 cgd
701 1.1 cgd /*
702 1.1 cgd * Mark the named message by setting its mark bit.
703 1.1 cgd */
704 1.1 cgd
705 1.1 cgd mark(mesg)
706 1.1 cgd {
707 1.1 cgd register int i;
708 1.1 cgd
709 1.1 cgd i = mesg;
710 1.1 cgd if (i < 1 || i > msgCount)
711 1.1 cgd panic("Bad message number to mark");
712 1.1 cgd message[i-1].m_flag |= MMARK;
713 1.1 cgd }
714 1.1 cgd
715 1.1 cgd /*
716 1.1 cgd * Unmark the named message.
717 1.1 cgd */
718 1.1 cgd
719 1.1 cgd unmark(mesg)
720 1.1 cgd {
721 1.1 cgd register int i;
722 1.1 cgd
723 1.1 cgd i = mesg;
724 1.1 cgd if (i < 1 || i > msgCount)
725 1.1 cgd panic("Bad message number to unmark");
726 1.1 cgd message[i-1].m_flag &= ~MMARK;
727 1.1 cgd }
728 1.1 cgd
729 1.1 cgd /*
730 1.1 cgd * Return the message number corresponding to the passed meta character.
731 1.1 cgd */
732 1.1 cgd
733 1.1 cgd metamess(meta, f)
734 1.1 cgd {
735 1.1 cgd register int c, m;
736 1.1 cgd register struct message *mp;
737 1.1 cgd
738 1.1 cgd c = meta;
739 1.1 cgd switch (c) {
740 1.1 cgd case '^':
741 1.1 cgd /*
742 1.1 cgd * First 'good' message left.
743 1.1 cgd */
744 1.1 cgd for (mp = &message[0]; mp < &message[msgCount]; mp++)
745 1.1 cgd if ((mp->m_flag & MDELETED) == f)
746 1.1 cgd return(mp - &message[0] + 1);
747 1.1 cgd printf("No applicable messages\n");
748 1.1 cgd return(-1);
749 1.1 cgd
750 1.1 cgd case '$':
751 1.1 cgd /*
752 1.1 cgd * Last 'good message left.
753 1.1 cgd */
754 1.1 cgd for (mp = &message[msgCount-1]; mp >= &message[0]; mp--)
755 1.1 cgd if ((mp->m_flag & MDELETED) == f)
756 1.1 cgd return(mp - &message[0] + 1);
757 1.1 cgd printf("No applicable messages\n");
758 1.1 cgd return(-1);
759 1.1 cgd
760 1.1 cgd case '.':
761 1.1 cgd /*
762 1.1 cgd * Current message.
763 1.1 cgd */
764 1.1 cgd m = dot - &message[0] + 1;
765 1.1 cgd if ((dot->m_flag & MDELETED) != f) {
766 1.1 cgd printf("%d: Inappropriate message\n", m);
767 1.1 cgd return(-1);
768 1.1 cgd }
769 1.1 cgd return(m);
770 1.1 cgd
771 1.1 cgd default:
772 1.1 cgd printf("Unknown metachar (%c)\n", c);
773 1.1 cgd return(-1);
774 1.1 cgd }
775 1.1 cgd }
776