]> diplodocus.org Git - nmh/blob - uip/picksbr.c
updating changelog, should have been done with last commit
[nmh] / uip / picksbr.c
1
2 /*
3 * picksbr.c -- routines to help pick along...
4 *
5 * $Id$
6 */
7
8 #include <h/mh.h>
9 #include <zotnet/tws/tws.h>
10 #include <h/picksbr.h>
11
12 static 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
72 static char linebuf[LBSIZE + 1];
73
74 /* the magic array for case-independence */
75 static 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
103 struct 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
142 static int talked;
143 static int pdebug = 0;
144
145 static char *datesw;
146 static char **argp;
147
148 static struct nexus *head;
149
150 /*
151 * prototypes for date routines
152 */
153 static struct tws *tws_parse();
154 static struct tws *tws_special();
155
156 /*
157 * static prototypes
158 */
159 static void PRaction();
160 static int gcompile();
161 static int advance();
162 static int cclass();
163 static int tcompile();
164
165 static struct nexus *parse();
166 static struct nexus *exp1();
167 static struct nexus *exp2();
168 static struct nexus *exp3();
169 static struct nexus *newnexus();
170
171 static int ORaction();
172 static int ANDaction();
173 static int NOTaction();
174 static int GREPaction();
175 static int TWSaction();
176
177
178 int
179 pcompile (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
203 static struct nexus *
204 parse (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
237 header: ;
238 default:
239 prvarg ();
240 return n;
241 }
242 }
243
244 static struct nexus *
245 exp1 (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
278 header: ;
279 default:
280 prvarg ();
281 return n;
282 }
283 }
284
285
286 static struct nexus *
287 exp2 (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
319 header: ;
320 default:
321 prvarg ();
322 return exp3 ();
323 }
324 }
325
326 static struct nexus *
327 exp3 (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
437 static struct nexus *
438 newnexus (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
459 int
460 pmatches (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
472 static void
473 PRaction (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
512 static int
513 ORaction (params)
514 plist
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
522 static int
523 ANDaction (params)
524 plist
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
532 static int
533 NOTaction (params)
534 plist
535 {
536 return (!(*n->n_L_child->n_action) (args (n->n_L_child)));
537 }
538
539
540 static int
541 gcompile (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
608 cerror: ;
609 return 0;
610 }
611
612
613 static int
614 GREPaction (params)
615 plist
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 }
652 if (c == '\n') {
653 if (body)
654 break;
655 else {
656 if (lf) {
657 body++;
658 break;
659 }
660 lf++;
661 c = ' ';
662 }
663 }
664 if (c && p1 < &linebuf[LBSIZE - 1])
665 *p1++ = c;
666 }
667
668 *p1++ = 0;
669 cbp = p2;
670 p1 = linebuf;
671 p2 = n->n_expbuf;
672
673 if (n->n_circf) {
674 if (advance (p1, p2))
675 return 1;
676 continue;
677 }
678
679 if (*p2 == CCHR) {
680 c = p2[1];
681 do {
682 if (*p1 == c || cc[*p1] == c)
683 if (advance (p1, p2))
684 return 1;
685 } while (*p1++);
686 continue;
687 }
688
689 do {
690 if (advance (p1, p2))
691 return 1;
692 } while (*p1++);
693 }
694 }
695
696
697 static int
698 advance (char *alp, char *aep)
699 {
700 register char *lp, *ep, *curlp;
701
702 lp = alp;
703 ep = aep;
704 for (;;)
705 switch (*ep++) {
706 case CCHR:
707 if (*ep++ == *lp++ || ep[-1] == cc[lp[-1]])
708 continue;
709 return 0;
710
711 case CDOT:
712 if (*lp++)
713 continue;
714 return 0;
715
716 case CDOL:
717 if (*lp == 0)
718 continue;
719 return 0;
720
721 case CEOF:
722 return 1;
723
724 case CCL:
725 if (cclass (ep, *lp++, 1)) {
726 ep += *ep;
727 continue;
728 }
729 return 0;
730
731 case NCCL:
732 if (cclass (ep, *lp++, 0)) {
733 ep += *ep;
734 continue;
735 }
736 return 0;
737
738 case CDOT | STAR:
739 curlp = lp;
740 while (*lp++)
741 continue;
742 goto star;
743
744 case CCHR | STAR:
745 curlp = lp;
746 while (*lp++ == *ep || cc[lp[-1]] == *ep)
747 continue;
748 ep++;
749 goto star;
750
751 case CCL | STAR:
752 case NCCL | STAR:
753 curlp = lp;
754 while (cclass (ep, *lp++, ep[-1] == (CCL | STAR)))
755 continue;
756 ep += *ep;
757 goto star;
758
759 star:
760 do {
761 lp--;
762 if (advance (lp, ep))
763 return (1);
764 } while (lp > curlp);
765 return 0;
766
767 default:
768 admonish (NULL, "advance() botch -- you lose big");
769 return 0;
770 }
771 }
772
773
774 static int
775 cclass (char *aset, int ac, int af)
776 {
777 register int n;
778 register char c,
779 *set;
780
781 set = aset;
782 if ((c = ac) == 0)
783 return (0);
784
785 n = *set++;
786 while (--n)
787 if (*set++ == c)
788 return (af);
789
790 return (!af);
791 }
792
793
794 static int
795 tcompile (char *ap, struct tws *tb, int isafter)
796 {
797 register struct tws *tw;
798
799 if ((tw = tws_parse (ap, isafter)) == NULL)
800 return 0;
801
802 twscopy (tb, tw);
803 return 1;
804 }
805
806
807 static struct tws *
808 tws_parse (char *ap, int isafter)
809 {
810 char buffer[BUFSIZ];
811 register struct tws *tw, *ts;
812
813 if ((tw = tws_special (ap)) != NULL) {
814 tw->tw_sec = tw->tw_min = isafter ? 59 : 0;
815 tw->tw_hour = isafter ? 23 : 0;
816 return tw;
817 }
818 if ((tw = dparsetime (ap)) != NULL)
819 return tw;
820
821 if ((ts = dlocaltimenow ()) == NULL)
822 return NULL;
823
824 snprintf (buffer, sizeof(buffer), "%s %s", ap, dtwszone (ts));
825 if ((tw = dparsetime (buffer)) != NULL)
826 return tw;
827
828 snprintf (buffer, sizeof(buffer), "%s %02d:%02d:%02d %s", ap,
829 ts->tw_hour, ts->tw_min, ts->tw_sec, dtwszone (ts));
830 if ((tw = dparsetime (buffer)) != NULL)
831 return tw;
832
833 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s",
834 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year, ap);
835 if ((tw = dparsetime (buffer)) != NULL)
836 return tw;
837
838 snprintf (buffer, sizeof(buffer), "%02d %s %04d %s %s",
839 ts->tw_mday, tw_moty[ts->tw_mon], ts->tw_year,
840 ap, dtwszone (ts));
841 if ((tw = dparsetime (buffer)) != NULL)
842 return tw;
843
844 return NULL;
845 }
846
847
848 static struct tws *
849 tws_special (char *ap)
850 {
851 int i;
852 time_t clock;
853 register struct tws *tw;
854
855 time (&clock);
856 if (!strcasecmp (ap, "today"))
857 return dlocaltime (&clock);
858 if (!strcasecmp (ap, "yesterday")) {
859 clock -= (long) (60 * 60 * 24);
860 return dlocaltime (&clock);
861 }
862 if (!strcasecmp (ap, "tomorrow")) {
863 clock += (long) (60 * 60 * 24);
864 return dlocaltime (&clock);
865 }
866
867 for (i = 0; tw_ldotw[i]; i++)
868 if (!strcasecmp (ap, tw_ldotw[i]))
869 break;
870 if (tw_ldotw[i]) {
871 if ((tw = dlocaltime (&clock)) == NULL)
872 return NULL;
873 if ((i -= tw->tw_wday) > 0)
874 i -= 7;
875 }
876 else
877 if (*ap != '-')
878 return NULL;
879 else /* -ddd days ago */
880 i = atoi (ap); /* we should error check this */
881
882 clock += (long) ((60 * 60 * 24) * i);
883 return dlocaltime (&clock);
884 }
885
886
887 static int
888 TWSaction (params)
889 plist
890 {
891 int state;
892 register char *bp;
893 char buf[BUFSIZ], name[NAMESZ];
894 register struct tws *tw;
895
896 fseek (fp, start, SEEK_SET);
897 for (state = FLD, bp = NULL;;) {
898 switch (state = m_getfld (state, name, buf, sizeof buf, fp)) {
899 case FLD:
900 case FLDEOF:
901 case FLDPLUS:
902 if (bp != NULL)
903 free (bp), bp = NULL;
904 bp = add (buf, NULL);
905 while (state == FLDPLUS) {
906 state = m_getfld (state, name, buf, sizeof buf, fp);
907 bp = add (buf, bp);
908 }
909 if (!strcasecmp (name, n->n_datef))
910 break;
911 if (state != FLDEOF)
912 continue;
913
914 case BODY:
915 case BODYEOF:
916 case FILEEOF:
917 case LENERR:
918 case FMTERR:
919 if (state == LENERR || state == FMTERR)
920 advise (NULL, "format error in message %d", msgnum);
921 if (bp != NULL)
922 free (bp);
923 return 0;
924
925 default:
926 adios (NULL, "internal error -- you lose");
927 }
928 break;
929 }
930
931 if ((tw = dparsetime (bp)) == NULL)
932 advise (NULL, "unable to parse %s field in message %d, matching...",
933 n->n_datef, msgnum), state = 1;
934 else
935 state = n->n_after ? (twsort (tw, &n->n_tws) > 0)
936 : (twsort (tw, &n->n_tws) < 0);
937
938 if (bp != NULL)
939 free (bp);
940 return state;
941 }