]> diplodocus.org Git - nmh/blob - uip/picksbr.c
We're not using the .Bu macro anymore.
[nmh] / uip / picksbr.c
1
2 /*
3 * picksbr.c -- routines to help pick along...
4 *
5 * $Id$
6 *
7 * This code is Copyright (c) 2002, by the authors of nmh. See the
8 * COPYRIGHT file in the root directory of the nmh distribution for
9 * complete copyright information.
10 */
11
12 #include <h/mh.h>
13 #include <h/tws.h>
14 #include <h/picksbr.h>
15 #include <h/utils.h>
16
17 #ifdef TIME_WITH_SYS_TIME
18 # include <sys/time.h>
19 # include <time.h>
20 #else
21 # ifdef TM_IN_SYS_TIME
22 # include <sys/time.h>
23 # else
24 # include <time.h>
25 # endif
26 #endif
27
28 static struct swit parswit[] = {
29 #define PRAND 0
30 { "and", 0 },
31 #define PROR 1
32 { "or", 0 },
33 #define PRNOT 2
34 { "not", 0 },
35 #define PRLBR 3
36 { "lbrace", 0 },
37 #define PRRBR 4
38 { "rbrace", 0 },
39 #define PRCC 5
40 { "cc pattern", 0 },
41 #define PRDATE 6
42 { "date pattern", 0 },
43 #define PRFROM 7
44 { "from pattern", 0 },
45 #define PRSRCH 8
46 { "search pattern", 0 },
47 #define PRSUBJ 9
48 { "subject pattern", 0 },
49 #define PRTO 10
50 { "to pattern", 0 },
51 #define PROTHR 11
52 { "-othercomponent pattern", 15 },
53 #define PRAFTR 12
54 { "after date", 0 },
55 #define PRBEFR 13
56 { "before date", 0 },
57 #define PRDATF 14
58 { "datefield field", 5 },
59 { NULL, 0 }
60 };
61
62 /* DEFINITIONS FOR PATTERN MATCHING */
63
64 /*
65 * We really should be using re_comp() and re_exec() here. Unfortunately,
66 * pick advertises that lowercase characters matches characters of both
67 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
68 * with this version. Furthermore, we need to be able to save and restore
69 * the state of the pattern matcher in order to do things "efficiently".
70 *
71 * The matching power of this algorithm isn't as powerful as the re_xxx()
72 * routines (no \(xxx\) and \n constructs). Such is life.
73 */
74
75 #define CCHR 2
76 #define CDOT 4
77 #define CCL 6
78 #define NCCL 8
79 #define CDOL 10
80 #define CEOF 11
81
82 #define STAR 01
83
84 #define LBSIZE 1024
85 #define ESIZE 1024
86
87
88 static char linebuf[LBSIZE + 1];
89
90 /* the magic array for case-independence */
91 static char cc[] = {
92 0000,0001,0002,0003,0004,0005,0006,0007,
93 0010,0011,0012,0013,0014,0015,0016,0017,
94 0020,0021,0022,0023,0024,0025,0026,0027,
95 0030,0031,0032,0033,0034,0035,0036,0037,
96 0040,0041,0042,0043,0044,0045,0046,0047,
97 0050,0051,0052,0053,0054,0055,0056,0057,
98 0060,0061,0062,0063,0064,0065,0066,0067,
99 0070,0071,0072,0073,0074,0075,0076,0077,
100 0100,0141,0142,0143,0144,0145,0146,0147,
101 0150,0151,0152,0153,0154,0155,0156,0157,
102 0160,0161,0162,0163,0164,0165,0166,0167,
103 0170,0171,0172,0133,0134,0135,0136,0137,
104 0140,0141,0142,0143,0144,0145,0146,0147,
105 0150,0151,0152,0153,0154,0155,0156,0157,
106 0160,0161,0162,0163,0164,0165,0166,0167,
107 0170,0171,0172,0173,0174,0175,0176,0177,
108
109 0200,0201,0202,0203,0204,0205,0206,0207,
110 0210,0211,0212,0213,0214,0215,0216,0217,
111 0220,0221,0222,0223,0224,0225,0226,0227,
112 0230,0231,0232,0233,0234,0235,0236,0237,
113 0240,0241,0242,0243,0244,0245,0246,0247,
114 0250,0251,0252,0253,0254,0255,0256,0257,
115 0260,0261,0262,0263,0264,0265,0266,0267,
116 0270,0271,0272,0273,0274,0275,0276,0277,
117 0300,0301,0302,0303,0304,0305,0306,0307,
118 0310,0311,0312,0313,0314,0315,0316,0317,
119 0320,0321,0322,0323,0324,0325,0326,0327,
120 0330,0331,0332,0333,0334,0335,0336,0337,
121 0340,0341,0342,0343,0344,0345,0346,0347,
122 0350,0351,0352,0353,0354,0355,0356,0357,
123 0360,0361,0362,0363,0364,0365,0366,0367,
124 0370,0371,0372,0373,0374,0375,0376,0377,
125 };
126
127 /*
128 * DEFINITIONS FOR NEXUS
129 */
130
131 #define nxtarg() (*argp ? *argp++ : NULL)
132 #define prvarg() argp--
133
134 #define padvise if (!talked++) advise
135
136 struct nexus {
137 int (*n_action)();
138
139 union {
140 /* for {OR,AND,NOT}action */
141 struct {
142 struct nexus *un_L_child;
143 struct nexus *un_R_child;
144 } st1;
145
146 /* for GREPaction */
147 struct {
148 int un_header;
149 int un_circf;
150 char un_expbuf[ESIZE];
151 char *un_patbuf;
152 } st2;
153
154 /* for TWSaction */
155 struct {
156 char *un_datef;
157 int un_after;
158 struct tws un_tws;
159 } st3;
160 } un;
161 };
162
163 #define n_L_child un.st1.un_L_child
164 #define n_R_child un.st1.un_R_child
165
166 #define n_header un.st2.un_header
167 #define n_circf un.st2.un_circf
168 #define n_expbuf un.st2.un_expbuf
169 #define n_patbuf un.st2.un_patbuf
170
171 #define n_datef un.st3.un_datef
172 #define n_after un.st3.un_after
173 #define n_tws un.st3.un_tws
174
175 static int talked;
176 static int pdebug = 0;
177
178 static char *datesw;
179 static char **argp;
180
181 static struct nexus *head;
182
183 /*
184 * prototypes for date routines
185 */
186 static struct tws *tws_parse();
187 static struct tws *tws_special();
188
189 /*
190 * static prototypes
191 */
192 static void PRaction();
193 static int gcompile();
194 static int advance();
195 static int cclass();
196 static int tcompile();
197
198 static struct nexus *parse();
199 static struct nexus *exp1();
200 static struct nexus *exp2();
201 static struct nexus *exp3();
202 static struct nexus *newnexus();
203
204 static int ORaction();
205 static int ANDaction();
206 static int NOTaction();
207 static int GREPaction();
208 static int TWSaction();
209
210
211 int
212 pcompile (char **vec, char *date)
213 {
214 register char *cp;
215
216 if ((cp = getenv ("MHPDEBUG")) && *cp)
217 pdebug++;
218
219 argp = vec;
220 if ((datesw = date) == NULL)
221 datesw = "date";
222 talked = 0;
223
224 if ((head = parse ()) == NULL)
225 return (talked ? 0 : 1);
226
227 if (*argp) {
228 padvise (NULL, "%s unexpected", *argp);
229 return 0;
230 }
231
232 return 1;
233 }
234
235
236 static struct nexus *
237 parse (void)
238 {
239 register char *cp;
240 register struct nexus *n, *o;
241
242 if ((n = exp1 ()) == NULL || (cp = nxtarg ()) == NULL)
243 return n;
244
245 if (*cp != '-') {
246 padvise (NULL, "%s unexpected", cp);
247 return NULL;
248 }
249
250 if (*++cp == '-')
251 goto header;
252 switch (smatch (cp, parswit)) {
253 case AMBIGSW:
254 ambigsw (cp, parswit);
255 talked++;
256 return NULL;
257 case UNKWNSW:
258 fprintf (stderr, "-%s unknown\n", cp);
259 talked++;
260 return NULL;
261
262 case PROR:
263 o = newnexus (ORaction);
264 o->n_L_child = n;
265 if ((o->n_R_child = parse ()))
266 return o;
267 padvise (NULL, "missing disjunctive");
268 return NULL;
269
270 header: ;
271 default:
272 prvarg ();
273 return n;
274 }
275 }
276
277 static struct nexus *
278 exp1 (void)
279 {
280 register char *cp;
281 register struct nexus *n, *o;
282
283 if ((n = exp2 ()) == NULL || (cp = nxtarg ()) == NULL)
284 return n;
285
286 if (*cp != '-') {
287 padvise (NULL, "%s unexpected", cp);
288 return NULL;
289 }
290
291 if (*++cp == '-')
292 goto header;
293 switch (smatch (cp, parswit)) {
294 case AMBIGSW:
295 ambigsw (cp, parswit);
296 talked++;
297 return NULL;
298 case UNKWNSW:
299 fprintf (stderr, "-%s unknown\n", cp);
300 talked++;
301 return NULL;
302
303 case PRAND:
304 o = newnexus (ANDaction);
305 o->n_L_child = n;
306 if ((o->n_R_child = exp1 ()))
307 return o;
308 padvise (NULL, "missing conjunctive");
309 return NULL;
310
311 header: ;
312 default:
313 prvarg ();
314 return n;
315 }
316 }
317
318
319 static struct nexus *
320 exp2 (void)
321 {
322 register char *cp;
323 register struct nexus *n;
324
325 if ((cp = nxtarg ()) == NULL)
326 return NULL;
327
328 if (*cp != '-') {
329 prvarg ();
330 return exp3 ();
331 }
332
333 if (*++cp == '-')
334 goto header;
335 switch (smatch (cp, parswit)) {
336 case AMBIGSW:
337 ambigsw (cp, parswit);
338 talked++;
339 return NULL;
340 case UNKWNSW:
341 fprintf (stderr, "-%s unknown\n", cp);
342 talked++;
343 return NULL;
344
345 case PRNOT:
346 n = newnexus (NOTaction);
347 if ((n->n_L_child = exp3 ()))
348 return n;
349 padvise (NULL, "missing negation");
350 return NULL;
351
352 header: ;
353 default:
354 prvarg ();
355 return exp3 ();
356 }
357 }
358
359 static struct nexus *
360 exp3 (void)
361 {
362 int i;
363 register char *cp, *dp;
364 char buffer[BUFSIZ], temp[64];
365 register struct nexus *n;
366
367 if ((cp = nxtarg ()) == NULL)
368 return NULL;
369
370 if (*cp != '-') {
371 padvise (NULL, "%s unexpected", cp);
372 return NULL;
373 }
374
375 if (*++cp == '-') {
376 dp = ++cp;
377 goto header;
378 }
379 switch (i = smatch (cp, parswit)) {
380 case AMBIGSW:
381 ambigsw (cp, parswit);
382 talked++;
383 return NULL;
384 case UNKWNSW:
385 fprintf (stderr, "-%s unknown\n", cp);
386 talked++;
387 return NULL;
388
389 case PRLBR:
390 if ((n = parse ()) == NULL) {
391 padvise (NULL, "missing group");
392 return NULL;
393 }
394 if ((cp = nxtarg ()) == NULL) {
395 padvise (NULL, "missing -rbrace");
396 return NULL;
397 }
398 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
399 return n;
400 padvise (NULL, "%s unexpected", --cp);
401 return NULL;
402
403 default:
404 prvarg ();
405 return NULL;
406
407 case PRCC:
408 case PRDATE:
409 case PRFROM:
410 case PRTO:
411 case PRSUBJ:
412 strncpy(temp, parswit[i].sw, sizeof(temp));
413 temp[sizeof(temp) - 1] = '\0';
414 dp = *brkstring (temp, " ", NULL);
415 header: ;
416 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
417 padvise (NULL, "missing argument to %s", argp[-2]);
418 return NULL;
419 }
420 n = newnexus (GREPaction);
421 n->n_header = 1;
422 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
423 dp = buffer;
424 goto pattern;
425
426 case PRSRCH:
427 n = newnexus (GREPaction);
428 n->n_header = 0;
429 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
430 padvise (NULL, "missing argument to %s", argp[-2]);
431 return NULL;
432 }
433 dp = cp;
434 pattern: ;
435 if (!gcompile (n, dp)) {
436 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
437 return NULL;
438 }
439 n->n_patbuf = getcpy (dp);
440 return n;
441
442 case PROTHR:
443 padvise (NULL, "internal error!");
444 return NULL;
445
446 case PRDATF:
447 if (!(datesw = nxtarg ()) || *datesw == '-') {
448 padvise (NULL, "missing argument to %s", argp[-2]);
449 return NULL;
450 }
451 return exp3 ();
452
453 case PRAFTR:
454 case PRBEFR:
455 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
456 padvise (NULL, "missing argument to %s", argp[-2]);
457 return NULL;
458 }
459 n = newnexus (TWSaction);
460 n->n_datef = datesw;
461 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
462 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
463 return NULL;
464 }
465 return n;
466 }
467 }
468
469
470 static struct nexus *
471 newnexus (int (*action)())
472 {
473 register struct nexus *p;
474
475 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
476 adios (NULL, "unable to allocate component storage");
477
478 p->n_action = action;
479 return p;
480 }
481
482
483 #define args(a) a, fp, msgnum, start, stop
484 #define params args (n)
485 #define plist \
486 register struct nexus *n; \
487 register FILE *fp; \
488 int msgnum; \
489 long start, \
490 stop;
491
492 int
493 pmatches (FILE *fp, int msgnum, long start, long stop)
494 {
495 if (!head)
496 return 1;
497
498 if (!talked++ && pdebug)
499 PRaction (head, 0);
500
501 return (*head->n_action) (args (head));
502 }
503
504
505 static void
506 PRaction (struct nexus *n, int level)
507 {
508 register int i;
509
510 for (i = 0; i < level; i++)
511 fprintf (stderr, "| ");
512
513 if (n->n_action == ORaction) {
514 fprintf (stderr, "OR\n");
515 PRaction (n->n_L_child, level + 1);
516 PRaction (n->n_R_child, level + 1);
517 return;
518 }
519 if (n->n_action == ANDaction) {
520 fprintf (stderr, "AND\n");
521 PRaction (n->n_L_child, level + 1);
522 PRaction (n->n_R_child, level + 1);
523 return;
524 }
525 if (n->n_action == NOTaction) {
526 fprintf (stderr, "NOT\n");
527 PRaction (n->n_L_child, level + 1);
528 return;
529 }
530 if (n->n_action == GREPaction) {
531 fprintf (stderr, "PATTERN(%s) %s\n",
532 n->n_header ? "header" : "body", n->n_patbuf);
533 return;
534 }
535 if (n->n_action == TWSaction) {
536 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
537 n->n_after ? "after" : "before", n->n_datef,
538 dasctime (&n->n_tws, TW_NULL));
539 return;
540 }
541 fprintf (stderr, "UNKNOWN(0x%x)\n", (unsigned int) (*n->n_action));
542 }
543
544
545 static int
546 ORaction (params)
547 plist
548 {
549 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
550 return 1;
551 return (*n->n_R_child->n_action) (args (n->n_R_child));
552 }
553
554
555 static int
556 ANDaction (params)
557 plist
558 {
559 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
560 return 0;
561 return (*n->n_R_child->n_action) (args (n->n_R_child));
562 }
563
564
565 static int
566 NOTaction (params)
567 plist
568 {
569 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
570 }
571
572
573 static int
574 gcompile (struct nexus *n, char *astr)
575 {
576 register int c;
577 int cclcnt;
578 register unsigned char *ep, *dp, *sp, *lastep = 0;
579
580 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
581 sp = astr;
582 if (*sp == '^') {
583 n->n_circf = 1;
584 sp++;
585 }
586 else
587 n->n_circf = 0;
588 for (;;) {
589 if (ep >= dp)
590 goto cerror;
591 if ((c = *sp++) != '*')
592 lastep = ep;
593 switch (c) {
594 case '\0':
595 *ep++ = CEOF;
596 return 1;
597
598 case '.':
599 *ep++ = CDOT;
600 continue;
601
602 case '*':
603 if (lastep == 0)
604 goto defchar;
605 *lastep |= STAR;
606 continue;
607
608 case '$':
609 if (*sp != '\0')
610 goto defchar;
611 *ep++ = CDOL;
612 continue;
613
614 case '[':
615 *ep++ = CCL;
616 *ep++ = 0;
617 cclcnt = 0;
618 if ((c = *sp++) == '^') {
619 c = *sp++;
620 ep[-2] = NCCL;
621 }
622 if (c == '-') {
623 *ep++ = c;
624 cclcnt++;
625 c = *sp++;
626 }
627 do {
628 if (c == '-' && *sp != '\0' && *sp != ']') {
629 for (c = ep[-1]+1; c < *sp; c++) {
630 *ep++ = c;
631 cclcnt++;
632 if (c == '\0' || ep >= dp)
633 goto cerror;
634 }
635 } else {
636 *ep++ = c;
637 cclcnt++;
638 if (c == '\0' || ep >= dp)
639 goto cerror;
640 }
641 } while ((c = *sp++) != ']');
642 if (cclcnt > 255)
643 goto cerror;
644 lastep[1] = cclcnt;
645 continue;
646
647 case '\\':
648 if ((c = *sp++) == '\0')
649 goto cerror;
650 defchar:
651 default:
652 *ep++ = CCHR;
653 *ep++ = c;
654 }
655 }
656
657 cerror: ;
658 return 0;
659 }
660
661
662 static int
663 GREPaction (params)
664 plist
665 {
666 int c, body, lf;
667 long pos = start;
668 register char *p1, *p2, *ebp, *cbp;
669 char ibuf[BUFSIZ];
670
671 fseek (fp, start, SEEK_SET);
672 body = 0;
673 ebp = cbp = ibuf;
674 for (;;) {
675 if (body && n->n_header)
676 return 0;
677 p1 = linebuf;
678 p2 = cbp;
679 lf = 0;
680 for (;;) {
681 if (p2 >= ebp) {
682 if (fgets (ibuf, sizeof ibuf, fp) == NULL
683 || (stop && pos >= stop)) {
684 if (lf)
685 break;
686 return 0;
687 }
688 pos += (long) strlen (ibuf);
689 p2 = ibuf;
690 ebp = ibuf + strlen (ibuf);
691 }
692 c = *p2++;
693 if (lf && c != '\n') {
694 if (c != ' ' && c != '\t') {
695 --p2;
696 break;
697 }
698 else
699 lf = 0;
700 }
701 if (c == '\n') {
702 if (body)
703 break;
704 else {
705 if (lf) {
706 body++;
707 break;
708 }
709 lf++;
710 c = ' ';
711 }
712 }
713 if (c && p1 < &linebuf[LBSIZE - 1])
714 *p1++ = c;
715 }
716
717 *p1++ = 0;
718 cbp = p2;
719 p1 = linebuf;
720 p2 = n->n_expbuf;
721
722 if (n->n_circf) {
723 if (advance (p1, p2))
724 return 1;
725 continue;
726 }
727
728 if (*p2 == CCHR) {
729 c = p2[1];
730 do {
731 if (*p1 == c || cc[(unsigned char)*p1] == c)
732 if (advance (p1, p2))
733 return 1;
734 } while (*p1++);
735 continue;
736 }
737
738 do {
739 if (advance (p1, p2))
740 return 1;
741 } while (*p1++);
742 }
743 }
744
745
746 static int
747 advance (char *alp, char *aep)
748 {
749 register unsigned char *lp, *ep, *curlp;
750
751 lp = (unsigned char *)alp;
752 ep = (unsigned char *)aep;
753 for (;;)
754 switch (*ep++) {
755 case CCHR:
756 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
757 continue;
758 return 0;
759
760 case CDOT:
761 if (*lp++)
762 continue;
763 return 0;
764
765 case CDOL:
766 if (*lp == 0)
767 continue;
768 return 0;
769
770 case CEOF:
771 return 1;
772
773 case CCL:
774 if (cclass (ep, *lp++, 1)) {
775 ep += *ep + 1;
776 continue;
777 }
778 return 0;
779
780 case NCCL:
781 if (cclass (ep, *lp++, 0)) {
782 ep += *ep + 1;
783 continue;
784 }
785 return 0;
786
787 case CDOT | STAR:
788 curlp = lp;
789 while (*lp++)
790 continue;
791 goto star;
792
793 case CCHR | STAR:
794 curlp = lp;
795 while (*lp++ == *ep || cc[lp[-1]] == *ep)
796 continue;
797 ep++;
798 goto star;
799
800 case CCL | STAR:
801 case NCCL | STAR:
802 curlp = lp;
803 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
804 continue;
805 ep += *ep + 1;
806 goto star;
807
808 star:
809 do {
810 lp--;
811 if (advance (lp, ep))
812 return (1);
813 } while (lp > curlp);
814 return 0;
815
816 default:
817 admonish (NULL, "advance() botch -- you lose big");
818 return 0;
819 }
820 }
821
822
823 static int
824 cclass (unsigned char *aset, int ac, int af)
825 {
826 register unsigned int n;
827 register unsigned char c, *set;
828
829 set = aset;
830 if ((c = ac) == 0)
831 return (0);
832
833 n = *set++;
834 while (n--)
835 if (*set++ == c || set[-1] == cc[c])
836 return (af);
837
838 return (!af);
839 }
840
841
842 static int
843 tcompile (char *ap, struct tws *tb, int isafter)
844 {
845 register struct tws *tw;
846
847 if ((tw = tws_parse (ap, isafter)) == NULL)
848 return 0;
849
850 twscopy (tb, tw);
851 return 1;
852 }
853
854
855 static struct tws *
856 tws_parse (char *ap, int isafter)
857 {
858 char buffer[BUFSIZ];
859 register struct tws *tw, *ts;
860
861 if ((tw = tws_special (ap)) != NULL) {
862 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
863 tw->tw_hour = isafter ? 23 : 0;
864 return tw;
865 }
866 if ((tw = dparsetime (ap)) != NULL)
867 return tw;
868
869 if ((ts = dlocaltimenow ()) == NULL)
870 return NULL;
871
872 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
873 if ((tw = dparsetime (buffer)) != NULL)
874 return tw;
875
876 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
877 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
878 if ((tw = dparsetime (buffer)) != NULL)
879 return tw;
880
881 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
882 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
883 if ((tw = dparsetime (buffer)) != NULL)
884 return tw;
885
886 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
887 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
888 ap, dtwszone (ts));
889 if ((tw = dparsetime (buffer)) != NULL)
890 return tw;
891
892 return NULL;
893 }
894
895
896 static struct tws *
897 tws_special (char *ap)
898 {
899 int i;
900 time_t clock;
901 register struct tws *tw;
902
903 time (&clock);
904 if (!mh_strcasecmp (ap, "today"))
905 return dlocaltime (&clock);
906 if (!mh_strcasecmp (ap, "yesterday")) {
907 clock -= (long) (60 * 60 * 24);
908 return dlocaltime (&clock);
909 }
910 if (!mh_strcasecmp (ap, "tomorrow")) {
911 clock += (long) (60 * 60 * 24);
912 return dlocaltime (&clock);
913 }
914
915 for (i = 0; tw_ldotw[i]; i++)
916 if (!mh_strcasecmp (ap, tw_ldotw[i]))
917 break;
918 if (tw_ldotw[i]) {
919 if ((tw = dlocaltime (&clock)) == NULL)
920 return NULL;
921 if ((i -= tw->tw_wday) > 0)
922 i -= 7;
923 }
924 else
925 if (*ap != '-')
926 return NULL;
927 else /* -ddd days ago */
928 i = atoi (ap); /* we should error check this */
929
930 clock += (long) ((60 * 60 * 24) * i);
931 return dlocaltime (&clock);
932 }
933
934
935 static int
936 TWSaction (params)
937 plist
938 {
939 int state;
940 register char *bp;
941 char buf[BUFSIZ], name[NAMESZ];
942 register struct tws *tw;
943
944 fseek (fp, start, SEEK_SET);
945 for (state = FLD, bp = NULL;;) {
946 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
947 case FLD:
948 case FLDEOF:
949 case FLDPLUS:
950 if (bp != NULL)
951 free (bp), bp = NULL;
952 bp = add (buf, NULL);
953 while (state == FLDPLUS) {
954 state = m_getfld (state, name, buf, sizeof buf, fp);
955 bp = add (buf, bp);
956 }
957 if (!mh_strcasecmp (name, n->n_datef))
958 break;
959 if (state != FLDEOF)
960 continue;
961
962 case BODY:
963 case BODYEOF:
964 case FILEEOF:
965 case LENERR:
966 case FMTERR:
967 if (state == LENERR || state == FMTERR)
968 advise (NULL, "format error in message %d", msgnum);
969 if (bp != NULL)
970 free (bp);
971 return 0;
972
973 default:
974 adios (NULL, "internal error -- you lose");
975 }
976 break;
977 }
978
979 if ((tw = dparsetime (bp)) == NULL)
980 advise (NULL, "unable to parse %s field in message %d, matching...",
981 n->n_datef, msgnum), state = 1;
982 else
983 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
984 : (twsort (tw, &n->n_tws) < 0);
985
986 if (bp != NULL)
987 free (bp);
988 return state;
989 }