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];
82 /* the magic array for case-independence */
83 static unsigned char cc[] = {
84 0000,0001,0002,0003,0004,0005,0006,0007,
85 0010,0011,0012,0013,0014,0015,0016,0017,
86 0020,0021,0022,0023,0024,0025,0026,0027,
87 0030,0031,0032,0033,0034,0035,0036,0037,
88 0040,0041,0042,0043,0044,0045,0046,0047,
89 0050,0051,0052,0053,0054,0055,0056,0057,
90 0060,0061,0062,0063,0064,0065,0066,0067,
91 0070,0071,0072,0073,0074,0075,0076,0077,
92 0100,0141,0142,0143,0144,0145,0146,0147,
93 0150,0151,0152,0153,0154,0155,0156,0157,
94 0160,0161,0162,0163,0164,0165,0166,0167,
95 0170,0171,0172,0133,0134,0135,0136,0137,
96 0140,0141,0142,0143,0144,0145,0146,0147,
97 0150,0151,0152,0153,0154,0155,0156,0157,
98 0160,0161,0162,0163,0164,0165,0166,0167,
99 0170,0171,0172,0173,0174,0175,0176,0177,
101 0200,0201,0202,0203,0204,0205,0206,0207,
102 0210,0211,0212,0213,0214,0215,0216,0217,
103 0220,0221,0222,0223,0224,0225,0226,0227,
104 0230,0231,0232,0233,0234,0235,0236,0237,
105 0240,0241,0242,0243,0244,0245,0246,0247,
106 0250,0251,0252,0253,0254,0255,0256,0257,
107 0260,0261,0262,0263,0264,0265,0266,0267,
108 0270,0271,0272,0273,0274,0275,0276,0277,
109 0300,0301,0302,0303,0304,0305,0306,0307,
110 0310,0311,0312,0313,0314,0315,0316,0317,
111 0320,0321,0322,0323,0324,0325,0326,0327,
112 0330,0331,0332,0333,0334,0335,0336,0337,
113 0340,0341,0342,0343,0344,0345,0346,0347,
114 0350,0351,0352,0353,0354,0355,0356,0357,
115 0360,0361,0362,0363,0364,0365,0366,0367,
116 0370,0371,0372,0373,0374,0375,0376,0377,
120 * DEFINITIONS FOR NEXUS
123 #define nxtarg() (*argp ? *argp++ : NULL)
124 #define prvarg() argp--
126 #define padvise if (!talked++) advise
132 /* for {OR,AND,NOT}action */
134 struct nexus *un_L_child;
135 struct nexus *un_R_child;
142 char un_expbuf[ESIZE];
155 #define n_L_child un.st1.un_L_child
156 #define n_R_child un.st1.un_R_child
158 #define n_header un.st2.un_header
159 #define n_circf un.st2.un_circf
160 #define n_expbuf un.st2.un_expbuf
161 #define n_patbuf un.st2.un_patbuf
163 #define n_datef un.st3.un_datef
164 #define n_after un.st3.un_after
165 #define n_tws un.st3.un_tws
168 static int pdebug = 0;
173 static struct nexus *head;
176 * prototypes for date routines
178 static struct tws *tws_parse(char *, int);
179 static struct tws *tws_special(char *);
184 static void PRaction(struct nexus *, int);
185 static int gcompile(struct nexus *, char *);
186 static int advance(char *, char *);
187 static int cclass(unsigned char *, int, int);
188 static int tcompile(char *, struct tws *, int);
190 static struct nexus *parse(void);
191 static struct nexus *nexp1(void);
192 static struct nexus *nexp2(void);
193 static struct nexus *nexp3(void);
194 static struct nexus *newnexus(int (*)());
196 static int ORaction();
197 static int ANDaction();
198 static int NOTaction();
199 static int GREPaction();
200 static int TWSaction();
204 pcompile (char **vec, char *date)
208 if ((cp = getenv ("MHPDEBUG")) && *cp)
212 if ((datesw = date) == NULL)
216 if ((head = parse ()) == NULL)
217 return (talked ? 0 : 1);
220 padvise (NULL, "%s unexpected", *argp);
228 static struct nexus *
232 register struct nexus *n, *o;
234 if ((n = nexp1 ()) == NULL || (cp = nxtarg ()) == NULL)
238 padvise (NULL, "%s unexpected", cp);
244 switch (smatch (cp, parswit)) {
246 ambigsw (cp, parswit);
250 fprintf (stderr, "-%s unknown\n", cp);
255 o = newnexus (ORaction);
257 if ((o->n_R_child = parse ()))
259 padvise (NULL, "missing disjunctive");
269 static struct nexus *
273 register struct nexus *n, *o;
275 if ((n = nexp2 ()) == NULL || (cp = nxtarg ()) == NULL)
279 padvise (NULL, "%s unexpected", cp);
285 switch (smatch (cp, parswit)) {
287 ambigsw (cp, parswit);
291 fprintf (stderr, "-%s unknown\n", cp);
296 o = newnexus (ANDaction);
298 if ((o->n_R_child = nexp1 ()))
300 padvise (NULL, "missing conjunctive");
311 static struct nexus *
315 register struct nexus *n;
317 if ((cp = nxtarg ()) == NULL)
327 switch (smatch (cp, parswit)) {
329 ambigsw (cp, parswit);
333 fprintf (stderr, "-%s unknown\n", cp);
338 n = newnexus (NOTaction);
339 if ((n->n_L_child = nexp3 ()))
341 padvise (NULL, "missing negation");
351 static struct nexus *
355 register char *cp, *dp;
356 char buffer[BUFSIZ], temp[64];
357 register struct nexus *n;
359 if ((cp = nxtarg ()) == NULL)
363 padvise (NULL, "%s unexpected", cp);
371 switch (i = smatch (cp, parswit)) {
373 ambigsw (cp, parswit);
377 fprintf (stderr, "-%s unknown\n", cp);
382 if ((n = parse ()) == NULL) {
383 padvise (NULL, "missing group");
386 if ((cp = nxtarg ()) == NULL) {
387 padvise (NULL, "missing -rbrace");
390 if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
392 padvise (NULL, "%s unexpected", --cp);
404 strncpy(temp, parswit[i].sw, sizeof(temp));
405 temp[sizeof(temp) - 1] = '\0';
406 dp = *brkstring (temp, " ", NULL);
408 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
409 padvise (NULL, "missing argument to %s", argp[-2]);
412 n = newnexus (GREPaction);
414 snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
419 n = newnexus (GREPaction);
421 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
422 padvise (NULL, "missing argument to %s", argp[-2]);
427 if (!gcompile (n, dp)) {
428 padvise (NULL, "pattern error in %s %s", argp[-2], cp);
431 n->n_patbuf = getcpy (dp);
435 padvise (NULL, "internal error!");
439 if (!(datesw = nxtarg ()) || *datesw == '-') {
440 padvise (NULL, "missing argument to %s", argp[-2]);
447 if (!(cp = nxtarg ())) {/* allow -xyz arguments */
448 padvise (NULL, "missing argument to %s", argp[-2]);
451 n = newnexus (TWSaction);
453 if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
454 padvise (NULL, "unable to parse %s %s", argp[-2], cp);
462 static struct nexus *
463 newnexus (int (*action)())
465 register struct nexus *p;
467 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
468 adios (NULL, "unable to allocate component storage");
470 p->n_action = action;
475 #define args(a) a, fp, msgnum, start, stop
476 #define params args (n)
478 register struct nexus *n; \
485 pmatches (FILE *fp, int msgnum, long start, long stop)
490 if (!talked++ && pdebug)
493 return (*head->n_action) (args (head));
498 PRaction (struct nexus *n, int level)
502 for (i = 0; i < level; i++)
503 fprintf (stderr, "| ");
505 if (n->n_action == ORaction) {
506 fprintf (stderr, "OR\n");
507 PRaction (n->n_L_child, level + 1);
508 PRaction (n->n_R_child, level + 1);
511 if (n->n_action == ANDaction) {
512 fprintf (stderr, "AND\n");
513 PRaction (n->n_L_child, level + 1);
514 PRaction (n->n_R_child, level + 1);
517 if (n->n_action == NOTaction) {
518 fprintf (stderr, "NOT\n");
519 PRaction (n->n_L_child, level + 1);
522 if (n->n_action == GREPaction) {
523 fprintf (stderr, "PATTERN(%s) %s\n",
524 n->n_header ? "header" : "body", n->n_patbuf);
527 if (n->n_action == TWSaction) {
528 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
529 n->n_after ? "after" : "before", n->n_datef,
530 dasctime (&n->n_tws, TW_NULL));
533 fprintf (stderr, "UNKNOWN(0x%x)\n",
534 (unsigned int)(unsigned long) (*n->n_action));
542 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
544 return (*n->n_R_child->n_action) (args (n->n_R_child));
552 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
554 return (*n->n_R_child->n_action) (args (n->n_R_child));
562 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
567 gcompile (struct nexus *n, char *astr)
571 register unsigned char *ep, *dp, *sp, *lastep = 0;
573 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
584 if ((c = *sp++) != '*')
611 if ((c = *sp++) == '^') {
621 if (c == '-' && *sp != '\0' && *sp != ']') {
622 for (c = ep[-1]+1; c < *sp; c++) {
625 if (c == '\0' || ep >= dp)
631 if (c == '\0' || ep >= dp)
634 } while ((c = *sp++) != ']');
641 if ((c = *sp++) == '\0')
661 register char *p1, *p2, *ebp, *cbp;
665 fseek (fp, start, SEEK_SET);
669 if (body && n->n_header)
676 if (fgets (ibuf, sizeof ibuf, fp) == NULL
677 || (stop && pos >= stop)) {
682 pos += (long) strlen (ibuf);
684 ebp = ibuf + strlen (ibuf);
687 if (lf && c != '\n') {
688 if (c != ' ' && c != '\t') {
707 if (c && p1 < &linebuf[LBSIZE - 1])
717 if (advance (p1, p2))
725 if (*p1 == c || cc[(unsigned char)*p1] == c)
726 if (advance (p1, p2))
733 if (advance (p1, p2))
741 advance (char *alp, char *aep)
743 register unsigned char *lp, *ep, *curlp;
745 lp = (unsigned char *)alp;
746 ep = (unsigned char *)aep;
750 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
768 if (cclass (ep, *lp++, 1)) {
775 if (cclass (ep, *lp++, 0)) {
789 while (*lp++ == *ep || cc[lp[-1]] == *ep)
797 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
805 if (advance (lp, ep))
807 } while (lp > curlp);
811 admonish (NULL, "advance() botch -- you lose big");
818 cclass (unsigned char *aset, int ac, int af)
820 register unsigned int n;
821 register unsigned char c, *set;
829 if (*set++ == c || set[-1] == cc[c])
837 tcompile (char *ap, struct tws *tb, int isafter)
839 register struct tws *tw;
841 if ((tw = tws_parse (ap, isafter)) == NULL)
850 tws_parse (char *ap, int isafter)
853 register struct tws *tw, *ts;
855 if ((tw = tws_special (ap)) != NULL) {
856 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
857 tw->tw_hour = isafter ? 23 : 0;
860 if ((tw = dparsetime (ap)) != NULL)
863 if ((ts = dlocaltimenow ()) == NULL)
866 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
867 if ((tw = dparsetime (buffer)) != NULL)
870 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
871 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
872 if ((tw = dparsetime (buffer)) != NULL)
875 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
876 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
877 if ((tw = dparsetime (buffer)) != NULL)
880 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
881 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
883 if ((tw = dparsetime (buffer)) != NULL)
891 tws_special (char *ap)
895 register struct tws *tw;
898 if (!mh_strcasecmp (ap, "today"))
899 return dlocaltime (&clock);
900 if (!mh_strcasecmp (ap, "yesterday")) {
901 clock -= (long) (60 * 60 * 24);
902 return dlocaltime (&clock);
904 if (!mh_strcasecmp (ap, "tomorrow")) {
905 clock += (long) (60 * 60 * 24);
906 return dlocaltime (&clock);
909 for (i = 0; tw_ldotw[i]; i++)
910 if (!mh_strcasecmp (ap, tw_ldotw[i]))
913 if ((tw = dlocaltime (&clock)) == NULL)
915 if ((i -= tw->tw_wday) > 0)
921 else /* -ddd days ago */
922 i = atoi (ap); /* we should error check this */
924 clock += (long) ((60 * 60 * 24) * i);
925 return dlocaltime (&clock);
935 char buf[BUFSIZ], name[NAMESZ];
936 register struct tws *tw;
939 fseek (fp, start, SEEK_SET);
940 for (state = FLD, bp = NULL;;) {
941 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
946 free (bp), bp = NULL;
947 bp = add (buf, NULL);
948 while (state == FLDPLUS) {
949 state = m_getfld (state, name, buf, sizeof buf, fp);
952 if (!mh_strcasecmp (name, n->n_datef))
962 if (state == LENERR || state == FMTERR)
963 advise (NULL, "format error in message %d", msgnum);
969 adios (NULL, "internal error -- you lose");
974 if ((tw = dparsetime (bp)) == NULL)
975 advise (NULL, "unable to parse %s field in message %d, matching...",
976 n->n_datef, msgnum), state = 1;
978 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
979 : (twsort (tw, &n->n_tws) < 0);