3 * picksbr.c -- routines to help pick along...
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.
14 #include <h/picksbr.h>
17 #ifdef TIME_WITH_SYS_TIME
18 # include <sys/time.h>
21 # ifdef TM_IN_SYS_TIME
22 # include <sys/time.h>
28 static struct swit parswit[] = {
42 { "date pattern", 0 },
44 { "from pattern", 0 },
46 { "search pattern", 0 },
48 { "subject pattern", 0 },
52 { "-othercomponent pattern", 15 },
58 { "datefield field", 5 },
62 /* DEFINITIONS FOR PATTERN MATCHING */
65 * We really should be using re_comp() and re_exec() here. Unfortunately,
66 * pick advertises that lowercase characters matches characters of both
67 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
68 * with this version. Furthermore, we need to be able to save and restore
69 * the state of the pattern matcher in order to do things "efficiently".
71 * The matching power of this algorithm isn't as powerful as the re_xxx()
72 * routines (no \(xxx\) and \n constructs). Such is life.
88 static char linebuf[LBSIZE + 1];
90 /* the magic array for case-independence */
92 0000,0001,0002,0003,0004,0005,0006,0007,
93 0010,0011,0012,0013,0014,0015,0016,0017,
94 0020,0021,0022,0023,0024,0025,0026,0027,
95 0030,0031,0032,0033,0034,0035,0036,0037,
96 0040,0041,0042,0043,0044,0045,0046,0047,
97 0050,0051,0052,0053,0054,0055,0056,0057,
98 0060,0061,0062,0063,0064,0065,0066,0067,
99 0070,0071,0072,0073,0074,0075,0076,0077,
100 0100,0141,0142,0143,0144,0145,0146,0147,
101 0150,0151,0152,0153,0154,0155,0156,0157,
102 0160,0161,0162,0163,0164,0165,0166,0167,
103 0170,0171,0172,0133,0134,0135,0136,0137,
104 0140,0141,0142,0143,0144,0145,0146,0147,
105 0150,0151,0152,0153,0154,0155,0156,0157,
106 0160,0161,0162,0163,0164,0165,0166,0167,
107 0170,0171,0172,0173,0174,0175,0176,0177,
109 0200,0201,0202,0203,0204,0205,0206,0207,
110 0210,0211,0212,0213,0214,0215,0216,0217,
111 0220,0221,0222,0223,0224,0225,0226,0227,
112 0230,0231,0232,0233,0234,0235,0236,0237,
113 0240,0241,0242,0243,0244,0245,0246,0247,
114 0250,0251,0252,0253,0254,0255,0256,0257,
115 0260,0261,0262,0263,0264,0265,0266,0267,
116 0270,0271,0272,0273,0274,0275,0276,0277,
117 0300,0301,0302,0303,0304,0305,0306,0307,
118 0310,0311,0312,0313,0314,0315,0316,0317,
119 0320,0321,0322,0323,0324,0325,0326,0327,
120 0330,0331,0332,0333,0334,0335,0336,0337,
121 0340,0341,0342,0343,0344,0345,0346,0347,
122 0350,0351,0352,0353,0354,0355,0356,0357,
123 0360,0361,0362,0363,0364,0365,0366,0367,
124 0370,0371,0372,0373,0374,0375,0376,0377,
128 * DEFINITIONS FOR NEXUS
131 #define nxtarg() (*argp ? *argp++ : NULL)
132 #define prvarg() argp--
134 #define padvise if (!talked++) advise
140 /* for {OR,AND,NOT}action */
142 struct nexus *un_L_child;
143 struct nexus *un_R_child;
150 char un_expbuf[ESIZE];
163 #define n_L_child un.st1.un_L_child
164 #define n_R_child un.st1.un_R_child
166 #define n_header un.st2.un_header
167 #define n_circf un.st2.un_circf
168 #define n_expbuf un.st2.un_expbuf
169 #define n_patbuf un.st2.un_patbuf
171 #define n_datef un.st3.un_datef
172 #define n_after un.st3.un_after
173 #define n_tws un.st3.un_tws
176 static int pdebug = 0;
181 static struct nexus *head;
184 * prototypes for date routines
186 static struct tws *tws_parse();
187 static struct tws *tws_special();
192 static void PRaction();
193 static int gcompile();
194 static int advance();
196 static int tcompile();
198 static struct nexus *parse();
199 static struct nexus *exp1();
200 static struct nexus *exp2();
201 static struct nexus *exp3();
202 static struct nexus *newnexus();
204 static int ORaction();
205 static int ANDaction();
206 static int NOTaction();
207 static int GREPaction();
208 static int TWSaction();
212 pcompile (char **vec, char *date)
216 if ((cp = getenv ("MHPDEBUG")) && *cp)
220 if ((datesw = date) == NULL)
224 if ((head = parse ()) == NULL)
225 return (talked ? 0 : 1);
228 padvise (NULL, "%s unexpected", *argp);
236 static struct nexus *
240 register struct nexus *n, *o;
242 if ((n = exp1 ()) == NULL || (cp = nxtarg ()) == NULL)
246 padvise (NULL, "%s unexpected", cp);
252 switch (smatch (cp, parswit)) {
254 ambigsw (cp, parswit);
258 fprintf (stderr, "-%s unknown\n", cp);
263 o = newnexus (ORaction);
265 if ((o->n_R_child = parse ()))
267 padvise (NULL, "missing disjunctive");
277 static struct nexus *
281 register struct nexus *n, *o;
283 if ((n = exp2 ()) == NULL || (cp = nxtarg ()) == NULL)
287 padvise (NULL, "%s unexpected", cp);
293 switch (smatch (cp, parswit)) {
295 ambigsw (cp, parswit);
299 fprintf (stderr, "-%s unknown\n", cp);
304 o = newnexus (ANDaction);
306 if ((o->n_R_child = exp1 ()))
308 padvise (NULL, "missing conjunctive");
319 static struct nexus *
323 register struct nexus *n;
325 if ((cp = nxtarg ()) == NULL)
335 switch (smatch (cp, parswit)) {
337 ambigsw (cp, parswit);
341 fprintf (stderr, "-%s unknown\n", cp);
346 n = newnexus (NOTaction);
347 if ((n->n_L_child = exp3 ()))
349 padvise (NULL, "missing negation");
359 static struct nexus *
363 register char *cp, *dp;
364 char buffer[BUFSIZ], temp[64];
365 register struct nexus *n;
367 if ((cp = nxtarg ()) == NULL)
371 padvise (NULL, "%s unexpected", cp);
379 switch (i = smatch (cp, parswit)) {
381 ambigsw (cp, parswit);
385 fprintf (stderr, "-%s unknown\n", cp);
390 if ((n = parse ()) == NULL) {
391 padvise (NULL, "missing group");
394 if ((cp = nxtarg ()) == NULL) {
395 padvise (NULL, "missing -rbrace");
398 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
400 padvise (NULL, "%s unexpected", --cp);
412 strncpy(temp, parswit[i].sw, sizeof(temp));
413 temp[sizeof(temp) - 1] = '\0';
414 dp = *brkstring (temp, " ", NULL);
416 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
417 padvise (NULL, "missing argument to %s", argp[-2]);
420 n = newnexus (GREPaction);
422 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
427 n = newnexus (GREPaction);
429 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
430 padvise (NULL, "missing argument to %s", argp[-2]);
435 if (!gcompile (n, dp)) {
436 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
439 n->n_patbuf = getcpy (dp);
443 padvise (NULL, "internal error!");
447 if (!(datesw = nxtarg ()) || *datesw == '-') {
448 padvise (NULL, "missing argument to %s", argp[-2]);
455 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
456 padvise (NULL, "missing argument to %s", argp[-2]);
459 n = newnexus (TWSaction);
461 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
462 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
470 static struct nexus *
471 newnexus (int (*action)())
473 register struct nexus *p;
475 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
476 adios (NULL, "unable to allocate component storage");
478 p->n_action = action;
483 #define args(a) a, fp, msgnum, start, stop
484 #define params args (n)
486 register struct nexus *n; \
493 pmatches (FILE *fp, int msgnum, long start, long stop)
498 if (!talked++ && pdebug)
501 return (*head->n_action) (args (head));
506 PRaction (struct nexus *n, int level)
510 for (i = 0; i < level; i++)
511 fprintf (stderr, "| ");
513 if (n->n_action == ORaction) {
514 fprintf (stderr, "OR\n");
515 PRaction (n->n_L_child, level + 1);
516 PRaction (n->n_R_child, level + 1);
519 if (n->n_action == ANDaction) {
520 fprintf (stderr, "AND\n");
521 PRaction (n->n_L_child, level + 1);
522 PRaction (n->n_R_child, level + 1);
525 if (n->n_action == NOTaction) {
526 fprintf (stderr, "NOT\n");
527 PRaction (n->n_L_child, level + 1);
530 if (n->n_action == GREPaction) {
531 fprintf (stderr, "PATTERN(%s) %s\n",
532 n->n_header ? "header" : "body", n->n_patbuf);
535 if (n->n_action == TWSaction) {
536 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
537 n->n_after ? "after" : "before", n->n_datef,
538 dasctime (&n->n_tws, TW_NULL));
541 fprintf (stderr, "UNKNOWN(0x%x)\n", (unsigned int) (*n->n_action));
549 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
551 return (*n->n_R_child->n_action) (args (n->n_R_child));
559 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
561 return (*n->n_R_child->n_action) (args (n->n_R_child));
569 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
574 gcompile (struct nexus *n, char *astr)
578 register char *ep, *dp, *sp, *lastep = 0;
580 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
591 if ((c = *sp++) != '*')
618 if ((c = *sp++) == '^') {
628 if (c == '-' && *sp != '\0' && *sp != ']') {
629 for (c = ep[-1]+1; c < *sp; c++) {
632 if (c == '\0' || ep >= dp)
638 if (c == '\0' || ep >= dp)
641 } while ((c = *sp++) != ']');
646 if ((c = *sp++) == '\0')
666 register char *p1, *p2, *ebp, *cbp;
669 fseek (fp, start, SEEK_SET);
673 if (body && n->n_header)
680 if (fgets (ibuf, sizeof ibuf, fp) == NULL
681 || (stop && pos >= stop)) {
686 pos += (long) strlen (ibuf);
688 ebp = ibuf + strlen (ibuf);
691 if (lf && c != '\n') {
692 if (c != ' ' && c != '\t') {
711 if (c && p1 < &linebuf[LBSIZE - 1])
721 if (advance (p1, p2))
729 if (*p1 == c || cc[(unsigned char)*p1] == c)
730 if (advance (p1, p2))
737 if (advance (p1, p2))
745 advance (char *alp, char *aep)
747 register char *lp, *ep, *curlp;
754 if (*ep++ == *lp++ || ep[-1] == cc[(unsigned char)lp[-1]])
772 if (cclass (ep, *lp++, 1)) {
779 if (cclass (ep, *lp++, 0)) {
793 while (*lp++ == *ep || cc[(unsigned char)lp[-1]] == *ep)
801 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
809 if (advance (lp, ep))
811 } while (lp > curlp);
815 admonish (NULL, "advance() botch -- you lose big");
822 cclass (char *aset, int ac, int af)
834 if (*set++ == c || set[-1] == cc[(unsigned char)c])
842 tcompile (char *ap, struct tws *tb, int isafter)
844 register struct tws *tw;
846 if ((tw = tws_parse (ap, isafter)) == NULL)
855 tws_parse (char *ap, int isafter)
858 register struct tws *tw, *ts;
860 if ((tw = tws_special (ap)) != NULL) {
861 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
862 tw->tw_hour = isafter ? 23 : 0;
865 if ((tw = dparsetime (ap)) != NULL)
868 if ((ts = dlocaltimenow ()) == NULL)
871 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
872 if ((tw = dparsetime (buffer)) != NULL)
875 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
876 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
877 if ((tw = dparsetime (buffer)) != NULL)
880 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
881 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
882 if ((tw = dparsetime (buffer)) != NULL)
885 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
886 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
888 if ((tw = dparsetime (buffer)) != NULL)
896 tws_special (char *ap)
900 register struct tws *tw;
903 if (!mh_strcasecmp (ap, "today"))
904 return dlocaltime (&clock);
905 if (!mh_strcasecmp (ap, "yesterday")) {
906 clock -= (long) (60 * 60 * 24);
907 return dlocaltime (&clock);
909 if (!mh_strcasecmp (ap, "tomorrow")) {
910 clock += (long) (60 * 60 * 24);
911 return dlocaltime (&clock);
914 for (i = 0; tw_ldotw[i]; i++)
915 if (!mh_strcasecmp (ap, tw_ldotw[i]))
918 if ((tw = dlocaltime (&clock)) == NULL)
920 if ((i -= tw->tw_wday) > 0)
926 else /* -ddd days ago */
927 i = atoi (ap); /* we should error check this */
929 clock += (long) ((60 * 60 * 24) * i);
930 return dlocaltime (&clock);
940 char buf[BUFSIZ], name[NAMESZ];
941 register struct tws *tw;
943 fseek (fp, start, SEEK_SET);
944 for (state = FLD, bp = NULL;;) {
945 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
950 free (bp), bp = NULL;
951 bp = add (buf, NULL);
952 while (state == FLDPLUS) {
953 state = m_getfld (state, name, buf, sizeof buf, fp);
956 if (!mh_strcasecmp (name, n->n_datef))
966 if (state == LENERR || state == FMTERR)
967 advise (NULL, "format error in message %d", msgnum);
973 adios (NULL, "internal error -- you lose");
978 if ((tw = dparsetime (bp)) == NULL)
979 advise (NULL, "unable to parse %s field in message %d, matching...",
980 n->n_datef, msgnum), state = 1;
982 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
983 : (twsort (tw, &n->n_tws) < 0);