| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866186718681869187018711872187318741875187618771878187918801881188218831884188518861887188818891890189118921893189418951896189718981899190019011902190319041905190619071908190919101911191219131914191519161917191819191920192119221923192419251926192719281929193019311932193319341935193619371938193919401941194219431944194519461947194819491950195119521953195419551956195719581959196019611962196319641965196619671968196919701971197219731974197519761977197819791980198119821983198419851986198719881989199019911992199319941995199619971998199920002001200220032004200520062007200820092010201120122013201420152016201720182019202020212022202320242025202620272028202920302031203220332034203520362037203820392040204120422043204420452046204720482049205020512052205320542055205620572058205920602061206220632064206520662067206820692070207120722073207420752076207720782079208020812082208320842085208620872088208920902091209220932094209520962097209820992100210121022103210421052106210721082109211021112112211321142115211621172118211921202121212221232124212521262127212821292130213121322133213421352136213721382139214021412142214321442145 | /* * regex(3) test harness * * build:	cc -o testregex testregex.c * help:	testregex --man * note:	REG_* features are detected by #ifdef; if REG_* are enums *		then supply #define REG_foo REG_foo for each enum REG_foo * *	Glenn Fowler <gsf@research.att.com> *	AT&T Labs Research * * PLEASE: publish your tests so everyone can benefit * * Permission is hereby granted, free of charge, to any person obtaining a * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, * copy, modify, merge, publish, distribute, and/or sell copies of the * Software, and to permit persons to whom the Software is furnished to do * so, subject to the following disclaimer: * * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2005-05-20 $\0\n";#if _PACKAGE_ast#include <ast.h>#else#include <sys/types.h>#endif#include <stdio.h>#include <regex.h>#include <ctype.h>#include <setjmp.h>#include <signal.h>#include <string.h>#include <unistd.h>#ifdef	__STDC__#include <stdlib.h>#include <locale.h>#endif#if !_PACKAGE_ast#undef	REG_DISCIPLINE#endif#ifndef REG_DELIMITED#undef	_REG_subcomp#endif#define TEST_ARE		0x00000001#define TEST_BRE		0x00000002#define TEST_ERE		0x00000004#define TEST_KRE		0x00000008#define TEST_LRE		0x00000010#define TEST_SRE		0x00000020#define TEST_EXPAND		0x00000040#define TEST_LENIENT		0x00000080#define TEST_QUERY		0x00000100#define TEST_SUB		0x00000200#define TEST_UNSPECIFIED	0x00000400#define TEST_VERIFY		0x00000800#define TEST_AND		0x00001000#define TEST_OR			0x00002000#define TEST_DELIMIT		0x00010000#define TEST_OK			0x00020000#define TEST_SAME		0x00040000#define TEST_ACTUAL		0x00100000#define TEST_BASELINE		0x00200000#define TEST_FAIL		0x00400000#define TEST_PASS		0x00800000#define TEST_SUMMARY		0x01000000#define TEST_IGNORE_ERROR	0x02000000#define TEST_IGNORE_OVER	0x04000000#define TEST_IGNORE_POSITION	0x08000000#define TEST_CATCH		0x10000000#define TEST_VERBOSE		0x20000000#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)#ifdef REG_DISCIPLINE#include <stk.h>typedef struct Disc_s{	regdisc_t	disc;	int		ordinal;	Sfio_t*		sp;} Disc_t;static void*compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc){	Disc_t*		dp = (Disc_t*)disc;	return (void*)++dp->ordinal;}static intexecf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc){	Disc_t*		dp = (Disc_t*)disc;	sfprintf(dp->sp, "{%-.*s}(%d:%d)", xlen, xstr, (int)data, slen);	return atoi(xstr);}static void*resizef(void* handle, void* data, size_t size){	if (!size)		return 0;	return stkalloc((Sfio_t*)handle, size);}#endif#ifndef NiL#ifdef	__STDC__#define NiL		0#else#define NiL		(char*)0#endif#endif#define H(x)		do{if(html)fprintf(stderr,x);}while(0)#define T(x)		fprintf(stderr,x)static voidhelp(int html){H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");H("<HTML>\n");H("<HEAD>\n");H("<TITLE>testregex man document</TITLE>\n");H("</HEAD>\n");H("<BODY bgcolor=white>\n");H("<PRE>\n");T("NAME\n");T("  testregex - regex(3) test harness\n");T("\n");T("SYNOPSIS\n");T("  testregex [ options ]\n");T("\n");T("DESCRIPTION\n");T("  testregex reads regex(3) test specifications, one per line, from the\n");T("  standard input and writes one output line for each failed test. A\n");T("  summary line is written after all tests are done. Each successful\n");T("  test is run again with REG_NOSUB. Unsupported features are noted\n");T("  before the first test, and tests requiring these features are\n");T("  silently ignored.\n");T("\n");T("OPTIONS\n");T("  -c	catch signals and non-terminating calls\n");T("  -e	ignore error return mismatches\n");T("  -h	list help on standard error\n");T("  -n	do not repeat successful tests with regnexec()\n");T("  -o	ignore match[] overrun errors\n");T("  -p	ignore negative position mismatches\n");T("  -s	use stack instead of malloc\n");T("  -x	do not repeat successful tests with REG_NOSUB\n");T("  -v	list each test line\n");T("  -A	list failed test lines with actual answers\n");T("  -B	list all test lines with actual answers\n");T("  -F	list failed test lines\n");T("  -P	list passed test lines\n");T("  -S	output one summary line\n");T("\n");T("INPUT FORMAT\n");T("  Input lines may be blank, a comment beginning with #, or a test\n");T("  specification. A specification is five fields separated by one\n");T("  or more tabs. NULL denotes the empty string and NIL denotes the\n");T("  0 pointer.\n");T("\n");T("  Field 1: the regex(3) flags to apply, one character per REG_feature\n");T("  flag. The test is skipped if REG_feature is not supported by the\n");T("  implementation. If the first character is not [BEASKL] then the\n");T("  specification is a global control line. One or more of [BEASKL] may be\n");T("  specified; the test will be repeated for each mode.\n");T("\n");T("    B 	basic			BRE	(grep, ed, sed)\n");T("    E 	REG_EXTENDED		ERE	(egrep)\n");T("    A	REG_AUGMENTED		ARE	(egrep with negation)\n");T("    S	REG_SHELL		SRE	(sh glob)\n");T("    K	REG_SHELL|REG_AUGMENTED	KRE	(ksh glob)\n");T("    L	REG_LITERAL		LRE	(fgrep)\n");T("\n");T("    a	REG_LEFT|REG_RIGHT	implicit ^...$\n");T("    b	REG_NOTBOL		lhs does not match ^\n");T("    c	REG_COMMENT		ignore space and #...\\n\n");T("    d	REG_SHELL_DOT		explicit leading . match\n");T("    e	REG_NOTEOL		rhs does not match $\n");T("    f	REG_MULTIPLE		multiple \\n separated patterns\n");T("    g	FNM_LEADING_DIR		testfnmatch only -- match until /\n");T("    h	REG_MULTIREF		multiple digit backref\n");T("    i	REG_ICASE		ignore case\n");T("    j	REG_SPAN		. matches \\n\n");T("    k	REG_ESCAPE		\\ to ecape [...] delimiter\n");T("    l	REG_LEFT		implicit ^...\n");T("    m	REG_MINIMAL		minimal match\n");T("    n	REG_NEWLINE		explicit \\n match\n");T("    o	REG_ENCLOSED		(|&) magic inside [@|&](...)\n");T("    p	REG_SHELL_PATH		explicit / match\n");T("    q	REG_DELIMITED		delimited pattern\n");T("    r	REG_RIGHT		implicit ...$\n");T("    s	REG_SHELL_ESCAPED	\\ not special\n");T("    t	REG_MUSTDELIM		all delimiters must be specified\n");T("    u	standard unspecified behavior -- errors not counted\n");T("    w	REG_NOSUB		no subexpression match array\n");T("    x	REG_LENIENT		let some errors slide\n");T("    y	REG_LEFT		regexec() implicit ^...\n");T("    z	REG_NULL		NULL subexpressions ok\n");T("    $	                        expand C \\c escapes in fields 2 and 3\n");T("    /	                        field 2 is a regsubcomp() expression\n");T("\n");T("  Field 1 control lines:\n");T("\n");T("    C		set LC_COLLATE and LC_CTYPE to locale in field 2\n");T("\n");T("    ?test ...	output field 5 if passed and != EXPECTED, silent otherwise\n");T("    &test ...	output field 5 if current and previous passed\n");T("    |test ...	output field 5 if current passed and previous failed\n");T("    ; ...	output field 2 if previous failed\n");T("    {test ...	skip if failed until }\n");T("    }		end of skip\n");T("\n");T("    : comment		comment copied as output NOTE\n");T("    :comment:test	:comment: ignored\n");T("    N[OTE] comment	comment copied as output NOTE\n");T("    T[EST] comment	comment\n");T("\n");T("    number		use number for nmatch (20 by default)\n");T("\n");T("  Field 2: the regular expression pattern; SAME uses the pattern from\n");T("    the previous specification.\n");T("\n");T("  Field 3: the string to match.\n");T("\n");T("  Field 4: the test outcome. This is either one of the posix error\n");T("    codes (with REG_ omitted) or the match array, a list of (m,n)\n");T("    entries with m and n being first and last+1 positions in the\n");T("    field 3 string, or NULL if REG_NOSUB is in effect and success\n");T("    is expected. BADPAT is acceptable in place of any regcomp(3)\n");T("    error code. The match[] array is initialized to (-2,-2) before\n");T("    each test. All array elements from 0 to nmatch-1 must be specified\n");T("    in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");T("    Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");T("    matched (?{...}) expression, where x is the text enclosed by {...},\n");T("    o is the expression ordinal counting from 1, and n is the length of\n");T("    the unmatched portion of the subject string. If x starts with a\n");T("    number then that is the return value of re_execf(), otherwise 0 is\n");T("    returned.\n");T("\n");T("  Field 5: optional comment appended to the report.\n");T("\n");T("CAVEAT\n");T("    If a regex implementation misbehaves with memory then all bets are off.\n");T("\n");T("CONTRIBUTORS\n");T("  Glenn Fowler    gsf@research.att.com        (ksh strmatch, regex extensions)\n");T("  David Korn      dgk@research.att.com        (ksh glob matcher)\n");T("  Doug McIlroy    mcilroy@dartmouth.edu       (ast regex/testre in C++)\n");T("  Tom Lord        lord@regexps.com            (rx tests)\n");T("  Henry Spencer   henry@zoo.toronto.edu       (original public regex)\n");T("  Andrew Hume     andrew@research.att.com     (gre tests)\n");T("  John Maddock    John_Maddock@compuserve.com (regex++ tests)\n");T("  Philip Hazel    ph10@cam.ac.uk              (pcre tests)\n");T("  Ville Laurikari vl@iki.fi                   (libtre tests)\n");H("</PRE>\n");H("</BODY>\n");H("</HTML>\n");}#ifndef elementsof#define elementsof(x)	(sizeof(x)/sizeof(x[0]))#endif#ifndef streq#define streq(a,b)	(*(a)==*(b)&&!strcmp(a,b))#endif#define HUNG		5#define NOTEST		(~0)#ifndef REG_TEST_DEFAULT#define REG_TEST_DEFAULT	0#endif#ifndef REG_EXEC_DEFAULT#define REG_EXEC_DEFAULT	0#endifstatic const char* unsupported[] ={	"BASIC",#ifndef REG_EXTENDED	"EXTENDED",#endif#ifndef REG_AUGMENTED	"AUGMENTED",#endif#ifndef REG_SHELL	"SHELL",#endif#ifndef REG_COMMENT	"COMMENT",#endif#ifndef REG_DELIMITED	"DELIMITED",#endif#ifndef REG_DISCIPLINE	"DISCIPLINE",#endif#ifndef REG_ESCAPE	"ESCAPE",#endif#ifndef REG_ICASE	"ICASE",#endif#ifndef REG_LEFT	"LEFT",#endif#ifndef REG_LENIENT	"LENIENT",#endif#ifndef REG_LITERAL	"LITERAL",#endif#ifndef REG_MINIMAL	"MINIMAL",#endif#ifndef REG_MULTIPLE	"MULTIPLE",#endif#ifndef REG_MULTIREF	"MULTIREF",#endif#ifndef REG_MUSTDELIM	"MUSTDELIM",#endif#ifndef REG_NEWLINE	"NEWLINE",#endif#ifndef REG_NOTBOL	"NOTBOL",#endif#ifndef REG_NOTEOL	"NOTEOL",#endif#ifndef REG_NULL	"NULL",#endif#ifndef REG_RIGHT	"RIGHT",#endif#ifndef REG_SHELL_DOT	"SHELL_DOT",#endif#ifndef REG_SHELL_ESCAPED	"SHELL_ESCAPED",#endif#ifndef REG_SHELL_GROUP	"SHELL_GROUP",#endif#ifndef REG_SHELL_PATH	"SHELL_PATH",#endif#ifndef REG_SPAN	"SPAN",#endif#if REG_NOSUB & REG_TEST_DEFAULT	"SUBMATCH",#endif#if !_REG_nexec	"regnexec",#endif#if !_REG_subcomp	"regsubcomp",#endif	0};#ifndef REG_COMMENT#define REG_COMMENT	NOTEST#endif#ifndef REG_DELIMITED#define REG_DELIMITED	NOTEST#endif#ifndef REG_ESCAPE#define REG_ESCAPE	NOTEST#endif#ifndef REG_ICASE#define REG_ICASE	NOTEST#endif#ifndef REG_LEFT#define REG_LEFT	NOTEST#endif#ifndef REG_LENIENT#define REG_LENIENT	0#endif#ifndef REG_MINIMAL#define REG_MINIMAL	NOTEST#endif#ifndef REG_MULTIPLE#define REG_MULTIPLE	NOTEST#endif#ifndef REG_MULTIREF#define REG_MULTIREF	NOTEST#endif#ifndef REG_MUSTDELIM#define REG_MUSTDELIM	NOTEST#endif#ifndef REG_NEWLINE#define REG_NEWLINE	NOTEST#endif#ifndef REG_NOTBOL#define REG_NOTBOL	NOTEST#endif#ifndef REG_NOTEOL#define REG_NOTEOL	NOTEST#endif#ifndef REG_NULL#define REG_NULL	NOTEST#endif#ifndef REG_RIGHT#define REG_RIGHT	NOTEST#endif#ifndef REG_SHELL_DOT#define REG_SHELL_DOT	NOTEST#endif#ifndef REG_SHELL_ESCAPED#define REG_SHELL_ESCAPED	NOTEST#endif#ifndef REG_SHELL_GROUP#define REG_SHELL_GROUP	NOTEST#endif#ifndef REG_SHELL_PATH#define REG_SHELL_PATH	NOTEST#endif#ifndef REG_SPAN#define REG_SPAN	NOTEST#endif#define REG_UNKNOWN	(-1)#ifndef REG_ENEWLINE#define REG_ENEWLINE	(REG_UNKNOWN-1)#endif#ifndef REG_ENULL#ifndef REG_EMPTY#define REG_ENULL	(REG_UNKNOWN-2)#else#define REG_ENULL	REG_EMPTY#endif#endif#ifndef REG_ECOUNT#define REG_ECOUNT	(REG_UNKNOWN-3)#endif#ifndef REG_BADESC#define REG_BADESC	(REG_UNKNOWN-4)#endif#ifndef REG_EMEM#define REG_EMEM	(REG_UNKNOWN-5)#endif#ifndef REG_EHUNG#define REG_EHUNG	(REG_UNKNOWN-6)#endif#ifndef REG_EBUS#define REG_EBUS	(REG_UNKNOWN-7)#endif#ifndef REG_EFAULT#define REG_EFAULT	(REG_UNKNOWN-8)#endif#ifndef REG_EFLAGS#define REG_EFLAGS	(REG_UNKNOWN-9)#endif#ifndef REG_EDELIM#define REG_EDELIM	(REG_UNKNOWN-9)#endifstatic const struct { int code; char* name; } codes[] ={	{REG_UNKNOWN,	"UNKNOWN"},	{REG_NOMATCH,	"NOMATCH"},	{REG_BADPAT,	"BADPAT"},	{REG_ECOLLATE,	"ECOLLATE"},	{REG_ECTYPE,	"ECTYPE"},	{REG_EESCAPE,	"EESCAPE"},	{REG_ESUBREG,	"ESUBREG"},	{REG_EBRACK,	"EBRACK"},	{REG_EPAREN,	"EPAREN"},	{REG_EBRACE,	"EBRACE"},	{REG_BADBR,	"BADBR"},	{REG_ERANGE,	"ERANGE"},	{REG_ESPACE,	"ESPACE"},	{REG_BADRPT,	"BADRPT"},	{REG_ENEWLINE,	"ENEWLINE"},	{REG_ENULL,	"ENULL"},	{REG_ECOUNT,	"ECOUNT"},	{REG_BADESC,	"BADESC"},	{REG_EMEM,	"EMEM"},	{REG_EHUNG,	"EHUNG"},	{REG_EBUS,	"EBUS"},	{REG_EFAULT,	"EFAULT"},	{REG_EFLAGS,	"EFLAGS"},	{REG_EDELIM,	"EDELIM"},};static struct{	regmatch_t	NOMATCH;	int		errors;	int		extracted;	int		ignored;	int		lineno;	int		passed;	int		signals;	int		unspecified;	int		verify;	int		warnings;	char*		file;	char*		stack;	char*		which;	jmp_buf		gotcha;#ifdef REG_DISCIPLINE	Disc_t		disc;#endif} state;static voidquote(char* s, int len, unsigned long test){	unsigned char*	u = (unsigned char*)s;	unsigned char*	e;	int		c;	if (!u)		printf("NIL");	else if (!*u && len <= 1)		printf("NULL");	else if (test & TEST_EXPAND)	{		if (len < 0)			len = strlen((char*)u);		e = u + len;		if (test & TEST_DELIMIT)			printf("\"");		while (u < e)			switch (c = *u++)			{			case '\\':				printf("\\\\");				break;			case '"':				if (test & TEST_DELIMIT)					printf("\\\"");				else					printf("\"");				break;			case '\a':				printf("\\a");				break;			case '\b':				printf("\\b");				break;			case 033:				printf("\\e");				break;			case '\f':				printf("\\f");				break;			case '\n':				printf("\\n");				break;			case '\r':				printf("\\r");				break;			case '\t':				printf("\\t");				break;			case '\v':				printf("\\v");				break;			default:				if (!iscntrl(c) && isprint(c))					putchar(c);				else					printf("\\x%02x", c);				break;			}		if (test & TEST_DELIMIT)			printf("\"");	}	else		printf("%s", s);}static voidreport(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test){	if (state.file)		printf("%s:", state.file);	printf("%d:", state.lineno);	if (re)	{		printf(" ");		quote(re, -1, test|TEST_DELIMIT);		if (s)		{			printf(" versus ");			quote(s, len, test|TEST_DELIMIT);		}	}	if (test & TEST_UNSPECIFIED)	{		state.unspecified++;		printf(" unspecified behavior");	}	else		state.errors++;	if (state.which)		printf(" %s", state.which);	if (flags & REG_NOSUB)		printf(" NOSUB");	if (fun)		printf(" %s", fun);	if (comment[strlen(comment)-1] == '\n')		printf(" %s", comment);	else	{		printf(" %s: ", comment);		if (msg)			printf("%s: ", msg);	}}static voiderror(regex_t* preg, int code){	char*	msg;	char	buf[256];	switch (code)	{	case REG_EBUS:		msg = "bus error";		break;	case REG_EFAULT:		msg = "memory fault";		break;	case REG_EHUNG:		msg = "did not terminate";		break;	default:		regerror(code, preg, msg = buf, sizeof buf);		break;	}	printf("%s\n", msg);}static voidbad(char* comment, char* re, char* s, int len, unsigned long test){	printf("bad test case ");	report(comment, NiL, re, s, len, NiL, 0, test);	exit(1);}static intescape(char* s){	char*	b;	char*	t;	char*	q;	char*	e;	int	c;	for (b = t = s; (*t = *s); s++, t++)		if (*s == '\\')			switch (*++s)			{			case '\\':				break;			case 'a':				*t = '\a';				break;			case 'b':				*t = '\b';				break;			case 'c':				if ((*t = *++s))					*t &= 037;				else					s--;				break;			case 'e':			case 'E':				*t = 033;				break;			case 'f':				*t = '\f';				break;			case 'n':				*t = '\n';				break;			case 'r':				*t = '\r';				break;			case 's':				*t = ' ';				break;			case 't':				*t = '\t';				break;			case 'v':				*t = '\v';				break;			case 'u':			case 'x':				c = 0;				q = c == 'u' ? (s + 5) : (char*)0;				e = s + 1;				while (!e || !q || s < q)				{					switch (*++s)					{					case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':						c = (c << 4) + *s - 'a' + 10;						continue;					case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':						c = (c << 4) + *s - 'A' + 10;						continue;					case '0': case '1': case '2': case '3': case '4':					case '5': case '6': case '7': case '8': case '9':						c = (c << 4) + *s - '0';						continue;					case '{':					case '[':						if (s != e)						{							s--;							break;						}						e = 0;						continue;					case '}':					case ']':						if (e)							s--;						break;					default:						s--;						break;					}					break;				}				*t = c;				break;			case '0': case '1': case '2': case '3':			case '4': case '5': case '6': case '7':				c = *s - '0';				q = s + 2;				while (s < q)				{					switch (*++s)					{					case '0': case '1': case '2': case '3':					case '4': case '5': case '6': case '7':						c = (c << 3) + *s - '0';						break;					default:						q = --s;						break;					}				}				*t = c;				break;			default:				*(s + 1) = 0;				bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);			}	return t - b;}static voidmatchoffprint(int off){	switch (off)	{	case -2:		printf("X");		break;	case -1:		printf("?");		break;	default:		printf("%d", off);		break;	}}static voidmatchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test){	int	i;	for (; nmatch > nsub + 1; nmatch--)		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)))			break;	for (i = 0; i < nmatch; i++)	{		printf("(");		matchoffprint(match[i].rm_so);		printf(",");		matchoffprint(match[i].rm_eo);		printf(")");	}	if (!(test & (TEST_ACTUAL|TEST_BASELINE)))	{		if (ans)			printf(" expected: %s", ans);		printf("\n");	}}static intmatchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test){	char*	p;	int	i;	int	m;	int	n;	if (streq(ans, "OK"))		return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);	for (i = 0, p = ans; i < nmatch && *p; i++)	{		if (*p == '{')		{#ifdef REG_DISCIPLINE			char*	x;			x = sfstruse(state.disc.sp);			if (strcmp(p, x))			{				if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))					return 0;				report("callout failed", NiL, re, s, len, NiL, flags, test);				quote(p, -1, test);				printf(" expected, ");				quote(x, -1, test);				printf(" returned\n");			}#endif			break;		}		if (*p++ != '(')			bad("improper answer\n", re, s, -1, test);		if (*p == '?')		{			m = -1;			p++;		}		else			m = strtol(p, &p, 10);		if (*p++ != ',')			bad("improper answer\n", re, s, -1, test);		if (*p == '?')		{			n = -1;			p++;		}		else			n = strtol(p, &p, 10);		if (*p++ != ')')			bad("improper answer\n", re, s, -1, test);		if (m!=match[i].rm_so || n!=match[i].rm_eo)		{			if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))			{				report("failed: match was", NiL, re, s, len, NiL, flags, test);				matchprint(match, nmatch, nsub, ans, test);			}			return 0;		}	}	for (; i < nmatch; i++)	{		if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)		{			if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))			{				if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))				{					state.ignored++;					return 0;				}				if (!(test & TEST_SUMMARY))				{					report("failed: match was", NiL, re, s, len, NiL, flags, test);					matchprint(match, nmatch, nsub, ans, test);				}			}			return 0;		}	}	if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)	{		if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))		{			report("failed: overran match array", NiL, re, s, len, NiL, flags, test);			matchprint(match, nmatch + 1, nsub, NiL, test);		}		return 0;	}	return 1;}static voidsigunblock(int s){#ifdef SIG_SETMASK	int		op;	sigset_t	mask;	sigemptyset(&mask);	if (s)	{		sigaddset(&mask, s);		op = SIG_UNBLOCK;	}	else op = SIG_SETMASK;	sigprocmask(op, &mask, NiL);#else#ifdef sigmask	sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);#endif#endif}static voidgotcha(int sig){	int	ret;	signal(sig, gotcha);	alarm(0);	state.signals++;	switch (sig)	{	case SIGALRM:		ret = REG_EHUNG;		break;	case SIGBUS:		ret = REG_EBUS;		break;	default:		ret = REG_EFAULT;		break;	}	sigunblock(sig);	longjmp(state.gotcha, ret);}static char*my_getline(FILE* fp){	static char	buf[32 * 1024];	register char*	s = buf;	register char*	e = &buf[sizeof(buf)];	register char*	b;	for (;;)	{		if (!(b = fgets(s, e - s, fp)))			return 0;		state.lineno++;		s += strlen(s);		if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')		{			*s = 0;			break;		}		s--;	}	return buf;}static unsigned longnote(unsigned long level, char* msg, unsigned long skip, unsigned long test){	if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)	{		printf("NOTE\t");		if (msg)			printf("%s: ", msg);		printf("skipping lines %d", state.lineno);	}	return skip | level;}#define TABS(n)		&ts[7-((n)&7)]static char		ts[] = "\t\t\t\t\t\t\t";static unsigned longextract(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){	if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))	{		state.extracted = 1;		if (test & TEST_OK)		{			state.passed++;			if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))			{				if (msg && strcmp(msg, "EXPECTED"))					printf("NOTE\t%s\n", msg);				return skip;			}			test &= ~(TEST_PASS|TEST_QUERY);		}		if (test & (TEST_QUERY|TEST_VERIFY))		{			if (test & TEST_BASELINE)				test &= ~(TEST_BASELINE|TEST_PASS);			else				test |= TEST_PASS;			skip |= level;		}		if (!(test & TEST_OK))		{			if (test & TEST_UNSPECIFIED)				state.unspecified++;			else				state.errors++;		}		if (test & (TEST_PASS|TEST_SUMMARY))			return skip;		test &= ~TEST_DELIMIT;		printf("%s%s", spec, TABS(*tabs++));		if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))			printf("SAME");		else			quote(re, -1, test);		printf("%s", TABS(*tabs++));		quote(s, -1, test);		printf("%s", TABS(*tabs++));		if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || (!accept && !match))			printf("%s", ans);		else if (accept)			printf("%s", accept);		else			matchprint(match, nmatch, nsub, NiL, test);		if (msg)			printf("%s%s", TABS(*tabs++), msg);		putchar('\n');	}	else if (test & TEST_QUERY)		skip = note(level, msg, skip, test);	else if (test & TEST_VERIFY)		state.extracted = 1;	return skip;}static intcatchfree(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){	int	eret;	if (!(test & TEST_CATCH))	{		regfree(preg);		eret = 0;	}	else if (!(eret = setjmp(state.gotcha)))	{		alarm(HUNG);		regfree(preg);		alarm(0);	}	else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))		extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);	else	{		report("failed", "regfree", re, NiL, -1, msg, flags, test);		error(preg, eret);	}	return eret;}intold_main(int unused_param_argc, char** argv){	int		flags;	int		cflags;	int		eflags;	int		nmatch;	int		nexec;	int		nstr;	int		cret;	int		eret;	int		nsub;	int		i;	int		j;	int		expected;	int		got;	int		locale;	int		subunitlen = 0;	int		testno;	unsigned long	level;	unsigned long	skip;	char*		p;	char*		line;	char*		spec;	char*		re;	char*		s;	char*		ans;	char*		msg;	char*		fun;	char*		ppat = NULL;	char*		subunit = NULL;	char*		version;	char*		field[6];	char*		delim[6];	FILE*		fp;	int		tabs[6];	char		unit[64];	regmatch_t	match[100];	regex_t		preg;	static char	pat[32 * 1024];	int		nonosub = REG_NOSUB == 0;	int		nonexec = 0;	unsigned long	test = 0;	static char*	filter[] = { "-", 0 };	state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;	p = unit;	version = (char*)id + 10;	while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))		p++;	*p = 0;	while ((p = *++argv) && *p == '-')		for (;;)		{			switch (*++p)			{			case 0:				break;			case 'c':				test |= TEST_CATCH;				continue;			case 'e':				test |= TEST_IGNORE_ERROR;				continue;			case 'h':			case '?':				help(0);				return 2;			case '-':				help(p[1] == 'h');				return 2;			case 'n':				nonexec = 1;				continue;			case 'o':				test |= TEST_IGNORE_OVER;				continue;			case 'p':				test |= TEST_IGNORE_POSITION;				continue;			case 's':#ifdef REG_DISCIPLINE				if (!(state.stack = stkalloc(stkstd, 0)))					fprintf(stderr, "%s: out of space [stack]", unit);				state.disc.disc.re_resizef = resizef;				state.disc.disc.re_resizehandle = (void*)stkstd;#endif				continue;			case 'x':				nonosub = 1;				continue;			case 'v':				test |= TEST_VERBOSE;				continue;			case 'A':				test |= TEST_ACTUAL;				continue;			case 'B':				test |= TEST_BASELINE;				continue;			case 'F':				test |= TEST_FAIL;				continue;			case 'P':				test |= TEST_PASS;				continue;			case 'S':				test |= TEST_SUMMARY;				continue;			default:				fprintf(stderr, "%s: %c: invalid option\n", unit, *p);				return 2;			}			break;		}	if (!*argv)		argv = filter;	locale = 0;	while ((state.file = *argv++))	{		if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))		{			state.file = 0;			fp = stdin;		}		else if (!(fp = fopen(state.file, "r")))		{			fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);			return 2;		}		testno = state.errors = state.ignored = state.lineno = state.passed =		state.signals = state.unspecified = state.warnings = 0;		skip = 0;		level = 1;		if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))		{			printf("TEST\t%s ", unit);			if ((s = state.file))			{				subunit = p = 0;				for (;;)				{					switch (*s++)					{					case 0:						break;					case '/':						subunit = s;						continue;					case '.':						p = s - 1;						continue;					default:						continue;					}					break;				}				if (!subunit)					subunit = state.file;				if (p < subunit)					p = s - 1;				subunitlen = p - subunit;				printf("%-.*s ", subunitlen, subunit);			}			else				subunit = 0;			for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)				putchar(*s);			if (test & TEST_CATCH)				printf(", catch");			if (test & TEST_IGNORE_ERROR)				printf(", ignore error code mismatches");			if (test & TEST_IGNORE_POSITION)				printf(", ignore negative position mismatches");#ifdef REG_DISCIPLINE			if (state.stack)				printf(", stack");#endif			if (test & TEST_VERBOSE)				printf(", verbose");			printf("\n");#ifdef REG_VERSIONID			if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)				s = pat;			else#endif#ifdef REG_TEST_VERSION			s = REG_TEST_VERSION;#else			s = "regex";#endif			printf("NOTE\t%s\n", s);			if (elementsof(unsupported) > 1)			{#if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)				i = 0;#else				i = REG_EXTENDED != 0;#endif				for (got = 0; i < elementsof(unsupported) - 1; i++)				{					if (!got)					{						got = 1;						printf("NOTE\tunsupported: %s", unsupported[i]);					}					else						printf(",%s", unsupported[i]);				}				if (got)					printf("\n");			}		}#ifdef REG_DISCIPLINE		state.disc.disc.re_version = REG_VERSION;		state.disc.disc.re_compf = compf;		state.disc.disc.re_execf = execf;		if (!(state.disc.sp = sfstropen()))			bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);		preg.re_disc = &state.disc.disc;#endif		if (test & TEST_CATCH)		{			signal(SIGALRM, gotcha);			signal(SIGBUS, gotcha);			signal(SIGSEGV, gotcha);		}		while ((p = my_getline(fp)))		{		/* parse: */			line = p;			if (*p == ':' && !isspace(*(p + 1)))			{				while (*++p && *p != ':');				if (!*p++)				{					if (test & TEST_BASELINE)						printf("%s\n", line);					continue;				}			}			while (isspace(*p))				p++;			if (*p == 0 || *p == '#' || *p == 'T')			{				if (test & TEST_BASELINE)					printf("%s\n", line);				continue;			}			if (*p == ':' || *p == 'N')			{				if (test & TEST_BASELINE)					printf("%s\n", line);				else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))				{					while (*++p && !isspace(*p));					while (isspace(*p))						p++;					printf("NOTE	%s\n", p);				}				continue;			}			j = 0;			i = 0;			field[i++] = p;			for (;;)			{				switch (*p++)				{				case 0:					p--;					j = 0;					goto checkfield;				case '\t':					*(delim[i] = p - 1) = 0;					j = 1;				checkfield:					s = field[i - 1];					if (streq(s, "NIL"))						field[i - 1] = 0;					else if (streq(s, "NULL"))						*s = 0;					while (*p == '\t')					{						p++;						j++;					}					tabs[i - 1] = j;					if (!*p)						break;					if (i >= elementsof(field))						bad("too many fields\n", NiL, NiL, 0, 0);					field[i++] = p;					/*FALLTHROUGH*/				default:					continue;				}				break;			}			if (!(spec = field[0]))				bad("NIL spec\n", NiL, NiL, 0, 0);		/* interpret: */			cflags = REG_TEST_DEFAULT;			eflags = REG_EXEC_DEFAULT;			test &= TEST_GLOBAL;			state.extracted = 0;			nmatch = 20;			nsub = -1;			for (p = spec; *p; p++)			{				if (isdigit(*p))				{					nmatch = strtol(p, &p, 10);					if (nmatch >= elementsof(match))						bad("nmatch must be < 100\n", NiL, NiL, 0, 0);					p--;					continue;				}				switch (*p)				{				case 'A':					test |= TEST_ARE;					continue;				case 'B':					test |= TEST_BRE;					continue;				case 'C':					if (!(test & TEST_QUERY) && !(skip & level))						bad("locale must be nested\n", NiL, NiL, 0, 0);					test &= ~TEST_QUERY;					if (locale)						bad("locale nesting not supported\n", NiL, NiL, 0, 0);					if (i != 2)						bad("locale field expected\n", NiL, NiL, 0, 0);					if (!(skip & level))					{#if defined(LC_COLLATE) && defined(LC_CTYPE)						s = field[1];						if (!s || streq(s, "POSIX"))							s = "C";						if (!(ans = setlocale(LC_COLLATE, s)) || streq(ans, "C") || streq(ans, "POSIX") || !(ans = setlocale(LC_CTYPE, s)) || streq(ans, "C") || streq(ans, "POSIX"))							skip = note(level, s, skip, test);						else						{							if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))								printf("NOTE	\"%s\" locale\n", s);							locale = level;						}#else						skip = note(level, skip, test, "locales not supported");#endif					}					cflags = NOTEST;					continue;				case 'E':					test |= TEST_ERE;					continue;				case 'K':					test |= TEST_KRE;					continue;				case 'L':					test |= TEST_LRE;					continue;				case 'S':					test |= TEST_SRE;					continue;				case 'a':					cflags |= REG_LEFT|REG_RIGHT;					continue;				case 'b':					eflags |= REG_NOTBOL;					continue;				case 'c':					cflags |= REG_COMMENT;					continue;				case 'd':					cflags |= REG_SHELL_DOT;					continue;				case 'e':					eflags |= REG_NOTEOL;					continue;				case 'f':					cflags |= REG_MULTIPLE;					continue;				case 'g':					cflags |= NOTEST;					continue;				case 'h':					cflags |= REG_MULTIREF;					continue;				case 'i':					cflags |= REG_ICASE;					continue;				case 'j':					cflags |= REG_SPAN;					continue;				case 'k':					cflags |= REG_ESCAPE;					continue;				case 'l':					cflags |= REG_LEFT;					continue;				case 'm':					cflags |= REG_MINIMAL;					continue;				case 'n':					cflags |= REG_NEWLINE;					continue;				case 'o':					cflags |= REG_SHELL_GROUP;					continue;				case 'p':					cflags |= REG_SHELL_PATH;					continue;				case 'q':					cflags |= REG_DELIMITED;					continue;				case 'r':					cflags |= REG_RIGHT;					continue;				case 's':					cflags |= REG_SHELL_ESCAPED;					continue;				case 't':					cflags |= REG_MUSTDELIM;					continue;				case 'u':					test |= TEST_UNSPECIFIED;					continue;				case 'w':					cflags |= REG_NOSUB;					continue;				case 'x':					if (REG_LENIENT)						cflags |= REG_LENIENT;					else						test |= TEST_LENIENT;					continue;				case 'y':					eflags |= REG_LEFT;					continue;				case 'z':					cflags |= REG_NULL;					continue;				case '$':					test |= TEST_EXPAND;					continue;				case '/':					test |= TEST_SUB;					continue;				case '?':					test |= TEST_VERIFY;					test &= ~(TEST_AND|TEST_OR);					state.verify = state.passed;					continue;				case '&':					test |= TEST_VERIFY|TEST_AND;					test &= ~TEST_OR;					continue;				case '|':					test |= TEST_VERIFY|TEST_OR;					test &= ~TEST_AND;					continue;				case ';':					test |= TEST_OR;					test &= ~TEST_AND;					continue;				case '{':					level <<= 1;					if (skip & (level >> 1))					{						skip |= level;						cflags = NOTEST;					}					else					{						skip &= ~level;						test |= TEST_QUERY;					}					continue;				case '}':					if (level == 1)						bad("invalid {...} nesting\n", NiL, NiL, 0, 0);					if ((skip & level) && !(skip & (level>>1)))					{						if (!(test & (TEST_BASELINE|TEST_SUMMARY)))						{							if (test & (TEST_ACTUAL|TEST_FAIL))								printf("}\n");							else if (!(test & TEST_PASS))								printf("-%d\n", state.lineno);						}					}#if defined(LC_COLLATE) && defined(LC_CTYPE)					else if (locale & level)					{						locale = 0;						if (!(skip & level))						{							s = "C";							setlocale(LC_COLLATE, s);							setlocale(LC_CTYPE, s);							if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))								printf("NOTE	\"%s\" locale\n", s);							else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))								printf("}\n");						}						else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))							printf("}\n");					}#endif					level >>= 1;					cflags = NOTEST;					continue;				default:					bad("bad spec\n", spec, NiL, 0, test);					break;				}				break;			}			if ((cflags|eflags) == NOTEST || ((skip & level) && (test & TEST_BASELINE)))			{				if (test & TEST_BASELINE)				{					while (i > 1)						*delim[--i] = '\t';					printf("%s\n", line);				}				continue;			}			if (test & TEST_OR)			{				if (!(test & TEST_VERIFY))				{					test &= ~TEST_OR;					if (state.passed == state.verify && i > 1)						printf("NOTE\t%s\n", field[1]);					continue;				}				else if (state.passed > state.verify)					continue;			}			else if (test & TEST_AND)			{				if (state.passed == state.verify)					continue;				state.passed = state.verify;			}			if (i < 4)				bad("too few fields\n", NiL, NiL, 0, test);			while (i < elementsof(field))				field[i++] = 0;			if ((re = field[1]))			{				if (streq(re, "SAME"))				{					re = ppat;					test |= TEST_SAME;				}				else				{					if (test & TEST_EXPAND)						escape(re);					strcpy(ppat = pat, re);				}			}			else				ppat = 0;			nstr = -1;			if ((s = field[2]) && (test & TEST_EXPAND))			{				nstr = escape(s);#if _REG_nexec				if (nstr != strlen(s))					nexec = nstr;#endif			}			if (!(ans = field[3]))				bad("NIL answer\n", NiL, NiL, 0, test);			msg = field[4];			fflush(stdout);			if (test & TEST_SUB)#if _REG_subcomp				cflags |= REG_DELIMITED;#else				continue;#endif		compile:			if (state.extracted || (skip & level))				continue;#if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))#ifdef REG_EXTENDED			if (REG_EXTENDED != 0 && (test & TEST_BRE))#else			if (test & TEST_BRE)#endif			{				test &= ~TEST_BRE;				flags = cflags;				state.which = "BRE";			}			else#endif#ifdef REG_EXTENDED			if (test & TEST_ERE)			{				test &= ~TEST_ERE;				flags = cflags | REG_EXTENDED;				state.which = "ERE";			}			else#endif#ifdef REG_AUGMENTED			if (test & TEST_ARE)			{				test &= ~TEST_ARE;				flags = cflags | REG_AUGMENTED;				state.which = "ARE";			}			else#endif#ifdef REG_LITERAL			if (test & TEST_LRE)			{				test &= ~TEST_LRE;				flags = cflags | REG_LITERAL;				state.which = "LRE";			}			else#endif#ifdef REG_SHELL			if (test & TEST_SRE)			{				test &= ~TEST_SRE;				flags = cflags | REG_SHELL;				state.which = "SRE";			}			else#ifdef REG_AUGMENTED			if (test & TEST_KRE)			{				test &= ~TEST_KRE;				flags = cflags | REG_SHELL | REG_AUGMENTED;				state.which = "KRE";			}			else#endif#endif			{				if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))					extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);				continue;			}			if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)			{				printf("test %-3d %s ", state.lineno, state.which);				quote(re, -1, test|TEST_DELIMIT);				printf(" ");				quote(s, nstr, test|TEST_DELIMIT);				printf("\n");			}		nosub:			fun = "regcomp";#if _REG_nexec			if (nstr >= 0 && nstr != strlen(s))				nexec = nstr;			else#endif				nexec = -1;			if (state.extracted || (skip & level))				continue;			if (!(test & TEST_QUERY))				testno++;#ifdef REG_DISCIPLINE			if (state.stack)				stkset(stkstd, state.stack, 0);			flags |= REG_DISCIPLINE;			state.disc.ordinal = 0;			sfstrseek(state.disc.sp, 0, SEEK_SET);#endif			if (!(test & TEST_CATCH))				cret = regcomp(&preg, re, flags);			else if (!(cret = setjmp(state.gotcha)))			{				alarm(HUNG);				cret = regcomp(&preg, re, flags);				alarm(0);			}#if _REG_subcomp			if (!cret && (test & TEST_SUB))			{				fun = "regsubcomp";				p = re + preg.re_npat;				if (!(test & TEST_CATCH))					cret = regsubcomp(&preg, p, NiL, 0, 0);				else if (!(cret = setjmp(state.gotcha)))				{					alarm(HUNG);					cret = regsubcomp(&preg, p, NiL, 0, 0);					alarm(0);				}				if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))				{					if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))						continue;					cret = REG_EFLAGS;				}			}#endif			if (!cret)			{				if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')				{					for (p = ans; *p; p++)						if (*p == '(')							nsub++;						else if (*p == '{')							nsub--;					if (nsub >= 0)					{						if (test & TEST_IGNORE_OVER)						{							if (nmatch > nsub)								nmatch = nsub + 1;						}						else if (nsub != preg.re_nsub)						{							if (nsub > preg.re_nsub)							{								if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))									skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);								else								{									report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);									printf("at least %d expected, %zd returned\n", nsub, preg.re_nsub);									state.errors++;								}							}							else								nsub = preg.re_nsub;						}					}				}				if (!(test & TEST_SUB) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))				{					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))						skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);					else if (!(test & TEST_LENIENT))					{						report("failed", fun, re, NiL, -1, msg, flags, test);						printf("%s expected, OK returned\n", ans);					}					catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);					continue;				}			}			else			{				if (test & TEST_LENIENT)					/* we'll let it go this time */;				else if (!*ans || ans[0]=='(' || (cret == REG_BADPAT && streq(ans, "NOMATCH")))				{					got = 0;					for (i = 1; i < elementsof(codes); i++)						if (cret==codes[i].code)							got = i;					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))						skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);					else					{						report("failed", fun, re, NiL, -1, msg, flags, test);						printf("%s returned: ", codes[got].name);						error(&preg, cret);					}				}				else				{					expected = got = 0;					for (i = 1; i < elementsof(codes); i++)					{						if (streq(ans, codes[i].name))							expected = i;						if (cret==codes[i].code)							got = i;					}					if (!expected)					{						if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))							skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);						else						{							report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);							printf("%s expected, %s returned\n", ans, codes[got].name);						}					}					else if (cret != codes[expected].code && cret != REG_BADPAT)					{						if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))							skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);						else if (test & TEST_IGNORE_ERROR)							state.ignored++;						else						{							report("should fail and did", fun, re, NiL, -1, msg, flags, test);							printf("%s expected, %s returned: ", ans, codes[got].name);							state.errors--;							state.warnings++;							error(&preg, cret);						}					}				}				goto compile;			}#if _REG_nexec		execute:			if (nexec >= 0)				fun = "regnexec";			else#endif				fun = "regexec";			for (i = 0; i < elementsof(match); i++)				match[i] = state.NOMATCH;#if _REG_nexec			if (nexec >= 0)			{				eret = regnexec(&preg, s, nexec, nmatch, match, eflags);				s[nexec] = 0;			}			else#endif			{				if (!(test & TEST_CATCH))					eret = regexec(&preg, s, nmatch, match, eflags);				else if (!(eret = setjmp(state.gotcha)))				{					alarm(HUNG);					eret = regexec(&preg, s, nmatch, match, eflags);					alarm(0);				}			}#if _REG_subcomp			if ((test & TEST_SUB) && !eret)			{				fun = "regsubexec";				if (!(test & TEST_CATCH))					eret = regsubexec(&preg, s, nmatch, match);				else if (!(eret = setjmp(state.gotcha)))				{					alarm(HUNG);					eret = regsubexec(&preg, s, nmatch, match);					alarm(0);				}			}#endif			if (flags & REG_NOSUB)			{				if (eret)				{					if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))					{						if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))							skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);						else						{							report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);							error(&preg, eret);						}					}				}				else if (streq(ans, "NOMATCH"))				{					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))						skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);					else					{						report("should fail and didn't", fun, re, s, nstr, msg, flags, test);						error(&preg, eret);					}				}			}			else if (eret)			{				if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))				{					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))						skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);					else					{						report("failed", fun, re, s, nstr, msg, flags, test);						if (eret != REG_NOMATCH)							error(&preg, eret);						else if (*ans)							printf("expected: %s\n", ans);						else							printf("\n");					}				}			}			else if (streq(ans, "NOMATCH"))			{				if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))					skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);				else				{					report("should fail and didn't", fun, re, s, nstr, msg, flags, test);					matchprint(match, nmatch, nsub, NiL, test);				}			}#if _REG_subcomp			else if (test & TEST_SUB)			{				p = preg.re_sub->re_buf;				if (strcmp(p, ans))				{					report("failed", fun, re, s, nstr, msg, flags, test);					quote(ans, -1, test|TEST_DELIMIT);					printf(" expected, ");					quote(p, -1, test|TEST_DELIMIT);					printf(" returned\n");				}			}#endif			else if (!*ans)			{				if (match[0].rm_so != state.NOMATCH.rm_so)				{					if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))						skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);					else					{						report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);						matchprint(match, nmatch, nsub, NiL, test);					}				}			}			else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))			{#if _REG_nexec				if (nexec < 0 && !nonexec)				{					nexec = nstr >= 0 ? nstr : strlen(s);					s[nexec] = '\n';					testno++;					goto execute;				}#endif				if (!(test & (TEST_SUB|TEST_VERIFY)) && !nonosub)				{					if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))						continue;					flags |= REG_NOSUB;					goto nosub;				}				if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))					skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);			}			else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))				skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);			if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))				continue;			goto compile;		}		if (test & TEST_SUMMARY)			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);		else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))		{			printf("TEST\t%s", unit);			if (subunit)				printf(" %-.*s", subunitlen, subunit);			printf(", %d test%s", testno, testno == 1 ? "" : "s");			if (state.ignored)				printf(", %d ignored mismatch%s", state.ignored, state.ignored == 1 ? "" : "es");			if (state.warnings)				printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");			if (state.unspecified)				printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");			if (state.signals)				printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");			printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");		}		if (fp != stdin)			fclose(fp);	}	return 0;}int main(int argc, char **argv){	static char *param[][4] = {		{ NULL,       "basic.dat"         , NULL },		{ NULL,       "categorize.dat"    , NULL },		{ NULL,       "forcedassoc.dat"   , NULL },		{ NULL, "-c", "interpretation.dat", NULL },		{ NULL,       "leftassoc.dat"     , NULL },		{ NULL, "-c", "nullsubexpr.dat"   , NULL },		{ NULL,       "repetition.dat"    , NULL },		{ NULL,       "rightassoc.dat"    , NULL },	};	int r, i;	if (argv[1])		return old_main(argc, argv);	r = 0;	for (i = 0; i < sizeof(param) / sizeof(param[0]); i++) {		param[i][0] = argv[0];		printf("Testing %s\n", param[i][1][0] != '-' ? param[i][1] : param[i][2]);		r |= old_main(3 /* not used */, param[i]);	}	return r;}
 |