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 TIME_WITH_SYS_TIME
16 # include <sys/time.h>
19 # ifdef TM_IN_SYS_TIME
20 # include <sys/time.h>
26 static struct swit parswit[] = {
40 { "date pattern", 0 },
42 { "from pattern", 0 },
44 { "search pattern", 0 },
46 { "subject pattern", 0 },
50 { "-othercomponent pattern", 15 },
56 { "datefield field", 5 },
60 /* DEFINITIONS FOR PATTERN MATCHING */
63 * We really should be using re_comp() and re_exec() here. Unfortunately,
64 * pick advertises that lowercase characters matches characters of both
65 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
66 * with this version. Furthermore, we need to be able to save and restore
67 * the state of the pattern matcher in order to do things "efficiently".
69 * The matching power of this algorithm isn't as powerful as the re_xxx()
70 * routines (no \(xxx\) and \n constructs). Such is life.
86 static char linebuf[LBSIZE + 1];
88 /* the magic array for case-independence */
90 0000,0001,0002,0003,0004,0005,0006,0007,
91 0010,0011,0012,0013,0014,0015,0016,0017,
92 0020,0021,0022,0023,0024,0025,0026,0027,
93 0030,0031,0032,0033,0034,0035,0036,0037,
94 0040,0041,0042,0043,0044,0045,0046,0047,
95 0050,0051,0052,0053,0054,0055,0056,0057,
96 0060,0061,0062,0063,0064,0065,0066,0067,
97 0070,0071,0072,0073,0074,0075,0076,0077,
98 0100,0141,0142,0143,0144,0145,0146,0147,
99 0150,0151,0152,0153,0154,0155,0156,0157,
100 0160,0161,0162,0163,0164,0165,0166,0167,
101 0170,0171,0172,0133,0134,0135,0136,0137,
102 0140,0141,0142,0143,0144,0145,0146,0147,
103 0150,0151,0152,0153,0154,0155,0156,0157,
104 0160,0161,0162,0163,0164,0165,0166,0167,
105 0170,0171,0172,0173,0174,0175,0176,0177,
107 0200,0201,0202,0203,0204,0205,0206,0207,
108 0210,0211,0212,0213,0214,0215,0216,0217,
109 0220,0221,0222,0223,0224,0225,0226,0227,
110 0230,0231,0232,0233,0234,0235,0236,0237,
111 0240,0241,0242,0243,0244,0245,0246,0247,
112 0250,0251,0252,0253,0254,0255,0256,0257,
113 0260,0261,0262,0263,0264,0265,0266,0267,
114 0270,0271,0272,0273,0274,0275,0276,0277,
115 0300,0301,0302,0303,0304,0305,0306,0307,
116 0310,0311,0312,0313,0314,0315,0316,0317,
117 0320,0321,0322,0323,0324,0325,0326,0327,
118 0330,0331,0332,0333,0334,0335,0336,0337,
119 0340,0341,0342,0343,0344,0345,0346,0347,
120 0350,0351,0352,0353,0354,0355,0356,0357,
121 0360,0361,0362,0363,0364,0365,0366,0367,
122 0370,0371,0372,0373,0374,0375,0376,0377,
126 * DEFINITIONS FOR NEXUS
129 #define nxtarg() (*argp ? *argp++ : NULL)
130 #define prvarg() argp--
132 #define padvise if (!talked++) advise
138 /* for {OR,AND,NOT}action */
140 struct nexus *un_L_child;
141 struct nexus *un_R_child;
148 char un_expbuf[ESIZE];
161 #define n_L_child un.st1.un_L_child
162 #define n_R_child un.st1.un_R_child
164 #define n_header un.st2.un_header
165 #define n_circf un.st2.un_circf
166 #define n_expbuf un.st2.un_expbuf
167 #define n_patbuf un.st2.un_patbuf
169 #define n_datef un.st3.un_datef
170 #define n_after un.st3.un_after
171 #define n_tws un.st3.un_tws
174 static int pdebug = 0;
179 static struct nexus *head;
182 * prototypes for date routines
184 static struct tws *tws_parse();
185 static struct tws *tws_special();
190 static void PRaction();
191 static int gcompile();
192 static int advance();
194 static int tcompile();
196 static struct nexus *parse();
197 static struct nexus *nexp1();
198 static struct nexus *nexp2();
199 static struct nexus *nexp3();
200 static struct nexus *newnexus();
202 static int ORaction();
203 static int ANDaction();
204 static int NOTaction();
205 static int GREPaction();
206 static int TWSaction();
210 pcompile (char **vec, char *date)
214 if ((cp = getenv ("MHPDEBUG")) && *cp)
218 if ((datesw = date) == NULL)
222 if ((head = parse ()) == NULL)
223 return (talked ? 0 : 1);
226 padvise (NULL, "%s unexpected", *argp);
234 static struct nexus *
238 register struct nexus *n, *o;
240 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
244 padvise (NULL, "%s unexpected", cp);
250 switch (smatch (cp, parswit)) {
252 ambigsw (cp, parswit);
256 fprintf (stderr, "-%s unknown\n", cp);
261 o = newnexus (ORaction);
263 if ((o->n_R_child = parse ()))
265 padvise (NULL, "missing disjunctive");
275 static struct nexus *
279 register struct nexus *n, *o;
281 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
285 padvise (NULL, "%s unexpected", cp);
291 switch (smatch (cp, parswit)) {
293 ambigsw (cp, parswit);
297 fprintf (stderr, "-%s unknown\n", cp);
302 o = newnexus (ANDaction);
304 if ((o->n_R_child = nexp1 ()))
306 padvise (NULL, "missing conjunctive");
317 static struct nexus *
321 register struct nexus *n;
323 if ((cp = nxtarg ()) == NULL)
333 switch (smatch (cp, parswit)) {
335 ambigsw (cp, parswit);
339 fprintf (stderr, "-%s unknown\n", cp);
344 n = newnexus (NOTaction);
345 if ((n->n_L_child = nexp3 ()))
347 padvise (NULL, "missing negation");
357 static struct nexus *
361 register char *cp, *dp;
362 char buffer[BUFSIZ], temp[64];
363 register struct nexus *n;
365 if ((cp = nxtarg ()) == NULL)
369 padvise (NULL, "%s unexpected", cp);
377 switch (i = smatch (cp, parswit)) {
379 ambigsw (cp, parswit);
383 fprintf (stderr, "-%s unknown\n", cp);
388 if ((n = parse ()) == NULL) {
389 padvise (NULL, "missing group");
392 if ((cp = nxtarg ()) == NULL) {
393 padvise (NULL, "missing -rbrace");
396 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
398 padvise (NULL, "%s unexpected", --cp);
410 strncpy(temp, parswit[i].sw, sizeof(temp));
411 temp[sizeof(temp) - 1] = '\0';
412 dp = *brkstring (temp, " ", NULL);
414 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
415 padvise (NULL, "missing argument to %s", argp[-2]);
418 n = newnexus (GREPaction);
420 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
425 n = newnexus (GREPaction);
427 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
428 padvise (NULL, "missing argument to %s", argp[-2]);
433 if (!gcompile (n, dp)) {
434 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
437 n->n_patbuf = getcpy (dp);
441 padvise (NULL, "internal error!");
445 if (!(datesw = nxtarg ()) || *datesw == '-') {
446 padvise (NULL, "missing argument to %s", argp[-2]);
453 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
454 padvise (NULL, "missing argument to %s", argp[-2]);
457 n = newnexus (TWSaction);
459 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
460 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
468 static struct nexus *
469 newnexus (int (*action)())
471 register struct nexus *p;
473 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
474 adios (NULL, "unable to allocate component storage");
476 p->n_action = action;
481 #define args(a) a, fp, msgnum, start, stop
482 #define params args (n)
484 register struct nexus *n; \
491 pmatches (FILE *fp, int msgnum, long start, long stop)
496 if (!talked++ && pdebug)
499 return (*head->n_action) (args (head));
504 PRaction (struct nexus *n, int level)
508 for (i = 0; i < level; i++)
509 fprintf (stderr, "| ");
511 if (n->n_action == ORaction) {
512 fprintf (stderr, "OR\n");
513 PRaction (n->n_L_child, level + 1);
514 PRaction (n->n_R_child, level + 1);
517 if (n->n_action == ANDaction) {
518 fprintf (stderr, "AND\n");
519 PRaction (n->n_L_child, level + 1);
520 PRaction (n->n_R_child, level + 1);
523 if (n->n_action == NOTaction) {
524 fprintf (stderr, "NOT\n");
525 PRaction (n->n_L_child, level + 1);
528 if (n->n_action == GREPaction) {
529 fprintf (stderr, "PATTERN(%s) %s\n",
530 n->n_header ? "header" : "body", n->n_patbuf);
533 if (n->n_action == TWSaction) {
534 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
535 n->n_after ? "after" : "before", n->n_datef,
536 dasctime (&n->n_tws, TW_NULL));
539 fprintf (stderr, "UNKNOWN(0x%x)\n",
540 (unsigned int)(unsigned long) (*n->n_action));
548 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
550 return (*n->n_R_child->n_action) (args (n->n_R_child));
558 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
560 return (*n->n_R_child->n_action) (args (n->n_R_child));
568 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
573 gcompile (struct nexus *n, char *astr)
577 register unsigned char *ep, *dp, *sp, *lastep = 0;
579 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
590 if ((c = *sp++) != '*')
617 if ((c = *sp++) == '^') {
627 if (c == '-' && *sp != '\0' && *sp != ']') {
628 for (c = ep[-1]+1; c < *sp; c++) {
631 if (c == '\0' || ep >= dp)
637 if (c == '\0' || ep >= dp)
640 } while ((c = *sp++) != ']');
647 if ((c = *sp++) == '\0')
667 register char *p1, *p2, *ebp, *cbp;
670 fseek (fp, start, SEEK_SET);
674 if (body && n->n_header)
681 if (fgets (ibuf, sizeof ibuf, fp) == NULL
682 || (stop && pos >= stop)) {
687 pos += (long) strlen (ibuf);
689 ebp = ibuf + strlen (ibuf);
692 if (lf && c != '\n') {
693 if (c != ' ' && c != '\t') {
712 if (c && p1 < &linebuf[LBSIZE - 1])
722 if (advance (p1, p2))
730 if (*p1 == c || cc[(unsigned char)*p1] == c)
731 if (advance (p1, p2))
738 if (advance (p1, p2))
746 advance (char *alp, char *aep)
748 register unsigned char *lp, *ep, *curlp;
750 lp = (unsigned char *)alp;
751 ep = (unsigned char *)aep;
755 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
773 if (cclass (ep, *lp++, 1)) {
780 if (cclass (ep, *lp++, 0)) {
794 while (*lp++ == *ep || cc[lp[-1]] == *ep)
802 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
810 if (advance (lp, ep))
812 } while (lp > curlp);
816 admonish (NULL, "advance() botch -- you lose big");
823 cclass (unsigned char *aset, int ac, int af)
825 register unsigned int n;
826 register unsigned char c, *set;
834 if (*set++ == c || set[-1] == cc[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);