]>
diplodocus.org Git - nmh/blob - uip/picksbr.c
1 /* picksbr.c -- routines to help pick along...
3 * This code is Copyright (c) 2002, by the authors of nmh. See the
4 * COPYRIGHT file in the root directory of the nmh distribution for
5 * complete copyright information.
9 #include "sbr/smatch.h"
10 #include "sbr/fmt_rfc2047.h"
11 #include "sbr/brkstring.h"
12 #include "sbr/ambigsw.h"
13 #include "sbr/error.h"
15 #include "h/picksbr.h"
18 #ifdef HAVE_SYS_TIME_H
19 # include <sys/time.h>
23 #define PARSE_SWITCHES \
27 X("lbrace", 0, PRLBR) \
28 X("rbrace", 0, PRRBR) \
29 X("cc pattern", 0, PRCC) \
30 X("date pattern", 0, PRDATE) \
31 X("from pattern", 0, PRFROM) \
32 X("search pattern", 0, PRSRCH) \
33 X("subject pattern", 0, PRSUBJ) \
34 X("to pattern", 0, PRTO) \
35 X("-othercomponent pattern", 15, PROTHR) \
36 X("after date", 0, PRAFTR) \
37 X("before date", 0, PRBEFR) \
38 X("datefield field", 5, PRDATF) \
40 #define X(sw, minchars, id) id,
41 DEFINE_SWITCH_ENUM(PARSE
);
44 #define X(sw, minchars, id) { sw, minchars, id },
45 DEFINE_SWITCH_ARRAY(PARSE
, parswit
);
48 /* DEFINITIONS FOR PATTERN MATCHING */
51 * We really should be using re_comp() and re_exec() here. Unfortunately,
52 * pick advertises that lowercase characters matches characters of both
53 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
54 * with this version. Furthermore, we need to be able to save and restore
55 * the state of the pattern matcher in order to do things "efficiently".
57 * The matching power of this algorithm isn't as powerful as the re_xxx()
58 * routines (no \(xxx\) and \n constructs). Such is life.
70 #define LBSIZE NMH_BUFSIZ
74 static char linebuf
[LBSIZE
+ 1];
75 static char decoded_linebuf
[LBSIZE
+ 1];
77 /* the magic array for case-independence */
78 static unsigned char cc
[] = {
79 0000,0001,0002,0003,0004,0005,0006,0007,
80 0010,0011,0012,0013,0014,0015,0016,0017,
81 0020,0021,0022,0023,0024,0025,0026,0027,
82 0030,0031,0032,0033,0034,0035,0036,0037,
83 0040,0041,0042,0043,0044,0045,0046,0047,
84 0050,0051,0052,0053,0054,0055,0056,0057,
85 0060,0061,0062,0063,0064,0065,0066,0067,
86 0070,0071,0072,0073,0074,0075,0076,0077,
87 0100,0141,0142,0143,0144,0145,0146,0147,
88 0150,0151,0152,0153,0154,0155,0156,0157,
89 0160,0161,0162,0163,0164,0165,0166,0167,
90 0170,0171,0172,0133,0134,0135,0136,0137,
91 0140,0141,0142,0143,0144,0145,0146,0147,
92 0150,0151,0152,0153,0154,0155,0156,0157,
93 0160,0161,0162,0163,0164,0165,0166,0167,
94 0170,0171,0172,0173,0174,0175,0176,0177,
96 0200,0201,0202,0203,0204,0205,0206,0207,
97 0210,0211,0212,0213,0214,0215,0216,0217,
98 0220,0221,0222,0223,0224,0225,0226,0227,
99 0230,0231,0232,0233,0234,0235,0236,0237,
100 0240,0241,0242,0243,0244,0245,0246,0247,
101 0250,0251,0252,0253,0254,0255,0256,0257,
102 0260,0261,0262,0263,0264,0265,0266,0267,
103 0270,0271,0272,0273,0274,0275,0276,0277,
104 0300,0301,0302,0303,0304,0305,0306,0307,
105 0310,0311,0312,0313,0314,0315,0316,0317,
106 0320,0321,0322,0323,0324,0325,0326,0327,
107 0330,0331,0332,0333,0334,0335,0336,0337,
108 0340,0341,0342,0343,0344,0345,0346,0347,
109 0350,0351,0352,0353,0354,0355,0356,0357,
110 0360,0361,0362,0363,0364,0365,0366,0367,
111 0370,0371,0372,0373,0374,0375,0376,0377,
115 * DEFINITIONS FOR NEXUS
118 #define nxtarg() (*argp ? *argp++ : NULL)
119 #define prvarg() argp--
121 #define pinform if (!talked++) inform
124 int (*n_action
)(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
);
127 /* for {OR,AND,NOT}action */
129 struct nexus
*un_L_child
;
130 struct nexus
*un_R_child
;
137 char un_expbuf
[ESIZE
];
150 #define n_L_child un.st1.un_L_child
151 #define n_R_child un.st1.un_R_child
153 #define n_header un.st2.un_header
154 #define n_circf un.st2.un_circf
155 #define n_expbuf un.st2.un_expbuf
156 #define n_patbuf un.st2.un_patbuf
158 #define n_datef un.st3.un_datef
159 #define n_after un.st3.un_after
160 #define n_tws un.st3.un_tws
167 static struct nexus
*head
;
170 * prototypes for date routines
172 static struct tws
*tws_parse(char *, int);
173 static struct tws
*tws_special(char *);
178 static void PRaction(struct nexus
*, int);
179 static int gcompile(struct nexus
*, char *);
180 static int advance(char *, char *);
181 static int cclass(unsigned char *, int, int);
182 static int tcompile(char *, struct tws
*, int);
184 static struct nexus
*parse(void);
185 static struct nexus
*nexp1(void);
186 static struct nexus
*nexp2(void);
187 static struct nexus
*nexp3(void);
188 static struct nexus
*newnexus(int (*action
)(struct nexus
*n
,
189 FILE *fp
, int msgnum
, long start
, long stop
));
191 static int ORaction(struct nexus
*n
, FILE *fp
, int msgnum
,
192 long start
, long stop
);
193 static int ANDaction(struct nexus
*n
, FILE *fp
, int msgnum
,
194 long start
, long stop
);
195 static int NOTaction(struct nexus
*n
, FILE *fp
, int msgnum
,
196 long start
, long stop
);
197 static int GREPaction(struct nexus
*n
, FILE *fp
, int msgnum
,
198 long start
, long stop
);
199 static int TWSaction(struct nexus
*n
, FILE *fp
, int msgnum
,
200 long start
, long stop
);
204 pcompile (char **vec
, char *date
)
207 if ((datesw
= date
) == NULL
)
211 if ((head
= parse ()) == NULL
)
215 inform("%s unexpected", *argp
);
223 static struct nexus
*
229 if ((n
= nexp1 ()) == NULL
|| (cp
= nxtarg ()) == NULL
)
233 pinform("%s unexpected", cp
);
239 switch (smatch (cp
, parswit
)) {
241 ambigsw (cp
, parswit
);
245 fprintf (stderr
, "-%s unknown\n", cp
);
250 o
= newnexus (ORaction
);
252 if ((o
->n_R_child
= parse ()))
254 pinform("missing disjunctive");
265 static struct nexus
*
271 if ((n
= nexp2 ()) == NULL
|| (cp
= nxtarg ()) == NULL
)
275 pinform("%s unexpected", cp
);
282 switch (smatch (cp
, parswit
)) {
284 ambigsw (cp
, parswit
);
289 fprintf (stderr
, "-%s unknown\n", cp
);
295 o
= newnexus (ANDaction
);
297 if ((o
->n_R_child
= nexp1 ()))
299 pinform("missing conjunctive");
311 static struct nexus
*
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 pinform("missing negation");
352 static struct nexus
*
357 char buffer
[BUFSIZ
], temp
[64];
360 if ((cp
= nxtarg ()) == NULL
)
364 pinform("%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 pinform("missing group");
387 if ((cp
= nxtarg ()) == NULL
) {
388 pinform("missing -rbrace");
391 if (*cp
++ == '-' && smatch (cp
, parswit
) == PRRBR
)
393 pinform("%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 pinform("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 pinform("missing argument to %s", argp
[-2]);
429 if (!gcompile (n
, dp
)) {
430 pinform("pattern error in %s %s", argp
[-2], cp
);
434 n
->n_patbuf
= mh_xstrdup(dp
);
438 pinform("internal error!");
442 if (!(datesw
= nxtarg ()) || *datesw
== '-') {
443 pinform("missing argument to %s", argp
[-2]);
450 if (!(cp
= nxtarg ())) {/* allow -xyz arguments */
451 pinform("missing argument to %s", argp
[-2]);
454 n
= newnexus (TWSaction
);
456 if (!tcompile (cp
, &n
->n_tws
, n
->n_after
= i
== PRAFTR
)) {
457 pinform("unable to parse %s %s", argp
[-2], cp
);
466 static struct nexus
*
467 newnexus(int (*action
)(struct nexus
*n
, FILE *fp
, int msgnum
,
468 long start
, long stop
))
473 p
->n_action
= action
;
479 pmatches (FILE *fp
, int msgnum
, long start
, long stop
, int debug
)
484 if (!talked
++ && debug
)
487 return (*head
->n_action
)(head
, fp
, msgnum
, start
, stop
);
492 PRaction (struct nexus
*n
, int level
)
496 for (i
= 0; i
< level
; i
++)
497 fprintf (stderr
, "| ");
499 if (n
->n_action
== ORaction
) {
500 fprintf (stderr
, "OR\n");
501 PRaction (n
->n_L_child
, level
+ 1);
502 PRaction (n
->n_R_child
, level
+ 1);
505 if (n
->n_action
== ANDaction
) {
506 fprintf (stderr
, "AND\n");
507 PRaction (n
->n_L_child
, level
+ 1);
508 PRaction (n
->n_R_child
, level
+ 1);
511 if (n
->n_action
== NOTaction
) {
512 fprintf (stderr
, "NOT\n");
513 PRaction (n
->n_L_child
, level
+ 1);
516 if (n
->n_action
== GREPaction
) {
517 fprintf (stderr
, "PATTERN(%s) %s\n",
518 n
->n_header
? "header" : "body", n
->n_patbuf
);
521 if (n
->n_action
== TWSaction
) {
522 fprintf (stderr
, "TEMPORAL(%s) %s: %s\n",
523 n
->n_after
? "after" : "before", n
->n_datef
,
524 dasctime (&n
->n_tws
, TW_NULL
));
529 gp
.f
= (void (*)(void))n
->n_action
;
530 fprintf(stderr
, "UNKNOWN(%p)\n", gp
.v
);
535 ORaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
537 if ((*n
->n_L_child
->n_action
)(n
->n_L_child
, fp
, msgnum
, start
, stop
))
539 return (*n
->n_R_child
->n_action
)(n
->n_R_child
, fp
, msgnum
, start
, stop
);
544 ANDaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
546 if (!(*n
->n_L_child
->n_action
)(n
->n_L_child
, fp
, msgnum
, start
, stop
))
548 return (*n
->n_R_child
->n_action
)(n
->n_R_child
, fp
, msgnum
, start
, stop
);
553 NOTaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
555 return (!(*n
->n_L_child
->n_action
)(n
->n_L_child
, fp
, msgnum
, start
, stop
));
560 gcompile (struct nexus
*n
, char *astr
)
564 unsigned char *ep
, *dp
, *sp
, *lastep
= 0;
566 dp
= (ep
= (unsigned char *) n
->n_expbuf
) + sizeof n
->n_expbuf
;
567 sp
= (unsigned char *) astr
;
577 if ((c
= *sp
++) != '*')
604 if ((c
= *sp
++) == '^') {
614 if (c
== '-' && *sp
!= '\0' && *sp
!= ']') {
615 for (c
= ep
[-1]+1; c
< *sp
; c
++) {
618 if (c
== '\0' || ep
>= dp
)
624 if (c
== '\0' || ep
>= dp
)
627 } while ((c
= *sp
++) != ']');
634 if ((c
= *sp
++) == '\0')
650 GREPaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
656 char *p1
, *p2
, *ebp
, *cbp
;
660 fseek (fp
, start
, SEEK_SET
);
664 if (body
&& n
->n_header
)
671 if (fgets (ibuf
, sizeof ibuf
, fp
) == NULL
672 || (stop
&& pos
>= stop
)) {
677 pos
+= (long) strlen (ibuf
);
679 ebp
= ibuf
+ strlen (ibuf
);
682 if (lf
&& c
!= '\n') {
683 if (c
!= ' ' && c
!= '\t') {
697 /* Unfold by skipping the newline. */
700 if (c
&& p1
< &linebuf
[LBSIZE
- 1])
709 /* Attempt to decode as a MIME header. If it's the last header,
710 body will be 1 and lf will be at least 1. */
712 decode_rfc2047 (linebuf
, decoded_linebuf
, sizeof decoded_linebuf
)) {
713 p1
= decoded_linebuf
;
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 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 ((char *) lp
, (char *) ep
))
807 } while (lp
> curlp
);
811 inform("advance() botch -- you lose big, continuing...");
818 cclass (unsigned char *aset
, int ac
, int af
)
821 unsigned char c
, *set
;
829 if (*set
++ == c
|| set
[-1] == cc
[c
])
837 tcompile (char *ap
, struct tws
*tb
, int isafter
)
841 if ((tw
= tws_parse (ap
, isafter
)) == NULL
)
850 tws_parse (char *ap
, int isafter
)
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
)
898 if (!strcasecmp (ap
, "today"))
899 return dlocaltime (&clock
);
900 if (!strcasecmp (ap
, "yesterday")) {
901 clock
-= (long) (60 * 60 * 24);
902 return dlocaltime (&clock
);
904 if (!strcasecmp (ap
, "tomorrow")) {
905 clock
+= (long) (60 * 60 * 24);
906 return dlocaltime (&clock
);
909 for (i
= 0; tw_ldotw
[i
]; i
++)
910 if (!strcasecmp (ap
, tw_ldotw
[i
]))
913 if ((tw
= dlocaltime (&clock
)) == NULL
)
915 if ((i
-= tw
->tw_wday
) > 0)
922 i
= atoi (ap
); /* we should error check this */
925 clock
+= (long) ((60 * 60 * 24) * i
);
926 return dlocaltime (&clock
);
931 TWSaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
935 char buf
[NMH_BUFSIZ
], name
[NAMESZ
];
937 m_getfld_state_t gstate
;
940 fseek (fp
, start
, SEEK_SET
);
941 gstate
= m_getfld_state_init(fp
);
943 int bufsz
= sizeof buf
;
944 switch (state
= m_getfld2(&gstate
, name
, buf
, &bufsz
)) {
948 bp
= mh_xstrdup(buf
);
949 while (state
== FLDPLUS
) {
951 state
= m_getfld2(&gstate
, name
, buf
, &bufsz
);
954 if (!strcasecmp (name
, n
->n_datef
))
962 if (state
== LENERR
|| state
== FMTERR
)
963 inform("format error in message %d", msgnum
);
968 die("internal error -- you lose");
972 m_getfld_state_destroy (&gstate
);
974 if ((tw
= dparsetime (bp
)) == NULL
)
975 inform("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);