]>
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.
10 #include "sbr/dtime.h"
11 #include "sbr/dtime.h"
12 #include "sbr/m_getfld.h"
13 #include "sbr/smatch.h"
14 #include "sbr/fmt_rfc2047.h"
15 #include "sbr/brkstring.h"
16 #include "sbr/ambigsw.h"
17 #include "sbr/error.h"
21 #ifdef HAVE_SYS_TIME_H
22 # include <sys/time.h>
26 #define PARSE_SWITCHES \
30 X("lbrace", 0, PRLBR) \
31 X("rbrace", 0, PRRBR) \
32 X("cc pattern", 0, PRCC) \
33 X("date pattern", 0, PRDATE) \
34 X("from pattern", 0, PRFROM) \
35 X("search pattern", 0, PRSRCH) \
36 X("subject pattern", 0, PRSUBJ) \
37 X("to pattern", 0, PRTO) \
38 X("-othercomponent pattern", 15, PROTHR) \
39 X("after date", 0, PRAFTR) \
40 X("before date", 0, PRBEFR) \
41 X("datefield field", 5, PRDATF) \
43 #define X(sw, minchars, id) id,
44 DEFINE_SWITCH_ENUM(PARSE
);
47 #define X(sw, minchars, id) { sw, minchars, id },
48 DEFINE_SWITCH_ARRAY(PARSE
, parswit
);
51 /* DEFINITIONS FOR PATTERN MATCHING */
54 * We really should be using re_comp() and re_exec() here. Unfortunately,
55 * pick advertises that lowercase characters matches characters of both
56 * cases. Since re_exec() doesn't exhibit this behavior, we are stuck
57 * with this version. Furthermore, we need to be able to save and restore
58 * the state of the pattern matcher in order to do things "efficiently".
60 * The matching power of this algorithm isn't as powerful as the re_xxx()
61 * routines (no \(xxx\) and \n constructs). Such is life.
73 #define LBSIZE NMH_BUFSIZ
77 static char linebuf
[LBSIZE
+ 1];
78 static char decoded_linebuf
[LBSIZE
+ 1];
80 /* the magic array for case-independence */
81 static unsigned char cc
[] = {
82 0000,0001,0002,0003,0004,0005,0006,0007,
83 0010,0011,0012,0013,0014,0015,0016,0017,
84 0020,0021,0022,0023,0024,0025,0026,0027,
85 0030,0031,0032,0033,0034,0035,0036,0037,
86 0040,0041,0042,0043,0044,0045,0046,0047,
87 0050,0051,0052,0053,0054,0055,0056,0057,
88 0060,0061,0062,0063,0064,0065,0066,0067,
89 0070,0071,0072,0073,0074,0075,0076,0077,
90 0100,0141,0142,0143,0144,0145,0146,0147,
91 0150,0151,0152,0153,0154,0155,0156,0157,
92 0160,0161,0162,0163,0164,0165,0166,0167,
93 0170,0171,0172,0133,0134,0135,0136,0137,
94 0140,0141,0142,0143,0144,0145,0146,0147,
95 0150,0151,0152,0153,0154,0155,0156,0157,
96 0160,0161,0162,0163,0164,0165,0166,0167,
97 0170,0171,0172,0173,0174,0175,0176,0177,
99 0200,0201,0202,0203,0204,0205,0206,0207,
100 0210,0211,0212,0213,0214,0215,0216,0217,
101 0220,0221,0222,0223,0224,0225,0226,0227,
102 0230,0231,0232,0233,0234,0235,0236,0237,
103 0240,0241,0242,0243,0244,0245,0246,0247,
104 0250,0251,0252,0253,0254,0255,0256,0257,
105 0260,0261,0262,0263,0264,0265,0266,0267,
106 0270,0271,0272,0273,0274,0275,0276,0277,
107 0300,0301,0302,0303,0304,0305,0306,0307,
108 0310,0311,0312,0313,0314,0315,0316,0317,
109 0320,0321,0322,0323,0324,0325,0326,0327,
110 0330,0331,0332,0333,0334,0335,0336,0337,
111 0340,0341,0342,0343,0344,0345,0346,0347,
112 0350,0351,0352,0353,0354,0355,0356,0357,
113 0360,0361,0362,0363,0364,0365,0366,0367,
114 0370,0371,0372,0373,0374,0375,0376,0377,
118 * DEFINITIONS FOR NEXUS
121 #define nxtarg() (*argp ? *argp++ : NULL)
122 #define prvarg() argp--
124 #define pinform if (!talked++) inform
127 int (*n_action
)(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
);
130 /* for {OR,AND,NOT}action */
132 struct nexus
*un_L_child
;
133 struct nexus
*un_R_child
;
140 char un_expbuf
[ESIZE
];
153 #define n_L_child un.st1.un_L_child
154 #define n_R_child un.st1.un_R_child
156 #define n_header un.st2.un_header
157 #define n_circf un.st2.un_circf
158 #define n_expbuf un.st2.un_expbuf
159 #define n_patbuf un.st2.un_patbuf
161 #define n_datef un.st3.un_datef
162 #define n_after un.st3.un_after
163 #define n_tws un.st3.un_tws
170 static struct nexus
*head
;
173 * prototypes for date routines
175 static struct tws
*tws_parse(char *, int);
176 static struct tws
*tws_special(char *);
181 static void PRaction(struct nexus
*, int);
182 static int gcompile(struct nexus
*, char *);
183 static int advance(char *, char *);
184 static int cclass(unsigned char *, int, int);
185 static int tcompile(char *, struct tws
*, int);
187 static struct nexus
*parse(void);
188 static struct nexus
*nexp1(void);
189 static struct nexus
*nexp2(void);
190 static struct nexus
*nexp3(void);
191 static struct nexus
*newnexus(int (*action
)(struct nexus
*n
,
192 FILE *fp
, int msgnum
, long start
, long stop
));
194 static int ORaction(struct nexus
*n
, FILE *fp
, int msgnum
,
195 long start
, long stop
);
196 static int ANDaction(struct nexus
*n
, FILE *fp
, int msgnum
,
197 long start
, long stop
);
198 static int NOTaction(struct nexus
*n
, FILE *fp
, int msgnum
,
199 long start
, long stop
);
200 static int GREPaction(struct nexus
*n
, FILE *fp
, int msgnum
,
201 long start
, long stop
);
202 static int TWSaction(struct nexus
*n
, FILE *fp
, int msgnum
,
203 long start
, long stop
);
207 pcompile (char **vec
, char *date
)
210 if ((datesw
= date
) == NULL
)
214 if ((head
= parse ()) == NULL
)
218 inform("%s unexpected", *argp
);
226 static struct nexus
*
232 if ((n
= nexp1 ()) == NULL
|| (cp
= nxtarg ()) == NULL
)
236 pinform("%s unexpected", cp
);
242 switch (smatch (cp
, parswit
)) {
244 ambigsw (cp
, parswit
);
248 fprintf (stderr
, "-%s unknown\n", cp
);
253 o
= newnexus (ORaction
);
255 if ((o
->n_R_child
= parse ()))
257 pinform("missing disjunctive");
268 static struct nexus
*
274 if ((n
= nexp2 ()) == NULL
|| (cp
= nxtarg ()) == NULL
)
278 pinform("%s unexpected", cp
);
285 switch (smatch (cp
, parswit
)) {
287 ambigsw (cp
, parswit
);
292 fprintf (stderr
, "-%s unknown\n", cp
);
298 o
= newnexus (ANDaction
);
300 if ((o
->n_R_child
= nexp1 ()))
302 pinform("missing conjunctive");
314 static struct nexus
*
320 if ((cp
= nxtarg ()) == NULL
)
330 switch (smatch (cp
, parswit
)) {
332 ambigsw (cp
, parswit
);
336 fprintf (stderr
, "-%s unknown\n", cp
);
341 n
= newnexus (NOTaction
);
342 if ((n
->n_L_child
= nexp3 ()))
344 pinform("missing negation");
355 static struct nexus
*
360 char buffer
[BUFSIZ
], temp
[64];
363 if ((cp
= nxtarg ()) == NULL
)
367 pinform("%s unexpected", cp
);
375 switch (i
= smatch (cp
, parswit
)) {
377 ambigsw (cp
, parswit
);
381 fprintf (stderr
, "-%s unknown\n", cp
);
386 if ((n
= parse ()) == NULL
) {
387 pinform("missing group");
390 if ((cp
= nxtarg ()) == NULL
) {
391 pinform("missing -rbrace");
394 if (*cp
++ == '-' && smatch (cp
, parswit
) == PRRBR
)
396 pinform("%s unexpected", --cp
);
408 strncpy(temp
, parswit
[i
].sw
, sizeof(temp
));
409 temp
[sizeof(temp
) - 1] = '\0';
410 dp
= *brkstring (temp
, " ", NULL
);
412 if (!(cp
= nxtarg ())) {/* allow -xyz arguments */
413 pinform("missing argument to %s", argp
[-2]);
416 n
= newnexus (GREPaction
);
418 snprintf (buffer
, sizeof(buffer
), "^%s[ \t]*:.*%s", dp
, cp
);
423 n
= newnexus (GREPaction
);
425 if (!(cp
= nxtarg ())) {/* allow -xyz arguments */
426 pinform("missing argument to %s", argp
[-2]);
432 if (!gcompile (n
, dp
)) {
433 pinform("pattern error in %s %s", argp
[-2], cp
);
437 n
->n_patbuf
= mh_xstrdup(dp
);
441 pinform("internal error!");
445 if (!(datesw
= nxtarg ()) || *datesw
== '-') {
446 pinform("missing argument to %s", argp
[-2]);
453 if (!(cp
= nxtarg ())) {/* allow -xyz arguments */
454 pinform("missing argument to %s", argp
[-2]);
457 n
= newnexus (TWSaction
);
459 if (!tcompile (cp
, &n
->n_tws
, n
->n_after
= i
== PRAFTR
)) {
460 pinform("unable to parse %s %s", argp
[-2], cp
);
469 static struct nexus
*
470 newnexus(int (*action
)(struct nexus
*n
, FILE *fp
, int msgnum
,
471 long start
, long stop
))
476 p
->n_action
= action
;
482 pmatches (FILE *fp
, int msgnum
, long start
, long stop
, int debug
)
487 if (!talked
++ && debug
)
490 return (*head
->n_action
)(head
, fp
, msgnum
, start
, stop
);
495 PRaction (struct nexus
*n
, int level
)
499 for (i
= 0; i
< level
; i
++)
500 fprintf (stderr
, "| ");
502 if (n
->n_action
== ORaction
) {
503 fprintf (stderr
, "OR\n");
504 PRaction (n
->n_L_child
, level
+ 1);
505 PRaction (n
->n_R_child
, level
+ 1);
508 if (n
->n_action
== ANDaction
) {
509 fprintf (stderr
, "AND\n");
510 PRaction (n
->n_L_child
, level
+ 1);
511 PRaction (n
->n_R_child
, level
+ 1);
514 if (n
->n_action
== NOTaction
) {
515 fprintf (stderr
, "NOT\n");
516 PRaction (n
->n_L_child
, level
+ 1);
519 if (n
->n_action
== GREPaction
) {
520 fprintf (stderr
, "PATTERN(%s) %s\n",
521 n
->n_header
? "header" : "body", n
->n_patbuf
);
524 if (n
->n_action
== TWSaction
) {
525 fprintf (stderr
, "TEMPORAL(%s) %s: %s\n",
526 n
->n_after
? "after" : "before", n
->n_datef
,
527 dasctime (&n
->n_tws
, TW_NULL
));
532 gp
.f
= (void (*)(void))n
->n_action
;
533 fprintf(stderr
, "UNKNOWN(%p)\n", gp
.v
);
538 ORaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
540 if ((*n
->n_L_child
->n_action
)(n
->n_L_child
, fp
, msgnum
, start
, stop
))
542 return (*n
->n_R_child
->n_action
)(n
->n_R_child
, fp
, msgnum
, start
, stop
);
547 ANDaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
549 if (!(*n
->n_L_child
->n_action
)(n
->n_L_child
, fp
, msgnum
, start
, stop
))
551 return (*n
->n_R_child
->n_action
)(n
->n_R_child
, fp
, msgnum
, start
, stop
);
556 NOTaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
558 return (!(*n
->n_L_child
->n_action
)(n
->n_L_child
, fp
, msgnum
, start
, stop
));
563 gcompile (struct nexus
*n
, char *astr
)
567 unsigned char *ep
, *dp
, *sp
, *lastep
= 0;
569 dp
= (ep
= (unsigned char *) n
->n_expbuf
) + sizeof n
->n_expbuf
;
570 sp
= (unsigned char *) astr
;
580 if ((c
= *sp
++) != '*')
607 if ((c
= *sp
++) == '^') {
617 if (c
== '-' && *sp
!= '\0' && *sp
!= ']') {
618 for (c
= ep
[-1]+1; c
< *sp
; c
++) {
621 if (c
== '\0' || ep
>= dp
)
627 if (c
== '\0' || ep
>= dp
)
630 } while ((c
= *sp
++) != ']');
637 if ((c
= *sp
++) == '\0')
653 GREPaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
659 char *p1
, *p2
, *ebp
, *cbp
;
663 fseek (fp
, start
, SEEK_SET
);
667 if (body
&& n
->n_header
)
674 if (fgets (ibuf
, sizeof ibuf
, fp
) == NULL
675 || (stop
&& pos
>= stop
)) {
680 pos
+= (long) strlen (ibuf
);
682 ebp
= ibuf
+ strlen (ibuf
);
685 if (lf
&& c
!= '\n') {
686 if (c
!= ' ' && c
!= '\t') {
700 /* Unfold by skipping the newline. */
703 if (c
&& p1
< &linebuf
[LBSIZE
- 1])
712 /* Attempt to decode as a MIME header. If it's the last header,
713 body will be 1 and lf will be at least 1. */
715 decode_rfc2047 (linebuf
, decoded_linebuf
, sizeof decoded_linebuf
)) {
716 p1
= decoded_linebuf
;
720 if (advance (p1
, p2
))
728 if (*p1
== c
|| cc
[(unsigned char)*p1
] == c
)
729 if (advance (p1
, p2
))
736 if (advance (p1
, p2
))
744 advance (char *alp
, char *aep
)
746 unsigned char *lp
, *ep
, *curlp
;
748 lp
= (unsigned char *)alp
;
749 ep
= (unsigned char *)aep
;
753 if (*ep
++ == *lp
++ || ep
[-1] == cc
[lp
[-1]])
771 if (cclass (ep
, *lp
++, 1)) {
778 if (cclass (ep
, *lp
++, 0)) {
792 while (*lp
++ == *ep
|| cc
[lp
[-1]] == *ep
)
800 while (cclass (ep
, *lp
++, ep
[-1] == (CCL
| STAR
)))
808 if (advance ((char *) lp
, (char *) ep
))
810 } while (lp
> curlp
);
814 inform("advance() botch -- you lose big, continuing...");
821 cclass (unsigned char *aset
, int ac
, int af
)
824 unsigned char c
, *set
;
832 if (*set
++ == c
|| set
[-1] == cc
[c
])
840 tcompile (char *ap
, struct tws
*tb
, int isafter
)
844 if ((tw
= tws_parse (ap
, isafter
)) == NULL
)
853 tws_parse (char *ap
, int isafter
)
858 if ((tw
= tws_special (ap
)) != NULL
) {
859 tw
->tw_sec
= tw
->tw_min
= isafter
? 59 : 0;
860 tw
->tw_hour
= isafter
? 23 : 0;
863 if ((tw
= dparsetime (ap
)) != NULL
)
866 if ((ts
= dlocaltimenow ()) == NULL
)
869 snprintf (buffer
, sizeof(buffer
), "%s %s", ap
, dtwszone (ts
));
870 if ((tw
= dparsetime (buffer
)) != NULL
)
873 snprintf (buffer
, sizeof(buffer
), "%s %02d:%02d:%02d %s", ap
,
874 ts
->tw_hour
, ts
->tw_min
, ts
->tw_sec
, dtwszone (ts
));
875 if ((tw
= dparsetime (buffer
)) != NULL
)
878 snprintf (buffer
, sizeof(buffer
), "%02d %s %04d %s",
879 ts
->tw_mday
, tw_moty
[ts
->tw_mon
], ts
->tw_year
, ap
);
880 if ((tw
= dparsetime (buffer
)) != NULL
)
883 snprintf (buffer
, sizeof(buffer
), "%02d %s %04d %s %s",
884 ts
->tw_mday
, tw_moty
[ts
->tw_mon
], ts
->tw_year
,
886 if ((tw
= dparsetime (buffer
)) != NULL
)
894 tws_special (char *ap
)
901 if (!strcasecmp (ap
, "today"))
902 return dlocaltime (&clock
);
903 if (!strcasecmp (ap
, "yesterday")) {
904 clock
-= (long) (60 * 60 * 24);
905 return dlocaltime (&clock
);
907 if (!strcasecmp (ap
, "tomorrow")) {
908 clock
+= (long) (60 * 60 * 24);
909 return dlocaltime (&clock
);
912 for (i
= 0; tw_ldotw
[i
]; i
++)
913 if (!strcasecmp (ap
, tw_ldotw
[i
]))
916 if ((tw
= dlocaltime (&clock
)) == NULL
)
918 if ((i
-= tw
->tw_wday
) > 0)
925 i
= atoi (ap
); /* we should error check this */
928 clock
+= (long) ((60 * 60 * 24) * i
);
929 return dlocaltime (&clock
);
934 TWSaction(struct nexus
*n
, FILE *fp
, int msgnum
, long start
, long stop
)
938 char buf
[NMH_BUFSIZ
], name
[NAMESZ
];
940 m_getfld_state_t gstate
;
943 fseek (fp
, start
, SEEK_SET
);
944 gstate
= m_getfld_state_init(fp
);
946 int bufsz
= sizeof buf
;
947 switch (state
= m_getfld2(&gstate
, name
, buf
, &bufsz
)) {
951 bp
= mh_xstrdup(buf
);
952 while (state
== FLDPLUS
) {
954 state
= m_getfld2(&gstate
, name
, buf
, &bufsz
);
957 if (!strcasecmp (name
, n
->n_datef
))
965 if (state
== LENERR
|| state
== FMTERR
)
966 inform("format error in message %d", msgnum
);
971 die("internal error -- you lose");
975 m_getfld_state_destroy (&gstate
);
977 if ((tw
= dparsetime (bp
)) == NULL
)
978 inform("unable to parse %s field in message %d, matching...",
979 n
->n_datef
, msgnum
), state
= 1;
981 state
= n
->n_after
? (twsort (tw
, &n
->n_tws
) > 0)
982 : (twsort (tw
, &n
->n_tws
) < 0);