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