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