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