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 HAVE_SYS_TIME_H
16 # include <sys/time.h>
20 static struct swit parswit[] = {
34 { "date pattern", 0 },
36 { "from pattern", 0 },
38 { "search pattern", 0 },
40 { "subject pattern", 0 },
44 { "-othercomponent pattern", 15 },
50 { "datefield field", 5 },
54 /* DEFINITIONS FOR PATTERN MATCHING */
57 * We really should be using re_comp() and re_exec() here. Unfortunately,
58 * pick advertises that lowercase characters matches characters of both
59 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
60 * with this version. Furthermore, we need to be able to save and restore
61 * the state of the pattern matcher in order to do things "efficiently".
63 * The matching power of this algorithm isn't as powerful as the re_xxx()
64 * routines (no \(xxx\) and \n constructs). Such is life.
80 static char linebuf[LBSIZE + 1];
81 static char decoded_linebuf[LBSIZE + 1];
83 /* the magic array for case-independence */
84 static unsigned char cc[] = {
85 0000,0001,0002,0003,0004,0005,0006,0007,
86 0010,0011,0012,0013,0014,0015,0016,0017,
87 0020,0021,0022,0023,0024,0025,0026,0027,
88 0030,0031,0032,0033,0034,0035,0036,0037,
89 0040,0041,0042,0043,0044,0045,0046,0047,
90 0050,0051,0052,0053,0054,0055,0056,0057,
91 0060,0061,0062,0063,0064,0065,0066,0067,
92 0070,0071,0072,0073,0074,0075,0076,0077,
93 0100,0141,0142,0143,0144,0145,0146,0147,
94 0150,0151,0152,0153,0154,0155,0156,0157,
95 0160,0161,0162,0163,0164,0165,0166,0167,
96 0170,0171,0172,0133,0134,0135,0136,0137,
97 0140,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,0173,0174,0175,0176,0177,
102 0200,0201,0202,0203,0204,0205,0206,0207,
103 0210,0211,0212,0213,0214,0215,0216,0217,
104 0220,0221,0222,0223,0224,0225,0226,0227,
105 0230,0231,0232,0233,0234,0235,0236,0237,
106 0240,0241,0242,0243,0244,0245,0246,0247,
107 0250,0251,0252,0253,0254,0255,0256,0257,
108 0260,0261,0262,0263,0264,0265,0266,0267,
109 0270,0271,0272,0273,0274,0275,0276,0277,
110 0300,0301,0302,0303,0304,0305,0306,0307,
111 0310,0311,0312,0313,0314,0315,0316,0317,
112 0320,0321,0322,0323,0324,0325,0326,0327,
113 0330,0331,0332,0333,0334,0335,0336,0337,
114 0340,0341,0342,0343,0344,0345,0346,0347,
115 0350,0351,0352,0353,0354,0355,0356,0357,
116 0360,0361,0362,0363,0364,0365,0366,0367,
117 0370,0371,0372,0373,0374,0375,0376,0377,
121 * DEFINITIONS FOR NEXUS
124 #define nxtarg() (*argp ? *argp++ : NULL)
125 #define prvarg() argp--
127 #define padvise if (!talked++) advise
133 /* for {OR,AND,NOT}action */
135 struct nexus *un_L_child;
136 struct nexus *un_R_child;
143 char un_expbuf[ESIZE];
156 #define n_L_child un.st1.un_L_child
157 #define n_R_child un.st1.un_R_child
159 #define n_header un.st2.un_header
160 #define n_circf un.st2.un_circf
161 #define n_expbuf un.st2.un_expbuf
162 #define n_patbuf un.st2.un_patbuf
164 #define n_datef un.st3.un_datef
165 #define n_after un.st3.un_after
166 #define n_tws un.st3.un_tws
169 static int pdebug = 0;
174 static struct nexus *head;
177 * prototypes for date routines
179 static struct tws *tws_parse(char *, int);
180 static struct tws *tws_special(char *);
185 static void PRaction(struct nexus *, int);
186 static int gcompile(struct nexus *, char *);
187 static int advance(char *, char *);
188 static int cclass(unsigned char *, int, int);
189 static int tcompile(char *, struct tws *, int);
191 static struct nexus *parse(void);
192 static struct nexus *nexp1(void);
193 static struct nexus *nexp2(void);
194 static struct nexus *nexp3(void);
195 static struct nexus *newnexus(int (*)());
197 static int ORaction();
198 static int ANDaction();
199 static int NOTaction();
200 static int GREPaction();
201 static int TWSaction();
205 pcompile (char **vec, char *date)
209 if ((cp = getenv ("MHPDEBUG")) && *cp)
213 if ((datesw = date) == NULL)
217 if ((head = parse ()) == NULL)
218 return (talked ? 0 : 1);
221 padvise (NULL, "%s unexpected", *argp);
229 static struct nexus *
233 register struct nexus *n, *o;
235 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
239 padvise (NULL, "%s unexpected", cp);
245 switch (smatch (cp, parswit)) {
247 ambigsw (cp, parswit);
251 fprintf (stderr, "-%s unknown\n", cp);
256 o = newnexus (ORaction);
258 if ((o->n_R_child = parse ()))
260 padvise (NULL, "missing disjunctive");
270 static struct nexus *
274 register struct nexus *n, *o;
276 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
280 padvise (NULL, "%s unexpected", cp);
286 switch (smatch (cp, parswit)) {
288 ambigsw (cp, parswit);
292 fprintf (stderr, "-%s unknown\n", cp);
297 o = newnexus (ANDaction);
299 if ((o->n_R_child = nexp1 ()))
301 padvise (NULL, "missing conjunctive");
312 static struct nexus *
316 register struct nexus *n;
318 if ((cp = nxtarg ()) == NULL)
328 switch (smatch (cp, parswit)) {
330 ambigsw (cp, parswit);
334 fprintf (stderr, "-%s unknown\n", cp);
339 n = newnexus (NOTaction);
340 if ((n->n_L_child = nexp3 ()))
342 padvise (NULL, "missing negation");
352 static struct nexus *
356 register char *cp, *dp;
357 char buffer[BUFSIZ], temp[64];
358 register struct nexus *n;
360 if ((cp = nxtarg ()) == NULL)
364 padvise (NULL, "%s unexpected", cp);
372 switch (i = smatch (cp, parswit)) {
374 ambigsw (cp, parswit);
378 fprintf (stderr, "-%s unknown\n", cp);
383 if ((n = parse ()) == NULL) {
384 padvise (NULL, "missing group");
387 if ((cp = nxtarg ()) == NULL) {
388 padvise (NULL, "missing -rbrace");
391 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
393 padvise (NULL, "%s unexpected", --cp);
405 strncpy(temp, parswit[i].sw, sizeof(temp));
406 temp[sizeof(temp) - 1] = '\0';
407 dp = *brkstring (temp, " ", NULL);
409 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
410 padvise (NULL, "missing argument to %s", argp[-2]);
413 n = newnexus (GREPaction);
415 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
420 n = newnexus (GREPaction);
422 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
423 padvise (NULL, "missing argument to %s", argp[-2]);
428 if (!gcompile (n, dp)) {
429 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
432 n->n_patbuf = getcpy (dp);
436 padvise (NULL, "internal error!");
440 if (!(datesw = nxtarg ()) || *datesw == '-') {
441 padvise (NULL, "missing argument to %s", argp[-2]);
448 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
449 padvise (NULL, "missing argument to %s", argp[-2]);
452 n = newnexus (TWSaction);
454 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
455 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
463 static struct nexus *
464 newnexus (int (*action)())
466 register struct nexus *p;
468 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
469 adios (NULL, "unable to allocate component storage");
471 p->n_action = action;
476 #define args(a) a, fp, msgnum, start, stop
477 #define params args (n)
479 register struct nexus *n; \
486 pmatches (FILE *fp, int msgnum, long start, long stop)
491 if (!talked++ && pdebug)
494 return (*head->n_action) (args (head));
499 PRaction (struct nexus *n, int level)
503 for (i = 0; i < level; i++)
504 fprintf (stderr, "| ");
506 if (n->n_action == ORaction) {
507 fprintf (stderr, "OR\n");
508 PRaction (n->n_L_child, level + 1);
509 PRaction (n->n_R_child, level + 1);
512 if (n->n_action == ANDaction) {
513 fprintf (stderr, "AND\n");
514 PRaction (n->n_L_child, level + 1);
515 PRaction (n->n_R_child, level + 1);
518 if (n->n_action == NOTaction) {
519 fprintf (stderr, "NOT\n");
520 PRaction (n->n_L_child, level + 1);
523 if (n->n_action == GREPaction) {
524 fprintf (stderr, "PATTERN(%s) %s\n",
525 n->n_header ? "header" : "body", n->n_patbuf);
528 if (n->n_action == TWSaction) {
529 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
530 n->n_after ? "after" : "before", n->n_datef,
531 dasctime (&n->n_tws, TW_NULL));
534 fprintf (stderr, "UNKNOWN(0x%x)\n",
535 (unsigned int)(unsigned long) (*n->n_action));
543 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
545 return (*n->n_R_child->n_action) (args (n->n_R_child));
553 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
555 return (*n->n_R_child->n_action) (args (n->n_R_child));
563 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
568 gcompile (struct nexus *n, char *astr)
572 register unsigned char *ep, *dp, *sp, *lastep = 0;
574 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
585 if ((c = *sp++) != '*')
612 if ((c = *sp++) == '^') {
622 if (c == '-' && *sp != '\0' && *sp != ']') {
623 for (c = ep[-1]+1; c < *sp; c++) {
626 if (c == '\0' || ep >= dp)
632 if (c == '\0' || ep >= dp)
635 } while ((c = *sp++) != ']');
642 if ((c = *sp++) == '\0')
662 register char *p1, *p2, *ebp, *cbp;
666 fseek (fp, start, SEEK_SET);
670 if (body && n->n_header)
677 if (fgets (ibuf, sizeof ibuf, fp) == NULL
678 || (stop && pos >= stop)) {
683 pos += (long) strlen (ibuf);
685 ebp = ibuf + strlen (ibuf);
688 if (lf && c != '\n') {
689 if (c != ' ' && c != '\t') {
705 /* Unfold by skipping the newline. */
709 if (c && p1 < &linebuf[LBSIZE - 1])
718 /* Attempt to decode as a MIME header. If it's the last header,
719 body will be 1 and lf will be at least 1. */
720 if ((body == 0 || lf > 0) &&
721 decode_rfc2047 (linebuf, decoded_linebuf, sizeof decoded_linebuf)) {
722 p1 = decoded_linebuf;
726 if (advance (p1, p2))
734 if (*p1 == c || cc[(unsigned char)*p1] == c)
735 if (advance (p1, p2))
742 if (advance (p1, p2))
750 advance (char *alp, char *aep)
752 register unsigned char *lp, *ep, *curlp;
754 lp = (unsigned char *)alp;
755 ep = (unsigned char *)aep;
759 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
777 if (cclass (ep, *lp++, 1)) {
784 if (cclass (ep, *lp++, 0)) {
798 while (*lp++ == *ep || cc[lp[-1]] == *ep)
806 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
814 if (advance (lp, ep))
816 } while (lp > curlp);
820 admonish (NULL, "advance() botch -- you lose big");
827 cclass (unsigned char *aset, int ac, int af)
829 register unsigned int n;
830 register unsigned char c, *set;
838 if (*set++ == c || set[-1] == cc[c])
846 tcompile (char *ap, struct tws *tb, int isafter)
848 register struct tws *tw;
850 if ((tw = tws_parse (ap, isafter)) == NULL)
859 tws_parse (char *ap, int isafter)
862 register struct tws *tw, *ts;
864 if ((tw = tws_special (ap)) != NULL) {
865 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
866 tw->tw_hour = isafter ? 23 : 0;
869 if ((tw = dparsetime (ap)) != NULL)
872 if ((ts = dlocaltimenow ()) == NULL)
875 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
876 if ((tw = dparsetime (buffer)) != NULL)
879 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
880 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
881 if ((tw = dparsetime (buffer)) != NULL)
884 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
885 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
886 if ((tw = dparsetime (buffer)) != NULL)
889 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
890 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
892 if ((tw = dparsetime (buffer)) != NULL)
900 tws_special (char *ap)
904 register struct tws *tw;
907 if (!mh_strcasecmp (ap, "today"))
908 return dlocaltime (&clock);
909 if (!mh_strcasecmp (ap, "yesterday")) {
910 clock -= (long) (60 * 60 * 24);
911 return dlocaltime (&clock);
913 if (!mh_strcasecmp (ap, "tomorrow")) {
914 clock += (long) (60 * 60 * 24);
915 return dlocaltime (&clock);
918 for (i = 0; tw_ldotw[i]; i++)
919 if (!mh_strcasecmp (ap, tw_ldotw[i]))
922 if ((tw = dlocaltime (&clock)) == NULL)
924 if ((i -= tw->tw_wday) > 0)
930 else /* -ddd days ago */
931 i = atoi (ap); /* we should error check this */
933 clock += (long) ((60 * 60 * 24) * i);
934 return dlocaltime (&clock);
944 char buf[BUFSIZ], name[NAMESZ];
945 register struct tws *tw;
948 fseek (fp, start, SEEK_SET);
949 for (state = FLD, bp = NULL;;) {
950 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
955 free (bp), bp = NULL;
956 bp = add (buf, NULL);
957 while (state == FLDPLUS) {
958 state = m_getfld (state, name, buf, sizeof buf, fp);
961 if (!mh_strcasecmp (name, n->n_datef))
971 if (state == LENERR || state == FMTERR)
972 advise (NULL, "format error in message %d", msgnum);
978 adios (NULL, "internal error -- you lose");
983 if ((tw = dparsetime (bp)) == NULL)
984 advise (NULL, "unable to parse %s field in message %d, matching...",
985 n->n_datef, msgnum), state = 1;
987 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
988 : (twsort (tw, &n->n_tws) < 0);