]> rtime.felk.cvut.cz Git - l4.git/blob - l4/pkg/l4re-core/uclibc/lib/contrib/uclibc/test/regex/testregex.c
Update
[l4.git] / l4 / pkg / l4re-core / uclibc / lib / contrib / uclibc / test / regex / testregex.c
1 /*
2  * regex(3) test harness
3  *
4  * build:       cc -o testregex testregex.c
5  * help:        testregex --man
6  * note:        REG_* features are detected by #ifdef; if REG_* are enums
7  *              then supply #define REG_foo REG_foo for each enum REG_foo
8  *
9  *      Glenn Fowler <gsf@research.att.com>
10  *      AT&T Labs Research
11  *
12  * PLEASE: publish your tests so everyone can benefit
13  *
14  * Permission is hereby granted, free of charge, to any person obtaining a
15  * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
16  * without restriction, including without limitation the rights to use,
17  * copy, modify, merge, publish, distribute, and/or sell copies of the
18  * Software, and to permit persons to whom the Software is furnished to do
19  * so, subject to the following disclaimer:
20  *
21  * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
22  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24  * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2005-05-20 $\0\n";
34
35 #if _PACKAGE_ast
36 #include <ast.h>
37 #else
38 #include <sys/types.h>
39 #endif
40
41 #include <stdio.h>
42 #include <regex.h>
43 #include <ctype.h>
44 #include <setjmp.h>
45 #include <signal.h>
46 #include <string.h>
47 #include <unistd.h>
48
49 #ifdef  __STDC__
50 #include <stdlib.h>
51 #include <locale.h>
52 #endif
53
54 #if !_PACKAGE_ast
55 #undef  REG_DISCIPLINE
56 #endif
57
58 #ifndef REG_DELIMITED
59 #undef  _REG_subcomp
60 #endif
61
62 #define TEST_ARE                0x00000001
63 #define TEST_BRE                0x00000002
64 #define TEST_ERE                0x00000004
65 #define TEST_KRE                0x00000008
66 #define TEST_LRE                0x00000010
67 #define TEST_SRE                0x00000020
68
69 #define TEST_EXPAND             0x00000040
70 #define TEST_LENIENT            0x00000080
71
72 #define TEST_QUERY              0x00000100
73 #define TEST_SUB                0x00000200
74 #define TEST_UNSPECIFIED        0x00000400
75 #define TEST_VERIFY             0x00000800
76 #define TEST_AND                0x00001000
77 #define TEST_OR                 0x00002000
78
79 #define TEST_DELIMIT            0x00010000
80 #define TEST_OK                 0x00020000
81 #define TEST_SAME               0x00040000
82
83 #define TEST_ACTUAL             0x00100000
84 #define TEST_BASELINE           0x00200000
85 #define TEST_FAIL               0x00400000
86 #define TEST_PASS               0x00800000
87 #define TEST_SUMMARY            0x01000000
88
89 #define TEST_IGNORE_ERROR       0x02000000
90 #define TEST_IGNORE_OVER        0x04000000
91 #define TEST_IGNORE_POSITION    0x08000000
92
93 #define TEST_CATCH              0x10000000
94 #define TEST_VERBOSE            0x20000000
95
96 #define TEST_GLOBAL             (TEST_ACTUAL|TEST_AND|TEST_BASELINE|TEST_CATCH|TEST_FAIL|TEST_IGNORE_ERROR|TEST_IGNORE_OVER|TEST_IGNORE_POSITION|TEST_OR|TEST_PASS|TEST_SUMMARY|TEST_VERBOSE)
97
98 #ifdef REG_DISCIPLINE
99
100
101 #include <stk.h>
102
103 typedef struct Disc_s
104 {
105         regdisc_t       disc;
106         int             ordinal;
107         Sfio_t*         sp;
108 } Disc_t;
109
110 static void*
111 compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc)
112 {
113         Disc_t*         dp = (Disc_t*)disc;
114
115         return (void*)++dp->ordinal;
116 }
117
118 static int
119 execf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc)
120 {
121         Disc_t*         dp = (Disc_t*)disc;
122
123         sfprintf(dp->sp, "{%-.*s}(%d:%d)", xlen, xstr, (int)data, slen);
124         return atoi(xstr);
125 }
126
127 static void*
128 resizef(void* handle, void* data, size_t size)
129 {
130         if (!size)
131                 return 0;
132         return stkalloc((Sfio_t*)handle, size);
133 }
134
135 #endif
136
137 #ifndef NiL
138 #ifdef  __STDC__
139 #define NiL             0
140 #else
141 #define NiL             (char*)0
142 #endif
143 #endif
144
145 #define H(x)            do{if(html)fprintf(stderr,x);}while(0)
146 #define T(x)            fprintf(stderr,x)
147
148 static void
149 help(int html)
150 {
151 H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");
152 H("<HTML>\n");
153 H("<HEAD>\n");
154 H("<TITLE>testregex man document</TITLE>\n");
155 H("</HEAD>\n");
156 H("<BODY bgcolor=white>\n");
157 H("<PRE>\n");
158 T("NAME\n");
159 T("  testregex - regex(3) test harness\n");
160 T("\n");
161 T("SYNOPSIS\n");
162 T("  testregex [ options ]\n");
163 T("\n");
164 T("DESCRIPTION\n");
165 T("  testregex reads regex(3) test specifications, one per line, from the\n");
166 T("  standard input and writes one output line for each failed test. A\n");
167 T("  summary line is written after all tests are done. Each successful\n");
168 T("  test is run again with REG_NOSUB. Unsupported features are noted\n");
169 T("  before the first test, and tests requiring these features are\n");
170 T("  silently ignored.\n");
171 T("\n");
172 T("OPTIONS\n");
173 T("  -c catch signals and non-terminating calls\n");
174 T("  -e ignore error return mismatches\n");
175 T("  -h list help on standard error\n");
176 T("  -n do not repeat successful tests with regnexec()\n");
177 T("  -o ignore match[] overrun errors\n");
178 T("  -p ignore negative position mismatches\n");
179 T("  -s use stack instead of malloc\n");
180 T("  -x do not repeat successful tests with REG_NOSUB\n");
181 T("  -v list each test line\n");
182 T("  -A list failed test lines with actual answers\n");
183 T("  -B list all test lines with actual answers\n");
184 T("  -F list failed test lines\n");
185 T("  -P list passed test lines\n");
186 T("  -S output one summary line\n");
187 T("\n");
188 T("INPUT FORMAT\n");
189 T("  Input lines may be blank, a comment beginning with #, or a test\n");
190 T("  specification. A specification is five fields separated by one\n");
191 T("  or more tabs. NULL denotes the empty string and NIL denotes the\n");
192 T("  0 pointer.\n");
193 T("\n");
194 T("  Field 1: the regex(3) flags to apply, one character per REG_feature\n");
195 T("  flag. The test is skipped if REG_feature is not supported by the\n");
196 T("  implementation. If the first character is not [BEASKL] then the\n");
197 T("  specification is a global control line. One or more of [BEASKL] may be\n");
198 T("  specified; the test will be repeated for each mode.\n");
199 T("\n");
200 T("    B        basic                   BRE     (grep, ed, sed)\n");
201 T("    E        REG_EXTENDED            ERE     (egrep)\n");
202 T("    A        REG_AUGMENTED           ARE     (egrep with negation)\n");
203 T("    S        REG_SHELL               SRE     (sh glob)\n");
204 T("    K        REG_SHELL|REG_AUGMENTED KRE     (ksh glob)\n");
205 T("    L        REG_LITERAL             LRE     (fgrep)\n");
206 T("\n");
207 T("    a        REG_LEFT|REG_RIGHT      implicit ^...$\n");
208 T("    b        REG_NOTBOL              lhs does not match ^\n");
209 T("    c        REG_COMMENT             ignore space and #...\\n\n");
210 T("    d        REG_SHELL_DOT           explicit leading . match\n");
211 T("    e        REG_NOTEOL              rhs does not match $\n");
212 T("    f        REG_MULTIPLE            multiple \\n separated patterns\n");
213 T("    g        FNM_LEADING_DIR         testfnmatch only -- match until /\n");
214 T("    h        REG_MULTIREF            multiple digit backref\n");
215 T("    i        REG_ICASE               ignore case\n");
216 T("    j        REG_SPAN                . matches \\n\n");
217 T("    k        REG_ESCAPE              \\ to ecape [...] delimiter\n");
218 T("    l        REG_LEFT                implicit ^...\n");
219 T("    m        REG_MINIMAL             minimal match\n");
220 T("    n        REG_NEWLINE             explicit \\n match\n");
221 T("    o        REG_ENCLOSED            (|&) magic inside [@|&](...)\n");
222 T("    p        REG_SHELL_PATH          explicit / match\n");
223 T("    q        REG_DELIMITED           delimited pattern\n");
224 T("    r        REG_RIGHT               implicit ...$\n");
225 T("    s        REG_SHELL_ESCAPED       \\ not special\n");
226 T("    t        REG_MUSTDELIM           all delimiters must be specified\n");
227 T("    u        standard unspecified behavior -- errors not counted\n");
228 T("    w        REG_NOSUB               no subexpression match array\n");
229 T("    x        REG_LENIENT             let some errors slide\n");
230 T("    y        REG_LEFT                regexec() implicit ^...\n");
231 T("    z        REG_NULL                NULL subexpressions ok\n");
232 T("    $                                expand C \\c escapes in fields 2 and 3\n");
233 T("    /                                field 2 is a regsubcomp() expression\n");
234 T("\n");
235 T("  Field 1 control lines:\n");
236 T("\n");
237 T("    C                set LC_COLLATE and LC_CTYPE to locale in field 2\n");
238 T("\n");
239 T("    ?test ...        output field 5 if passed and != EXPECTED, silent otherwise\n");
240 T("    &test ...        output field 5 if current and previous passed\n");
241 T("    |test ...        output field 5 if current passed and previous failed\n");
242 T("    ; ...    output field 2 if previous failed\n");
243 T("    {test ...        skip if failed until }\n");
244 T("    }                end of skip\n");
245 T("\n");
246 T("    : comment                comment copied as output NOTE\n");
247 T("    :comment:test    :comment: ignored\n");
248 T("    N[OTE] comment   comment copied as output NOTE\n");
249 T("    T[EST] comment   comment\n");
250 T("\n");
251 T("    number           use number for nmatch (20 by default)\n");
252 T("\n");
253 T("  Field 2: the regular expression pattern; SAME uses the pattern from\n");
254 T("    the previous specification.\n");
255 T("\n");
256 T("  Field 3: the string to match.\n");
257 T("\n");
258 T("  Field 4: the test outcome. This is either one of the posix error\n");
259 T("    codes (with REG_ omitted) or the match array, a list of (m,n)\n");
260 T("    entries with m and n being first and last+1 positions in the\n");
261 T("    field 3 string, or NULL if REG_NOSUB is in effect and success\n");
262 T("    is expected. BADPAT is acceptable in place of any regcomp(3)\n");
263 T("    error code. The match[] array is initialized to (-2,-2) before\n");
264 T("    each test. All array elements from 0 to nmatch-1 must be specified\n");
265 T("    in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");
266 T("    Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");
267 T("    matched (?{...}) expression, where x is the text enclosed by {...},\n");
268 T("    o is the expression ordinal counting from 1, and n is the length of\n");
269 T("    the unmatched portion of the subject string. If x starts with a\n");
270 T("    number then that is the return value of re_execf(), otherwise 0 is\n");
271 T("    returned.\n");
272 T("\n");
273 T("  Field 5: optional comment appended to the report.\n");
274 T("\n");
275 T("CAVEAT\n");
276 T("    If a regex implementation misbehaves with memory then all bets are off.\n");
277 T("\n");
278 T("CONTRIBUTORS\n");
279 T("  Glenn Fowler    gsf@research.att.com        (ksh strmatch, regex extensions)\n");
280 T("  David Korn      dgk@research.att.com        (ksh glob matcher)\n");
281 T("  Doug McIlroy    mcilroy@dartmouth.edu       (ast regex/testre in C++)\n");
282 T("  Tom Lord        lord@regexps.com            (rx tests)\n");
283 T("  Henry Spencer   henry@zoo.toronto.edu       (original public regex)\n");
284 T("  Andrew Hume     andrew@research.att.com     (gre tests)\n");
285 T("  John Maddock    John_Maddock@compuserve.com (regex++ tests)\n");
286 T("  Philip Hazel    ph10@cam.ac.uk              (pcre tests)\n");
287 T("  Ville Laurikari vl@iki.fi                   (libtre tests)\n");
288 H("</PRE>\n");
289 H("</BODY>\n");
290 H("</HTML>\n");
291 }
292
293 #ifndef elementsof
294 #define elementsof(x)   (sizeof(x)/sizeof(x[0]))
295 #endif
296
297 #ifndef streq
298 #define streq(a,b)      (*(a)==*(b)&&!strcmp(a,b))
299 #endif
300
301 #define HUNG            5
302 #define NOTEST          (~0)
303
304 #ifndef REG_TEST_DEFAULT
305 #define REG_TEST_DEFAULT        0
306 #endif
307
308 #ifndef REG_EXEC_DEFAULT
309 #define REG_EXEC_DEFAULT        0
310 #endif
311
312 static const char* unsupported[] =
313 {
314         "BASIC",
315 #ifndef REG_EXTENDED
316         "EXTENDED",
317 #endif
318 #ifndef REG_AUGMENTED
319         "AUGMENTED",
320 #endif
321 #ifndef REG_SHELL
322         "SHELL",
323 #endif
324
325 #ifndef REG_COMMENT
326         "COMMENT",
327 #endif
328 #ifndef REG_DELIMITED
329         "DELIMITED",
330 #endif
331 #ifndef REG_DISCIPLINE
332         "DISCIPLINE",
333 #endif
334 #ifndef REG_ESCAPE
335         "ESCAPE",
336 #endif
337 #ifndef REG_ICASE
338         "ICASE",
339 #endif
340 #ifndef REG_LEFT
341         "LEFT",
342 #endif
343 #ifndef REG_LENIENT
344         "LENIENT",
345 #endif
346 #ifndef REG_LITERAL
347         "LITERAL",
348 #endif
349 #ifndef REG_MINIMAL
350         "MINIMAL",
351 #endif
352 #ifndef REG_MULTIPLE
353         "MULTIPLE",
354 #endif
355 #ifndef REG_MULTIREF
356         "MULTIREF",
357 #endif
358 #ifndef REG_MUSTDELIM
359         "MUSTDELIM",
360 #endif
361 #ifndef REG_NEWLINE
362         "NEWLINE",
363 #endif
364 #ifndef REG_NOTBOL
365         "NOTBOL",
366 #endif
367 #ifndef REG_NOTEOL
368         "NOTEOL",
369 #endif
370 #ifndef REG_NULL
371         "NULL",
372 #endif
373 #ifndef REG_RIGHT
374         "RIGHT",
375 #endif
376 #ifndef REG_SHELL_DOT
377         "SHELL_DOT",
378 #endif
379 #ifndef REG_SHELL_ESCAPED
380         "SHELL_ESCAPED",
381 #endif
382 #ifndef REG_SHELL_GROUP
383         "SHELL_GROUP",
384 #endif
385 #ifndef REG_SHELL_PATH
386         "SHELL_PATH",
387 #endif
388 #ifndef REG_SPAN
389         "SPAN",
390 #endif
391 #if REG_NOSUB & REG_TEST_DEFAULT
392         "SUBMATCH",
393 #endif
394 #if !_REG_nexec
395         "regnexec",
396 #endif
397 #if !_REG_subcomp
398         "regsubcomp",
399 #endif
400         0
401 };
402
403 #ifndef REG_COMMENT
404 #define REG_COMMENT     NOTEST
405 #endif
406 #ifndef REG_DELIMITED
407 #define REG_DELIMITED   NOTEST
408 #endif
409 #ifndef REG_ESCAPE
410 #define REG_ESCAPE      NOTEST
411 #endif
412 #ifndef REG_ICASE
413 #define REG_ICASE       NOTEST
414 #endif
415 #ifndef REG_LEFT
416 #define REG_LEFT        NOTEST
417 #endif
418 #ifndef REG_LENIENT
419 #define REG_LENIENT     0
420 #endif
421 #ifndef REG_MINIMAL
422 #define REG_MINIMAL     NOTEST
423 #endif
424 #ifndef REG_MULTIPLE
425 #define REG_MULTIPLE    NOTEST
426 #endif
427 #ifndef REG_MULTIREF
428 #define REG_MULTIREF    NOTEST
429 #endif
430 #ifndef REG_MUSTDELIM
431 #define REG_MUSTDELIM   NOTEST
432 #endif
433 #ifndef REG_NEWLINE
434 #define REG_NEWLINE     NOTEST
435 #endif
436 #ifndef REG_NOTBOL
437 #define REG_NOTBOL      NOTEST
438 #endif
439 #ifndef REG_NOTEOL
440 #define REG_NOTEOL      NOTEST
441 #endif
442 #ifndef REG_NULL
443 #define REG_NULL        NOTEST
444 #endif
445 #ifndef REG_RIGHT
446 #define REG_RIGHT       NOTEST
447 #endif
448 #ifndef REG_SHELL_DOT
449 #define REG_SHELL_DOT   NOTEST
450 #endif
451 #ifndef REG_SHELL_ESCAPED
452 #define REG_SHELL_ESCAPED       NOTEST
453 #endif
454 #ifndef REG_SHELL_GROUP
455 #define REG_SHELL_GROUP NOTEST
456 #endif
457 #ifndef REG_SHELL_PATH
458 #define REG_SHELL_PATH  NOTEST
459 #endif
460 #ifndef REG_SPAN
461 #define REG_SPAN        NOTEST
462 #endif
463
464 #define REG_UNKNOWN     (-1)
465
466 #ifndef REG_ENEWLINE
467 #define REG_ENEWLINE    (REG_UNKNOWN-1)
468 #endif
469 #ifndef REG_ENULL
470 #ifndef REG_EMPTY
471 #define REG_ENULL       (REG_UNKNOWN-2)
472 #else
473 #define REG_ENULL       REG_EMPTY
474 #endif
475 #endif
476 #ifndef REG_ECOUNT
477 #define REG_ECOUNT      (REG_UNKNOWN-3)
478 #endif
479 #ifndef REG_BADESC
480 #define REG_BADESC      (REG_UNKNOWN-4)
481 #endif
482 #ifndef REG_EMEM
483 #define REG_EMEM        (REG_UNKNOWN-5)
484 #endif
485 #ifndef REG_EHUNG
486 #define REG_EHUNG       (REG_UNKNOWN-6)
487 #endif
488 #ifndef REG_EBUS
489 #define REG_EBUS        (REG_UNKNOWN-7)
490 #endif
491 #ifndef REG_EFAULT
492 #define REG_EFAULT      (REG_UNKNOWN-8)
493 #endif
494 #ifndef REG_EFLAGS
495 #define REG_EFLAGS      (REG_UNKNOWN-9)
496 #endif
497 #ifndef REG_EDELIM
498 #define REG_EDELIM      (REG_UNKNOWN-9)
499 #endif
500
501 static const struct { int code; char* name; } codes[] =
502 {
503         {REG_UNKNOWN,   "UNKNOWN"},
504         {REG_NOMATCH,   "NOMATCH"},
505         {REG_BADPAT,    "BADPAT"},
506         {REG_ECOLLATE,  "ECOLLATE"},
507         {REG_ECTYPE,    "ECTYPE"},
508         {REG_EESCAPE,   "EESCAPE"},
509         {REG_ESUBREG,   "ESUBREG"},
510         {REG_EBRACK,    "EBRACK"},
511         {REG_EPAREN,    "EPAREN"},
512         {REG_EBRACE,    "EBRACE"},
513         {REG_BADBR,     "BADBR"},
514         {REG_ERANGE,    "ERANGE"},
515         {REG_ESPACE,    "ESPACE"},
516         {REG_BADRPT,    "BADRPT"},
517         {REG_ENEWLINE,  "ENEWLINE"},
518         {REG_ENULL,     "ENULL"},
519         {REG_ECOUNT,    "ECOUNT"},
520         {REG_BADESC,    "BADESC"},
521         {REG_EMEM,      "EMEM"},
522         {REG_EHUNG,     "EHUNG"},
523         {REG_EBUS,      "EBUS"},
524         {REG_EFAULT,    "EFAULT"},
525         {REG_EFLAGS,    "EFLAGS"},
526         {REG_EDELIM,    "EDELIM"},
527 };
528
529 static struct
530 {
531         regmatch_t      NOMATCH;
532         int             errors;
533         int             extracted;
534         int             ignored;
535         int             lineno;
536         int             passed;
537         int             signals;
538         int             unspecified;
539         int             verify;
540         int             warnings;
541         char*           file;
542         char*           stack;
543         char*           which;
544         jmp_buf         gotcha;
545 #ifdef REG_DISCIPLINE
546         Disc_t          disc;
547 #endif
548 } state;
549
550 static void
551 quote(char* s, int len, unsigned long test)
552 {
553         unsigned char*  u = (unsigned char*)s;
554         unsigned char*  e;
555         int             c;
556
557         if (!u)
558                 printf("NIL");
559         else if (!*u && len <= 1)
560                 printf("NULL");
561         else if (test & TEST_EXPAND)
562         {
563                 if (len < 0)
564                         len = strlen((char*)u);
565                 e = u + len;
566                 if (test & TEST_DELIMIT)
567                         printf("\"");
568                 while (u < e)
569                         switch (c = *u++)
570                         {
571                         case '\\':
572                                 printf("\\\\");
573                                 break;
574                         case '"':
575                                 if (test & TEST_DELIMIT)
576                                         printf("\\\"");
577                                 else
578                                         printf("\"");
579                                 break;
580                         case '\a':
581                                 printf("\\a");
582                                 break;
583                         case '\b':
584                                 printf("\\b");
585                                 break;
586                         case 033:
587                                 printf("\\e");
588                                 break;
589                         case '\f':
590                                 printf("\\f");
591                                 break;
592                         case '\n':
593                                 printf("\\n");
594                                 break;
595                         case '\r':
596                                 printf("\\r");
597                                 break;
598                         case '\t':
599                                 printf("\\t");
600                                 break;
601                         case '\v':
602                                 printf("\\v");
603                                 break;
604                         default:
605                                 if (!iscntrl(c) && isprint(c))
606                                         putchar(c);
607                                 else
608                                         printf("\\x%02x", c);
609                                 break;
610                         }
611                 if (test & TEST_DELIMIT)
612                         printf("\"");
613         }
614         else
615                 printf("%s", s);
616 }
617
618 static void
619 report(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test)
620 {
621         if (state.file)
622                 printf("%s:", state.file);
623         printf("%d:", state.lineno);
624         if (re)
625         {
626                 printf(" ");
627                 quote(re, -1, test|TEST_DELIMIT);
628                 if (s)
629                 {
630                         printf(" versus ");
631                         quote(s, len, test|TEST_DELIMIT);
632                 }
633         }
634         if (test & TEST_UNSPECIFIED)
635         {
636                 state.unspecified++;
637                 printf(" unspecified behavior");
638         }
639         else
640                 state.errors++;
641         if (state.which)
642                 printf(" %s", state.which);
643         if (flags & REG_NOSUB)
644                 printf(" NOSUB");
645         if (fun)
646                 printf(" %s", fun);
647         if (comment[strlen(comment)-1] == '\n')
648                 printf(" %s", comment);
649         else
650         {
651                 printf(" %s: ", comment);
652                 if (msg)
653                         printf("%s: ", msg);
654         }
655 }
656
657 static void
658 error(regex_t* preg, int code)
659 {
660         char*   msg;
661         char    buf[256];
662
663         switch (code)
664         {
665         case REG_EBUS:
666                 msg = "bus error";
667                 break;
668         case REG_EFAULT:
669                 msg = "memory fault";
670                 break;
671         case REG_EHUNG:
672                 msg = "did not terminate";
673                 break;
674         default:
675                 regerror(code, preg, msg = buf, sizeof buf);
676                 break;
677         }
678         printf("%s\n", msg);
679 }
680
681 static void
682 bad(char* comment, char* re, char* s, int len, unsigned long test)
683 {
684         printf("bad test case ");
685         report(comment, NiL, re, s, len, NiL, 0, test);
686         exit(1);
687 }
688
689 static int
690 escape(char* s)
691 {
692         char*   b;
693         char*   t;
694         char*   q;
695         char*   e;
696         int     c;
697
698         for (b = t = s; (*t = *s); s++, t++)
699                 if (*s == '\\')
700                         switch (*++s)
701                         {
702                         case '\\':
703                                 break;
704                         case 'a':
705                                 *t = '\a';
706                                 break;
707                         case 'b':
708                                 *t = '\b';
709                                 break;
710                         case 'c':
711                                 if ((*t = *++s))
712                                         *t &= 037;
713                                 else
714                                         s--;
715                                 break;
716                         case 'e':
717                         case 'E':
718                                 *t = 033;
719                                 break;
720                         case 'f':
721                                 *t = '\f';
722                                 break;
723                         case 'n':
724                                 *t = '\n';
725                                 break;
726                         case 'r':
727                                 *t = '\r';
728                                 break;
729                         case 's':
730                                 *t = ' ';
731                                 break;
732                         case 't':
733                                 *t = '\t';
734                                 break;
735                         case 'v':
736                                 *t = '\v';
737                                 break;
738                         case 'u':
739                         case 'x':
740                                 c = 0;
741                                 q = c == 'u' ? (s + 5) : (char*)0;
742                                 e = s + 1;
743                                 while (!e || !q || s < q)
744                                 {
745                                         switch (*++s)
746                                         {
747                                         case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
748                                                 c = (c << 4) + *s - 'a' + 10;
749                                                 continue;
750                                         case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
751                                                 c = (c << 4) + *s - 'A' + 10;
752                                                 continue;
753                                         case '0': case '1': case '2': case '3': case '4':
754                                         case '5': case '6': case '7': case '8': case '9':
755                                                 c = (c << 4) + *s - '0';
756                                                 continue;
757                                         case '{':
758                                         case '[':
759                                                 if (s != e)
760                                                 {
761                                                         s--;
762                                                         break;
763                                                 }
764                                                 e = 0;
765                                                 continue;
766                                         case '}':
767                                         case ']':
768                                                 if (e)
769                                                         s--;
770                                                 break;
771                                         default:
772                                                 s--;
773                                                 break;
774                                         }
775                                         break;
776                                 }
777                                 *t = c;
778                                 break;
779                         case '0': case '1': case '2': case '3':
780                         case '4': case '5': case '6': case '7':
781                                 c = *s - '0';
782                                 q = s + 2;
783                                 while (s < q)
784                                 {
785                                         switch (*++s)
786                                         {
787                                         case '0': case '1': case '2': case '3':
788                                         case '4': case '5': case '6': case '7':
789                                                 c = (c << 3) + *s - '0';
790                                                 break;
791                                         default:
792                                                 q = --s;
793                                                 break;
794                                         }
795                                 }
796                                 *t = c;
797                                 break;
798                         default:
799                                 *(s + 1) = 0;
800                                 bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);
801                         }
802         return t - b;
803 }
804
805 static void
806 matchoffprint(int off)
807 {
808         switch (off)
809         {
810         case -2:
811                 printf("X");
812                 break;
813         case -1:
814                 printf("?");
815                 break;
816         default:
817                 printf("%d", off);
818                 break;
819         }
820 }
821
822 static void
823 matchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test)
824 {
825         int     i;
826
827         for (; nmatch > nsub + 1; nmatch--)
828                 if ((match[nmatch-1].rm_so != -1 || match[nmatch-1].rm_eo != -1) && (!(test & TEST_IGNORE_POSITION) || (match[nmatch-1].rm_so >= 0 && match[nmatch-1].rm_eo >= 0)))
829                         break;
830         for (i = 0; i < nmatch; i++)
831         {
832                 printf("(");
833                 matchoffprint(match[i].rm_so);
834                 printf(",");
835                 matchoffprint(match[i].rm_eo);
836                 printf(")");
837         }
838         if (!(test & (TEST_ACTUAL|TEST_BASELINE)))
839         {
840                 if (ans)
841                         printf(" expected: %s", ans);
842                 printf("\n");
843         }
844 }
845
846 static int
847 matchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test)
848 {
849         char*   p;
850         int     i;
851         int     m;
852         int     n;
853
854         if (streq(ans, "OK"))
855                 return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);
856         for (i = 0, p = ans; i < nmatch && *p; i++)
857         {
858                 if (*p == '{')
859                 {
860 #ifdef REG_DISCIPLINE
861                         char*   x;
862
863                         x = sfstruse(state.disc.sp);
864                         if (strcmp(p, x))
865                         {
866                                 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
867                                         return 0;
868                                 report("callout failed", NiL, re, s, len, NiL, flags, test);
869                                 quote(p, -1, test);
870                                 printf(" expected, ");
871                                 quote(x, -1, test);
872                                 printf(" returned\n");
873                         }
874 #endif
875                         break;
876                 }
877                 if (*p++ != '(')
878                         bad("improper answer\n", re, s, -1, test);
879                 if (*p == '?')
880                 {
881                         m = -1;
882                         p++;
883                 }
884                 else
885                         m = strtol(p, &p, 10);
886                 if (*p++ != ',')
887                         bad("improper answer\n", re, s, -1, test);
888                 if (*p == '?')
889                 {
890                         n = -1;
891                         p++;
892                 }
893                 else
894                         n = strtol(p, &p, 10);
895                 if (*p++ != ')')
896                         bad("improper answer\n", re, s, -1, test);
897                 if (m!=match[i].rm_so || n!=match[i].rm_eo)
898                 {
899                         if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
900                         {
901                                 report("failed: match was", NiL, re, s, len, NiL, flags, test);
902                                 matchprint(match, nmatch, nsub, ans, test);
903                         }
904                         return 0;
905                 }
906         }
907         for (; i < nmatch; i++)
908         {
909                 if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)
910                 {
911                         if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))
912                         {
913                                 if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))
914                                 {
915                                         state.ignored++;
916                                         return 0;
917                                 }
918                                 if (!(test & TEST_SUMMARY))
919                                 {
920                                         report("failed: match was", NiL, re, s, len, NiL, flags, test);
921                                         matchprint(match, nmatch, nsub, ans, test);
922                                 }
923                         }
924                         return 0;
925                 }
926         }
927         if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)
928         {
929                 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
930                 {
931                         report("failed: overran match array", NiL, re, s, len, NiL, flags, test);
932                         matchprint(match, nmatch + 1, nsub, NiL, test);
933                 }
934                 return 0;
935         }
936         return 1;
937 }
938
939 static void
940 sigunblock(int s)
941 {
942 #ifdef SIG_SETMASK
943         int             op;
944         sigset_t        mask;
945
946         sigemptyset(&mask);
947         if (s)
948         {
949                 sigaddset(&mask, s);
950                 op = SIG_UNBLOCK;
951         }
952         else op = SIG_SETMASK;
953         sigprocmask(op, &mask, NiL);
954 #else
955 #ifdef sigmask
956         sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
957 #endif
958 #endif
959 }
960
961 static void
962 gotcha(int sig)
963 {
964         int     ret;
965
966         signal(sig, gotcha);
967         alarm(0);
968         state.signals++;
969         switch (sig)
970         {
971         case SIGALRM:
972                 ret = REG_EHUNG;
973                 break;
974         case SIGBUS:
975                 ret = REG_EBUS;
976                 break;
977         default:
978                 ret = REG_EFAULT;
979                 break;
980         }
981         sigunblock(sig);
982         longjmp(state.gotcha, ret);
983 }
984
985 static char*
986 my_getline(FILE* fp)
987 {
988         static char     buf[32 * 1024];
989
990         register char*  s = buf;
991         register char*  e = &buf[sizeof(buf)];
992         register char*  b;
993
994         for (;;)
995         {
996                 if (!(b = fgets(s, e - s, fp)))
997                         return 0;
998                 state.lineno++;
999                 s += strlen(s);
1000                 if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
1001                 {
1002                         *s = 0;
1003                         break;
1004                 }
1005                 s--;
1006         }
1007         return buf;
1008 }
1009
1010 static unsigned long
1011 note(unsigned long level, char* msg, unsigned long skip, unsigned long test)
1012 {
1013         if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)
1014         {
1015                 printf("NOTE\t");
1016                 if (msg)
1017                         printf("%s: ", msg);
1018                 printf("skipping lines %d", state.lineno);
1019         }
1020         return skip | level;
1021 }
1022
1023 #define TABS(n)         &ts[7-((n)&7)]
1024
1025 static char             ts[] = "\t\t\t\t\t\t\t";
1026
1027 static unsigned long
1028 extract(int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
1029 {
1030         if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))
1031         {
1032                 state.extracted = 1;
1033                 if (test & TEST_OK)
1034                 {
1035                         state.passed++;
1036                         if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1037                         {
1038                                 if (msg && strcmp(msg, "EXPECTED"))
1039                                         printf("NOTE\t%s\n", msg);
1040                                 return skip;
1041                         }
1042                         test &= ~(TEST_PASS|TEST_QUERY);
1043                 }
1044                 if (test & (TEST_QUERY|TEST_VERIFY))
1045                 {
1046                         if (test & TEST_BASELINE)
1047                                 test &= ~(TEST_BASELINE|TEST_PASS);
1048                         else
1049                                 test |= TEST_PASS;
1050                         skip |= level;
1051                 }
1052                 if (!(test & TEST_OK))
1053                 {
1054                         if (test & TEST_UNSPECIFIED)
1055                                 state.unspecified++;
1056                         else
1057                                 state.errors++;
1058                 }
1059                 if (test & (TEST_PASS|TEST_SUMMARY))
1060                         return skip;
1061                 test &= ~TEST_DELIMIT;
1062                 printf("%s%s", spec, TABS(*tabs++));
1063                 if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))
1064                         printf("SAME");
1065                 else
1066                         quote(re, -1, test);
1067                 printf("%s", TABS(*tabs++));
1068                 quote(s, -1, test);
1069                 printf("%s", TABS(*tabs++));
1070                 if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || (!accept && !match))
1071                         printf("%s", ans);
1072                 else if (accept)
1073                         printf("%s", accept);
1074                 else
1075                         matchprint(match, nmatch, nsub, NiL, test);
1076                 if (msg)
1077                         printf("%s%s", TABS(*tabs++), msg);
1078                 putchar('\n');
1079         }
1080         else if (test & TEST_QUERY)
1081                 skip = note(level, msg, skip, test);
1082         else if (test & TEST_VERIFY)
1083                 state.extracted = 1;
1084         return skip;
1085 }
1086
1087 static int
1088 catchfree(regex_t* preg, int flags, int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
1089 {
1090         int     eret;
1091
1092         if (!(test & TEST_CATCH))
1093         {
1094                 regfree(preg);
1095                 eret = 0;
1096         }
1097         else if (!(eret = setjmp(state.gotcha)))
1098         {
1099                 alarm(HUNG);
1100                 regfree(preg);
1101                 alarm(0);
1102         }
1103         else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1104                 extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
1105         else
1106         {
1107                 report("failed", "regfree", re, NiL, -1, msg, flags, test);
1108                 error(preg, eret);
1109         }
1110         return eret;
1111 }
1112
1113 int
1114 old_main(int unused_param_argc, char** argv)
1115 {
1116         int             flags;
1117         int             cflags;
1118         int             eflags;
1119         int             nmatch;
1120         int             nexec;
1121         int             nstr;
1122         int             cret;
1123         int             eret;
1124         int             nsub;
1125         int             i;
1126         int             j;
1127         int             expected;
1128         int             got;
1129         int             locale;
1130         int             subunitlen = 0;
1131         int             testno;
1132         unsigned long   level;
1133         unsigned long   skip;
1134         char*           p;
1135         char*           line;
1136         char*           spec;
1137         char*           re;
1138         char*           s;
1139         char*           ans;
1140         char*           msg;
1141         char*           fun;
1142         char*           ppat = NULL;
1143         char*           subunit = NULL;
1144         char*           version;
1145         char*           field[6];
1146         char*           delim[6];
1147         FILE*           fp;
1148         int             tabs[6];
1149         char            unit[64];
1150         regmatch_t      match[100];
1151         regex_t         preg;
1152
1153         static char     pat[32 * 1024];
1154
1155         int             nonosub = REG_NOSUB == 0;
1156         int             nonexec = 0;
1157
1158         unsigned long   test = 0;
1159
1160         static char*    filter[] = { "-", 0 };
1161
1162         state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
1163         p = unit;
1164         version = (char*)id + 10;
1165         while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
1166                 p++;
1167         *p = 0;
1168         while ((p = *++argv) && *p == '-')
1169                 for (;;)
1170                 {
1171                         switch (*++p)
1172                         {
1173                         case 0:
1174                                 break;
1175                         case 'c':
1176                                 test |= TEST_CATCH;
1177                                 continue;
1178                         case 'e':
1179                                 test |= TEST_IGNORE_ERROR;
1180                                 continue;
1181                         case 'h':
1182                         case '?':
1183                                 help(0);
1184                                 return 2;
1185                         case '-':
1186                                 help(p[1] == 'h');
1187                                 return 2;
1188                         case 'n':
1189                                 nonexec = 1;
1190                                 continue;
1191                         case 'o':
1192                                 test |= TEST_IGNORE_OVER;
1193                                 continue;
1194                         case 'p':
1195                                 test |= TEST_IGNORE_POSITION;
1196                                 continue;
1197                         case 's':
1198 #ifdef REG_DISCIPLINE
1199                                 if (!(state.stack = stkalloc(stkstd, 0)))
1200                                         fprintf(stderr, "%s: out of space [stack]", unit);
1201                                 state.disc.disc.re_resizef = resizef;
1202                                 state.disc.disc.re_resizehandle = (void*)stkstd;
1203 #endif
1204                                 continue;
1205                         case 'x':
1206                                 nonosub = 1;
1207                                 continue;
1208                         case 'v':
1209                                 test |= TEST_VERBOSE;
1210                                 continue;
1211                         case 'A':
1212                                 test |= TEST_ACTUAL;
1213                                 continue;
1214                         case 'B':
1215                                 test |= TEST_BASELINE;
1216                                 continue;
1217                         case 'F':
1218                                 test |= TEST_FAIL;
1219                                 continue;
1220                         case 'P':
1221                                 test |= TEST_PASS;
1222                                 continue;
1223                         case 'S':
1224                                 test |= TEST_SUMMARY;
1225                                 continue;
1226                         default:
1227                                 fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
1228                                 return 2;
1229                         }
1230                         break;
1231                 }
1232         if (!*argv)
1233                 argv = filter;
1234         locale = 0;
1235         while ((state.file = *argv++))
1236         {
1237                 if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
1238                 {
1239                         state.file = 0;
1240                         fp = stdin;
1241                 }
1242                 else if (!(fp = fopen(state.file, "r")))
1243                 {
1244                         fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
1245                         return 2;
1246                 }
1247                 testno = state.errors = state.ignored = state.lineno = state.passed =
1248                 state.signals = state.unspecified = state.warnings = 0;
1249                 skip = 0;
1250                 level = 1;
1251                 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1252                 {
1253                         printf("TEST\t%s ", unit);
1254                         if ((s = state.file))
1255                         {
1256                                 subunit = p = 0;
1257                                 for (;;)
1258                                 {
1259                                         switch (*s++)
1260                                         {
1261                                         case 0:
1262                                                 break;
1263                                         case '/':
1264                                                 subunit = s;
1265                                                 continue;
1266                                         case '.':
1267                                                 p = s - 1;
1268                                                 continue;
1269                                         default:
1270                                                 continue;
1271                                         }
1272                                         break;
1273                                 }
1274                                 if (!subunit)
1275                                         subunit = state.file;
1276                                 if (p < subunit)
1277                                         p = s - 1;
1278                                 subunitlen = p - subunit;
1279                                 printf("%-.*s ", subunitlen, subunit);
1280                         }
1281                         else
1282                                 subunit = 0;
1283                         for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
1284                                 putchar(*s);
1285                         if (test & TEST_CATCH)
1286                                 printf(", catch");
1287                         if (test & TEST_IGNORE_ERROR)
1288                                 printf(", ignore error code mismatches");
1289                         if (test & TEST_IGNORE_POSITION)
1290                                 printf(", ignore negative position mismatches");
1291 #ifdef REG_DISCIPLINE
1292                         if (state.stack)
1293                                 printf(", stack");
1294 #endif
1295                         if (test & TEST_VERBOSE)
1296                                 printf(", verbose");
1297                         printf("\n");
1298 #ifdef REG_VERSIONID
1299                         if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
1300                                 s = pat;
1301                         else
1302 #endif
1303 #ifdef REG_TEST_VERSION
1304                         s = REG_TEST_VERSION;
1305 #else
1306                         s = "regex";
1307 #endif
1308                         printf("NOTE\t%s\n", s);
1309                         if (elementsof(unsupported) > 1)
1310                         {
1311 #if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
1312                                 i = 0;
1313 #else
1314                                 i = REG_EXTENDED != 0;
1315 #endif
1316                                 for (got = 0; i < elementsof(unsupported) - 1; i++)
1317                                 {
1318                                         if (!got)
1319                                         {
1320                                                 got = 1;
1321                                                 printf("NOTE\tunsupported: %s", unsupported[i]);
1322                                         }
1323                                         else
1324                                                 printf(",%s", unsupported[i]);
1325                                 }
1326                                 if (got)
1327                                         printf("\n");
1328                         }
1329                 }
1330 #ifdef REG_DISCIPLINE
1331                 state.disc.disc.re_version = REG_VERSION;
1332                 state.disc.disc.re_compf = compf;
1333                 state.disc.disc.re_execf = execf;
1334                 if (!(state.disc.sp = sfstropen()))
1335                         bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
1336                 preg.re_disc = &state.disc.disc;
1337 #endif
1338                 if (test & TEST_CATCH)
1339                 {
1340                         signal(SIGALRM, gotcha);
1341                         signal(SIGBUS, gotcha);
1342                         signal(SIGSEGV, gotcha);
1343                 }
1344                 while ((p = my_getline(fp)))
1345                 {
1346
1347                 /* parse: */
1348
1349                         line = p;
1350                         if (*p == ':' && !isspace(*(p + 1)))
1351                         {
1352                                 while (*++p && *p != ':');
1353                                 if (!*p++)
1354                                 {
1355                                         if (test & TEST_BASELINE)
1356                                                 printf("%s\n", line);
1357                                         continue;
1358                                 }
1359                         }
1360                         while (isspace(*p))
1361                                 p++;
1362                         if (*p == 0 || *p == '#' || *p == 'T')
1363                         {
1364                                 if (test & TEST_BASELINE)
1365                                         printf("%s\n", line);
1366                                 continue;
1367                         }
1368                         if (*p == ':' || *p == 'N')
1369                         {
1370                                 if (test & TEST_BASELINE)
1371                                         printf("%s\n", line);
1372                                 else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1373                                 {
1374                                         while (*++p && !isspace(*p));
1375                                         while (isspace(*p))
1376                                                 p++;
1377                                         printf("NOTE    %s\n", p);
1378                                 }
1379                                 continue;
1380                         }
1381                         j = 0;
1382                         i = 0;
1383                         field[i++] = p;
1384                         for (;;)
1385                         {
1386                                 switch (*p++)
1387                                 {
1388                                 case 0:
1389                                         p--;
1390                                         j = 0;
1391                                         goto checkfield;
1392                                 case '\t':
1393                                         *(delim[i] = p - 1) = 0;
1394                                         j = 1;
1395                                 checkfield:
1396                                         s = field[i - 1];
1397                                         if (streq(s, "NIL"))
1398                                                 field[i - 1] = 0;
1399                                         else if (streq(s, "NULL"))
1400                                                 *s = 0;
1401                                         while (*p == '\t')
1402                                         {
1403                                                 p++;
1404                                                 j++;
1405                                         }
1406                                         tabs[i - 1] = j;
1407                                         if (!*p)
1408                                                 break;
1409                                         if (i >= elementsof(field))
1410                                                 bad("too many fields\n", NiL, NiL, 0, 0);
1411                                         field[i++] = p;
1412                                         /*FALLTHROUGH*/
1413                                 default:
1414                                         continue;
1415                                 }
1416                                 break;
1417                         }
1418                         if (!(spec = field[0]))
1419                                 bad("NIL spec\n", NiL, NiL, 0, 0);
1420
1421                 /* interpret: */
1422
1423                         cflags = REG_TEST_DEFAULT;
1424                         eflags = REG_EXEC_DEFAULT;
1425                         test &= TEST_GLOBAL;
1426                         state.extracted = 0;
1427                         nmatch = 20;
1428                         nsub = -1;
1429                         for (p = spec; *p; p++)
1430                         {
1431                                 if (isdigit(*p))
1432                                 {
1433                                         nmatch = strtol(p, &p, 10);
1434                                         if (nmatch >= elementsof(match))
1435                                                 bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
1436                                         p--;
1437                                         continue;
1438                                 }
1439                                 switch (*p)
1440                                 {
1441                                 case 'A':
1442                                         test |= TEST_ARE;
1443                                         continue;
1444                                 case 'B':
1445                                         test |= TEST_BRE;
1446                                         continue;
1447                                 case 'C':
1448                                         if (!(test & TEST_QUERY) && !(skip & level))
1449                                                 bad("locale must be nested\n", NiL, NiL, 0, 0);
1450                                         test &= ~TEST_QUERY;
1451                                         if (locale)
1452                                                 bad("locale nesting not supported\n", NiL, NiL, 0, 0);
1453                                         if (i != 2)
1454                                                 bad("locale field expected\n", NiL, NiL, 0, 0);
1455                                         if (!(skip & level))
1456                                         {
1457 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1458                                                 s = field[1];
1459                                                 if (!s || streq(s, "POSIX"))
1460                                                         s = "C";
1461                                                 if (!(ans = setlocale(LC_COLLATE, s)) || streq(ans, "C") || streq(ans, "POSIX") || !(ans = setlocale(LC_CTYPE, s)) || streq(ans, "C") || streq(ans, "POSIX"))
1462                                                         skip = note(level, s, skip, test);
1463                                                 else
1464                                                 {
1465                                                         if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1466                                                                 printf("NOTE    \"%s\" locale\n", s);
1467                                                         locale = level;
1468                                                 }
1469 #else
1470                                                 skip = note(level, skip, test, "locales not supported");
1471 #endif
1472                                         }
1473                                         cflags = NOTEST;
1474                                         continue;
1475                                 case 'E':
1476                                         test |= TEST_ERE;
1477                                         continue;
1478                                 case 'K':
1479                                         test |= TEST_KRE;
1480                                         continue;
1481                                 case 'L':
1482                                         test |= TEST_LRE;
1483                                         continue;
1484                                 case 'S':
1485                                         test |= TEST_SRE;
1486                                         continue;
1487
1488                                 case 'a':
1489                                         cflags |= REG_LEFT|REG_RIGHT;
1490                                         continue;
1491                                 case 'b':
1492                                         eflags |= REG_NOTBOL;
1493                                         continue;
1494                                 case 'c':
1495                                         cflags |= REG_COMMENT;
1496                                         continue;
1497                                 case 'd':
1498                                         cflags |= REG_SHELL_DOT;
1499                                         continue;
1500                                 case 'e':
1501                                         eflags |= REG_NOTEOL;
1502                                         continue;
1503                                 case 'f':
1504                                         cflags |= REG_MULTIPLE;
1505                                         continue;
1506                                 case 'g':
1507                                         cflags |= NOTEST;
1508                                         continue;
1509                                 case 'h':
1510                                         cflags |= REG_MULTIREF;
1511                                         continue;
1512                                 case 'i':
1513                                         cflags |= REG_ICASE;
1514                                         continue;
1515                                 case 'j':
1516                                         cflags |= REG_SPAN;
1517                                         continue;
1518                                 case 'k':
1519                                         cflags |= REG_ESCAPE;
1520                                         continue;
1521                                 case 'l':
1522                                         cflags |= REG_LEFT;
1523                                         continue;
1524                                 case 'm':
1525                                         cflags |= REG_MINIMAL;
1526                                         continue;
1527                                 case 'n':
1528                                         cflags |= REG_NEWLINE;
1529                                         continue;
1530                                 case 'o':
1531                                         cflags |= REG_SHELL_GROUP;
1532                                         continue;
1533                                 case 'p':
1534                                         cflags |= REG_SHELL_PATH;
1535                                         continue;
1536                                 case 'q':
1537                                         cflags |= REG_DELIMITED;
1538                                         continue;
1539                                 case 'r':
1540                                         cflags |= REG_RIGHT;
1541                                         continue;
1542                                 case 's':
1543                                         cflags |= REG_SHELL_ESCAPED;
1544                                         continue;
1545                                 case 't':
1546                                         cflags |= REG_MUSTDELIM;
1547                                         continue;
1548                                 case 'u':
1549                                         test |= TEST_UNSPECIFIED;
1550                                         continue;
1551                                 case 'w':
1552                                         cflags |= REG_NOSUB;
1553                                         continue;
1554                                 case 'x':
1555                                         if (REG_LENIENT)
1556                                                 cflags |= REG_LENIENT;
1557                                         else
1558                                                 test |= TEST_LENIENT;
1559                                         continue;
1560                                 case 'y':
1561                                         eflags |= REG_LEFT;
1562                                         continue;
1563                                 case 'z':
1564                                         cflags |= REG_NULL;
1565                                         continue;
1566
1567                                 case '$':
1568                                         test |= TEST_EXPAND;
1569                                         continue;
1570
1571                                 case '/':
1572                                         test |= TEST_SUB;
1573                                         continue;
1574
1575                                 case '?':
1576                                         test |= TEST_VERIFY;
1577                                         test &= ~(TEST_AND|TEST_OR);
1578                                         state.verify = state.passed;
1579                                         continue;
1580                                 case '&':
1581                                         test |= TEST_VERIFY|TEST_AND;
1582                                         test &= ~TEST_OR;
1583                                         continue;
1584                                 case '|':
1585                                         test |= TEST_VERIFY|TEST_OR;
1586                                         test &= ~TEST_AND;
1587                                         continue;
1588                                 case ';':
1589                                         test |= TEST_OR;
1590                                         test &= ~TEST_AND;
1591                                         continue;
1592
1593                                 case '{':
1594                                         level <<= 1;
1595                                         if (skip & (level >> 1))
1596                                         {
1597                                                 skip |= level;
1598                                                 cflags = NOTEST;
1599                                         }
1600                                         else
1601                                         {
1602                                                 skip &= ~level;
1603                                                 test |= TEST_QUERY;
1604                                         }
1605                                         continue;
1606                                 case '}':
1607                                         if (level == 1)
1608                                                 bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
1609                                         if ((skip & level) && !(skip & (level>>1)))
1610                                         {
1611                                                 if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
1612                                                 {
1613                                                         if (test & (TEST_ACTUAL|TEST_FAIL))
1614                                                                 printf("}\n");
1615                                                         else if (!(test & TEST_PASS))
1616                                                                 printf("-%d\n", state.lineno);
1617                                                 }
1618                                         }
1619 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1620                                         else if (locale & level)
1621                                         {
1622                                                 locale = 0;
1623                                                 if (!(skip & level))
1624                                                 {
1625                                                         s = "C";
1626                                                         setlocale(LC_COLLATE, s);
1627                                                         setlocale(LC_CTYPE, s);
1628                                                         if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1629                                                                 printf("NOTE    \"%s\" locale\n", s);
1630                                                         else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
1631                                                                 printf("}\n");
1632                                                 }
1633                                                 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
1634                                                         printf("}\n");
1635                                         }
1636 #endif
1637                                         level >>= 1;
1638                                         cflags = NOTEST;
1639                                         continue;
1640
1641                                 default:
1642                                         bad("bad spec\n", spec, NiL, 0, test);
1643                                         break;
1644
1645                                 }
1646                                 break;
1647                         }
1648                         if ((cflags|eflags) == NOTEST || ((skip & level) && (test & TEST_BASELINE)))
1649                         {
1650                                 if (test & TEST_BASELINE)
1651                                 {
1652                                         while (i > 1)
1653                                                 *delim[--i] = '\t';
1654                                         printf("%s\n", line);
1655                                 }
1656                                 continue;
1657                         }
1658                         if (test & TEST_OR)
1659                         {
1660                                 if (!(test & TEST_VERIFY))
1661                                 {
1662                                         test &= ~TEST_OR;
1663                                         if (state.passed == state.verify && i > 1)
1664                                                 printf("NOTE\t%s\n", field[1]);
1665                                         continue;
1666                                 }
1667                                 else if (state.passed > state.verify)
1668                                         continue;
1669                         }
1670                         else if (test & TEST_AND)
1671                         {
1672                                 if (state.passed == state.verify)
1673                                         continue;
1674                                 state.passed = state.verify;
1675                         }
1676                         if (i < 4)
1677                                 bad("too few fields\n", NiL, NiL, 0, test);
1678                         while (i < elementsof(field))
1679                                 field[i++] = 0;
1680                         if ((re = field[1]))
1681                         {
1682                                 if (streq(re, "SAME"))
1683                                 {
1684                                         re = ppat;
1685                                         test |= TEST_SAME;
1686                                 }
1687                                 else
1688                                 {
1689                                         if (test & TEST_EXPAND)
1690                                                 escape(re);
1691                                         strcpy(ppat = pat, re);
1692                                 }
1693                         }
1694                         else
1695                                 ppat = 0;
1696                         nstr = -1;
1697                         if ((s = field[2]) && (test & TEST_EXPAND))
1698                         {
1699                                 nstr = escape(s);
1700 #if _REG_nexec
1701                                 if (nstr != strlen(s))
1702                                         nexec = nstr;
1703 #endif
1704                         }
1705                         if (!(ans = field[3]))
1706                                 bad("NIL answer\n", NiL, NiL, 0, test);
1707                         msg = field[4];
1708                         fflush(stdout);
1709                         if (test & TEST_SUB)
1710 #if _REG_subcomp
1711                                 cflags |= REG_DELIMITED;
1712 #else
1713                                 continue;
1714 #endif
1715
1716                 compile:
1717
1718                         if (state.extracted || (skip & level))
1719                                 continue;
1720 #if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
1721 #ifdef REG_EXTENDED
1722                         if (REG_EXTENDED != 0 && (test & TEST_BRE))
1723 #else
1724                         if (test & TEST_BRE)
1725 #endif
1726                         {
1727                                 test &= ~TEST_BRE;
1728                                 flags = cflags;
1729                                 state.which = "BRE";
1730                         }
1731                         else
1732 #endif
1733 #ifdef REG_EXTENDED
1734                         if (test & TEST_ERE)
1735                         {
1736                                 test &= ~TEST_ERE;
1737                                 flags = cflags | REG_EXTENDED;
1738                                 state.which = "ERE";
1739                         }
1740                         else
1741 #endif
1742 #ifdef REG_AUGMENTED
1743                         if (test & TEST_ARE)
1744                         {
1745                                 test &= ~TEST_ARE;
1746                                 flags = cflags | REG_AUGMENTED;
1747                                 state.which = "ARE";
1748                         }
1749                         else
1750 #endif
1751 #ifdef REG_LITERAL
1752                         if (test & TEST_LRE)
1753                         {
1754                                 test &= ~TEST_LRE;
1755                                 flags = cflags | REG_LITERAL;
1756                                 state.which = "LRE";
1757                         }
1758                         else
1759 #endif
1760 #ifdef REG_SHELL
1761                         if (test & TEST_SRE)
1762                         {
1763                                 test &= ~TEST_SRE;
1764                                 flags = cflags | REG_SHELL;
1765                                 state.which = "SRE";
1766                         }
1767                         else
1768 #ifdef REG_AUGMENTED
1769                         if (test & TEST_KRE)
1770                         {
1771                                 test &= ~TEST_KRE;
1772                                 flags = cflags | REG_SHELL | REG_AUGMENTED;
1773                                 state.which = "KRE";
1774                         }
1775                         else
1776 #endif
1777 #endif
1778                         {
1779                                 if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
1780                                         extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
1781                                 continue;
1782                         }
1783                         if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
1784                         {
1785                                 printf("test %-3d %s ", state.lineno, state.which);
1786                                 quote(re, -1, test|TEST_DELIMIT);
1787                                 printf(" ");
1788                                 quote(s, nstr, test|TEST_DELIMIT);
1789                                 printf("\n");
1790                         }
1791
1792                 nosub:
1793                         fun = "regcomp";
1794 #if _REG_nexec
1795                         if (nstr >= 0 && nstr != strlen(s))
1796                                 nexec = nstr;
1797
1798                         else
1799 #endif
1800                                 nexec = -1;
1801                         if (state.extracted || (skip & level))
1802                                 continue;
1803                         if (!(test & TEST_QUERY))
1804                                 testno++;
1805 #ifdef REG_DISCIPLINE
1806                         if (state.stack)
1807                                 stkset(stkstd, state.stack, 0);
1808                         flags |= REG_DISCIPLINE;
1809                         state.disc.ordinal = 0;
1810                         sfstrseek(state.disc.sp, 0, SEEK_SET);
1811 #endif
1812                         if (!(test & TEST_CATCH))
1813                                 cret = regcomp(&preg, re, flags);
1814                         else if (!(cret = setjmp(state.gotcha)))
1815                         {
1816                                 alarm(HUNG);
1817                                 cret = regcomp(&preg, re, flags);
1818                                 alarm(0);
1819                         }
1820 #if _REG_subcomp
1821                         if (!cret && (test & TEST_SUB))
1822                         {
1823                                 fun = "regsubcomp";
1824                                 p = re + preg.re_npat;
1825                                 if (!(test & TEST_CATCH))
1826                                         cret = regsubcomp(&preg, p, NiL, 0, 0);
1827                                 else if (!(cret = setjmp(state.gotcha)))
1828                                 {
1829                                         alarm(HUNG);
1830                                         cret = regsubcomp(&preg, p, NiL, 0, 0);
1831                                         alarm(0);
1832                                 }
1833                                 if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
1834                                 {
1835                                         if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
1836                                                 continue;
1837                                         cret = REG_EFLAGS;
1838                                 }
1839                         }
1840 #endif
1841                         if (!cret)
1842                         {
1843                                 if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
1844                                 {
1845                                         for (p = ans; *p; p++)
1846                                                 if (*p == '(')
1847                                                         nsub++;
1848                                                 else if (*p == '{')
1849                                                         nsub--;
1850                                         if (nsub >= 0)
1851                                         {
1852                                                 if (test & TEST_IGNORE_OVER)
1853                                                 {
1854                                                         if (nmatch > nsub)
1855                                                                 nmatch = nsub + 1;
1856                                                 }
1857                                                 else if (nsub != preg.re_nsub)
1858                                                 {
1859                                                         if (nsub > preg.re_nsub)
1860                                                         {
1861                                                                 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1862                                                                         skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1863                                                                 else
1864                                                                 {
1865                                                                         report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
1866                                                                         printf("at least %d expected, %zd returned\n", nsub, preg.re_nsub);
1867                                                                         state.errors++;
1868                                                                 }
1869                                                         }
1870                                                         else
1871                                                                 nsub = preg.re_nsub;
1872                                                 }
1873                                         }
1874                                 }
1875                                 if (!(test & TEST_SUB) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
1876                                 {
1877                                         if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1878                                                 skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1879                                         else if (!(test & TEST_LENIENT))
1880                                         {
1881                                                 report("failed", fun, re, NiL, -1, msg, flags, test);
1882                                                 printf("%s expected, OK returned\n", ans);
1883                                         }
1884                                         catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
1885                                         continue;
1886                                 }
1887                         }
1888                         else
1889                         {
1890                                 if (test & TEST_LENIENT)
1891                                         /* we'll let it go this time */;
1892                                 else if (!*ans || ans[0]=='(' || (cret == REG_BADPAT && streq(ans, "NOMATCH")))
1893                                 {
1894                                         got = 0;
1895                                         for (i = 1; i < elementsof(codes); i++)
1896                                                 if (cret==codes[i].code)
1897                                                         got = i;
1898                                         if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1899                                                 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1900                                         else
1901                                         {
1902                                                 report("failed", fun, re, NiL, -1, msg, flags, test);
1903                                                 printf("%s returned: ", codes[got].name);
1904                                                 error(&preg, cret);
1905                                         }
1906                                 }
1907                                 else
1908                                 {
1909                                         expected = got = 0;
1910                                         for (i = 1; i < elementsof(codes); i++)
1911                                         {
1912                                                 if (streq(ans, codes[i].name))
1913                                                         expected = i;
1914                                                 if (cret==codes[i].code)
1915                                                         got = i;
1916                                         }
1917                                         if (!expected)
1918                                         {
1919                                                 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1920                                                         skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1921                                                 else
1922                                                 {
1923                                                         report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
1924                                                         printf("%s expected, %s returned\n", ans, codes[got].name);
1925                                                 }
1926                                         }
1927                                         else if (cret != codes[expected].code && cret != REG_BADPAT)
1928                                         {
1929                                                 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1930                                                         skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1931                                                 else if (test & TEST_IGNORE_ERROR)
1932                                                         state.ignored++;
1933                                                 else
1934                                                 {
1935                                                         report("should fail and did", fun, re, NiL, -1, msg, flags, test);
1936                                                         printf("%s expected, %s returned: ", ans, codes[got].name);
1937                                                         state.errors--;
1938                                                         state.warnings++;
1939                                                         error(&preg, cret);
1940                                                 }
1941                                         }
1942                                 }
1943                                 goto compile;
1944                         }
1945
1946 #if _REG_nexec
1947                 execute:
1948                         if (nexec >= 0)
1949                                 fun = "regnexec";
1950                         else
1951 #endif
1952                                 fun = "regexec";
1953
1954                         for (i = 0; i < elementsof(match); i++)
1955                                 match[i] = state.NOMATCH;
1956
1957 #if _REG_nexec
1958                         if (nexec >= 0)
1959                         {
1960                                 eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
1961                                 s[nexec] = 0;
1962                         }
1963                         else
1964 #endif
1965                         {
1966                                 if (!(test & TEST_CATCH))
1967                                         eret = regexec(&preg, s, nmatch, match, eflags);
1968                                 else if (!(eret = setjmp(state.gotcha)))
1969                                 {
1970                                         alarm(HUNG);
1971                                         eret = regexec(&preg, s, nmatch, match, eflags);
1972                                         alarm(0);
1973                                 }
1974                         }
1975 #if _REG_subcomp
1976                         if ((test & TEST_SUB) && !eret)
1977                         {
1978                                 fun = "regsubexec";
1979                                 if (!(test & TEST_CATCH))
1980                                         eret = regsubexec(&preg, s, nmatch, match);
1981                                 else if (!(eret = setjmp(state.gotcha)))
1982                                 {
1983                                         alarm(HUNG);
1984                                         eret = regsubexec(&preg, s, nmatch, match);
1985                                         alarm(0);
1986                                 }
1987                         }
1988 #endif
1989                         if (flags & REG_NOSUB)
1990                         {
1991                                 if (eret)
1992                                 {
1993                                         if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
1994                                         {
1995                                                 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1996                                                         skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1997                                                 else
1998                                                 {
1999                                                         report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
2000                                                         error(&preg, eret);
2001                                                 }
2002                                         }
2003                                 }
2004                                 else if (streq(ans, "NOMATCH"))
2005                                 {
2006                                         if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2007                                                 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2008                                         else
2009                                         {
2010                                                 report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2011                                                 error(&preg, eret);
2012                                         }
2013                                 }
2014                         }
2015                         else if (eret)
2016                         {
2017                                 if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
2018                                 {
2019                                         if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2020                                                 skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
2021                                         else
2022                                         {
2023                                                 report("failed", fun, re, s, nstr, msg, flags, test);
2024                                                 if (eret != REG_NOMATCH)
2025                                                         error(&preg, eret);
2026                                                 else if (*ans)
2027                                                         printf("expected: %s\n", ans);
2028                                                 else
2029                                                         printf("\n");
2030                                         }
2031                                 }
2032                         }
2033                         else if (streq(ans, "NOMATCH"))
2034                         {
2035                                 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2036                                         skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2037                                 else
2038                                 {
2039                                         report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2040                                         matchprint(match, nmatch, nsub, NiL, test);
2041                                 }
2042                         }
2043 #if _REG_subcomp
2044                         else if (test & TEST_SUB)
2045                         {
2046                                 p = preg.re_sub->re_buf;
2047                                 if (strcmp(p, ans))
2048                                 {
2049                                         report("failed", fun, re, s, nstr, msg, flags, test);
2050                                         quote(ans, -1, test|TEST_DELIMIT);
2051                                         printf(" expected, ");
2052                                         quote(p, -1, test|TEST_DELIMIT);
2053                                         printf(" returned\n");
2054                                 }
2055                         }
2056 #endif
2057                         else if (!*ans)
2058                         {
2059                                 if (match[0].rm_so != state.NOMATCH.rm_so)
2060                                 {
2061                                         if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2062                                                 skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
2063                                         else
2064                                         {
2065                                                 report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
2066                                                 matchprint(match, nmatch, nsub, NiL, test);
2067                                         }
2068                                 }
2069                         }
2070                         else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
2071                         {
2072 #if _REG_nexec
2073                                 if (nexec < 0 && !nonexec)
2074                                 {
2075                                         nexec = nstr >= 0 ? nstr : strlen(s);
2076                                         s[nexec] = '\n';
2077                                         testno++;
2078                                         goto execute;
2079                                 }
2080 #endif
2081                                 if (!(test & (TEST_SUB|TEST_VERIFY)) && !nonosub)
2082                                 {
2083                                         if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2084                                                 continue;
2085                                         flags |= REG_NOSUB;
2086                                         goto nosub;
2087                                 }
2088                                 if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
2089                                         skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
2090                         }
2091                         else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2092                                 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2093                         if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2094                                 continue;
2095                         goto compile;
2096                 }
2097                 if (test & TEST_SUMMARY)
2098                         printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
2099                 else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
2100                 {
2101                         printf("TEST\t%s", unit);
2102                         if (subunit)
2103                                 printf(" %-.*s", subunitlen, subunit);
2104                         printf(", %d test%s", testno, testno == 1 ? "" : "s");
2105                         if (state.ignored)
2106                                 printf(", %d ignored mismatch%s", state.ignored, state.ignored == 1 ? "" : "es");
2107                         if (state.warnings)
2108                                 printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
2109                         if (state.unspecified)
2110                                 printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
2111                         if (state.signals)
2112                                 printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
2113                         printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
2114                 }
2115                 if (fp != stdin)
2116                         fclose(fp);
2117         }
2118         return 0;
2119 }
2120
2121 int main(int argc, char **argv)
2122 {
2123         static char *param[][4] = {
2124                 { NULL,       "basic.dat"         , NULL },
2125                 { NULL,       "categorize.dat"    , NULL },
2126                 { NULL,       "forcedassoc.dat"   , NULL },
2127                 { NULL, "-c", "interpretation.dat", NULL },
2128                 { NULL,       "leftassoc.dat"     , NULL },
2129                 { NULL, "-c", "nullsubexpr.dat"   , NULL },
2130                 { NULL,       "repetition.dat"    , NULL },
2131                 { NULL,       "rightassoc.dat"    , NULL },
2132         };
2133         int r, i;
2134
2135         if (argv[1])
2136                 return old_main(argc, argv);
2137
2138         r = 0;
2139         for (i = 0; i < sizeof(param) / sizeof(param[0]); i++) {
2140                 param[i][0] = argv[0];
2141                 printf("Testing %s\n", param[i][1][0] != '-' ? param[i][1] : param[i][2]);
2142                 r |= old_main(3 /* not used */, param[i]);
2143         }
2144         return r;
2145 }