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