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