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 = i == PRAFTR)) {
465 padvise (NULL, "unable to parse %s %s",
474 static struct nexus *
475 newnexus (int (*action)())
477 register struct nexus *p;
479 if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
480 adios (NULL, "unable to allocate component storage");
482 p->n_action = action;
487 #define args(a) a, fp, msgnum, start, stop
488 #define params args (n)
490 register struct nexus *n; \
497 pmatches (FILE *fp, int msgnum, long start, long stop)
502 if (!talked++ && pdebug)
505 return (*head->n_action) (args (head));
510 PRaction (struct nexus *n, int level)
514 for (i = 0; i < level; i++)
515 fprintf (stderr, "| ");
517 if (n->n_action == ORaction) {
518 fprintf (stderr, "OR\n");
519 PRaction (n->n_L_child, level + 1);
520 PRaction (n->n_R_child, level + 1);
523 if (n->n_action == ANDaction) {
524 fprintf (stderr, "AND\n");
525 PRaction (n->n_L_child, level + 1);
526 PRaction (n->n_R_child, level + 1);
529 if (n->n_action == NOTaction) {
530 fprintf (stderr, "NOT\n");
531 PRaction (n->n_L_child, level + 1);
534 if (n->n_action == GREPaction) {
535 fprintf (stderr, "PATTERN(%s) %s\n",
536 n->n_header ? "header" : "body", n->n_patbuf);
539 if (n->n_action == TWSaction) {
540 fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
541 n->n_after ? "after" : "before", n->n_datef,
542 dasctime (&n->n_tws, TW_NULL));
545 fprintf (stderr, "UNKNOWN(0x%x)\n",
546 (unsigned int)(unsigned long) (*n->n_action));
554 if ((*n->n_L_child->n_action) (args (n->n_L_child)))
556 return (*n->n_R_child->n_action) (args (n->n_R_child));
564 if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
566 return (*n->n_R_child->n_action) (args (n->n_R_child));
574 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
579 gcompile (struct nexus *n, char *astr)
583 register unsigned char *ep, *dp, *sp, *lastep = 0;
585 dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
596 if ((c = *sp++) != '*')
623 if ((c = *sp++) == '^') {
633 if (c == '-' && *sp != '\0' && *sp != ']') {
634 for (c = ep[-1]+1; c < *sp; c++) {
637 if (c == '\0' || ep >= dp)
643 if (c == '\0' || ep >= dp)
646 } while ((c = *sp++) != ']');
653 if ((c = *sp++) == '\0')
673 register char *p1, *p2, *ebp, *cbp;
676 fseek (fp, start, SEEK_SET);
680 if (body && n->n_header)
687 if (fgets (ibuf, sizeof ibuf, fp) == NULL
688 || (stop && pos >= stop)) {
693 pos += (long) strlen (ibuf);
695 ebp = ibuf + strlen (ibuf);
698 if (lf && c != '\n') {
699 if (c != ' ' && c != '\t') {
718 if (c && p1 < &linebuf[LBSIZE - 1])
728 if (advance (p1, p2))
736 if (*p1 == c || cc[(unsigned char)*p1] == c)
737 if (advance (p1, p2))
744 if (advance (p1, p2))
752 advance (char *alp, char *aep)
754 register unsigned char *lp, *ep, *curlp;
756 lp = (unsigned char *)alp;
757 ep = (unsigned char *)aep;
761 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
779 if (cclass (ep, *lp++, 1)) {
786 if (cclass (ep, *lp++, 0)) {
800 while (*lp++ == *ep || cc[lp[-1]] == *ep)
808 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
816 if (advance (lp, ep))
818 } while (lp > curlp);
822 admonish (NULL, "advance() botch -- you lose big");
829 cclass (unsigned char *aset, int ac, int af)
831 register unsigned int n;
832 register unsigned char c, *set;
840 if (*set++ == c || set[-1] == cc[c])
848 tcompile (char *ap, struct tws *tb, int isafter)
850 register struct tws *tw;
852 if ((tw = tws_parse (ap, isafter)) == NULL)
861 tws_parse (char *ap, int isafter)
864 register struct tws *tw, *ts;
866 if ((tw = tws_special (ap)) != NULL) {
867 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
868 tw->tw_hour = isafter ? 23 : 0;
871 if ((tw = dparsetime (ap)) != NULL)
874 if ((ts = dlocaltimenow ()) == NULL)
877 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
878 if ((tw = dparsetime (buffer)) != NULL)
881 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
882 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
883 if ((tw = dparsetime (buffer)) != NULL)
886 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
887 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
888 if ((tw = dparsetime (buffer)) != NULL)
891 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
892 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
894 if ((tw = dparsetime (buffer)) != NULL)
902 tws_special (char *ap)
906 register struct tws *tw;
909 if (!mh_strcasecmp (ap, "today"))
910 return dlocaltime (&clock);
911 if (!mh_strcasecmp (ap, "yesterday")) {
912 clock -= (long) (60 * 60 * 24);
913 return dlocaltime (&clock);
915 if (!mh_strcasecmp (ap, "tomorrow")) {
916 clock += (long) (60 * 60 * 24);
917 return dlocaltime (&clock);
920 for (i = 0; tw_ldotw[i]; i++)
921 if (!mh_strcasecmp (ap, tw_ldotw[i]))
924 if ((tw = dlocaltime (&clock)) == NULL)
926 if ((i -= tw->tw_wday) > 0)
932 else /* -ddd days ago */
933 i = atoi (ap); /* we should error check this */
935 clock += (long) ((60 * 60 * 24) * i);
936 return dlocaltime (&clock);
946 char buf[BUFSIZ], name[NAMESZ];
947 register struct tws *tw;
949 fseek (fp, start, SEEK_SET);
950 for (state = FLD, bp = NULL;;) {
951 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
956 free (bp), bp = NULL;
957 bp = add (buf, NULL);
958 while (state == FLDPLUS) {
959 state = m_getfld (state, name, buf,
963 if (!mh_strcasecmp (name, n->n_datef))
973 if (state == LENERR || state == FMTERR)
974 advise (NULL, "format error in message %d", msgnum);
980 adios (NULL, "internal error -- you lose");
985 if ((tw = dparsetime (bp)) == NULL)
986 advise (NULL, "unable to parse %s field in message %d, matching...",
987 n->n_datef, msgnum), state = 1;
989 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
990 : (twsort (tw, &n->n_tws) < 0);