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