2 * picksbr.c -- routines to help pick along...
4 * This code is Copyright (c) 2002, by the authors of nmh. See the
5 * COPYRIGHT file in the root directory of the nmh distribution for
6 * complete copyright information.
11 #include <h/picksbr.h>
14 #ifdef TIME_WITH_SYS_TIME
15 # include <sys/time.h>
18 # ifdef TM_IN_SYS_TIME
19 # include <sys/time.h>
25 static struct swit parswit[] = {
39 { "date pattern", 0 },
41 { "from pattern", 0 },
43 { "search pattern", 0 },
45 { "subject pattern", 0 },
49 { "-othercomponent pattern", 15 },
55 { "datefield field", 5 },
59 /* DEFINITIONS FOR PATTERN MATCHING */
62 * We really should be using re_comp() and re_exec() here. Unfortunately,
63 * pick advertises that lowercase characters matches characters of both
64 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
65 * with this version. Furthermore, we need to be able to save and restore
66 * the state of the pattern matcher in order to do things "efficiently".
68 * The matching power of this algorithm isn't as powerful as the re_xxx()
69 * routines (no \(xxx\) and \n constructs). Such is life.
85 static char linebuf[LBSIZE + 1];
87 /* the magic array for case-independence */
89 0000,0001,0002,0003,0004,0005,0006,0007,
90 0010,0011,0012,0013,0014,0015,0016,0017,
91 0020,0021,0022,0023,0024,0025,0026,0027,
92 0030,0031,0032,0033,0034,0035,0036,0037,
93 0040,0041,0042,0043,0044,0045,0046,0047,
94 0050,0051,0052,0053,0054,0055,0056,0057,
95 0060,0061,0062,0063,0064,0065,0066,0067,
96 0070,0071,0072,0073,0074,0075,0076,0077,
97 0100,0141,0142,0143,0144,0145,0146,0147,
98 0150,0151,0152,0153,0154,0155,0156,0157,
99 0160,0161,0162,0163,0164,0165,0166,0167,
100 0170,0171,0172,0133,0134,0135,0136,0137,
101 0140,0141,0142,0143,0144,0145,0146,0147,
102 0150,0151,0152,0153,0154,0155,0156,0157,
103 0160,0161,0162,0163,0164,0165,0166,0167,
104 0170,0171,0172,0173,0174,0175,0176,0177,
106 0200,0201,0202,0203,0204,0205,0206,0207,
107 0210,0211,0212,0213,0214,0215,0216,0217,
108 0220,0221,0222,0223,0224,0225,0226,0227,
109 0230,0231,0232,0233,0234,0235,0236,0237,
110 0240,0241,0242,0243,0244,0245,0246,0247,
111 0250,0251,0252,0253,0254,0255,0256,0257,
112 0260,0261,0262,0263,0264,0265,0266,0267,
113 0270,0271,0272,0273,0274,0275,0276,0277,
114 0300,0301,0302,0303,0304,0305,0306,0307,
115 0310,0311,0312,0313,0314,0315,0316,0317,
116 0320,0321,0322,0323,0324,0325,0326,0327,
117 0330,0331,0332,0333,0334,0335,0336,0337,
118 0340,0341,0342,0343,0344,0345,0346,0347,
119 0350,0351,0352,0353,0354,0355,0356,0357,
120 0360,0361,0362,0363,0364,0365,0366,0367,
121 0370,0371,0372,0373,0374,0375,0376,0377,
125 * DEFINITIONS FOR NEXUS
128 #define nxtarg() (*argp ? *argp++ : NULL)
129 #define prvarg() argp--
131 #define padvise if (!talked++) advise
137 /* for {OR,AND,NOT}action */
139 struct nexus *un_L_child;
140 struct nexus *un_R_child;
147 char un_expbuf[ESIZE];
160 #define n_L_child un.st1.un_L_child
161 #define n_R_child un.st1.un_R_child
163 #define n_header un.st2.un_header
164 #define n_circf un.st2.un_circf
165 #define n_expbuf un.st2.un_expbuf
166 #define n_patbuf un.st2.un_patbuf
168 #define n_datef un.st3.un_datef
169 #define n_after un.st3.un_after
170 #define n_tws un.st3.un_tws
173 static int pdebug = 0;
178 static struct nexus *head;
181 * prototypes for date routines
183 static struct tws *tws_parse();
184 static struct tws *tws_special();
189 static void PRaction();
190 static int gcompile();
191 static int advance();
193 static int tcompile();
195 static struct nexus *parse();
196 static struct nexus *nexp1();
197 static struct nexus *nexp2();
198 static struct nexus *nexp3();
199 static struct nexus *newnexus();
201 static int ORaction();
202 static int ANDaction();
203 static int NOTaction();
204 static int GREPaction();
205 static int TWSaction();
209 pcompile (char **vec, char *date)
213 if ((cp = getenv ("MHPDEBUG")) && *cp)
217 if ((datesw = date) == NULL)
221 if ((head = parse ()) == NULL)
222 return (talked ? 0 : 1);
225 padvise (NULL, "%s unexpected", *argp);
233 static struct nexus *
237 register struct nexus *n, *o;
239 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
243 padvise (NULL, "%s unexpected", cp);
249 switch (smatch (cp, parswit)) {
251 ambigsw (cp, parswit);
255 fprintf (stderr, "-%s unknown\n", cp);
260 o = newnexus (ORaction);
262 if ((o->n_R_child = parse ()))
264 padvise (NULL, "missing disjunctive");
274 static struct nexus *
278 register struct nexus *n, *o;
280 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
284 padvise (NULL, "%s unexpected", cp);
290 switch (smatch (cp, parswit)) {
292 ambigsw (cp, parswit);
296 fprintf (stderr, "-%s unknown\n", cp);
301 o = newnexus (ANDaction);
303 if ((o->n_R_child = nexp1 ()))
305 padvise (NULL, "missing conjunctive");
316 static struct nexus *
320 register struct nexus *n;
322 if ((cp = nxtarg ()) == NULL)
332 switch (smatch (cp, parswit)) {
334 ambigsw (cp, parswit);
338 fprintf (stderr, "-%s unknown\n", cp);
343 n = newnexus (NOTaction);
344 if ((n->n_L_child = nexp3 ()))
346 padvise (NULL, "missing negation");
356 static struct nexus *
360 register char *cp, *dp;
361 char buffer[BUFSIZ], temp[64];
362 register struct nexus *n;
364 if ((cp = nxtarg ()) == NULL)
368 padvise (NULL, "%s unexpected", cp);
376 switch (i = smatch (cp, parswit)) {
378 ambigsw (cp, parswit);
382 fprintf (stderr, "-%s unknown\n", cp);
387 if ((n = parse ()) == NULL) {
388 padvise (NULL, "missing group");
391 if ((cp = nxtarg ()) == NULL) {
392 padvise (NULL, "missing -rbrace");
395 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
397 padvise (NULL, "%s unexpected", --cp);
409 strncpy(temp, parswit[i].sw, sizeof(temp));
410 temp[sizeof(temp) - 1] = '\0';
411 dp = *brkstring (temp, " ", NULL);
413 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
414 padvise (NULL, "missing argument to %s", argp[-2]);
417 n = newnexus (GREPaction);
419 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
424 n = newnexus (GREPaction);
426 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
427 padvise (NULL, "missing argument to %s", argp[-2]);
432 if (!gcompile (n, dp)) {
433 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
436 n->n_patbuf = getcpy (dp);
440 padvise (NULL, "internal error!");
444 if (!(datesw = nxtarg ()) || *datesw == '-') {
445 padvise (NULL, "missing argument to %s", argp[-2]);
452 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
453 padvise (NULL, "missing argument to %s", argp[-2]);
456 n = newnexus (TWSaction);
458 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
459 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
467 static struct nexus *
468 newnexus (int (*action)())
470 register struct nexus *p;
472 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
473 adios (NULL, "unable to allocate component storage");
475 p->n_action = action;
480 #define args(a) a, fp, msgnum, start, stop
481 #define params args (n)
483 register struct nexus *n; \
490 pmatches (FILE *fp, int msgnum, long start, long stop)
495 if (!talked++ && pdebug)
498 return (*head->n_action) (args (head));
503 PRaction (struct nexus *n, int level)
507 for (i = 0; i < level; i++)
508 fprintf (stderr, "| ");
510 if (n->n_action == ORaction) {
511 fprintf (stderr, "OR\n");
512 PRaction (n->n_L_child, level + 1);
513 PRaction (n->n_R_child, level + 1);
516 if (n->n_action == ANDaction) {
517 fprintf (stderr, "AND\n");
518 PRaction (n->n_L_child, level + 1);
519 PRaction (n->n_R_child, level + 1);
522 if (n->n_action == NOTaction) {
523 fprintf (stderr, "NOT\n");
524 PRaction (n->n_L_child, level + 1);
527 if (n->n_action == GREPaction) {
528 fprintf (stderr, "PATTERN(%s) %s\n",
529 n->n_header ? "header" : "body", n->n_patbuf);
532 if (n->n_action == TWSaction) {
533 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
534 n->n_after ? "after" : "before", n->n_datef,
535 dasctime (&n->n_tws, TW_NULL));
538 fprintf (stderr, "UNKNOWN(0x%x)\n",
539 (unsigned int)(unsigned long) (*n->n_action));
547 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
549 return (*n->n_R_child->n_action) (args (n->n_R_child));
557 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
559 return (*n->n_R_child->n_action) (args (n->n_R_child));
567 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
572 gcompile (struct nexus *n, char *astr)
576 register unsigned char *ep, *dp, *sp, *lastep = 0;
578 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
589 if ((c = *sp++) != '*')
616 if ((c = *sp++) == '^') {
626 if (c == '-' && *sp != '\0' && *sp != ']') {
627 for (c = ep[-1]+1; c < *sp; c++) {
630 if (c == '\0' || ep >= dp)
636 if (c == '\0' || ep >= dp)
639 } 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 unsigned char *lp, *ep, *curlp;
749 lp = (unsigned char *)alp;
750 ep = (unsigned char *)aep;
754 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
772 if (cclass (ep, *lp++, 1)) {
779 if (cclass (ep, *lp++, 0)) {
793 while (*lp++ == *ep || cc[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 (unsigned char *aset, int ac, int af)
824 register unsigned int n;
825 register unsigned char c, *set;
833 if (*set++ == c || set[-1] == cc[c])
841 tcompile (char *ap, struct tws *tb, int isafter)
843 register struct tws *tw;
845 if ((tw = tws_parse (ap, isafter)) == NULL)
854 tws_parse (char *ap, int isafter)
857 register struct tws *tw, *ts;
859 if ((tw = tws_special (ap)) != NULL) {
860 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
861 tw->tw_hour = isafter ? 23 : 0;
864 if ((tw = dparsetime (ap)) != NULL)
867 if ((ts = dlocaltimenow ()) == NULL)
870 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
871 if ((tw = dparsetime (buffer)) != NULL)
874 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
875 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
876 if ((tw = dparsetime (buffer)) != NULL)
879 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
880 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
881 if ((tw = dparsetime (buffer)) != NULL)
884 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
885 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
887 if ((tw = dparsetime (buffer)) != NULL)
895 tws_special (char *ap)
899 register struct tws *tw;
902 if (!mh_strcasecmp (ap, "today"))
903 return dlocaltime (&clock);
904 if (!mh_strcasecmp (ap, "yesterday")) {
905 clock -= (long) (60 * 60 * 24);
906 return dlocaltime (&clock);
908 if (!mh_strcasecmp (ap, "tomorrow")) {
909 clock += (long) (60 * 60 * 24);
910 return dlocaltime (&clock);
913 for (i = 0; tw_ldotw[i]; i++)
914 if (!mh_strcasecmp (ap, tw_ldotw[i]))
917 if ((tw = dlocaltime (&clock)) == NULL)
919 if ((i -= tw->tw_wday) > 0)
925 else /* -ddd days ago */
926 i = atoi (ap); /* we should error check this */
928 clock += (long) ((60 * 60 * 24) * i);
929 return dlocaltime (&clock);
939 char buf[BUFSIZ], name[NAMESZ];
940 register struct tws *tw;
942 fseek (fp, start, SEEK_SET);
943 for (state = FLD, bp = NULL;;) {
944 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
949 free (bp), bp = NULL;
950 bp = add (buf, NULL);
951 while (state == FLDPLUS) {
952 state = m_getfld (state, name, buf, sizeof buf, fp);
955 if (!mh_strcasecmp (name, n->n_datef))
965 if (state == LENERR || state == FMTERR)
966 advise (NULL, "format error in message %d", msgnum);
972 adios (NULL, "internal error -- you lose");
977 if ((tw = dparsetime (bp)) == NULL)
978 advise (NULL, "unable to parse %s field in message %d, matching...",
979 n->n_datef, msgnum), state = 1;
981 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
982 : (twsort (tw, &n->n_tws) < 0);