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