]> diplodocus.org Git - nmh/blob - uip/picksbr.c
61d5afb88e3df8599d0bdcd8fc0a968968f4f1ec
[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 *nexp1();
200 static struct nexus *nexp2();
201 static struct nexus *nexp3();
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 = nexp1 ()) == 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 nexp1 (void)
279 {
280 register char *cp;
281 register struct nexus *n, *o;
282
283 if ((n = nexp2 ()) == 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 = nexp1 ()))
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 nexp2 (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 nexp3 ();
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 = nexp3 ()))
348 return n;
349 padvise (NULL, "missing negation");
350 return NULL;
351
352 header: ;
353 default:
354 prvarg ();
355 return nexp3 ();
356 }
357 }
358
359 static struct nexus *
360 nexp3 (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 nexp3 ();
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",
542 (unsigned int)(unsigned long) (*n->n_action));
543 }
544
545
546 static int
547 ORaction (params)
548 plist
549 {
550 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
551 return 1;
552 return (*n->n_R_child->n_action) (args (n->n_R_child));
553 }
554
555
556 static int
557 ANDaction (params)
558 plist
559 {
560 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
561 return 0;
562 return (*n->n_R_child->n_action) (args (n->n_R_child));
563 }
564
565
566 static int
567 NOTaction (params)
568 plist
569 {
570 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
571 }
572
573
574 static int
575 gcompile (struct nexus *n, char *astr)
576 {
577 register int c;
578 int cclcnt;
579 register unsigned char *ep, *dp, *sp, *lastep = 0;
580
581 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
582 sp = astr;
583 if (*sp == '^') {
584 n->n_circf = 1;
585 sp++;
586 }
587 else
588 n->n_circf = 0;
589 for (;;) {
590 if (ep >= dp)
591 goto cerror;
592 if ((c = *sp++) != '*')
593 lastep = ep;
594 switch (c) {
595 case '\0':
596 *ep++ = CEOF;
597 return 1;
598
599 case '.':
600 *ep++ = CDOT;
601 continue;
602
603 case '*':
604 if (lastep == 0)
605 goto defchar;
606 *lastep |= STAR;
607 continue;
608
609 case '$':
610 if (*sp != '\0')
611 goto defchar;
612 *ep++ = CDOL;
613 continue;
614
615 case '[':
616 *ep++ = CCL;
617 *ep++ = 0;
618 cclcnt = 0;
619 if ((c = *sp++) == '^') {
620 c = *sp++;
621 ep[-2] = NCCL;
622 }
623 if (c == '-') {
624 *ep++ = c;
625 cclcnt++;
626 c = *sp++;
627 }
628 do {
629 if (c == '-' && *sp != '\0' && *sp != ']') {
630 for (c = ep[-1]+1; c < *sp; c++) {
631 *ep++ = c;
632 cclcnt++;
633 if (c == '\0' || ep >= dp)
634 goto cerror;
635 }
636 } else {
637 *ep++ = c;
638 cclcnt++;
639 if (c == '\0' || ep >= dp)
640 goto cerror;
641 }
642 } while ((c = *sp++) != ']');
643 if (cclcnt > 255)
644 goto cerror;
645 lastep[1] = cclcnt;
646 continue;
647
648 case '\\':
649 if ((c = *sp++) == '\0')
650 goto cerror;
651 defchar:
652 default:
653 *ep++ = CCHR;
654 *ep++ = c;
655 }
656 }
657
658 cerror: ;
659 return 0;
660 }
661
662
663 static int
664 GREPaction (params)
665 plist
666 {
667 int c, body, lf;
668 long pos = start;
669 register char *p1, *p2, *ebp, *cbp;
670 char ibuf[BUFSIZ];
671
672 fseek (fp, start, SEEK_SET);
673 body = 0;
674 ebp = cbp = ibuf;
675 for (;;) {
676 if (body && n->n_header)
677 return 0;
678 p1 = linebuf;
679 p2 = cbp;
680 lf = 0;
681 for (;;) {
682 if (p2 >= ebp) {
683 if (fgets (ibuf, sizeof ibuf, fp) == NULL
684 || (stop && pos >= stop)) {
685 if (lf)
686 break;
687 return 0;
688 }
689 pos += (long) strlen (ibuf);
690 p2 = ibuf;
691 ebp = ibuf + strlen (ibuf);
692 }
693 c = *p2++;
694 if (lf && c != '\n') {
695 if (c != ' ' && c != '\t') {
696 --p2;
697 break;
698 }
699 else
700 lf = 0;
701 }
702 if (c == '\n') {
703 if (body)
704 break;
705 else {
706 if (lf) {
707 body++;
708 break;
709 }
710 lf++;
711 c = ' ';
712 }
713 }
714 if (c && p1 < &linebuf[LBSIZE - 1])
715 *p1++ = c;
716 }
717
718 *p1++ = 0;
719 cbp = p2;
720 p1 = linebuf;
721 p2 = n->n_expbuf;
722
723 if (n->n_circf) {
724 if (advance (p1, p2))
725 return 1;
726 continue;
727 }
728
729 if (*p2 == CCHR) {
730 c = p2[1];
731 do {
732 if (*p1 == c || cc[(unsigned char)*p1] == c)
733 if (advance (p1, p2))
734 return 1;
735 } while (*p1++);
736 continue;
737 }
738
739 do {
740 if (advance (p1, p2))
741 return 1;
742 } while (*p1++);
743 }
744 }
745
746
747 static int
748 advance (char *alp, char *aep)
749 {
750 register unsigned char *lp, *ep, *curlp;
751
752 lp = (unsigned char *)alp;
753 ep = (unsigned char *)aep;
754 for (;;)
755 switch (*ep++) {
756 case CCHR:
757 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
758 continue;
759 return 0;
760
761 case CDOT:
762 if (*lp++)
763 continue;
764 return 0;
765
766 case CDOL:
767 if (*lp == 0)
768 continue;
769 return 0;
770
771 case CEOF:
772 return 1;
773
774 case CCL:
775 if (cclass (ep, *lp++, 1)) {
776 ep += *ep + 1;
777 continue;
778 }
779 return 0;
780
781 case NCCL:
782 if (cclass (ep, *lp++, 0)) {
783 ep += *ep + 1;
784 continue;
785 }
786 return 0;
787
788 case CDOT | STAR:
789 curlp = lp;
790 while (*lp++)
791 continue;
792 goto star;
793
794 case CCHR | STAR:
795 curlp = lp;
796 while (*lp++ == *ep || cc[lp[-1]] == *ep)
797 continue;
798 ep++;
799 goto star;
800
801 case CCL | STAR:
802 case NCCL | STAR:
803 curlp = lp;
804 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
805 continue;
806 ep += *ep + 1;
807 goto star;
808
809 star:
810 do {
811 lp--;
812 if (advance (lp, ep))
813 return (1);
814 } while (lp > curlp);
815 return 0;
816
817 default:
818 admonish (NULL, "advance() botch -- you lose big");
819 return 0;
820 }
821 }
822
823
824 static int
825 cclass (unsigned char *aset, int ac, int af)
826 {
827 register unsigned int n;
828 register unsigned char c, *set;
829
830 set = aset;
831 if ((c = ac) == 0)
832 return (0);
833
834 n = *set++;
835 while (n--)
836 if (*set++ == c || set[-1] == cc[c])
837 return (af);
838
839 return (!af);
840 }
841
842
843 static int
844 tcompile (char *ap, struct tws *tb, int isafter)
845 {
846 register struct tws *tw;
847
848 if ((tw = tws_parse (ap, isafter)) == NULL)
849 return 0;
850
851 twscopy (tb, tw);
852 return 1;
853 }
854
855
856 static struct tws *
857 tws_parse (char *ap, int isafter)
858 {
859 char buffer[BUFSIZ];
860 register struct tws *tw, *ts;
861
862 if ((tw = tws_special (ap)) != NULL) {
863 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
864 tw->tw_hour = isafter ? 23 : 0;
865 return tw;
866 }
867 if ((tw = dparsetime (ap)) != NULL)
868 return tw;
869
870 if ((ts = dlocaltimenow ()) == NULL)
871 return NULL;
872
873 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
874 if ((tw = dparsetime (buffer)) != NULL)
875 return tw;
876
877 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
878 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
879 if ((tw = dparsetime (buffer)) != NULL)
880 return tw;
881
882 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
883 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
884 if ((tw = dparsetime (buffer)) != NULL)
885 return tw;
886
887 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
888 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
889 ap, dtwszone (ts));
890 if ((tw = dparsetime (buffer)) != NULL)
891 return tw;
892
893 return NULL;
894 }
895
896
897 static struct tws *
898 tws_special (char *ap)
899 {
900 int i;
901 time_t clock;
902 register struct tws *tw;
903
904 time (&clock);
905 if (!mh_strcasecmp (ap, "today"))
906 return dlocaltime (&clock);
907 if (!mh_strcasecmp (ap, "yesterday")) {
908 clock -= (long) (60 * 60 * 24);
909 return dlocaltime (&clock);
910 }
911 if (!mh_strcasecmp (ap, "tomorrow")) {
912 clock += (long) (60 * 60 * 24);
913 return dlocaltime (&clock);
914 }
915
916 for (i = 0; tw_ldotw[i]; i++)
917 if (!mh_strcasecmp (ap, tw_ldotw[i]))
918 break;
919 if (tw_ldotw[i]) {
920 if ((tw = dlocaltime (&clock)) == NULL)
921 return NULL;
922 if ((i -= tw->tw_wday) > 0)
923 i -= 7;
924 }
925 else
926 if (*ap != '-')
927 return NULL;
928 else /* -ddd days ago */
929 i = atoi (ap); /* we should error check this */
930
931 clock += (long) ((60 * 60 * 24) * i);
932 return dlocaltime (&clock);
933 }
934
935
936 static int
937 TWSaction (params)
938 plist
939 {
940 int state;
941 register char *bp;
942 char buf[BUFSIZ], name[NAMESZ];
943 register struct tws *tw;
944
945 fseek (fp, start, SEEK_SET);
946 for (state = FLD, bp = NULL;;) {
947 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
948 case FLD:
949 case FLDEOF:
950 case FLDPLUS:
951 if (bp != NULL)
952 free (bp), bp = NULL;
953 bp = add (buf, NULL);
954 while (state == FLDPLUS) {
955 state = m_getfld (state, name, buf, sizeof buf, fp);
956 bp = add (buf, bp);
957 }
958 if (!mh_strcasecmp (name, n->n_datef))
959 break;
960 if (state != FLDEOF)
961 continue;
962
963 case BODY:
964 case BODYEOF:
965 case FILEEOF:
966 case LENERR:
967 case FMTERR:
968 if (state == LENERR || state == FMTERR)
969 advise (NULL, "format error in message %d", msgnum);
970 if (bp != NULL)
971 free (bp);
972 return 0;
973
974 default:
975 adios (NULL, "internal error -- you lose");
976 }
977 break;
978 }
979
980 if ((tw = dparsetime (bp)) == NULL)
981 advise (NULL, "unable to parse %s field in message %d, matching...",
982 n->n_datef, msgnum), state = 1;
983 else
984 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
985 : (twsort (tw, &n->n_tws) < 0);
986
987 if (bp != NULL)
988 free (bp);
989 return state;
990 }