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",
418 n = newnexus(GREPaction);
420 snprintf(buffer, sizeof(buffer), "^%s[ \t]*:.*%s",
426 n = newnexus(GREPaction);
428 if (!(cp = nxtarg())) { /* allow -xyz arguments */
429 padvise(NULL, "missing argument to %s",
435 if (!gcompile(n, dp)) {
436 padvise(NULL, "pattern error in %s %s",
440 n->n_patbuf = getcpy(dp);
444 padvise(NULL, "internal error!");
448 if (!(datesw = nxtarg()) || *datesw == '-') {
449 padvise(NULL, "missing argument to %s",
457 if (!(cp = nxtarg())) { /* allow -xyz arguments */
458 padvise(NULL, "missing argument to %s",
462 n = newnexus(TWSaction);
464 if (!tcompile(cp, &n->n_tws, n->n_after =
466 padvise(NULL, "unable to parse %s %s",
475 static struct nexus *
476 newnexus(int (*action)())
478 register struct nexus *p;
480 if ((p = (struct nexus *) calloc((size_t) 1, sizeof *p)) == NULL)
481 adios(NULL, "unable to allocate component storage");
483 p->n_action = action;
488 #define args(a) a, fp, msgnum, start, stop
489 #define params args(n)
491 register struct nexus *n; \
498 pmatches(FILE *fp, int msgnum, long start, long stop)
503 if (!talked++ && pdebug)
506 return (*head->n_action) (args(head));
511 PRaction(struct nexus *n, int level)
515 for (i = 0; i < level; i++)
516 fprintf(stderr, "| ");
518 if (n->n_action == ORaction) {
519 fprintf(stderr, "OR\n");
520 PRaction(n->n_L_child, level + 1);
521 PRaction(n->n_R_child, level + 1);
524 if (n->n_action == ANDaction) {
525 fprintf(stderr, "AND\n");
526 PRaction(n->n_L_child, level + 1);
527 PRaction(n->n_R_child, level + 1);
530 if (n->n_action == NOTaction) {
531 fprintf(stderr, "NOT\n");
532 PRaction(n->n_L_child, level + 1);
535 if (n->n_action == GREPaction) {
536 fprintf(stderr, "PATTERN(%s) %s\n",
537 n->n_header ? "header" : "body", n->n_patbuf);
540 if (n->n_action == TWSaction) {
541 fprintf(stderr, "TEMPORAL(%s) %s: %s\n",
542 n->n_after ? "after" : "before", n->n_datef,
543 dasctime(&n->n_tws, TW_NULL));
546 fprintf(stderr, "UNKNOWN(0x%x)\n",
547 (unsigned int)(unsigned long) (*n->n_action));
555 if ((*n->n_L_child->n_action) (args(n->n_L_child)))
557 return (*n->n_R_child->n_action) (args(n->n_R_child));
565 if (!(*n->n_L_child->n_action) (args(n->n_L_child)))
567 return (*n->n_R_child->n_action) (args(n->n_R_child));
575 return (!(*n->n_L_child->n_action) (args(n->n_L_child)));
580 gcompile(struct nexus *n, char *astr)
584 register unsigned char *ep, *dp, *sp, *lastep = 0;
586 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
597 if ((c = *sp++) != '*')
624 if ((c = *sp++) == '^') {
634 if (c == '-' && *sp != '\0' && *sp != ']') {
635 for (c = ep[-1]+1; c < *sp; c++) {
638 if (c == '\0' || ep >= dp)
644 if (c == '\0' || ep >= dp)
647 } while ((c = *sp++) != ']');
654 if ((c = *sp++) == '\0')
674 register char *p1, *p2, *ebp, *cbp;
677 fseek(fp, start, SEEK_SET);
681 if (body && n->n_header)
688 if (fgets(ibuf, sizeof ibuf, fp) == NULL
689 || (stop && pos >= stop)) {
694 pos += (long) strlen(ibuf);
696 ebp = ibuf + strlen(ibuf);
699 if (lf && c != '\n') {
700 if (c != ' ' && c != '\t') {
719 if (c && p1 < &linebuf[LBSIZE - 1])
737 if (*p1 == c || cc[(unsigned char)*p1] == c)
753 advance(char *alp, char *aep)
755 register unsigned char *lp, *ep, *curlp;
757 lp = (unsigned char *)alp;
758 ep = (unsigned char *)aep;
762 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
780 if (cclass(ep, *lp++, 1)) {
787 if (cclass(ep, *lp++, 0)) {
801 while (*lp++ == *ep || cc[lp[-1]] == *ep)
809 while (cclass(ep, *lp++, ep[-1] == (CCL | STAR)))
819 } while (lp > curlp);
823 admonish(NULL, "advance() botch -- you lose big");
830 cclass(unsigned char *aset, int ac, int af)
832 register unsigned int n;
833 register unsigned char c, *set;
841 if (*set++ == c || set[-1] == cc[c])
849 tcompile(char *ap, struct tws *tb, int isafter)
851 register struct tws *tw;
853 if ((tw = tws_parse(ap, isafter)) == NULL)
862 tws_parse(char *ap, int isafter)
865 register struct tws *tw, *ts;
867 if ((tw = tws_special(ap)) != NULL) {
868 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
869 tw->tw_hour = isafter ? 23 : 0;
872 if ((tw = dparsetime(ap)) != NULL)
875 if ((ts = dlocaltimenow()) == NULL)
878 snprintf(buffer, sizeof(buffer), "%s %s", ap, dtwszone(ts));
879 if ((tw = dparsetime(buffer)) != NULL)
882 snprintf(buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
883 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone(ts));
884 if ((tw = dparsetime(buffer)) != NULL)
887 snprintf(buffer, sizeof(buffer), "%02d %s %04d %s",
888 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
889 if ((tw = dparsetime(buffer)) != NULL)
892 snprintf(buffer, sizeof(buffer), "%02d %s %04d %s %s",
893 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
895 if ((tw = dparsetime(buffer)) != NULL)
903 tws_special(char *ap)
907 register struct tws *tw;
910 if (!mh_strcasecmp(ap, "today"))
911 return dlocaltime(&clock);
912 if (!mh_strcasecmp(ap, "yesterday")) {
913 clock -= (long) (60 * 60 * 24);
914 return dlocaltime(&clock);
916 if (!mh_strcasecmp(ap, "tomorrow")) {
917 clock += (long) (60 * 60 * 24);
918 return dlocaltime(&clock);
921 for (i = 0; tw_ldotw[i]; i++)
922 if (!mh_strcasecmp(ap, tw_ldotw[i]))
925 if ((tw = dlocaltime(&clock)) == NULL)
927 if ((i -= tw->tw_wday) > 0)
933 else /* -ddd days ago */
934 i = atoi(ap); /* we should error check this */
936 clock += (long) ((60 * 60 * 24) * i);
937 return dlocaltime(&clock);
947 char buf[BUFSIZ], name[NAMESZ];
948 register struct tws *tw;
950 fseek(fp, start, SEEK_SET);
951 for (state = FLD, bp = NULL;;) {
952 switch (state = m_getfld(state, name, buf, sizeof buf, fp)) {
959 while (state == FLDPLUS) {
960 state = m_getfld(state, name, buf,
964 if (!mh_strcasecmp(name, n->n_datef))
974 if (state == LENERR || state == FMTERR)
975 advise(NULL, "format error in message %d", msgnum);
981 adios(NULL, "internal error -- you lose");
986 if ((tw = dparsetime(bp)) == NULL)
987 advise(NULL, "unable to parse %s field in message %d, matching...",
988 n->n_datef, msgnum), state = 1;
990 state = n->n_after ? (twsort(tw, &n->n_tws) > 0)
991 : (twsort(tw, &n->n_tws) < 0);