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