3 * picksbr.c -- routines to help pick along...
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.
12 #include <h/picksbr.h>
15 #ifdef HAVE_SYS_TIME_H
16 # include <sys/time.h>
20 static struct swit parswit[] = {
34 { "date pattern", 0 },
36 { "from pattern", 0 },
38 { "search pattern", 0 },
40 { "subject pattern", 0 },
44 { "-othercomponent pattern", 15 },
50 { "datefield field", 5 },
54 /* DEFINITIONS FOR PATTERN MATCHING */
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".
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.
80 static char linebuf[LBSIZE + 1];
82 /* the magic array for case-independence */
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,
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,
120 * DEFINITIONS FOR NEXUS
123 #define nxtarg() (*argp ? *argp++ : NULL)
124 #define prvarg() argp--
126 #define padvise if (!talked++) advise
132 /* for {OR,AND,NOT}action */
134 struct nexus *un_L_child;
135 struct nexus *un_R_child;
142 char un_expbuf[ESIZE];
155 #define n_L_child un.st1.un_L_child
156 #define n_R_child un.st1.un_R_child
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
163 #define n_datef un.st3.un_datef
164 #define n_after un.st3.un_after
165 #define n_tws un.st3.un_tws
168 static int pdebug = 0;
173 static struct nexus *head;
176 * prototypes for date routines
178 static struct tws *tws_parse(char *, int);
179 static struct tws *tws_special(char *);
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);
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 (*)());
196 static int ORaction();
197 static int ANDaction();
198 static int NOTaction();
199 static int GREPaction();
200 static int TWSaction();
204 pcompile (char **vec, char *date)
208 if ((cp = getenv ("MHPDEBUG")) && *cp)
212 if ((datesw = date) == NULL)
216 if ((head = parse ()) == NULL)
217 return (talked ? 0 : 1);
220 padvise (NULL, "%s unexpected", *argp);
228 static struct nexus *
232 register struct nexus *n, *o;
234 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
238 padvise (NULL, "%s unexpected", cp);
244 switch (smatch (cp, parswit)) {
246 ambigsw (cp, parswit);
250 fprintf (stderr, "-%s unknown\n", cp);
255 o = newnexus (ORaction);
257 if ((o->n_R_child = parse ()))
259 padvise (NULL, "missing disjunctive");
269 static struct nexus *
273 register struct nexus *n, *o;
275 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
279 padvise (NULL, "%s unexpected", cp);
285 switch (smatch (cp, parswit)) {
287 ambigsw (cp, parswit);
291 fprintf (stderr, "-%s unknown\n", cp);
296 o = newnexus (ANDaction);
298 if ((o->n_R_child = nexp1 ()))
300 padvise (NULL, "missing conjunctive");
311 static struct nexus *
315 register struct nexus *n;
317 if ((cp = nxtarg ()) == NULL)
327 switch (smatch (cp, parswit)) {
329 ambigsw (cp, parswit);
333 fprintf (stderr, "-%s unknown\n", cp);
338 n = newnexus (NOTaction);
339 if ((n->n_L_child = nexp3 ()))
341 padvise (NULL, "missing negation");
351 static struct nexus *
355 register char *cp, *dp;
356 char buffer[BUFSIZ], temp[64];
357 register struct nexus *n;
359 if ((cp = nxtarg ()) == NULL)
363 padvise (NULL, "%s unexpected", cp);
371 switch (i = smatch (cp, parswit)) {
373 ambigsw (cp, parswit);
377 fprintf (stderr, "-%s unknown\n", cp);
382 if ((n = parse ()) == NULL) {
383 padvise (NULL, "missing group");
386 if ((cp = nxtarg ()) == NULL) {
387 padvise (NULL, "missing -rbrace");
390 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
392 padvise (NULL, "%s unexpected", --cp);
404 strncpy(temp, parswit[i].sw, sizeof(temp));
405 temp[sizeof(temp) - 1] = '\0';
406 dp = *brkstring (temp, " ", NULL);
408 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
409 padvise (NULL, "missing argument to %s", argp[-2]);
412 n = newnexus (GREPaction);
414 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
419 n = newnexus (GREPaction);
421 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
422 padvise (NULL, "missing argument to %s", argp[-2]);
427 if (!gcompile (n, dp)) {
428 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
431 n->n_patbuf = getcpy (dp);
435 padvise (NULL, "internal error!");
439 if (!(datesw = nxtarg ()) || *datesw == '-') {
440 padvise (NULL, "missing argument to %s", argp[-2]);
447 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
448 padvise (NULL, "missing argument to %s", argp[-2]);
451 n = newnexus (TWSaction);
453 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
454 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
462 static struct nexus *
463 newnexus (int (*action)())
465 register struct nexus *p;
467 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
468 adios (NULL, "unable to allocate component storage");
470 p->n_action = action;
475 #define args(a) a, fp, msgnum, start, stop
476 #define params args (n)
478 register struct nexus *n; \
485 pmatches (FILE *fp, int msgnum, long start, long stop)
490 if (!talked++ && pdebug)
493 return (*head->n_action) (args (head));
498 PRaction (struct nexus *n, int level)
502 for (i = 0; i < level; i++)
503 fprintf (stderr, "| ");
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);
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);
517 if (n->n_action == NOTaction) {
518 fprintf (stderr, "NOT\n");
519 PRaction (n->n_L_child, level + 1);
522 if (n->n_action == GREPaction) {
523 fprintf (stderr, "PATTERN(%s) %s\n",
524 n->n_header ? "header" : "body", n->n_patbuf);
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));
533 fprintf (stderr, "UNKNOWN(0x%x)\n",
534 (unsigned int)(unsigned long) (*n->n_action));
542 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
544 return (*n->n_R_child->n_action) (args (n->n_R_child));
552 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
554 return (*n->n_R_child->n_action) (args (n->n_R_child));
562 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
567 gcompile (struct nexus *n, char *astr)
571 register unsigned char *ep, *dp, *sp, *lastep = 0;
573 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
584 if ((c = *sp++) != '*')
611 if ((c = *sp++) == '^') {
621 if (c == '-' && *sp != '\0' && *sp != ']') {
622 for (c = ep[-1]+1; c < *sp; c++) {
625 if (c == '\0' || ep >= dp)
631 if (c == '\0' || ep >= dp)
634 } while ((c = *sp++) != ']');
641 if ((c = *sp++) == '\0')
663 register char *p1, *p2, *ebp, *cbp;
666 fseek (fp, start, SEEK_SET);
670 if (body && n->n_header)
677 if (fgets (ibuf, sizeof ibuf, fp) == NULL
678 || (stop && pos >= stop)) {
683 pos += (long) strlen (ibuf);
685 ebp = ibuf + strlen (ibuf);
688 if (lf && c != '\n') {
689 if (c != ' ' && c != '\t') {
708 if (c && p1 < &linebuf[LBSIZE - 1])
718 if (advance (p1, p2))
726 if (*p1 == c || cc[(unsigned char)*p1] == c)
727 if (advance (p1, p2))
734 if (advance (p1, p2))
742 advance (char *alp, char *aep)
744 register unsigned char *lp, *ep, *curlp;
746 lp = (unsigned char *)alp;
747 ep = (unsigned char *)aep;
751 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
769 if (cclass (ep, *lp++, 1)) {
776 if (cclass (ep, *lp++, 0)) {
790 while (*lp++ == *ep || cc[lp[-1]] == *ep)
798 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
806 if (advance (lp, ep))
808 } while (lp > curlp);
812 admonish (NULL, "advance() botch -- you lose big");
819 cclass (unsigned char *aset, int ac, int af)
821 register unsigned int n;
822 register unsigned char c, *set;
830 if (*set++ == c || set[-1] == cc[c])
838 tcompile (char *ap, struct tws *tb, int isafter)
840 register struct tws *tw;
842 if ((tw = tws_parse (ap, isafter)) == NULL)
851 tws_parse (char *ap, int isafter)
854 register struct tws *tw, *ts;
856 if ((tw = tws_special (ap)) != NULL) {
857 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
858 tw->tw_hour = isafter ? 23 : 0;
861 if ((tw = dparsetime (ap)) != NULL)
864 if ((ts = dlocaltimenow ()) == NULL)
867 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
868 if ((tw = dparsetime (buffer)) != NULL)
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)
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)
881 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
882 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
884 if ((tw = dparsetime (buffer)) != NULL)
892 tws_special (char *ap)
896 register struct tws *tw;
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);
905 if (!mh_strcasecmp (ap, "tomorrow")) {
906 clock += (long) (60 * 60 * 24);
907 return dlocaltime (&clock);
910 for (i = 0; tw_ldotw[i]; i++)
911 if (!mh_strcasecmp (ap, tw_ldotw[i]))
914 if ((tw = dlocaltime (&clock)) == NULL)
916 if ((i -= tw->tw_wday) > 0)
922 else /* -ddd days ago */
923 i = atoi (ap); /* we should error check this */
925 clock += (long) ((60 * 60 * 24) * i);
926 return dlocaltime (&clock);
938 char buf[BUFSIZ], name[NAMESZ];
939 register struct tws *tw;
941 fseek (fp, start, SEEK_SET);
942 for (state = FLD, bp = NULL;;) {
943 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
948 free (bp), bp = NULL;
949 bp = add (buf, NULL);
950 while (state == FLDPLUS) {
951 state = m_getfld (state, name, buf, sizeof buf, fp);
954 if (!mh_strcasecmp (name, n->n_datef))
964 if (state == LENERR || state == FMTERR)
965 advise (NULL, "format error in message %d", msgnum);
971 adios (NULL, "internal error -- you lose");
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;
980 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
981 : (twsort (tw, &n->n_tws) < 0);