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", argp[-2]);
417 n = newnexus(GREPaction);
419 snprintf(buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
424 n = newnexus(GREPaction);
426 if (!(cp = nxtarg())) { /* allow -xyz arguments */
427 padvise(NULL, "missing argument to %s", argp[-2]);
432 if (!gcompile(n, dp)) {
433 padvise(NULL, "pattern error in %s %s", argp[-2], cp);
436 n->n_patbuf = getcpy(dp);
440 padvise(NULL, "internal error!");
444 if (!(datesw = nxtarg()) || *datesw == '-') {
445 padvise(NULL, "missing argument to %s",
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])
730 if (*p1 == c || cc[(unsigned char)*p1] == c)
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)))
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)) {
952 while (state == FLDPLUS) {
953 state = m_getfld(state, name, buf,
957 if (!mh_strcasecmp(name, n->n_datef))
967 if (state == LENERR || state == FMTERR)
968 advise(NULL, "format error in message %d", msgnum);
974 adios(NULL, "internal error -- you lose");
979 if ((tw = dparsetime(bp)) == NULL)
980 advise(NULL, "unable to parse %s field in message %d, matching...",
981 n->n_datef, msgnum), state = 1;
983 state = n->n_after ? (twsort(tw, &n->n_tws) > 0)
984 : (twsort(tw, &n->n_tws) < 0);