xref: /illumos-gate/usr/src/test/libc-tests/tests/regex/testregex.c (revision 78801af7286cd73dbc996d470f789e75993cf15d)
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 #if _REG_nexec
1224 	int		nexec;
1225 #endif
1226 	int		nstr;
1227 	int		cret;
1228 	int		eret;
1229 	int		nsub;
1230 	int		i;
1231 	int		j;
1232 	int		expected;
1233 	int		got;
1234 	int		locale;
1235 	int		subunitlen;
1236 	int		testno;
1237 	unsigned long	level;
1238 	unsigned long	skip;
1239 	char*		p;
1240 	char*		line;
1241 	char*		spec;
1242 	char*		re;
1243 	char*		s;
1244 	char*		ans;
1245 	char*		msg;
1246 	char*		fun;
1247 	char*		ppat;
1248 	char*		subunit;
1249 	char*		version;
1250 	char*		field[6];
1251 	char*		delim[6];
1252 	FILE*		fp;
1253 	int		tabs[6];
1254 	char		unit[64];
1255 	regmatch_t	match[100];
1256 	regex_t		preg;
1257 
1258 	static char	pat[32 * 1024];
1259 	static char	patbuf[32 * 1024];
1260 	static char	strbuf[32 * 1024];
1261 
1262 	int		nonosub = REG_NOSUB == 0;
1263 #if _REG_nexec
1264 	int		nonexec = 0;
1265 #endif
1266 
1267 	unsigned long	test = 0;
1268 
1269 	static char*	filter[] = { "-", 0 };
1270 
1271 	state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
1272 	p = unit;
1273 	version = (char*)id + 10;
1274 	while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
1275 		p++;
1276 	*p = 0;
1277 	while ((p = *++argv) && *p == '-')
1278 		for (;;)
1279 		{
1280 			switch (*++p)
1281 			{
1282 			case 0:
1283 				break;
1284 			case 'c':
1285 				test |= TEST_CATCH;
1286 				continue;
1287 			case 'e':
1288 				test |= TEST_IGNORE_ERROR;
1289 				continue;
1290 			case 'h':
1291 			case '?':
1292 				help(0);
1293 				return 2;
1294 			case '-':
1295 				help(p[1] == 'h');
1296 				return 2;
1297 			case 'n':
1298 #if _REG_nexec
1299 				nonexec = 1;
1300 #endif
1301 				continue;
1302 			case 'o':
1303 				test |= TEST_IGNORE_OVER;
1304 				continue;
1305 			case 'p':
1306 				test |= TEST_IGNORE_POSITION;
1307 				continue;
1308 			case 's':
1309 #ifdef REG_DISCIPLINE
1310 				if (!(state.stack = stkalloc(stkstd, 0)))
1311 					fprintf(stderr, "%s: out of space [stack]", unit);
1312 				state.disc.disc.re_resizef = resizef;
1313 				state.disc.disc.re_resizehandle = (void*)stkstd;
1314 #endif
1315 				continue;
1316 			case 'x':
1317 				nonosub = 1;
1318 				continue;
1319 			case 'v':
1320 				test |= TEST_VERBOSE;
1321 				continue;
1322 			case 'A':
1323 				test |= TEST_ACTUAL;
1324 				continue;
1325 			case 'B':
1326 				test |= TEST_BASELINE;
1327 				continue;
1328 			case 'F':
1329 				test |= TEST_FAIL;
1330 				continue;
1331 			case 'P':
1332 				test |= TEST_PASS;
1333 				continue;
1334 			case 'S':
1335 				test |= TEST_SUMMARY;
1336 				continue;
1337 			default:
1338 				fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
1339 				return 2;
1340 			}
1341 			break;
1342 		}
1343 	if (!*argv)
1344 		argv = filter;
1345 	locale = 0;
1346 	while (state.file = *argv++)
1347 	{
1348 		if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
1349 		{
1350 			state.file = 0;
1351 			fp = stdin;
1352 		}
1353 		else if (!(fp = fopen(state.file, "r")))
1354 		{
1355 			fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
1356 			return 2;
1357 		}
1358 		testno = state.errors = state.ignored = state.lineno = state.passed =
1359 		state.signals = state.unspecified = state.warnings = 0;
1360 		skip = 0;
1361 		level = 1;
1362 		if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1363 		{
1364 			printf("TEST\t%s ", unit);
1365 			if (s = state.file)
1366 			{
1367 				subunit = p = 0;
1368 				for (;;)
1369 				{
1370 					switch (*s++)
1371 					{
1372 					case 0:
1373 						break;
1374 					case '/':
1375 						subunit = s;
1376 						continue;
1377 					case '.':
1378 						p = s - 1;
1379 						continue;
1380 					default:
1381 						continue;
1382 					}
1383 					break;
1384 				}
1385 				if (!subunit)
1386 					subunit = state.file;
1387 				if (p < subunit)
1388 					p = s - 1;
1389 				subunitlen = p - subunit;
1390 				printf("%-.*s ", subunitlen, subunit);
1391 			}
1392 			else
1393 				subunit = 0;
1394 			for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
1395 				putchar(*s);
1396 			if (test & TEST_CATCH)
1397 				printf(", catch");
1398 			if (test & TEST_IGNORE_ERROR)
1399 				printf(", ignore error code mismatches");
1400 			if (test & TEST_IGNORE_POSITION)
1401 				printf(", ignore negative position mismatches");
1402 #ifdef REG_DISCIPLINE
1403 			if (state.stack)
1404 				printf(", stack");
1405 #endif
1406 			if (test & TEST_VERBOSE)
1407 				printf(", verbose");
1408 			printf("\n");
1409 #ifdef REG_VERSIONID
1410 			if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
1411 				s = pat;
1412 			else
1413 #endif
1414 #ifdef REG_TEST_VERSION
1415 			s = REG_TEST_VERSION;
1416 #else
1417 			s = "regex";
1418 #endif
1419 			printf("NOTE\t%s\n", s);
1420 			if (elementsof(unsupported) > 1)
1421 			{
1422 #if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
1423 				i = 0;
1424 #else
1425 				i = REG_EXTENDED != 0;
1426 #endif
1427 				for (got = 0; i < elementsof(unsupported) - 1; i++)
1428 				{
1429 					if (!got)
1430 					{
1431 						got = 1;
1432 						printf("NOTE\tunsupported: %s", unsupported[i]);
1433 					}
1434 					else
1435 						printf(",%s", unsupported[i]);
1436 				}
1437 				if (got)
1438 					printf("\n");
1439 			}
1440 		}
1441 #ifdef REG_DISCIPLINE
1442 		state.disc.disc.re_version = REG_VERSION;
1443 		state.disc.disc.re_compf = compf;
1444 		state.disc.disc.re_execf = execf;
1445 		if (!(state.disc.sp = sfstropen()))
1446 			bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
1447 		preg.re_disc = &state.disc.disc;
1448 #endif
1449 		if (test & TEST_CATCH)
1450 		{
1451 			signal(SIGALRM, gotcha);
1452 			signal(SIGBUS, gotcha);
1453 			signal(SIGSEGV, gotcha);
1454 		}
1455 		while (p = get_line(fp))
1456 		{
1457 
1458 		/* parse: */
1459 
1460 			line = p;
1461 			if (*p == ':' && !isspace(*(p + 1)))
1462 			{
1463 				while (*++p && *p != ':');
1464 				if (!*p++)
1465 				{
1466 					if (test & TEST_BASELINE)
1467 						printf("%s\n", line);
1468 					continue;
1469 				}
1470 			}
1471 			while (isspace(*p))
1472 				p++;
1473 			if (*p == 0 || *p == '#' || *p == 'T')
1474 			{
1475 				if (test & TEST_BASELINE)
1476 					printf("%s\n", line);
1477 				continue;
1478 			}
1479 			if (*p == ':' || *p == 'N')
1480 			{
1481 				if (test & TEST_BASELINE)
1482 					printf("%s\n", line);
1483 				else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1484 				{
1485 					while (*++p && !isspace(*p));
1486 					while (isspace(*p))
1487 						p++;
1488 					printf("NOTE	%s\n", p);
1489 				}
1490 				continue;
1491 			}
1492 			j = 0;
1493 			i = 0;
1494 			field[i++] = p;
1495 			for (;;)
1496 			{
1497 				switch (*p++)
1498 				{
1499 				case 0:
1500 					p--;
1501 					j = 0;
1502 					goto checkfield;
1503 				case '\t':
1504 					*(delim[i] = p - 1) = 0;
1505 					j = 1;
1506 				checkfield:
1507 					s = field[i - 1];
1508 					if (streq(s, "NIL"))
1509 						field[i - 1] = 0;
1510 					else if (streq(s, "NULL"))
1511 						*s = 0;
1512 					while (*p == '\t')
1513 					{
1514 						p++;
1515 						j++;
1516 					}
1517 					tabs[i - 1] = j;
1518 					if (!*p)
1519 						break;
1520 					if (i >= elementsof(field))
1521 						bad("too many fields\n", NiL, NiL, 0, 0);
1522 					field[i++] = p;
1523 					/*FALLTHROUGH*/
1524 				default:
1525 					continue;
1526 				}
1527 				break;
1528 			}
1529 			if (!(spec = field[0]))
1530 				bad("NIL spec\n", NiL, NiL, 0, 0);
1531 
1532 		/* interpret: */
1533 
1534 			cflags = REG_TEST_DEFAULT;
1535 			eflags = REG_EXEC_DEFAULT;
1536 			test &= TEST_GLOBAL;
1537 			state.extracted = 0;
1538 			nmatch = 20;
1539 			nsub = -1;
1540 			for (p = spec; *p; p++)
1541 			{
1542 				if (isdigit(*p))
1543 				{
1544 					nmatch = strtol(p, &p, 10);
1545 					if (nmatch >= elementsof(match))
1546 						bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
1547 					p--;
1548 					continue;
1549 				}
1550 				switch (*p)
1551 				{
1552 				case 'A':
1553 					test |= TEST_ARE;
1554 					continue;
1555 				case 'B':
1556 					test |= TEST_BRE;
1557 					continue;
1558 				case 'C':
1559 					if (!(test & TEST_QUERY) && !(skip & level))
1560 						bad("locale must be nested\n", NiL, NiL, 0, 0);
1561 					test &= ~TEST_QUERY;
1562 					if (locale)
1563 						bad("locale nesting not supported\n", NiL, NiL, 0, 0);
1564 					if (i != 2)
1565 						bad("locale field expected\n", NiL, NiL, 0, 0);
1566 					if (!(skip & level))
1567 					{
1568 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1569 						s = field[1];
1570 						if (!s || streq(s, "POSIX"))
1571 							s = "C";
1572 						if ((ans = setlocale(LC_COLLATE, s)) && streq(ans, "POSIX"))
1573 							ans = "C";
1574 						if (!ans || !streq(ans, s) && streq(s, "C"))
1575 							ans = 0;
1576 						else if ((ans = setlocale(LC_CTYPE, s)) && streq(ans, "POSIX"))
1577 							ans = "C";
1578 						if (!ans || !streq(ans, s) && streq(s, "C"))
1579 							skip = note(level, s, skip, test);
1580 						else
1581 						{
1582 							if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1583 								printf("NOTE	\"%s\" locale\n", s);
1584 							locale = level;
1585 						}
1586 #else
1587 						skip = note(level, skip, test, "locales not supported");
1588 #endif
1589 					}
1590 					cflags = NOTEST;
1591 					continue;
1592 				case 'E':
1593 					test |= TEST_ERE;
1594 					continue;
1595 				case 'K':
1596 					test |= TEST_KRE;
1597 					continue;
1598 				case 'L':
1599 					test |= TEST_LRE;
1600 					continue;
1601 				case 'S':
1602 					test |= TEST_SRE;
1603 					continue;
1604 
1605 				case 'a':
1606 					cflags |= REG_LEFT|REG_RIGHT;
1607 					continue;
1608 				case 'b':
1609 					eflags |= REG_NOTBOL;
1610 					continue;
1611 				case 'c':
1612 					cflags |= REG_COMMENT;
1613 					continue;
1614 				case 'd':
1615 					cflags |= REG_SHELL_DOT;
1616 					continue;
1617 				case 'e':
1618 					eflags |= REG_NOTEOL;
1619 					continue;
1620 				case 'f':
1621 					cflags |= REG_MULTIPLE;
1622 					continue;
1623 				case 'g':
1624 					cflags |= NOTEST;
1625 					continue;
1626 				case 'h':
1627 					cflags |= REG_MULTIREF;
1628 					continue;
1629 				case 'i':
1630 					cflags |= REG_ICASE;
1631 					continue;
1632 				case 'j':
1633 					cflags |= REG_SPAN;
1634 					continue;
1635 				case 'k':
1636 					cflags |= REG_ESCAPE;
1637 					continue;
1638 				case 'l':
1639 					cflags |= REG_LEFT;
1640 					continue;
1641 				case 'm':
1642 					cflags |= REG_MINIMAL;
1643 					continue;
1644 				case 'n':
1645 					cflags |= REG_NEWLINE;
1646 					continue;
1647 				case 'o':
1648 					cflags |= REG_SHELL_GROUP;
1649 					continue;
1650 				case 'p':
1651 					cflags |= REG_SHELL_PATH;
1652 					continue;
1653 				case 'q':
1654 					cflags |= REG_DELIMITED;
1655 					continue;
1656 				case 'r':
1657 					cflags |= REG_RIGHT;
1658 					continue;
1659 				case 's':
1660 					cflags |= REG_SHELL_ESCAPED;
1661 					continue;
1662 				case 't':
1663 					cflags |= REG_MUSTDELIM;
1664 					continue;
1665 				case 'u':
1666 					test |= TEST_UNSPECIFIED;
1667 					continue;
1668 				case 'v':
1669 					cflags |= REG_CLASS_ESCAPE;
1670 					continue;
1671 				case 'w':
1672 					cflags |= REG_NOSUB;
1673 					continue;
1674 				case 'x':
1675 					if (REG_LENIENT)
1676 						cflags |= REG_LENIENT;
1677 					else
1678 						test |= TEST_LENIENT;
1679 					continue;
1680 				case 'y':
1681 					eflags |= REG_LEFT;
1682 					continue;
1683 				case 'z':
1684 					cflags |= REG_NULL;
1685 					continue;
1686 
1687 				case '$':
1688 					test |= TEST_EXPAND;
1689 					continue;
1690 
1691 				case '/':
1692 					test |= TEST_SUB;
1693 					continue;
1694 
1695 				case '=':
1696 					test |= TEST_DECOMP;
1697 					continue;
1698 
1699 				case '?':
1700 					test |= TEST_VERIFY;
1701 					test &= ~(TEST_AND|TEST_OR);
1702 					state.verify = state.passed;
1703 					continue;
1704 				case '&':
1705 					test |= TEST_VERIFY|TEST_AND;
1706 					test &= ~TEST_OR;
1707 					continue;
1708 				case '|':
1709 					test |= TEST_VERIFY|TEST_OR;
1710 					test &= ~TEST_AND;
1711 					continue;
1712 				case ';':
1713 					test |= TEST_OR;
1714 					test &= ~TEST_AND;
1715 					continue;
1716 
1717 				case '{':
1718 					level <<= 1;
1719 					if (skip & (level >> 1))
1720 					{
1721 						skip |= level;
1722 						cflags = NOTEST;
1723 					}
1724 					else
1725 					{
1726 						skip &= ~level;
1727 						test |= TEST_QUERY;
1728 					}
1729 					continue;
1730 				case '}':
1731 					if (level == 1)
1732 						bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
1733 					if ((skip & level) && !(skip & (level>>1)))
1734 					{
1735 						if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
1736 						{
1737 							if (test & (TEST_ACTUAL|TEST_FAIL))
1738 								printf("}\n");
1739 							else if (!(test & TEST_PASS))
1740 								printf("-%d\n", state.lineno);
1741 						}
1742 					}
1743 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1744 					else if (locale & level)
1745 					{
1746 						locale = 0;
1747 						if (!(skip & level))
1748 						{
1749 							s = "C";
1750 							setlocale(LC_COLLATE, s);
1751 							setlocale(LC_CTYPE, s);
1752 							if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1753 								printf("NOTE	\"%s\" locale\n", s);
1754 							else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
1755 								printf("}\n");
1756 						}
1757 						else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
1758 							printf("}\n");
1759 					}
1760 #endif
1761 					level >>= 1;
1762 					cflags = NOTEST;
1763 					continue;
1764 
1765 				default:
1766 					bad("bad spec\n", spec, NiL, 0, test);
1767 					break;
1768 
1769 				}
1770 				break;
1771 			}
1772 			if ((cflags|eflags) == NOTEST || (skip & level) && (test & TEST_BASELINE))
1773 			{
1774 				if (test & TEST_BASELINE)
1775 				{
1776 					while (i > 1)
1777 						*delim[--i] = '\t';
1778 					printf("%s\n", line);
1779 				}
1780 				continue;
1781 			}
1782 			if (test & TEST_OR)
1783 			{
1784 				if (!(test & TEST_VERIFY))
1785 				{
1786 					test &= ~TEST_OR;
1787 					if (state.passed == state.verify && i > 1)
1788 						printf("NOTE\t%s\n", field[1]);
1789 					continue;
1790 				}
1791 				else if (state.passed > state.verify)
1792 					continue;
1793 			}
1794 			else if (test & TEST_AND)
1795 			{
1796 				if (state.passed == state.verify)
1797 					continue;
1798 				state.passed = state.verify;
1799 			}
1800 			if (i < ((test & TEST_DECOMP) ? 3 : 4))
1801 				bad("too few fields\n", NiL, NiL, 0, test);
1802 			while (i < elementsof(field))
1803 				field[i++] = 0;
1804 			if (re = field[1])
1805 			{
1806 				if (streq(re, "SAME"))
1807 				{
1808 					re = ppat;
1809 					test |= TEST_SAME;
1810 				}
1811 				else
1812 				{
1813 					if (test & TEST_EXPAND)
1814 						escape(re);
1815 					re = expand(re, patbuf);
1816 					strcpy(ppat = pat, re);
1817 				}
1818 			}
1819 			else
1820 				ppat = 0;
1821 			nstr = -1;
1822 			if (s = field[2])
1823 			{
1824 				s = expand(s, strbuf);
1825 				if (test & TEST_EXPAND)
1826 				{
1827 					nstr = escape(s);
1828 #if _REG_nexec
1829 					if (nstr != strlen(s))
1830 						nexec = nstr;
1831 #endif
1832 				}
1833 			}
1834 			if (!(ans = field[(test & TEST_DECOMP) ? 2 : 3]))
1835 				bad("NIL answer\n", NiL, NiL, 0, test);
1836 			msg = field[4];
1837 			fflush(stdout);
1838 			if (test & TEST_SUB)
1839 #if _REG_subcomp
1840 				cflags |= REG_DELIMITED;
1841 #else
1842 				continue;
1843 #endif
1844 #if !_REG_decomp
1845 			if (test & TEST_DECOMP)
1846 				continue;
1847 #endif
1848 
1849 		compile:
1850 
1851 			if (state.extracted || (skip & level))
1852 				continue;
1853 #if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
1854 #ifdef REG_EXTENDED
1855 			if (REG_EXTENDED != 0 && (test & TEST_BRE))
1856 #else
1857 			if (test & TEST_BRE)
1858 #endif
1859 			{
1860 				test &= ~TEST_BRE;
1861 				flags = cflags;
1862 				state.which = "BRE";
1863 			}
1864 			else
1865 #endif
1866 #ifdef REG_EXTENDED
1867 			if (test & TEST_ERE)
1868 			{
1869 				test &= ~TEST_ERE;
1870 				flags = cflags | REG_EXTENDED;
1871 				state.which = "ERE";
1872 			}
1873 			else
1874 #endif
1875 #ifdef REG_AUGMENTED
1876 			if (test & TEST_ARE)
1877 			{
1878 				test &= ~TEST_ARE;
1879 				flags = cflags | REG_AUGMENTED;
1880 				state.which = "ARE";
1881 			}
1882 			else
1883 #endif
1884 #ifdef REG_LITERAL
1885 			if (test & TEST_LRE)
1886 			{
1887 				test &= ~TEST_LRE;
1888 				flags = cflags | REG_LITERAL;
1889 				state.which = "LRE";
1890 			}
1891 			else
1892 #endif
1893 #ifdef REG_SHELL
1894 			if (test & TEST_SRE)
1895 			{
1896 				test &= ~TEST_SRE;
1897 				flags = cflags | REG_SHELL;
1898 				state.which = "SRE";
1899 			}
1900 			else
1901 #ifdef REG_AUGMENTED
1902 			if (test & TEST_KRE)
1903 			{
1904 				test &= ~TEST_KRE;
1905 				flags = cflags | REG_SHELL | REG_AUGMENTED;
1906 				state.which = "KRE";
1907 			}
1908 			else
1909 #endif
1910 #endif
1911 			{
1912 				if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
1913 					extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
1914 				continue;
1915 			}
1916 			if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
1917 			{
1918 				printf("test %-3d %s ", state.lineno, state.which);
1919 				quote(re, -1, test|TEST_DELIMIT);
1920 				printf(" ");
1921 				quote(s, nstr, test|TEST_DELIMIT);
1922 				printf("\n");
1923 			}
1924 
1925 		nosub:
1926 			fun = "regcomp";
1927 #if _REG_nexec
1928 			if (nstr >= 0 && nstr != strlen(s))
1929 				nexec = nstr;
1930 #endif
1931 
1932 			if (state.extracted || (skip & level))
1933 				continue;
1934 			if (!(test & TEST_QUERY))
1935 				testno++;
1936 #ifdef REG_DISCIPLINE
1937 			if (state.stack)
1938 				stkset(stkstd, state.stack, 0);
1939 			flags |= REG_DISCIPLINE;
1940 			state.disc.ordinal = 0;
1941 			sfstrseek(state.disc.sp, 0, SEEK_SET);
1942 #endif
1943 			if (!(test & TEST_CATCH))
1944 				cret = regcomp(&preg, re, flags);
1945 			else if (!(cret = setjmp(state.gotcha)))
1946 			{
1947 				alarm(HUNG);
1948 				cret = regcomp(&preg, re, flags);
1949 				alarm(0);
1950 			}
1951 #if _REG_subcomp
1952 			if (!cret && (test & TEST_SUB))
1953 			{
1954 				fun = "regsubcomp";
1955 				p = re + preg.re_npat;
1956 				if (!(test & TEST_CATCH))
1957 					cret = regsubcomp(&preg, p, NiL, 0, 0);
1958 				else if (!(cret = setjmp(state.gotcha)))
1959 				{
1960 					alarm(HUNG);
1961 					cret = regsubcomp(&preg, p, NiL, 0, 0);
1962 					alarm(0);
1963 				}
1964 				if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
1965 				{
1966 					if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
1967 						continue;
1968 					cret = REG_EFLAGS;
1969 				}
1970 			}
1971 #endif
1972 #if _REG_decomp
1973 			if (!cret && (test & TEST_DECOMP))
1974 			{
1975 				char	buf[128];
1976 
1977 				if ((j = nmatch) > sizeof(buf))
1978 					j = sizeof(buf);
1979 				fun = "regdecomp";
1980 				p = re + preg.re_npat;
1981 				if (!(test & TEST_CATCH))
1982 					i = regdecomp(&preg, -1, buf, j);
1983 				else if (!(cret = setjmp(state.gotcha)))
1984 				{
1985 					alarm(HUNG);
1986 					i = regdecomp(&preg, -1, buf, j);
1987 					alarm(0);
1988 				}
1989 				if (!cret)
1990 				{
1991 					catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
1992 					if (i > j)
1993 					{
1994 						if (i != (strlen(ans) + 1))
1995 						{
1996 							report("failed", fun, re, s, nstr, msg, flags, test);
1997 							printf(" %d byte buffer supplied, %d byte buffer required\n", j, i);
1998 						}
1999 					}
2000 					else if (strcmp(buf, ans))
2001 					{
2002 						report("failed", fun, re, s, nstr, msg, flags, test);
2003 						quote(ans, -1, test|TEST_DELIMIT);
2004 						printf(" expected, ");
2005 						quote(buf, -1, test|TEST_DELIMIT);
2006 						printf(" returned\n");
2007 					}
2008 					continue;
2009 				}
2010 			}
2011 #endif
2012 			if (!cret)
2013 			{
2014 				if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
2015 				{
2016 					for (p = ans; *p; p++)
2017 						if (*p == '(')
2018 							nsub++;
2019 						else if (*p == '{')
2020 							nsub--;
2021 					if (nsub >= 0)
2022 					{
2023 						if (test & TEST_IGNORE_OVER)
2024 						{
2025 							if (nmatch > nsub)
2026 								nmatch = nsub + 1;
2027 						}
2028 						else if (nsub != preg.re_nsub)
2029 						{
2030 							if (nsub > preg.re_nsub)
2031 							{
2032 								if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2033 									skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2034 								else
2035 								{
2036 									report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
2037 									printf("at least %d expected, %d returned\n", nsub, preg.re_nsub);
2038 									state.errors++;
2039 								}
2040 							}
2041 							else
2042 								nsub = preg.re_nsub;
2043 						}
2044 					}
2045 				}
2046 				if (!(test & (TEST_DECOMP|TEST_SUB)) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
2047 				{
2048 					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2049 						skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2050 					else if (!(test & TEST_LENIENT))
2051 					{
2052 						report("failed", fun, re, NiL, -1, msg, flags, test);
2053 						printf("%s expected, OK returned\n", ans);
2054 					}
2055 					catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
2056 					continue;
2057 				}
2058 			}
2059 			else
2060 			{
2061 				if (test & TEST_LENIENT)
2062 					/* we'll let it go this time */;
2063 				else if (!*ans || ans[0]=='(' || cret == REG_BADPAT && streq(ans, "NOMATCH"))
2064 				{
2065 					got = 0;
2066 					for (i = 1; i < elementsof(codes); i++)
2067 						if (cret==codes[i].code)
2068 							got = i;
2069 					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2070 						skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2071 					else
2072 					{
2073 						report("failed", fun, re, NiL, -1, msg, flags, test);
2074 						printf("%s returned: ", codes[got].name);
2075 						error(&preg, cret);
2076 					}
2077 				}
2078 				else
2079 				{
2080 					expected = got = 0;
2081 					for (i = 1; i < elementsof(codes); i++)
2082 					{
2083 						if (streq(ans, codes[i].name))
2084 							expected = i;
2085 						if (cret==codes[i].code)
2086 							got = i;
2087 					}
2088 					if (!expected)
2089 					{
2090 						if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2091 							skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2092 						else
2093 						{
2094 							report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
2095 							printf("%s expected, %s returned\n", ans, codes[got].name);
2096 						}
2097 					}
2098 					else if (cret != codes[expected].code && cret != REG_BADPAT)
2099 					{
2100 						if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2101 							skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2102 						else if (test & TEST_IGNORE_ERROR)
2103 							state.ignored++;
2104 						else
2105 						{
2106 							report("should fail and did", fun, re, NiL, -1, msg, flags, test);
2107 							printf("%s expected, %s returned: ", ans, codes[got].name);
2108 							state.errors--;
2109 							state.warnings++;
2110 							error(&preg, cret);
2111 						}
2112 					}
2113 				}
2114 				goto compile;
2115 			}
2116 
2117 #if _REG_nexec
2118 		execute:
2119 			if (nexec >= 0)
2120 				fun = "regnexec";
2121 			else
2122 #endif
2123 				fun = "regexec";
2124 
2125 			for (i = 0; i < elementsof(match); i++)
2126 				match[i] = state.NOMATCH;
2127 
2128 #if _REG_nexec
2129 			if (nexec >= 0)
2130 			{
2131 				eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
2132 				s[nexec] = 0;
2133 			}
2134 			else
2135 #endif
2136 			{
2137 				if (!(test & TEST_CATCH))
2138 					eret = regexec(&preg, s, nmatch, match, eflags);
2139 				else if (!(eret = setjmp(state.gotcha)))
2140 				{
2141 					alarm(HUNG);
2142 					eret = regexec(&preg, s, nmatch, match, eflags);
2143 					alarm(0);
2144 				}
2145 			}
2146 #if _REG_subcomp
2147 			if ((test & TEST_SUB) && !eret)
2148 			{
2149 				fun = "regsubexec";
2150 				if (!(test & TEST_CATCH))
2151 					eret = regsubexec(&preg, s, nmatch, match);
2152 				else if (!(eret = setjmp(state.gotcha)))
2153 				{
2154 					alarm(HUNG);
2155 					eret = regsubexec(&preg, s, nmatch, match);
2156 					alarm(0);
2157 				}
2158 			}
2159 #endif
2160 			if (flags & REG_NOSUB)
2161 			{
2162 				if (eret)
2163 				{
2164 					if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
2165 					{
2166 						if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2167 							skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2168 						else
2169 						{
2170 							report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
2171 							error(&preg, eret);
2172 						}
2173 					}
2174 				}
2175 				else if (streq(ans, "NOMATCH"))
2176 				{
2177 					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2178 						skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2179 					else
2180 					{
2181 						report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2182 						error(&preg, eret);
2183 					}
2184 				}
2185 			}
2186 			else if (eret)
2187 			{
2188 				if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
2189 				{
2190 					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2191 						skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
2192 					else
2193 					{
2194 						report("failed", fun, re, s, nstr, msg, flags, test);
2195 						if (eret != REG_NOMATCH)
2196 							error(&preg, eret);
2197 						else if (*ans)
2198 							printf("expected: %s\n", ans);
2199 						else
2200 							printf("\n");
2201 					}
2202 				}
2203 			}
2204 			else if (streq(ans, "NOMATCH"))
2205 			{
2206 				if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2207 					skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2208 				else
2209 				{
2210 					report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2211 					matchprint(match, nmatch, nsub, NiL, test);
2212 				}
2213 			}
2214 #if _REG_subcomp
2215 			else if (test & TEST_SUB)
2216 			{
2217 				p = preg.re_sub->re_buf;
2218 				if (strcmp(p, ans))
2219 				{
2220 					report("failed", fun, re, s, nstr, msg, flags, test);
2221 					quote(ans, -1, test|TEST_DELIMIT);
2222 					printf(" expected, ");
2223 					quote(p, -1, test|TEST_DELIMIT);
2224 					printf(" returned\n");
2225 				}
2226 			}
2227 #endif
2228 			else if (!*ans)
2229 			{
2230 				if (match[0].rm_so != state.NOMATCH.rm_so)
2231 				{
2232 					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2233 						skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
2234 					else
2235 					{
2236 						report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
2237 						matchprint(match, nmatch, nsub, NiL, test);
2238 					}
2239 				}
2240 			}
2241 			else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
2242 			{
2243 #if _REG_nexec
2244 				if (nexec < 0 && !nonexec)
2245 				{
2246 					nexec = nstr >= 0 ? nstr : strlen(s);
2247 					s[nexec] = '\n';
2248 					testno++;
2249 					goto execute;
2250 				}
2251 #endif
2252 				if (!(test & (TEST_DECOMP|TEST_SUB|TEST_VERIFY)) && !nonosub)
2253 				{
2254 					if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2255 						continue;
2256 					flags |= REG_NOSUB;
2257 					goto nosub;
2258 				}
2259 				if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
2260 					skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
2261 			}
2262 			else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2263 				skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2264 			if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2265 				continue;
2266 			goto compile;
2267 		}
2268 		if (test & TEST_SUMMARY)
2269 			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);
2270 		else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
2271 		{
2272 			printf("TEST\t%s", unit);
2273 			if (subunit)
2274 				printf(" %-.*s", subunitlen, subunit);
2275 			printf(", %d test%s", testno, testno == 1 ? "" : "s");
2276 			if (state.ignored)
2277 				printf(", %d ignored mismatche%s", state.ignored, state.ignored == 1 ? "" : "s");
2278 			if (state.warnings)
2279 				printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
2280 			if (state.unspecified)
2281 				printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
2282 			if (state.signals)
2283 				printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
2284 			printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
2285 		}
2286 		if (fp != stdin)
2287 			fclose(fp);
2288 	}
2289 	return 0;
2290 }
2291