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