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();
179 static struct tws *tws_special();
184 static void PRaction();
185 static int gcompile();
186 static int advance();
188 static int tcompile();
190 static struct nexus *parse();
191 static struct nexus *nexp1();
192 static struct nexus *nexp2();
193 static struct nexus *nexp3();
194 static struct nexus *newnexus();
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')
661 register char *p1, *p2, *ebp, *cbp;
664 fseek (fp, start, SEEK_SET);
668 if (body && n->n_header)
675 if (fgets (ibuf, sizeof ibuf, fp) == NULL
676 || (stop && pos >= stop)) {
681 pos += (long) strlen (ibuf);
683 ebp = ibuf + strlen (ibuf);
686 if (lf && c != '\n') {
687 if (c != ' ' && c != '\t') {
706 if (c && p1 < &linebuf[LBSIZE - 1])
716 if (advance (p1, p2))
724 if (*p1 == c || cc[(unsigned char)*p1] == c)
725 if (advance (p1, p2))
732 if (advance (p1, p2))
740 advance (char *alp, char *aep)
742 register unsigned char *lp, *ep, *curlp;
744 lp = (unsigned char *)alp;
745 ep = (unsigned char *)aep;
749 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
767 if (cclass (ep, *lp++, 1)) {
774 if (cclass (ep, *lp++, 0)) {
788 while (*lp++ == *ep || cc[lp[-1]] == *ep)
796 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
804 if (advance (lp, ep))
806 } while (lp > curlp);
810 admonish (NULL, "advance() botch -- you lose big");
817 cclass (unsigned char *aset, int ac, int af)
819 register unsigned int n;
820 register unsigned char c, *set;
828 if (*set++ == c || set[-1] == cc[c])
836 tcompile (char *ap, struct tws *tb, int isafter)
838 register struct tws *tw;
840 if ((tw = tws_parse (ap, isafter)) == NULL)
849 tws_parse (char *ap, int isafter)
852 register struct tws *tw, *ts;
854 if ((tw = tws_special (ap)) != NULL) {
855 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
856 tw->tw_hour = isafter ? 23 : 0;
859 if ((tw = dparsetime (ap)) != NULL)
862 if ((ts = dlocaltimenow ()) == NULL)
865 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
866 if ((tw = dparsetime (buffer)) != NULL)
869 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
870 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
871 if ((tw = dparsetime (buffer)) != NULL)
874 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
875 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
876 if ((tw = dparsetime (buffer)) != NULL)
879 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
880 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
882 if ((tw = dparsetime (buffer)) != NULL)
890 tws_special (char *ap)
894 register struct tws *tw;
897 if (!mh_strcasecmp (ap, "today"))
898 return dlocaltime (&clock);
899 if (!mh_strcasecmp (ap, "yesterday")) {
900 clock -= (long) (60 * 60 * 24);
901 return dlocaltime (&clock);
903 if (!mh_strcasecmp (ap, "tomorrow")) {
904 clock += (long) (60 * 60 * 24);
905 return dlocaltime (&clock);
908 for (i = 0; tw_ldotw[i]; i++)
909 if (!mh_strcasecmp (ap, tw_ldotw[i]))
912 if ((tw = dlocaltime (&clock)) == NULL)
914 if ((i -= tw->tw_wday) > 0)
920 else /* -ddd days ago */
921 i = atoi (ap); /* we should error check this */
923 clock += (long) ((60 * 60 * 24) * i);
924 return dlocaltime (&clock);
934 char buf[BUFSIZ], name[NAMESZ];
935 register struct tws *tw;
937 fseek (fp, start, SEEK_SET);
938 for (state = FLD, bp = NULL;;) {
939 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
944 free (bp), bp = NULL;
945 bp = add (buf, NULL);
946 while (state == FLDPLUS) {
947 state = m_getfld (state, name, buf, sizeof buf, fp);
950 if (!mh_strcasecmp (name, n->n_datef))
960 if (state == LENERR || state == FMTERR)
961 advise (NULL, "format error in message %d", msgnum);
967 adios (NULL, "internal error -- you lose");
972 if ((tw = dparsetime (bp)) == NULL)
973 advise (NULL, "unable to parse %s field in message %d, matching...",
974 n->n_datef, msgnum), state = 1;
976 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
977 : (twsort (tw, &n->n_tws) < 0);