source: trunk/third/nmh/uip/picksbr.c @ 12455

Revision 12455, 17.6 KB checked in by danw, 26 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r12454, which included commits to RCS files with non-trunk default branches.
Line 
1
2/*
3 * picksbr.c -- routines to help pick along...
4 *
5 * $Id: picksbr.c,v 1.1.1.1 1999-02-07 18:14:15 danw Exp $
6 */
7
8#include <h/mh.h>
9#include <zotnet/tws/tws.h>
10#include <h/picksbr.h>
11
12static struct swit parswit[] = {
13#define PRAND                   0
14    { "and", 0 },
15#define PROR                    1
16    { "or", 0 },
17#define PRNOT                   2
18    { "not", 0 },
19#define PRLBR                   3
20    { "lbrace", 0 },
21#define PRRBR                   4
22    { "rbrace", 0 },
23#define PRCC                    5
24    { "cc  pattern", 0 },
25#define PRDATE                  6
26    { "date  pattern", 0 },
27#define PRFROM                  7
28    { "from  pattern", 0 },
29#define PRSRCH                  8
30    { "search  pattern", 0 },
31#define PRSUBJ                  9
32    { "subject  pattern", 0 },
33#define PRTO                   10
34    { "to  pattern", 0 },
35#define PROTHR                 11
36    { "-othercomponent  pattern", 15 },
37#define PRAFTR                 12
38    { "after date", 0 },
39#define PRBEFR                 13
40    { "before date", 0 },
41#define PRDATF                 14
42    { "datefield field", 5 },
43    { NULL, 0 }
44};
45
46/* DEFINITIONS FOR PATTERN MATCHING */
47
48/*
49 * We really should be using re_comp() and re_exec() here.  Unfortunately,
50 * pick advertises that lowercase characters matches characters of both
51 * cases.  Since re_exec() doesn't exhibit this behavior, we are stuck
52 * with this version.  Furthermore, we need to be able to save and restore
53 * the state of the pattern matcher in order to do things "efficiently".
54 *
55 * The matching power of this algorithm isn't as powerful as the re_xxx()
56 * routines (no \(xxx\) and \n constructs).  Such is life.
57 */
58
59#define CCHR    2
60#define CDOT    4
61#define CCL     6
62#define NCCL    8
63#define CDOL    10
64#define CEOF    11
65
66#define STAR    01
67
68#define LBSIZE  1024
69#define ESIZE   256
70
71
72static char linebuf[LBSIZE + 1];
73
74/* the magic array for case-independence */
75static char cc[] = {
76        0000,0001,0002,0003,0004,0005,0006,0007,
77        0010,0011,0012,0013,0014,0015,0016,0017,
78        0020,0021,0022,0023,0024,0025,0026,0027,
79        0030,0031,0032,0033,0034,0035,0036,0037,
80        0040,0041,0042,0043,0044,0045,0046,0047,
81        0050,0051,0052,0053,0054,0055,0056,0057,
82        0060,0061,0062,0063,0064,0065,0066,0067,
83        0070,0071,0072,0073,0074,0075,0076,0077,
84        0100,0141,0142,0143,0144,0145,0146,0147,
85        0150,0151,0152,0153,0154,0155,0156,0157,
86        0160,0161,0162,0163,0164,0165,0166,0167,
87        0170,0171,0172,0133,0134,0135,0136,0137,
88        0140,0141,0142,0143,0144,0145,0146,0147,
89        0150,0151,0152,0153,0154,0155,0156,0157,
90        0160,0161,0162,0163,0164,0165,0166,0167,
91        0170,0171,0172,0173,0174,0175,0176,0177,
92};
93
94/*
95 * DEFINITIONS FOR NEXUS
96 */
97
98#define nxtarg()        (*argp ? *argp++ : NULL)
99#define prvarg()        argp--
100
101#define padvise         if (!talked++) advise
102
103struct nexus {
104    int (*n_action)();
105
106    union {
107        /* for {OR,AND,NOT}action */
108        struct {
109            struct nexus *un_L_child;
110            struct nexus *un_R_child;
111        } st1;
112
113        /* for GREPaction */
114        struct {
115            int   un_header;
116            int   un_circf;
117            char  un_expbuf[ESIZE];
118            char *un_patbuf;
119        } st2;
120
121        /* for TWSaction */
122        struct {
123            char *un_datef;
124            int   un_after;
125            struct tws un_tws;
126        } st3;
127    } un;
128};
129
130#define n_L_child un.st1.un_L_child
131#define n_R_child un.st1.un_R_child
132
133#define n_header un.st2.un_header
134#define n_circf  un.st2.un_circf
135#define n_expbuf un.st2.un_expbuf
136#define n_patbuf un.st2.un_patbuf
137
138#define n_datef  un.st3.un_datef
139#define n_after  un.st3.un_after
140#define n_tws    un.st3.un_tws
141
142static int talked;
143static int pdebug = 0;
144
145static char *datesw;
146static char **argp;
147
148static struct nexus *head;
149
150/*
151 * prototypes for date routines
152 */
153static struct tws *tws_parse();
154static struct tws *tws_special();
155
156/*
157 * static prototypes
158 */
159static void PRaction();
160static int gcompile();
161static int advance();
162static int cclass();
163static int tcompile();
164
165static struct nexus *parse();
166static struct nexus *exp1();
167static struct nexus *exp2();
168static struct nexus *exp3();
169static struct nexus *newnexus();
170
171static int ORaction();
172static int ANDaction();
173static int NOTaction();
174static int GREPaction();
175static int TWSaction();
176
177
178int
179pcompile (char **vec, char *date)
180{
181    register char *cp;
182
183    if ((cp = getenv ("MHPDEBUG")) && *cp)
184        pdebug++;
185
186    argp = vec;
187    if ((datesw = date) == NULL)
188        datesw = "date";
189    talked = 0;
190
191    if ((head = parse ()) == NULL)
192        return (talked ? 0 : 1);
193
194    if (*argp) {
195        padvise (NULL, "%s unexpected", *argp);
196        return 0;
197    }
198
199    return 1;
200}
201
202
203static struct nexus *
204parse (void)
205{
206    register char  *cp;
207    register struct nexus *n, *o;
208
209    if ((n = exp1 ()) == NULL || (cp = nxtarg ()) == NULL)
210        return n;
211
212    if (*cp != '-') {
213        padvise (NULL, "%s unexpected", cp);
214        return NULL;
215    }
216
217    if (*++cp == '-')
218        goto header;
219    switch (smatch (cp, parswit)) {
220        case AMBIGSW:
221            ambigsw (cp, parswit);
222            talked++;
223            return NULL;
224        case UNKWNSW:
225            fprintf (stderr, "-%s unknown\n", cp);
226            talked++;
227            return NULL;
228
229        case PROR:
230            o = newnexus (ORaction);
231            o->n_L_child = n;
232            if ((o->n_R_child = parse ()))
233                return o;
234            padvise (NULL, "missing disjunctive");
235            return NULL;
236
237header: ;
238        default:
239            prvarg ();
240            return n;
241    }
242}
243
244static struct nexus *
245exp1 (void)
246{
247    register char *cp;
248    register struct nexus *n, *o;
249
250    if ((n = exp2 ()) == NULL || (cp = nxtarg ()) == NULL)
251        return n;
252
253    if (*cp != '-') {
254        padvise (NULL, "%s unexpected", cp);
255        return NULL;
256    }
257
258    if (*++cp == '-')
259        goto header;
260    switch (smatch (cp, parswit)) {
261        case AMBIGSW:
262            ambigsw (cp, parswit);
263            talked++;
264            return NULL;
265        case UNKWNSW:
266            fprintf (stderr, "-%s unknown\n", cp);
267            talked++;
268            return NULL;
269
270        case PRAND:
271            o = newnexus (ANDaction);
272            o->n_L_child = n;
273            if ((o->n_R_child = exp1 ()))
274                return o;
275            padvise (NULL, "missing conjunctive");
276            return NULL;
277
278header: ;
279        default:
280            prvarg ();
281            return n;
282    }
283}
284
285
286static struct nexus *
287exp2 (void)
288{
289    register char *cp;
290    register struct nexus *n;
291
292    if ((cp = nxtarg ()) == NULL)
293        return NULL;
294
295    if (*cp != '-') {
296        prvarg ();
297        return exp3 ();
298    }
299
300    if (*++cp == '-')
301        goto header;
302    switch (smatch (cp, parswit)) {
303        case AMBIGSW:
304            ambigsw (cp, parswit);
305            talked++;
306            return NULL;
307        case UNKWNSW:
308            fprintf (stderr, "-%s unknown\n", cp);
309            talked++;
310            return NULL;
311
312        case PRNOT:
313            n = newnexus (NOTaction);
314            if ((n->n_L_child = exp3 ()))
315                return n;
316            padvise (NULL, "missing negation");
317            return NULL;
318
319header: ;
320        default:
321            prvarg ();
322            return exp3 ();
323    }
324}
325
326static struct nexus *
327exp3 (void)
328{
329    int i;
330    register char *cp, *dp;
331    char buffer[BUFSIZ], temp[64];
332    register struct nexus *n;
333
334    if ((cp = nxtarg ()) == NULL)
335        return NULL;
336
337    if (*cp != '-') {
338        padvise (NULL, "%s unexpected", cp);
339        return NULL;
340    }
341
342    if (*++cp == '-') {
343        dp = ++cp;
344        goto header;
345    }
346    switch (i = smatch (cp, parswit)) {
347        case AMBIGSW:
348            ambigsw (cp, parswit);
349            talked++;
350            return NULL;
351        case UNKWNSW:
352            fprintf (stderr, "-%s unknown\n", cp);
353            talked++;
354            return NULL;
355
356        case PRLBR:
357            if ((n = parse ()) == NULL) {
358                padvise (NULL, "missing group");
359                return NULL;
360            }
361            if ((cp = nxtarg ()) == NULL) {
362                padvise (NULL, "missing -rbrace");
363                return NULL;
364            }
365            if (*cp++ == '-' && smatch (cp, parswit) == PRRBR)
366                return n;
367            padvise (NULL, "%s unexpected", --cp);
368            return NULL;
369
370        default:
371            prvarg ();
372            return NULL;
373
374        case PRCC:
375        case PRDATE:
376        case PRFROM:
377        case PRTO:
378        case PRSUBJ:
379            strncpy(temp, parswit[i].sw, sizeof(temp));
380            temp[sizeof(temp) - 1] = '\0';
381            dp = *brkstring (temp, " ", NULL);
382    header: ;
383            if (!(cp = nxtarg ())) {/* allow -xyz arguments */
384                padvise (NULL, "missing argument to %s", argp[-2]);
385                return NULL;
386            }
387            n = newnexus (GREPaction);
388            n->n_header = 1;
389            snprintf (buffer, sizeof(buffer), "^%s[ \t]*:.*%s", dp, cp);
390            dp = buffer;
391            goto pattern;
392
393        case PRSRCH:
394            n = newnexus (GREPaction);
395            n->n_header = 0;
396            if (!(cp = nxtarg ())) {/* allow -xyz arguments */
397                padvise (NULL, "missing argument to %s", argp[-2]);
398                return NULL;
399            }
400            dp = cp;
401    pattern: ;
402            if (!gcompile (n, dp)) {
403                padvise (NULL, "pattern error in %s %s", argp[-2], cp);
404                return NULL;
405            }
406            n->n_patbuf = getcpy (dp);
407            return n;
408
409        case PROTHR:
410            padvise (NULL, "internal error!");
411            return NULL;
412
413        case PRDATF:
414            if (!(datesw = nxtarg ()) || *datesw == '-') {
415                padvise (NULL, "missing argument to %s", argp[-2]);
416                return NULL;
417            }
418            return exp3 ();
419
420        case PRAFTR:
421        case PRBEFR:
422            if (!(cp = nxtarg ())) {/* allow -xyz arguments */
423                padvise (NULL, "missing argument to %s", argp[-2]);
424                return NULL;
425            }
426            n = newnexus (TWSaction);
427            n->n_datef = datesw;
428            if (!tcompile (cp, &n->n_tws, n->n_after = i == PRAFTR)) {
429                padvise (NULL, "unable to parse %s %s", argp[-2], cp);
430                return NULL;
431            }
432            return n;
433    }
434}
435
436
437static struct nexus *
438newnexus (int (*action)())
439{
440    register struct nexus *p;
441
442    if ((p = (struct nexus *) calloc ((size_t) 1, sizeof *p)) == NULL)
443        adios (NULL, "unable to allocate component storage");
444
445    p->n_action = action;
446    return p;
447}
448
449
450#define args(a) a, fp, msgnum, start, stop
451#define params  args (n)
452#define plist   \
453            register struct nexus  *n; \
454            register FILE *fp; \
455            int msgnum; \
456            long    start, \
457                    stop;
458
459int
460pmatches (FILE *fp, int msgnum, long start, long stop)
461{
462    if (!head)
463        return 1;
464
465    if (!talked++ && pdebug)
466        PRaction (head, 0);
467
468    return (*head->n_action) (args (head));
469}
470
471
472static void
473PRaction (struct nexus *n, int level)
474{
475    register int i;
476
477    for (i = 0; i < level; i++)
478        fprintf (stderr, "| ");
479
480    if (n->n_action == ORaction) {
481        fprintf (stderr, "OR\n");
482        PRaction (n->n_L_child, level + 1);
483        PRaction (n->n_R_child, level + 1);
484        return;
485    }
486    if (n->n_action == ANDaction) {
487        fprintf (stderr, "AND\n");
488        PRaction (n->n_L_child, level + 1);
489        PRaction (n->n_R_child, level + 1);
490        return;
491    }
492    if (n->n_action == NOTaction) {
493        fprintf (stderr, "NOT\n");
494        PRaction (n->n_L_child, level + 1);
495        return;
496    }
497    if (n->n_action == GREPaction) {
498        fprintf (stderr, "PATTERN(%s) %s\n",
499                n->n_header ? "header" : "body", n->n_patbuf);
500        return;
501    }
502    if (n->n_action == TWSaction) {
503        fprintf (stderr, "TEMPORAL(%s) %s: %s\n",
504                n->n_after ? "after" : "before", n->n_datef,
505                dasctime (&n->n_tws, TW_NULL));
506        return;
507    }
508    fprintf (stderr, "UNKNOWN(0x%x)\n", (unsigned int) (*n->n_action));
509}
510
511
512static int
513ORaction (params)
514plist
515{
516    if ((*n->n_L_child->n_action) (args (n->n_L_child)))
517        return 1;
518    return (*n->n_R_child->n_action) (args (n->n_R_child));
519}
520
521
522static int
523ANDaction (params)
524plist
525{
526    if (!(*n->n_L_child->n_action) (args (n->n_L_child)))
527        return 0;
528    return (*n->n_R_child->n_action) (args (n->n_R_child));
529}
530
531
532static int
533NOTaction (params)
534plist
535{
536    return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
537}
538
539
540static int
541gcompile (struct nexus *n, char *astr)
542{
543    register int c;
544    int cclcnt;
545    register char *ep, *dp, *sp, *lastep;
546
547    dp = (ep = n->n_expbuf) + sizeof n->n_expbuf;
548    sp = astr;
549    if (*sp == '^') {
550        n->n_circf = 1;
551        sp++;
552    }
553    else
554        n->n_circf = 0;
555    for (;;) {
556        if (ep >= dp)
557            goto cerror;
558        if ((c = *sp++) != '*')
559            lastep = ep;
560        switch (c) {
561            case '\0':
562                *ep++ = CEOF;
563                return 1;
564
565            case '.':
566                *ep++ = CDOT;
567                continue;
568
569            case '*':
570                if (lastep == 0)
571                    goto defchar;
572                *lastep |= STAR;
573                continue;
574
575            case '$':
576                if (*sp != '\0')
577                    goto defchar;
578                *ep++ = CDOL;
579                continue;
580
581            case '[':
582                *ep++ = CCL;
583                *ep++ = 0;
584                cclcnt = 1;
585                if ((c = *sp++) == '^') {
586                    c = *sp++;
587                    ep[-2] = NCCL;
588                }
589                do {
590                    *ep++ = c;
591                    cclcnt++;
592                    if (c == '\0' || ep >= dp)
593                        goto cerror;
594                } while ((c = *sp++) != ']');
595                lastep[1] = cclcnt;
596                continue;
597
598            case '\\':
599                if ((c = *sp++) == '\0')
600                    goto cerror;
601        defchar:
602            default:
603                *ep++ = CCHR;
604                *ep++ = c;
605        }
606    }
607
608cerror: ;
609    return 0;
610}
611
612
613static int
614GREPaction (params)
615plist
616{
617    int c, body, lf;
618    long pos = start;
619    register char *p1, *p2, *ebp, *cbp;
620    char ibuf[BUFSIZ];
621
622    fseek (fp, start, SEEK_SET);
623    body = 0;
624    ebp = cbp = ibuf;
625    for (;;) {
626        if (body && n->n_header)
627            return 0;
628        p1 = linebuf;
629        p2 = cbp;
630        lf = 0;
631        for (;;) {
632            if (p2 >= ebp) {
633                if (fgets (ibuf, sizeof ibuf, fp) == NULL
634                        || (stop && pos >= stop)) {
635                    if (lf)
636                        break;
637                    return 0;
638                }
639                pos += (long) strlen (ibuf);
640                p2 = ibuf;
641                ebp = ibuf + strlen (ibuf);
642            }
643            c = *p2++;
644            if (lf && c != '\n')
645                if (c != ' ' && c != '\t') {
646                    --p2;
647                    break;
648                }
649                else
650                    lf = 0;
651            if (c == '\n')
652                if (body)
653                    break;
654                else {
655                    if (lf) {
656                        body++;
657                        break;
658                    }
659                    lf++;
660                    c = ' ';
661                }
662            if (c && p1 < &linebuf[LBSIZE - 1])
663                *p1++ = c;
664        }
665
666        *p1++ = 0;
667        cbp = p2;
668        p1 = linebuf;
669        p2 = n->n_expbuf;
670
671        if (n->n_circf) {
672            if (advance (p1, p2))
673                return 1;
674            continue;
675        }
676
677        if (*p2 == CCHR) {
678            c = p2[1];
679            do {
680                if (*p1 == c || cc[*p1] == c)
681                    if (advance (p1, p2))
682                        return 1;
683            } while (*p1++);
684            continue;
685        }
686
687        do {
688            if (advance (p1, p2))
689                return 1;
690        } while (*p1++);
691    }
692}
693
694
695static int
696advance (char *alp, char *aep)
697{
698    register char *lp, *ep, *curlp;
699
700    lp = alp;
701    ep = aep;
702    for (;;)
703        switch (*ep++) {
704            case CCHR:
705                if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
706                    continue;
707                return 0;
708
709            case CDOT:
710                if (*lp++)
711                    continue;
712                return 0;
713
714            case CDOL:
715                if (*lp == 0)
716                    continue;
717                return 0;
718
719            case CEOF:
720                return 1;
721
722            case CCL:
723                if (cclass (ep, *lp++, 1)) {
724                    ep += *ep;
725                    continue;
726                }
727                return 0;
728
729            case NCCL:
730                if (cclass (ep, *lp++, 0)) {
731                    ep += *ep;
732                    continue;
733                }
734                return 0;
735
736            case CDOT | STAR:
737                curlp = lp;
738                while (*lp++)
739                    continue;
740                goto star;
741
742            case CCHR | STAR:
743                curlp = lp;
744                while (*lp++ == *ep || cc[lp[-1]] == *ep)
745                    continue;
746                ep++;
747                goto star;
748
749            case CCL | STAR:
750            case NCCL | STAR:
751                curlp = lp;
752                while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
753                    continue;
754                ep += *ep;
755                goto star;
756
757        star:
758                do {
759                    lp--;
760                    if (advance (lp, ep))
761                        return (1);
762                } while (lp > curlp);
763                return 0;
764
765            default:
766                admonish (NULL, "advance() botch -- you lose big");
767                return 0;
768        }
769}
770
771
772static int
773cclass (char *aset, int ac, int af)
774{
775    register int    n;
776    register char   c,
777                   *set;
778
779    set = aset;
780    if ((c = ac) == 0)
781        return (0);
782
783    n = *set++;
784    while (--n)
785        if (*set++ == c)
786            return (af);
787
788    return (!af);
789}
790
791
792static int
793tcompile (char *ap, struct tws *tb, int isafter)
794{
795    register struct tws *tw;
796
797    if ((tw = tws_parse (ap, isafter)) == NULL)
798        return 0;
799
800    twscopy (tb, tw);
801    return 1;
802}
803
804
805static struct tws *
806tws_parse (char *ap, int isafter)
807{
808    char buffer[BUFSIZ];
809    register struct tws *tw, *ts;
810
811    if ((tw = tws_special (ap)) != NULL) {
812        tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
813        tw->tw_hour = isafter ? 23 : 0;
814        return tw;
815    }
816    if ((tw = dparsetime (ap)) != NULL)
817        return tw;
818
819    if ((ts = dlocaltimenow ()) == NULL)
820        return NULL;
821
822    snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
823    if ((tw = dparsetime (buffer)) != NULL)
824        return tw;
825
826    snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
827            ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
828    if ((tw = dparsetime (buffer)) != NULL)
829        return tw;
830
831    snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
832            ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
833    if ((tw = dparsetime (buffer)) != NULL)
834        return tw;
835
836    snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
837            ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
838            ap, dtwszone (ts));
839    if ((tw = dparsetime (buffer)) != NULL)
840        return tw;
841
842    return NULL;
843}
844
845
846static struct tws *
847tws_special (char *ap)
848{
849    int i;
850    time_t clock;
851    register struct tws *tw;
852
853    time (&clock);
854    if (!strcasecmp (ap, "today"))
855        return dlocaltime (&clock);
856    if (!strcasecmp (ap, "yesterday")) {
857        clock -= (long) (60 * 60 * 24);
858        return dlocaltime (&clock);
859    }
860    if (!strcasecmp (ap, "tomorrow")) {
861        clock += (long) (60 * 60 * 24);
862        return dlocaltime (&clock);
863    }
864
865    for (i = 0; tw_ldotw[i]; i++)
866        if (!strcasecmp (ap, tw_ldotw[i]))
867            break;
868    if (tw_ldotw[i]) {
869        if ((tw = dlocaltime (&clock)) == NULL)
870            return NULL;
871        if ((i -= tw->tw_wday) > 0)
872            i -= 7;
873    }
874    else
875        if (*ap != '-')
876            return NULL;
877        else                    /* -ddd days ago */
878            i = atoi (ap);      /* we should error check this */
879
880    clock += (long) ((60 * 60 * 24) * i);
881    return dlocaltime (&clock);
882}
883
884
885static int
886TWSaction (params)
887plist
888{
889    int state;
890    register char *bp;
891    char buf[BUFSIZ], name[NAMESZ];
892    register struct tws *tw;
893
894    fseek (fp, start, SEEK_SET);
895    for (state = FLD, bp = NULL;;) {
896        switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
897            case FLD:
898            case FLDEOF:
899            case FLDPLUS:
900                if (bp != NULL)
901                    free (bp), bp = NULL;
902                bp = add (buf, NULL);
903                while (state == FLDPLUS) {
904                    state = m_getfld (state, name, buf, sizeof buf, fp);
905                    bp = add (buf, bp);
906                }
907                if (!strcasecmp (name, n->n_datef))
908                    break;
909                if (state != FLDEOF)
910                    continue;
911
912            case BODY:
913            case BODYEOF:
914            case FILEEOF:
915            case LENERR:
916            case FMTERR:
917                if (state == LENERR || state == FMTERR)
918                    advise (NULL, "format error in message %d", msgnum);
919                if (bp != NULL)
920                    free (bp);
921                return 0;
922
923            default:
924                adios (NULL, "internal error -- you lose");
925        }
926        break;
927    }
928
929    if ((tw = dparsetime (bp)) == NULL)
930        advise (NULL, "unable to parse %s field in message %d, matching...",
931                n->n_datef, msgnum), state = 1;
932    else
933        state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
934            : (twsort (tw, &n->n_tws) < 0);
935
936    if (bp != NULL)
937        free (bp);
938    return state;
939}
Note: See TracBrowser for help on using the repository browser.