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