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 *nexp1();
200 static struct nexus *nexp2();
201 static struct nexus *nexp3();
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 = nexp1 ()) == 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 = nexp2 ()) == 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 = nexp1 ()))
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 = nexp3 ()))
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 unsigned 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++) != ']');
648 if ((c = *sp++) == '\0')
668 register char *p1, *p2, *ebp, *cbp;
671 fseek (fp, start, SEEK_SET);
675 if (body && n->n_header)
682 if (fgets (ibuf, sizeof ibuf, fp) == NULL
683 || (stop && pos >= stop)) {
688 pos += (long) strlen (ibuf);
690 ebp = ibuf + strlen (ibuf);
693 if (lf && c != '\n') {
694 if (c != ' ' && c != '\t') {
713 if (c && p1 < &linebuf[LBSIZE - 1])
723 if (advance (p1, p2))
731 if (*p1 == c || cc[(unsigned char)*p1] == c)
732 if (advance (p1, p2))
739 if (advance (p1, p2))
747 advance (char *alp, char *aep)
749 register unsigned char *lp, *ep, *curlp;
751 lp = (unsigned char *)alp;
752 ep = (unsigned char *)aep;
756 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
774 if (cclass (ep, *lp++, 1)) {
781 if (cclass (ep, *lp++, 0)) {
795 while (*lp++ == *ep || cc[lp[-1]] == *ep)
803 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
811 if (advance (lp, ep))
813 } while (lp > curlp);
817 admonish (NULL, "advance() botch -- you lose big");
824 cclass (unsigned char *aset, int ac, int af)
826 register unsigned int n;
827 register unsigned char c, *set;
835 if (*set++ == c || set[-1] == cc[c])
843 tcompile (char *ap, struct tws *tb, int isafter)
845 register struct tws *tw;
847 if ((tw = tws_parse (ap, isafter)) == NULL)
856 tws_parse (char *ap, int isafter)
859 register struct tws *tw, *ts;
861 if ((tw = tws_special (ap)) != NULL) {
862 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
863 tw->tw_hour = isafter ? 23 : 0;
866 if ((tw = dparsetime (ap)) != NULL)
869 if ((ts = dlocaltimenow ()) == NULL)
872 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
873 if ((tw = dparsetime (buffer)) != NULL)
876 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
877 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
878 if ((tw = dparsetime (buffer)) != NULL)
881 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
882 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
883 if ((tw = dparsetime (buffer)) != NULL)
886 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
887 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
889 if ((tw = dparsetime (buffer)) != NULL)
897 tws_special (char *ap)
901 register struct tws *tw;
904 if (!mh_strcasecmp (ap, "today"))
905 return dlocaltime (&clock);
906 if (!mh_strcasecmp (ap, "yesterday")) {
907 clock -= (long) (60 * 60 * 24);
908 return dlocaltime (&clock);
910 if (!mh_strcasecmp (ap, "tomorrow")) {
911 clock += (long) (60 * 60 * 24);
912 return dlocaltime (&clock);
915 for (i = 0; tw_ldotw[i]; i++)
916 if (!mh_strcasecmp (ap, tw_ldotw[i]))
919 if ((tw = dlocaltime (&clock)) == NULL)
921 if ((i -= tw->tw_wday) > 0)
927 else /* -ddd days ago */
928 i = atoi (ap); /* we should error check this */
930 clock += (long) ((60 * 60 * 24) * i);
931 return dlocaltime (&clock);
941 char buf[BUFSIZ], name[NAMESZ];
942 register struct tws *tw;
944 fseek (fp, start, SEEK_SET);
945 for (state = FLD, bp = NULL;;) {
946 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
951 free (bp), bp = NULL;
952 bp = add (buf, NULL);
953 while (state == FLDPLUS) {
954 state = m_getfld (state, name, buf, sizeof buf, fp);
957 if (!mh_strcasecmp (name, n->n_datef))
967 if (state == LENERR || state == FMTERR)
968 advise (NULL, "format error in message %d", msgnum);
974 adios (NULL, "internal error -- you lose");
979 if ((tw = dparsetime (bp)) == NULL)
980 advise (NULL, "unable to parse %s field in message %d, matching...",
981 n->n_datef, msgnum), state = 1;
983 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
984 : (twsort (tw, &n->n_tws) < 0);