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",
542 (unsigned int)(unsigned long) (*n->n_action));
550 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
552 return (*n->n_R_child->n_action) (args (n->n_R_child));
560 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
562 return (*n->n_R_child->n_action) (args (n->n_R_child));
570 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
575 gcompile (struct nexus *n, char *astr)
579 register unsigned char *ep, *dp, *sp, *lastep = 0;
581 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
592 if ((c = *sp++) != '*')
619 if ((c = *sp++) == '^') {
629 if (c == '-' && *sp != '\0' && *sp != ']') {
630 for (c = ep[-1]+1; c < *sp; c++) {
633 if (c == '\0' || ep >= dp)
639 if (c == '\0' || ep >= dp)
642 } while ((c = *sp++) != ']');
649 if ((c = *sp++) == '\0')
669 register char *p1, *p2, *ebp, *cbp;
672 fseek (fp, start, SEEK_SET);
676 if (body && n->n_header)
683 if (fgets (ibuf, sizeof ibuf, fp) == NULL
684 || (stop && pos >= stop)) {
689 pos += (long) strlen (ibuf);
691 ebp = ibuf + strlen (ibuf);
694 if (lf && c != '\n') {
695 if (c != ' ' && c != '\t') {
714 if (c && p1 < &linebuf[LBSIZE - 1])
724 if (advance (p1, p2))
732 if (*p1 == c || cc[(unsigned char)*p1] == c)
733 if (advance (p1, p2))
740 if (advance (p1, p2))
748 advance (char *alp, char *aep)
750 register unsigned char *lp, *ep, *curlp;
752 lp = (unsigned char *)alp;
753 ep = (unsigned char *)aep;
757 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
775 if (cclass (ep, *lp++, 1)) {
782 if (cclass (ep, *lp++, 0)) {
796 while (*lp++ == *ep || cc[lp[-1]] == *ep)
804 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
812 if (advance (lp, ep))
814 } while (lp > curlp);
818 admonish (NULL, "advance() botch -- you lose big");
825 cclass (unsigned char *aset, int ac, int af)
827 register unsigned int n;
828 register unsigned char c, *set;
836 if (*set++ == c || set[-1] == cc[c])
844 tcompile (char *ap, struct tws *tb, int isafter)
846 register struct tws *tw;
848 if ((tw = tws_parse (ap, isafter)) == NULL)
857 tws_parse (char *ap, int isafter)
860 register struct tws *tw, *ts;
862 if ((tw = tws_special (ap)) != NULL) {
863 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
864 tw->tw_hour = isafter ? 23 : 0;
867 if ((tw = dparsetime (ap)) != NULL)
870 if ((ts = dlocaltimenow ()) == NULL)
873 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
874 if ((tw = dparsetime (buffer)) != NULL)
877 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
878 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
879 if ((tw = dparsetime (buffer)) != NULL)
882 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
883 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
884 if ((tw = dparsetime (buffer)) != NULL)
887 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
888 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
890 if ((tw = dparsetime (buffer)) != NULL)
898 tws_special (char *ap)
902 register struct tws *tw;
905 if (!mh_strcasecmp (ap, "today"))
906 return dlocaltime (&clock);
907 if (!mh_strcasecmp (ap, "yesterday")) {
908 clock -= (long) (60 * 60 * 24);
909 return dlocaltime (&clock);
911 if (!mh_strcasecmp (ap, "tomorrow")) {
912 clock += (long) (60 * 60 * 24);
913 return dlocaltime (&clock);
916 for (i = 0; tw_ldotw[i]; i++)
917 if (!mh_strcasecmp (ap, tw_ldotw[i]))
920 if ((tw = dlocaltime (&clock)) == NULL)
922 if ((i -= tw->tw_wday) > 0)
928 else /* -ddd days ago */
929 i = atoi (ap); /* we should error check this */
931 clock += (long) ((60 * 60 * 24) * i);
932 return dlocaltime (&clock);
942 char buf[BUFSIZ], name[NAMESZ];
943 register struct tws *tw;
945 fseek (fp, start, SEEK_SET);
946 for (state = FLD, bp = NULL;;) {
947 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
952 free (bp), bp = NULL;
953 bp = add (buf, NULL);
954 while (state == FLDPLUS) {
955 state = m_getfld (state, name, buf, sizeof buf, fp);
958 if (!mh_strcasecmp (name, n->n_datef))
968 if (state == LENERR || state == FMTERR)
969 advise (NULL, "format error in message %d", msgnum);
975 adios (NULL, "internal error -- you lose");
980 if ((tw = dparsetime (bp)) == NULL)
981 advise (NULL, "unable to parse %s field in message %d, matching...",
982 n->n_datef, msgnum), state = 1;
984 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
985 : (twsort (tw, &n->n_tws) < 0);