116b8cff5SYuri Pankov #pragma prototyped noticed
216b8cff5SYuri Pankov
316b8cff5SYuri Pankov /*
416b8cff5SYuri Pankov * regex(3) test harness
516b8cff5SYuri Pankov *
616b8cff5SYuri Pankov * build: cc -o testregex testregex.c
716b8cff5SYuri Pankov * help: testregex --man
816b8cff5SYuri Pankov * note: REG_* features are detected by #ifdef; if REG_* are enums
916b8cff5SYuri Pankov * then supply #define REG_foo REG_foo for each enum REG_foo
1016b8cff5SYuri Pankov *
1116b8cff5SYuri Pankov * Glenn Fowler <glenn.s.fowler@gmail.com>
1216b8cff5SYuri Pankov * AT&T Research
1316b8cff5SYuri Pankov *
1416b8cff5SYuri Pankov * PLEASE: publish your tests so everyone can benefit
1516b8cff5SYuri Pankov *
1616b8cff5SYuri Pankov * The following license covers testregex.c and all associated test data.
1716b8cff5SYuri Pankov *
1816b8cff5SYuri Pankov * Permission is hereby granted, free of charge, to any person obtaining a
1916b8cff5SYuri Pankov * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
2016b8cff5SYuri Pankov * without restriction, including without limitation the rights to use,
2116b8cff5SYuri Pankov * copy, modify, merge, publish, distribute, and/or sell copies of the
2216b8cff5SYuri Pankov * Software, and to permit persons to whom the Software is furnished to do
2316b8cff5SYuri Pankov * so, subject to the following disclaimer:
2416b8cff5SYuri Pankov *
2516b8cff5SYuri Pankov * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
2616b8cff5SYuri Pankov * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
2716b8cff5SYuri Pankov * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
2816b8cff5SYuri Pankov * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
2916b8cff5SYuri Pankov * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
3016b8cff5SYuri Pankov * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
3116b8cff5SYuri Pankov * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
3216b8cff5SYuri Pankov * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
3316b8cff5SYuri Pankov * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
3416b8cff5SYuri Pankov * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
3516b8cff5SYuri Pankov */
3616b8cff5SYuri Pankov
3716b8cff5SYuri Pankov static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2010-06-10 $\0\n";
3816b8cff5SYuri Pankov
3916b8cff5SYuri Pankov #if _PACKAGE_ast
4016b8cff5SYuri Pankov #include <ast.h>
4116b8cff5SYuri Pankov #else
4216b8cff5SYuri Pankov #include <sys/types.h>
4316b8cff5SYuri Pankov #endif
4416b8cff5SYuri Pankov
4516b8cff5SYuri Pankov #include <stdio.h>
4616b8cff5SYuri Pankov #include <regex.h>
4716b8cff5SYuri Pankov #include <ctype.h>
4816b8cff5SYuri Pankov #include <setjmp.h>
4916b8cff5SYuri Pankov #include <signal.h>
5016b8cff5SYuri Pankov #include <string.h>
5116b8cff5SYuri Pankov #include <unistd.h>
5216b8cff5SYuri Pankov
5316b8cff5SYuri Pankov #ifdef __STDC__
5416b8cff5SYuri Pankov #include <stdlib.h>
5516b8cff5SYuri Pankov #include <locale.h>
5616b8cff5SYuri Pankov #endif
5716b8cff5SYuri Pankov
5816b8cff5SYuri Pankov #ifndef RE_DUP_MAX
5916b8cff5SYuri Pankov #define RE_DUP_MAX 32767
6016b8cff5SYuri Pankov #endif
6116b8cff5SYuri Pankov
6216b8cff5SYuri Pankov #if !_PACKAGE_ast
6316b8cff5SYuri Pankov #undef REG_DISCIPLINE
6416b8cff5SYuri Pankov #endif
6516b8cff5SYuri Pankov
6616b8cff5SYuri Pankov #ifndef REG_DELIMITED
6716b8cff5SYuri Pankov #undef _REG_subcomp
6816b8cff5SYuri Pankov #endif
6916b8cff5SYuri Pankov
7016b8cff5SYuri Pankov #define TEST_ARE 0x00000001
7116b8cff5SYuri Pankov #define TEST_BRE 0x00000002
7216b8cff5SYuri Pankov #define TEST_ERE 0x00000004
7316b8cff5SYuri Pankov #define TEST_KRE 0x00000008
7416b8cff5SYuri Pankov #define TEST_LRE 0x00000010
7516b8cff5SYuri Pankov #define TEST_SRE 0x00000020
7616b8cff5SYuri Pankov
7716b8cff5SYuri Pankov #define TEST_EXPAND 0x00000100
7816b8cff5SYuri Pankov #define TEST_LENIENT 0x00000200
7916b8cff5SYuri Pankov
8016b8cff5SYuri Pankov #define TEST_QUERY 0x00000400
8116b8cff5SYuri Pankov #define TEST_SUB 0x00000800
8216b8cff5SYuri Pankov #define TEST_UNSPECIFIED 0x00001000
8316b8cff5SYuri Pankov #define TEST_VERIFY 0x00002000
8416b8cff5SYuri Pankov #define TEST_AND 0x00004000
8516b8cff5SYuri Pankov #define TEST_OR 0x00008000
8616b8cff5SYuri Pankov
8716b8cff5SYuri Pankov #define TEST_DELIMIT 0x00010000
8816b8cff5SYuri Pankov #define TEST_OK 0x00020000
8916b8cff5SYuri Pankov #define TEST_SAME 0x00040000
9016b8cff5SYuri Pankov
9116b8cff5SYuri Pankov #define TEST_ACTUAL 0x00100000
9216b8cff5SYuri Pankov #define TEST_BASELINE 0x00200000
9316b8cff5SYuri Pankov #define TEST_FAIL 0x00400000
9416b8cff5SYuri Pankov #define TEST_PASS 0x00800000
9516b8cff5SYuri Pankov #define TEST_SUMMARY 0x01000000
9616b8cff5SYuri Pankov
9716b8cff5SYuri Pankov #define TEST_IGNORE_ERROR 0x02000000
9816b8cff5SYuri Pankov #define TEST_IGNORE_OVER 0x04000000
9916b8cff5SYuri Pankov #define TEST_IGNORE_POSITION 0x08000000
10016b8cff5SYuri Pankov
10116b8cff5SYuri Pankov #define TEST_CATCH 0x10000000
10216b8cff5SYuri Pankov #define TEST_VERBOSE 0x20000000
10316b8cff5SYuri Pankov
10416b8cff5SYuri Pankov #define TEST_DECOMP 0x40000000
10516b8cff5SYuri Pankov
10616b8cff5SYuri Pankov #define TEST_GLOBAL (TEST_ACTUAL|TEST_AND|TEST_BASELINE|TEST_CATCH|TEST_FAIL|TEST_IGNORE_ERROR|TEST_IGNORE_OVER|TEST_IGNORE_POSITION|TEST_OR|TEST_PASS|TEST_SUMMARY|TEST_VERBOSE)
10716b8cff5SYuri Pankov
10816b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
10916b8cff5SYuri Pankov
11016b8cff5SYuri Pankov
11116b8cff5SYuri Pankov #include <stk.h>
11216b8cff5SYuri Pankov
11316b8cff5SYuri Pankov typedef struct Disc_s
11416b8cff5SYuri Pankov {
11516b8cff5SYuri Pankov regdisc_t disc;
11616b8cff5SYuri Pankov int ordinal;
11716b8cff5SYuri Pankov Sfio_t* sp;
11816b8cff5SYuri Pankov } Disc_t;
11916b8cff5SYuri Pankov
12016b8cff5SYuri Pankov static void*
compf(const regex_t * re,const char * xstr,size_t xlen,regdisc_t * disc)12116b8cff5SYuri Pankov compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc)
12216b8cff5SYuri Pankov {
12316b8cff5SYuri Pankov Disc_t* dp = (Disc_t*)disc;
12416b8cff5SYuri Pankov
12516b8cff5SYuri Pankov return (void*)((char*)0 + ++dp->ordinal);
12616b8cff5SYuri Pankov }
12716b8cff5SYuri Pankov
12816b8cff5SYuri Pankov static int
execf(const regex_t * re,void * data,const char * xstr,size_t xlen,const char * sstr,size_t slen,char ** snxt,regdisc_t * disc)12916b8cff5SYuri Pankov execf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc)
13016b8cff5SYuri Pankov {
13116b8cff5SYuri Pankov Disc_t* dp = (Disc_t*)disc;
13216b8cff5SYuri Pankov
13316b8cff5SYuri Pankov sfprintf(dp->sp, "{%-.*s}(%lu:%d)", xlen, xstr, (char*)data - (char*)0, slen);
13416b8cff5SYuri Pankov return atoi(xstr);
13516b8cff5SYuri Pankov }
13616b8cff5SYuri Pankov
13716b8cff5SYuri Pankov static void*
resizef(void * handle,void * data,size_t size)13816b8cff5SYuri Pankov resizef(void* handle, void* data, size_t size)
13916b8cff5SYuri Pankov {
14016b8cff5SYuri Pankov if (!size)
14116b8cff5SYuri Pankov return 0;
14216b8cff5SYuri Pankov return stkalloc((Sfio_t*)handle, size);
14316b8cff5SYuri Pankov }
14416b8cff5SYuri Pankov
14516b8cff5SYuri Pankov #endif
14616b8cff5SYuri Pankov
14716b8cff5SYuri Pankov #ifndef NiL
14816b8cff5SYuri Pankov #ifdef __STDC__
14916b8cff5SYuri Pankov #define NiL 0
15016b8cff5SYuri Pankov #else
15116b8cff5SYuri Pankov #define NiL (char*)0
15216b8cff5SYuri Pankov #endif
15316b8cff5SYuri Pankov #endif
15416b8cff5SYuri Pankov
15516b8cff5SYuri Pankov #define H(x) do{if(html)fprintf(stderr,x);}while(0)
15616b8cff5SYuri Pankov #define T(x) fprintf(stderr,x)
15716b8cff5SYuri Pankov
15816b8cff5SYuri Pankov static void
help(int html)15916b8cff5SYuri Pankov help(int html)
16016b8cff5SYuri Pankov {
16116b8cff5SYuri Pankov H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");
16216b8cff5SYuri Pankov H("<HTML>\n");
16316b8cff5SYuri Pankov H("<HEAD>\n");
16416b8cff5SYuri Pankov H("<TITLE>testregex man document</TITLE>\n");
16516b8cff5SYuri Pankov H("</HEAD>\n");
16616b8cff5SYuri Pankov H("<BODY bgcolor=white>\n");
16716b8cff5SYuri Pankov H("<PRE>\n");
16816b8cff5SYuri Pankov T("NAME\n");
16916b8cff5SYuri Pankov T(" testregex - regex(3) test harness\n");
17016b8cff5SYuri Pankov T("\n");
17116b8cff5SYuri Pankov T("SYNOPSIS\n");
17216b8cff5SYuri Pankov T(" testregex [ options ]\n");
17316b8cff5SYuri Pankov T("\n");
17416b8cff5SYuri Pankov T("DESCRIPTION\n");
17516b8cff5SYuri Pankov T(" testregex reads regex(3) test specifications, one per line, from the\n");
17616b8cff5SYuri Pankov T(" standard input and writes one output line for each failed test. A\n");
17716b8cff5SYuri Pankov T(" summary line is written after all tests are done. Each successful\n");
17816b8cff5SYuri Pankov T(" test is run again with REG_NOSUB. Unsupported features are noted\n");
17916b8cff5SYuri Pankov T(" before the first test, and tests requiring these features are\n");
18016b8cff5SYuri Pankov T(" silently ignored.\n");
18116b8cff5SYuri Pankov T("\n");
18216b8cff5SYuri Pankov T("OPTIONS\n");
18316b8cff5SYuri Pankov T(" -c catch signals and non-terminating calls\n");
18416b8cff5SYuri Pankov T(" -e ignore error return mismatches\n");
18516b8cff5SYuri Pankov T(" -h list help on standard error\n");
18616b8cff5SYuri Pankov T(" -n do not repeat successful tests with regnexec()\n");
18716b8cff5SYuri Pankov T(" -o ignore match[] overrun errors\n");
18816b8cff5SYuri Pankov T(" -p ignore negative position mismatches\n");
18916b8cff5SYuri Pankov T(" -s use stack instead of malloc\n");
19016b8cff5SYuri Pankov T(" -x do not repeat successful tests with REG_NOSUB\n");
19116b8cff5SYuri Pankov T(" -v list each test line\n");
19216b8cff5SYuri Pankov T(" -A list failed test lines with actual answers\n");
19316b8cff5SYuri Pankov T(" -B list all test lines with actual answers\n");
19416b8cff5SYuri Pankov T(" -F list failed test lines\n");
19516b8cff5SYuri Pankov T(" -P list passed test lines\n");
19616b8cff5SYuri Pankov T(" -S output one summary line\n");
19716b8cff5SYuri Pankov T("\n");
19816b8cff5SYuri Pankov T("INPUT FORMAT\n");
19916b8cff5SYuri Pankov T(" Input lines may be blank, a comment beginning with #, or a test\n");
20016b8cff5SYuri Pankov T(" specification. A specification is five fields separated by one\n");
20116b8cff5SYuri Pankov T(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
20216b8cff5SYuri Pankov T(" 0 pointer.\n");
20316b8cff5SYuri Pankov T("\n");
20416b8cff5SYuri Pankov T(" Field 1: the regex(3) flags to apply, one character per REG_feature\n");
20516b8cff5SYuri Pankov T(" flag. The test is skipped if REG_feature is not supported by the\n");
20616b8cff5SYuri Pankov T(" implementation. If the first character is not [BEASKLP] then the\n");
20716b8cff5SYuri Pankov T(" specification is a global control line. One or more of [BEASKLP] may be\n");
20816b8cff5SYuri Pankov T(" specified; the test will be repeated for each mode.\n");
20916b8cff5SYuri Pankov T("\n");
21016b8cff5SYuri Pankov T(" B basic BRE (grep, ed, sed)\n");
21116b8cff5SYuri Pankov T(" E REG_EXTENDED ERE (egrep)\n");
21216b8cff5SYuri Pankov T(" A REG_AUGMENTED ARE (egrep with negation)\n");
21316b8cff5SYuri Pankov T(" S REG_SHELL SRE (sh glob)\n");
21416b8cff5SYuri Pankov T(" K REG_SHELL|REG_AUGMENTED KRE (ksh glob)\n");
21516b8cff5SYuri Pankov T(" L REG_LITERAL LRE (fgrep)\n");
21616b8cff5SYuri Pankov T("\n");
21716b8cff5SYuri Pankov T(" a REG_LEFT|REG_RIGHT implicit ^...$\n");
21816b8cff5SYuri Pankov T(" b REG_NOTBOL lhs does not match ^\n");
21916b8cff5SYuri Pankov T(" c REG_COMMENT ignore space and #...\\n\n");
22016b8cff5SYuri Pankov T(" d REG_SHELL_DOT explicit leading . match\n");
22116b8cff5SYuri Pankov T(" e REG_NOTEOL rhs does not match $\n");
22216b8cff5SYuri Pankov T(" f REG_MULTIPLE multiple \\n separated patterns\n");
22316b8cff5SYuri Pankov T(" g FNM_LEADING_DIR testfnmatch only -- match until /\n");
22416b8cff5SYuri Pankov T(" h REG_MULTIREF multiple digit backref\n");
22516b8cff5SYuri Pankov T(" i REG_ICASE ignore case\n");
22616b8cff5SYuri Pankov T(" j REG_SPAN . matches \\n\n");
22716b8cff5SYuri Pankov T(" k REG_ESCAPE \\ to ecape [...] delimiter\n");
22816b8cff5SYuri Pankov T(" l REG_LEFT implicit ^...\n");
22916b8cff5SYuri Pankov T(" m REG_MINIMAL minimal match\n");
23016b8cff5SYuri Pankov T(" n REG_NEWLINE explicit \\n match\n");
23116b8cff5SYuri Pankov T(" o REG_ENCLOSED (|&) magic inside [@|&](...)\n");
23216b8cff5SYuri Pankov T(" p REG_SHELL_PATH explicit / match\n");
23316b8cff5SYuri Pankov T(" q REG_DELIMITED delimited pattern\n");
23416b8cff5SYuri Pankov T(" r REG_RIGHT implicit ...$\n");
23516b8cff5SYuri Pankov T(" s REG_SHELL_ESCAPED \\ not special\n");
23616b8cff5SYuri Pankov T(" t REG_MUSTDELIM all delimiters must be specified\n");
23716b8cff5SYuri Pankov T(" u standard unspecified behavior -- errors not counted\n");
23816b8cff5SYuri Pankov T(" v REG_CLASS_ESCAPE \\ special inside [...]\n");
23916b8cff5SYuri Pankov T(" w REG_NOSUB no subexpression match array\n");
24016b8cff5SYuri Pankov T(" x REG_LENIENT let some errors slide\n");
24116b8cff5SYuri Pankov T(" y REG_LEFT regexec() implicit ^...\n");
24216b8cff5SYuri Pankov T(" z REG_NULL NULL subexpressions ok\n");
24316b8cff5SYuri Pankov T(" $ expand C \\c escapes in fields 2 and 3\n");
24416b8cff5SYuri Pankov T(" / field 2 is a regsubcomp() expression\n");
24516b8cff5SYuri Pankov T(" = field 3 is a regdecomp() expression\n");
24616b8cff5SYuri Pankov T("\n");
24716b8cff5SYuri Pankov T(" Field 1 control lines:\n");
24816b8cff5SYuri Pankov T("\n");
24916b8cff5SYuri Pankov T(" C set LC_COLLATE and LC_CTYPE to locale in field 2\n");
25016b8cff5SYuri Pankov T("\n");
25116b8cff5SYuri Pankov T(" ?test ... output field 5 if passed and != EXPECTED, silent otherwise\n");
25216b8cff5SYuri Pankov T(" &test ... output field 5 if current and previous passed\n");
25316b8cff5SYuri Pankov T(" |test ... output field 5 if current passed and previous failed\n");
25416b8cff5SYuri Pankov T(" ; ... output field 2 if previous failed\n");
25516b8cff5SYuri Pankov T(" {test ... skip if failed until }\n");
25616b8cff5SYuri Pankov T(" } end of skip\n");
25716b8cff5SYuri Pankov T("\n");
25816b8cff5SYuri Pankov T(" : comment comment copied as output NOTE\n");
25916b8cff5SYuri Pankov T(" :comment:test :comment: ignored\n");
26016b8cff5SYuri Pankov T(" N[OTE] comment comment copied as output NOTE\n");
26116b8cff5SYuri Pankov T(" T[EST] comment comment\n");
26216b8cff5SYuri Pankov T("\n");
26316b8cff5SYuri Pankov T(" number use number for nmatch (20 by default)\n");
26416b8cff5SYuri Pankov T("\n");
26516b8cff5SYuri Pankov T(" Field 2: the regular expression pattern; SAME uses the pattern from\n");
26616b8cff5SYuri Pankov T(" the previous specification. RE_DUP_MAX inside {...} expands to the\n");
26716b8cff5SYuri Pankov T(" value from <limits.h>.\n");
26816b8cff5SYuri Pankov T("\n");
26916b8cff5SYuri Pankov T(" Field 3: the string to match. X...{RE_DUP_MAX} expands to RE_DUP_MAX\n");
27016b8cff5SYuri Pankov T(" copies of X.\n");
27116b8cff5SYuri Pankov T("\n");
27216b8cff5SYuri Pankov T(" Field 4: the test outcome. This is either one of the posix error\n");
27316b8cff5SYuri Pankov T(" codes (with REG_ omitted) or the match array, a list of (m,n)\n");
27416b8cff5SYuri Pankov T(" entries with m and n being first and last+1 positions in the\n");
27516b8cff5SYuri Pankov T(" field 3 string, or NULL if REG_NOSUB is in effect and success\n");
27616b8cff5SYuri Pankov T(" is expected. BADPAT is acceptable in place of any regcomp(3)\n");
27716b8cff5SYuri Pankov T(" error code. The match[] array is initialized to (-2,-2) before\n");
27816b8cff5SYuri Pankov T(" each test. All array elements from 0 to nmatch-1 must be specified\n");
27916b8cff5SYuri Pankov T(" in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");
28016b8cff5SYuri Pankov T(" Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");
28116b8cff5SYuri Pankov T(" matched (?{...}) expression, where x is the text enclosed by {...},\n");
28216b8cff5SYuri Pankov T(" o is the expression ordinal counting from 1, and n is the length of\n");
28316b8cff5SYuri Pankov T(" the unmatched portion of the subject string. If x starts with a\n");
28416b8cff5SYuri Pankov T(" number then that is the return value of re_execf(), otherwise 0 is\n");
28516b8cff5SYuri Pankov T(" returned. RE_DUP_MAX[-+]N expands to the <limits.h> value -+N.\n");
28616b8cff5SYuri Pankov T("\n");
28716b8cff5SYuri Pankov T(" Field 5: optional comment appended to the report.\n");
28816b8cff5SYuri Pankov T("\n");
28916b8cff5SYuri Pankov T("CAVEAT\n");
29016b8cff5SYuri Pankov T(" If a regex implementation misbehaves with memory then all bets are off.\n");
29116b8cff5SYuri Pankov T("\n");
29216b8cff5SYuri Pankov T("CONTRIBUTORS\n");
29316b8cff5SYuri Pankov T(" Glenn Fowler glenn.s.fowler@gmail.com (ksh strmatch, regex extensions)\n");
29416b8cff5SYuri Pankov T(" David Korn dgkorn@gmail.com (ksh glob matcher)\n");
29516b8cff5SYuri Pankov T(" Doug McIlroy mcilroy@dartmouth.edu (ast regex/testre in C++)\n");
29616b8cff5SYuri Pankov T(" Tom Lord lord@regexps.com (rx tests)\n");
29716b8cff5SYuri Pankov T(" Henry Spencer henry@zoo.toronto.edu (original public regex)\n");
29816b8cff5SYuri Pankov T(" Andrew Hume andrew@research.att.com (gre tests)\n");
29916b8cff5SYuri Pankov T(" John Maddock John_Maddock@compuserve.com (regex++ tests)\n");
30016b8cff5SYuri Pankov T(" Philip Hazel ph10@cam.ac.uk (pcre tests)\n");
30116b8cff5SYuri Pankov T(" Ville Laurikari vl@iki.fi (libtre tests)\n");
30216b8cff5SYuri Pankov H("</PRE>\n");
30316b8cff5SYuri Pankov H("</BODY>\n");
30416b8cff5SYuri Pankov H("</HTML>\n");
30516b8cff5SYuri Pankov }
30616b8cff5SYuri Pankov
30716b8cff5SYuri Pankov #ifndef elementsof
30816b8cff5SYuri Pankov #define elementsof(x) (sizeof(x)/sizeof(x[0]))
30916b8cff5SYuri Pankov #endif
31016b8cff5SYuri Pankov
31116b8cff5SYuri Pankov #ifndef streq
31216b8cff5SYuri Pankov #define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
31316b8cff5SYuri Pankov #endif
31416b8cff5SYuri Pankov
31516b8cff5SYuri Pankov #define HUNG 2
31616b8cff5SYuri Pankov #define NOTEST (~0)
31716b8cff5SYuri Pankov
31816b8cff5SYuri Pankov #ifndef REG_TEST_DEFAULT
31916b8cff5SYuri Pankov #define REG_TEST_DEFAULT 0
32016b8cff5SYuri Pankov #endif
32116b8cff5SYuri Pankov
32216b8cff5SYuri Pankov #ifndef REG_EXEC_DEFAULT
32316b8cff5SYuri Pankov #define REG_EXEC_DEFAULT 0
32416b8cff5SYuri Pankov #endif
32516b8cff5SYuri Pankov
32616b8cff5SYuri Pankov static const char* unsupported[] =
32716b8cff5SYuri Pankov {
32816b8cff5SYuri Pankov "BASIC",
32916b8cff5SYuri Pankov #ifndef REG_EXTENDED
33016b8cff5SYuri Pankov "EXTENDED",
33116b8cff5SYuri Pankov #endif
33216b8cff5SYuri Pankov #ifndef REG_AUGMENTED
33316b8cff5SYuri Pankov "AUGMENTED",
33416b8cff5SYuri Pankov #endif
33516b8cff5SYuri Pankov #ifndef REG_SHELL
33616b8cff5SYuri Pankov "SHELL",
33716b8cff5SYuri Pankov #endif
33816b8cff5SYuri Pankov
33916b8cff5SYuri Pankov #ifndef REG_CLASS_ESCAPE
34016b8cff5SYuri Pankov "CLASS_ESCAPE",
34116b8cff5SYuri Pankov #endif
34216b8cff5SYuri Pankov #ifndef REG_COMMENT
34316b8cff5SYuri Pankov "COMMENT",
34416b8cff5SYuri Pankov #endif
34516b8cff5SYuri Pankov #ifndef REG_DELIMITED
34616b8cff5SYuri Pankov "DELIMITED",
34716b8cff5SYuri Pankov #endif
34816b8cff5SYuri Pankov #ifndef REG_DISCIPLINE
34916b8cff5SYuri Pankov "DISCIPLINE",
35016b8cff5SYuri Pankov #endif
35116b8cff5SYuri Pankov #ifndef REG_ESCAPE
35216b8cff5SYuri Pankov "ESCAPE",
35316b8cff5SYuri Pankov #endif
35416b8cff5SYuri Pankov #ifndef REG_ICASE
35516b8cff5SYuri Pankov "ICASE",
35616b8cff5SYuri Pankov #endif
35716b8cff5SYuri Pankov #ifndef REG_LEFT
35816b8cff5SYuri Pankov "LEFT",
35916b8cff5SYuri Pankov #endif
36016b8cff5SYuri Pankov #ifndef REG_LENIENT
36116b8cff5SYuri Pankov "LENIENT",
36216b8cff5SYuri Pankov #endif
36316b8cff5SYuri Pankov #ifndef REG_LITERAL
36416b8cff5SYuri Pankov "LITERAL",
36516b8cff5SYuri Pankov #endif
36616b8cff5SYuri Pankov #ifndef REG_MINIMAL
36716b8cff5SYuri Pankov "MINIMAL",
36816b8cff5SYuri Pankov #endif
36916b8cff5SYuri Pankov #ifndef REG_MULTIPLE
37016b8cff5SYuri Pankov "MULTIPLE",
37116b8cff5SYuri Pankov #endif
37216b8cff5SYuri Pankov #ifndef REG_MULTIREF
37316b8cff5SYuri Pankov "MULTIREF",
37416b8cff5SYuri Pankov #endif
37516b8cff5SYuri Pankov #ifndef REG_MUSTDELIM
37616b8cff5SYuri Pankov "MUSTDELIM",
37716b8cff5SYuri Pankov #endif
37816b8cff5SYuri Pankov #ifndef REG_NEWLINE
37916b8cff5SYuri Pankov "NEWLINE",
38016b8cff5SYuri Pankov #endif
38116b8cff5SYuri Pankov #ifndef REG_NOTBOL
38216b8cff5SYuri Pankov "NOTBOL",
38316b8cff5SYuri Pankov #endif
38416b8cff5SYuri Pankov #ifndef REG_NOTEOL
38516b8cff5SYuri Pankov "NOTEOL",
38616b8cff5SYuri Pankov #endif
38716b8cff5SYuri Pankov #ifndef REG_NULL
38816b8cff5SYuri Pankov "NULL",
38916b8cff5SYuri Pankov #endif
39016b8cff5SYuri Pankov #ifndef REG_RIGHT
39116b8cff5SYuri Pankov "RIGHT",
39216b8cff5SYuri Pankov #endif
39316b8cff5SYuri Pankov #ifndef REG_SHELL_DOT
39416b8cff5SYuri Pankov "SHELL_DOT",
39516b8cff5SYuri Pankov #endif
39616b8cff5SYuri Pankov #ifndef REG_SHELL_ESCAPED
39716b8cff5SYuri Pankov "SHELL_ESCAPED",
39816b8cff5SYuri Pankov #endif
39916b8cff5SYuri Pankov #ifndef REG_SHELL_GROUP
40016b8cff5SYuri Pankov "SHELL_GROUP",
40116b8cff5SYuri Pankov #endif
40216b8cff5SYuri Pankov #ifndef REG_SHELL_PATH
40316b8cff5SYuri Pankov "SHELL_PATH",
40416b8cff5SYuri Pankov #endif
40516b8cff5SYuri Pankov #ifndef REG_SPAN
40616b8cff5SYuri Pankov "SPAN",
40716b8cff5SYuri Pankov #endif
40816b8cff5SYuri Pankov #if REG_NOSUB & REG_TEST_DEFAULT
40916b8cff5SYuri Pankov "SUBMATCH",
41016b8cff5SYuri Pankov #endif
41116b8cff5SYuri Pankov #if !_REG_nexec
41216b8cff5SYuri Pankov "regnexec",
41316b8cff5SYuri Pankov #endif
41416b8cff5SYuri Pankov #if !_REG_subcomp
41516b8cff5SYuri Pankov "regsubcomp",
41616b8cff5SYuri Pankov #endif
41716b8cff5SYuri Pankov #if !_REG_decomp
41816b8cff5SYuri Pankov "redecomp",
41916b8cff5SYuri Pankov #endif
42016b8cff5SYuri Pankov 0
42116b8cff5SYuri Pankov };
42216b8cff5SYuri Pankov
42316b8cff5SYuri Pankov #ifndef REG_CLASS_ESCAPE
42416b8cff5SYuri Pankov #define REG_CLASS_ESCAPE NOTEST
42516b8cff5SYuri Pankov #endif
42616b8cff5SYuri Pankov #ifndef REG_COMMENT
42716b8cff5SYuri Pankov #define REG_COMMENT NOTEST
42816b8cff5SYuri Pankov #endif
42916b8cff5SYuri Pankov #ifndef REG_DELIMITED
43016b8cff5SYuri Pankov #define REG_DELIMITED NOTEST
43116b8cff5SYuri Pankov #endif
43216b8cff5SYuri Pankov #ifndef REG_ESCAPE
43316b8cff5SYuri Pankov #define REG_ESCAPE NOTEST
43416b8cff5SYuri Pankov #endif
43516b8cff5SYuri Pankov #ifndef REG_ICASE
43616b8cff5SYuri Pankov #define REG_ICASE NOTEST
43716b8cff5SYuri Pankov #endif
43816b8cff5SYuri Pankov #ifndef REG_LEFT
43916b8cff5SYuri Pankov #define REG_LEFT NOTEST
44016b8cff5SYuri Pankov #endif
44116b8cff5SYuri Pankov #ifndef REG_LENIENT
44216b8cff5SYuri Pankov #define REG_LENIENT 0
44316b8cff5SYuri Pankov #endif
44416b8cff5SYuri Pankov #ifndef REG_MINIMAL
44516b8cff5SYuri Pankov #define REG_MINIMAL NOTEST
44616b8cff5SYuri Pankov #endif
44716b8cff5SYuri Pankov #ifndef REG_MULTIPLE
44816b8cff5SYuri Pankov #define REG_MULTIPLE NOTEST
44916b8cff5SYuri Pankov #endif
45016b8cff5SYuri Pankov #ifndef REG_MULTIREF
45116b8cff5SYuri Pankov #define REG_MULTIREF NOTEST
45216b8cff5SYuri Pankov #endif
45316b8cff5SYuri Pankov #ifndef REG_MUSTDELIM
45416b8cff5SYuri Pankov #define REG_MUSTDELIM NOTEST
45516b8cff5SYuri Pankov #endif
45616b8cff5SYuri Pankov #ifndef REG_NEWLINE
45716b8cff5SYuri Pankov #define REG_NEWLINE NOTEST
45816b8cff5SYuri Pankov #endif
45916b8cff5SYuri Pankov #ifndef REG_NOTBOL
46016b8cff5SYuri Pankov #define REG_NOTBOL NOTEST
46116b8cff5SYuri Pankov #endif
46216b8cff5SYuri Pankov #ifndef REG_NOTEOL
46316b8cff5SYuri Pankov #define REG_NOTEOL NOTEST
46416b8cff5SYuri Pankov #endif
46516b8cff5SYuri Pankov #ifndef REG_NULL
46616b8cff5SYuri Pankov #define REG_NULL NOTEST
46716b8cff5SYuri Pankov #endif
46816b8cff5SYuri Pankov #ifndef REG_RIGHT
46916b8cff5SYuri Pankov #define REG_RIGHT NOTEST
47016b8cff5SYuri Pankov #endif
47116b8cff5SYuri Pankov #ifndef REG_SHELL_DOT
47216b8cff5SYuri Pankov #define REG_SHELL_DOT NOTEST
47316b8cff5SYuri Pankov #endif
47416b8cff5SYuri Pankov #ifndef REG_SHELL_ESCAPED
47516b8cff5SYuri Pankov #define REG_SHELL_ESCAPED NOTEST
47616b8cff5SYuri Pankov #endif
47716b8cff5SYuri Pankov #ifndef REG_SHELL_GROUP
47816b8cff5SYuri Pankov #define REG_SHELL_GROUP NOTEST
47916b8cff5SYuri Pankov #endif
48016b8cff5SYuri Pankov #ifndef REG_SHELL_PATH
48116b8cff5SYuri Pankov #define REG_SHELL_PATH NOTEST
48216b8cff5SYuri Pankov #endif
48316b8cff5SYuri Pankov #ifndef REG_SPAN
48416b8cff5SYuri Pankov #define REG_SPAN NOTEST
48516b8cff5SYuri Pankov #endif
48616b8cff5SYuri Pankov
48716b8cff5SYuri Pankov #define REG_UNKNOWN (-1)
48816b8cff5SYuri Pankov
48916b8cff5SYuri Pankov #ifndef REG_ENEWLINE
49016b8cff5SYuri Pankov #define REG_ENEWLINE (REG_UNKNOWN-1)
49116b8cff5SYuri Pankov #endif
49216b8cff5SYuri Pankov #ifndef REG_ENULL
49316b8cff5SYuri Pankov #ifndef REG_EMPTY
49416b8cff5SYuri Pankov #define REG_ENULL (REG_UNKNOWN-2)
49516b8cff5SYuri Pankov #else
49616b8cff5SYuri Pankov #define REG_ENULL REG_EMPTY
49716b8cff5SYuri Pankov #endif
49816b8cff5SYuri Pankov #endif
49916b8cff5SYuri Pankov #ifndef REG_ECOUNT
50016b8cff5SYuri Pankov #define REG_ECOUNT (REG_UNKNOWN-3)
50116b8cff5SYuri Pankov #endif
50216b8cff5SYuri Pankov #ifndef REG_BADESC
50316b8cff5SYuri Pankov #define REG_BADESC (REG_UNKNOWN-4)
50416b8cff5SYuri Pankov #endif
50516b8cff5SYuri Pankov #ifndef REG_EMEM
50616b8cff5SYuri Pankov #define REG_EMEM (REG_UNKNOWN-5)
50716b8cff5SYuri Pankov #endif
50816b8cff5SYuri Pankov #ifndef REG_EHUNG
50916b8cff5SYuri Pankov #define REG_EHUNG (REG_UNKNOWN-6)
51016b8cff5SYuri Pankov #endif
51116b8cff5SYuri Pankov #ifndef REG_EBUS
51216b8cff5SYuri Pankov #define REG_EBUS (REG_UNKNOWN-7)
51316b8cff5SYuri Pankov #endif
51416b8cff5SYuri Pankov #ifndef REG_EFAULT
51516b8cff5SYuri Pankov #define REG_EFAULT (REG_UNKNOWN-8)
51616b8cff5SYuri Pankov #endif
51716b8cff5SYuri Pankov #ifndef REG_EFLAGS
51816b8cff5SYuri Pankov #define REG_EFLAGS (REG_UNKNOWN-9)
51916b8cff5SYuri Pankov #endif
52016b8cff5SYuri Pankov #ifndef REG_EDELIM
52116b8cff5SYuri Pankov #define REG_EDELIM (REG_UNKNOWN-9)
52216b8cff5SYuri Pankov #endif
52316b8cff5SYuri Pankov
52416b8cff5SYuri Pankov static const struct { int code; char* name; } codes[] =
52516b8cff5SYuri Pankov {
52616b8cff5SYuri Pankov REG_UNKNOWN, "UNKNOWN",
52716b8cff5SYuri Pankov REG_NOMATCH, "NOMATCH",
52816b8cff5SYuri Pankov REG_BADPAT, "BADPAT",
52916b8cff5SYuri Pankov REG_ECOLLATE, "ECOLLATE",
53016b8cff5SYuri Pankov REG_ECTYPE, "ECTYPE",
53116b8cff5SYuri Pankov REG_EESCAPE, "EESCAPE",
53216b8cff5SYuri Pankov REG_ESUBREG, "ESUBREG",
53316b8cff5SYuri Pankov REG_EBRACK, "EBRACK",
53416b8cff5SYuri Pankov REG_EPAREN, "EPAREN",
53516b8cff5SYuri Pankov REG_EBRACE, "EBRACE",
53616b8cff5SYuri Pankov REG_BADBR, "BADBR",
53716b8cff5SYuri Pankov REG_ERANGE, "ERANGE",
53816b8cff5SYuri Pankov REG_ESPACE, "ESPACE",
53916b8cff5SYuri Pankov REG_BADRPT, "BADRPT",
54016b8cff5SYuri Pankov REG_ENEWLINE, "ENEWLINE",
54116b8cff5SYuri Pankov REG_ENULL, "ENULL",
54216b8cff5SYuri Pankov REG_ECOUNT, "ECOUNT",
54316b8cff5SYuri Pankov REG_BADESC, "BADESC",
54416b8cff5SYuri Pankov REG_EMEM, "EMEM",
54516b8cff5SYuri Pankov REG_EHUNG, "EHUNG",
54616b8cff5SYuri Pankov REG_EBUS, "EBUS",
54716b8cff5SYuri Pankov REG_EFAULT, "EFAULT",
54816b8cff5SYuri Pankov REG_EFLAGS, "EFLAGS",
54916b8cff5SYuri Pankov REG_EDELIM, "EDELIM",
55016b8cff5SYuri Pankov };
55116b8cff5SYuri Pankov
55216b8cff5SYuri Pankov static struct
55316b8cff5SYuri Pankov {
55416b8cff5SYuri Pankov regmatch_t NOMATCH;
55516b8cff5SYuri Pankov int errors;
55616b8cff5SYuri Pankov int extracted;
55716b8cff5SYuri Pankov int ignored;
55816b8cff5SYuri Pankov int lineno;
55916b8cff5SYuri Pankov int passed;
56016b8cff5SYuri Pankov int signals;
56116b8cff5SYuri Pankov int unspecified;
56216b8cff5SYuri Pankov int verify;
56316b8cff5SYuri Pankov int warnings;
56416b8cff5SYuri Pankov char* file;
56516b8cff5SYuri Pankov char* stack;
56616b8cff5SYuri Pankov char* which;
56716b8cff5SYuri Pankov jmp_buf gotcha;
56816b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
56916b8cff5SYuri Pankov Disc_t disc;
57016b8cff5SYuri Pankov #endif
57116b8cff5SYuri Pankov } state;
57216b8cff5SYuri Pankov
57316b8cff5SYuri Pankov static void
quote(char * s,int len,unsigned long test)57416b8cff5SYuri Pankov quote(char* s, int len, unsigned long test)
57516b8cff5SYuri Pankov {
57616b8cff5SYuri Pankov unsigned char* u = (unsigned char*)s;
57716b8cff5SYuri Pankov unsigned char* e;
57816b8cff5SYuri Pankov int c;
57916b8cff5SYuri Pankov #ifdef MB_CUR_MAX
58016b8cff5SYuri Pankov int w;
58116b8cff5SYuri Pankov #endif
58216b8cff5SYuri Pankov
58316b8cff5SYuri Pankov if (!u)
58416b8cff5SYuri Pankov printf("NIL");
58516b8cff5SYuri Pankov else if (!*u && len <= 1)
58616b8cff5SYuri Pankov printf("NULL");
58716b8cff5SYuri Pankov else if (test & TEST_EXPAND)
58816b8cff5SYuri Pankov {
58916b8cff5SYuri Pankov if (len < 0)
59016b8cff5SYuri Pankov len = strlen((char*)u);
59116b8cff5SYuri Pankov e = u + len;
59216b8cff5SYuri Pankov if (test & TEST_DELIMIT)
59316b8cff5SYuri Pankov printf("\"");
59416b8cff5SYuri Pankov while (u < e)
59516b8cff5SYuri Pankov switch (c = *u++)
59616b8cff5SYuri Pankov {
59716b8cff5SYuri Pankov case '\\':
59816b8cff5SYuri Pankov printf("\\\\");
59916b8cff5SYuri Pankov break;
60016b8cff5SYuri Pankov case '"':
60116b8cff5SYuri Pankov if (test & TEST_DELIMIT)
60216b8cff5SYuri Pankov printf("\\\"");
60316b8cff5SYuri Pankov else
60416b8cff5SYuri Pankov printf("\"");
60516b8cff5SYuri Pankov break;
60616b8cff5SYuri Pankov case '\a':
60716b8cff5SYuri Pankov printf("\\a");
60816b8cff5SYuri Pankov break;
60916b8cff5SYuri Pankov case '\b':
61016b8cff5SYuri Pankov printf("\\b");
61116b8cff5SYuri Pankov break;
61216b8cff5SYuri Pankov case 033:
61316b8cff5SYuri Pankov printf("\\e");
61416b8cff5SYuri Pankov break;
61516b8cff5SYuri Pankov case '\f':
61616b8cff5SYuri Pankov printf("\\f");
61716b8cff5SYuri Pankov break;
61816b8cff5SYuri Pankov case '\n':
61916b8cff5SYuri Pankov printf("\\n");
62016b8cff5SYuri Pankov break;
62116b8cff5SYuri Pankov case '\r':
62216b8cff5SYuri Pankov printf("\\r");
62316b8cff5SYuri Pankov break;
62416b8cff5SYuri Pankov case '\t':
62516b8cff5SYuri Pankov printf("\\t");
62616b8cff5SYuri Pankov break;
62716b8cff5SYuri Pankov case '\v':
62816b8cff5SYuri Pankov printf("\\v");
62916b8cff5SYuri Pankov break;
63016b8cff5SYuri Pankov default:
63116b8cff5SYuri Pankov #ifdef MB_CUR_MAX
63216b8cff5SYuri Pankov s = (char*)u - 1;
63316b8cff5SYuri Pankov if ((w = mblen(s, (char*)e - s)) > 1)
63416b8cff5SYuri Pankov {
63516b8cff5SYuri Pankov u += w - 1;
63616b8cff5SYuri Pankov fwrite(s, 1, w, stdout);
63716b8cff5SYuri Pankov }
63816b8cff5SYuri Pankov else
63916b8cff5SYuri Pankov #endif
64016b8cff5SYuri Pankov if (!iscntrl(c) && isprint(c))
64116b8cff5SYuri Pankov putchar(c);
64216b8cff5SYuri Pankov else
64316b8cff5SYuri Pankov printf("\\x%02x", c);
64416b8cff5SYuri Pankov break;
64516b8cff5SYuri Pankov }
64616b8cff5SYuri Pankov if (test & TEST_DELIMIT)
64716b8cff5SYuri Pankov printf("\"");
64816b8cff5SYuri Pankov }
64916b8cff5SYuri Pankov else
65016b8cff5SYuri Pankov printf("%s", s);
65116b8cff5SYuri Pankov }
65216b8cff5SYuri Pankov
65316b8cff5SYuri Pankov static void
report(char * comment,char * fun,char * re,char * s,int len,char * msg,int flags,unsigned long test)65416b8cff5SYuri Pankov report(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test)
65516b8cff5SYuri Pankov {
65616b8cff5SYuri Pankov if (state.file)
65716b8cff5SYuri Pankov printf("%s:", state.file);
65816b8cff5SYuri Pankov printf("%d:", state.lineno);
65916b8cff5SYuri Pankov if (re)
66016b8cff5SYuri Pankov {
66116b8cff5SYuri Pankov printf(" ");
66216b8cff5SYuri Pankov quote(re, -1, test|TEST_DELIMIT);
66316b8cff5SYuri Pankov if (s)
66416b8cff5SYuri Pankov {
66516b8cff5SYuri Pankov printf(" versus ");
66616b8cff5SYuri Pankov quote(s, len, test|TEST_DELIMIT);
66716b8cff5SYuri Pankov }
66816b8cff5SYuri Pankov }
66916b8cff5SYuri Pankov if (test & TEST_UNSPECIFIED)
67016b8cff5SYuri Pankov {
67116b8cff5SYuri Pankov state.unspecified++;
67216b8cff5SYuri Pankov printf(" unspecified behavior");
67316b8cff5SYuri Pankov }
67416b8cff5SYuri Pankov else
67516b8cff5SYuri Pankov state.errors++;
67616b8cff5SYuri Pankov if (state.which)
67716b8cff5SYuri Pankov printf(" %s", state.which);
67816b8cff5SYuri Pankov if (flags & REG_NOSUB)
67916b8cff5SYuri Pankov printf(" NOSUB");
68016b8cff5SYuri Pankov if (fun)
68116b8cff5SYuri Pankov printf(" %s", fun);
68216b8cff5SYuri Pankov if (comment[strlen(comment)-1] == '\n')
68316b8cff5SYuri Pankov printf(" %s", comment);
68416b8cff5SYuri Pankov else
68516b8cff5SYuri Pankov {
68616b8cff5SYuri Pankov printf(" %s: ", comment);
68716b8cff5SYuri Pankov if (msg)
68816b8cff5SYuri Pankov printf("%s: ", msg);
68916b8cff5SYuri Pankov }
69016b8cff5SYuri Pankov }
69116b8cff5SYuri Pankov
69216b8cff5SYuri Pankov static void
error(regex_t * preg,int code)69316b8cff5SYuri Pankov error(regex_t* preg, int code)
69416b8cff5SYuri Pankov {
69516b8cff5SYuri Pankov char* msg;
69616b8cff5SYuri Pankov char buf[256];
69716b8cff5SYuri Pankov
69816b8cff5SYuri Pankov switch (code)
69916b8cff5SYuri Pankov {
70016b8cff5SYuri Pankov case REG_EBUS:
70116b8cff5SYuri Pankov msg = "bus error";
70216b8cff5SYuri Pankov break;
70316b8cff5SYuri Pankov case REG_EFAULT:
70416b8cff5SYuri Pankov msg = "memory fault";
70516b8cff5SYuri Pankov break;
70616b8cff5SYuri Pankov case REG_EHUNG:
70716b8cff5SYuri Pankov msg = "did not terminate";
70816b8cff5SYuri Pankov break;
70916b8cff5SYuri Pankov default:
71016b8cff5SYuri Pankov regerror(code, preg, msg = buf, sizeof buf);
71116b8cff5SYuri Pankov break;
71216b8cff5SYuri Pankov }
71316b8cff5SYuri Pankov printf("%s\n", msg);
71416b8cff5SYuri Pankov }
71516b8cff5SYuri Pankov
71616b8cff5SYuri Pankov static void
bad(char * comment,char * re,char * s,int len,unsigned long test)71716b8cff5SYuri Pankov bad(char* comment, char* re, char* s, int len, unsigned long test)
71816b8cff5SYuri Pankov {
71916b8cff5SYuri Pankov printf("bad test case ");
72016b8cff5SYuri Pankov report(comment, NiL, re, s, len, NiL, 0, test);
72116b8cff5SYuri Pankov exit(1);
72216b8cff5SYuri Pankov }
72316b8cff5SYuri Pankov
72416b8cff5SYuri Pankov static int
escape(char * s)72516b8cff5SYuri Pankov escape(char* s)
72616b8cff5SYuri Pankov {
72716b8cff5SYuri Pankov char* b;
72816b8cff5SYuri Pankov char* t;
72916b8cff5SYuri Pankov char* q;
73016b8cff5SYuri Pankov char* e;
73116b8cff5SYuri Pankov int c;
73216b8cff5SYuri Pankov
73316b8cff5SYuri Pankov for (b = t = s; *t = *s; s++, t++)
73416b8cff5SYuri Pankov if (*s == '\\')
73516b8cff5SYuri Pankov switch (*++s)
73616b8cff5SYuri Pankov {
73716b8cff5SYuri Pankov case '\\':
73816b8cff5SYuri Pankov break;
73916b8cff5SYuri Pankov case 'a':
74016b8cff5SYuri Pankov *t = '\a';
74116b8cff5SYuri Pankov break;
74216b8cff5SYuri Pankov case 'b':
74316b8cff5SYuri Pankov *t = '\b';
74416b8cff5SYuri Pankov break;
74516b8cff5SYuri Pankov case 'c':
74616b8cff5SYuri Pankov if (*t = *++s)
74716b8cff5SYuri Pankov *t &= 037;
74816b8cff5SYuri Pankov else
74916b8cff5SYuri Pankov s--;
75016b8cff5SYuri Pankov break;
75116b8cff5SYuri Pankov case 'e':
75216b8cff5SYuri Pankov case 'E':
75316b8cff5SYuri Pankov *t = 033;
75416b8cff5SYuri Pankov break;
75516b8cff5SYuri Pankov case 'f':
75616b8cff5SYuri Pankov *t = '\f';
75716b8cff5SYuri Pankov break;
75816b8cff5SYuri Pankov case 'n':
75916b8cff5SYuri Pankov *t = '\n';
76016b8cff5SYuri Pankov break;
76116b8cff5SYuri Pankov case 'r':
76216b8cff5SYuri Pankov *t = '\r';
76316b8cff5SYuri Pankov break;
76416b8cff5SYuri Pankov case 's':
76516b8cff5SYuri Pankov *t = ' ';
76616b8cff5SYuri Pankov break;
76716b8cff5SYuri Pankov case 't':
76816b8cff5SYuri Pankov *t = '\t';
76916b8cff5SYuri Pankov break;
77016b8cff5SYuri Pankov case 'v':
77116b8cff5SYuri Pankov *t = '\v';
77216b8cff5SYuri Pankov break;
77316b8cff5SYuri Pankov case 'u':
77416b8cff5SYuri Pankov case 'x':
77516b8cff5SYuri Pankov c = 0;
77616b8cff5SYuri Pankov q = c == 'u' ? (s + 5) : (char*)0;
77716b8cff5SYuri Pankov e = s + 1;
77816b8cff5SYuri Pankov while (!e || !q || s < q)
77916b8cff5SYuri Pankov {
78016b8cff5SYuri Pankov switch (*++s)
78116b8cff5SYuri Pankov {
78216b8cff5SYuri Pankov case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
78316b8cff5SYuri Pankov c = (c << 4) + *s - 'a' + 10;
78416b8cff5SYuri Pankov continue;
78516b8cff5SYuri Pankov case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
78616b8cff5SYuri Pankov c = (c << 4) + *s - 'A' + 10;
78716b8cff5SYuri Pankov continue;
78816b8cff5SYuri Pankov case '0': case '1': case '2': case '3': case '4':
78916b8cff5SYuri Pankov case '5': case '6': case '7': case '8': case '9':
79016b8cff5SYuri Pankov c = (c << 4) + *s - '0';
79116b8cff5SYuri Pankov continue;
79216b8cff5SYuri Pankov case '{':
79316b8cff5SYuri Pankov case '[':
79416b8cff5SYuri Pankov if (s != e)
79516b8cff5SYuri Pankov {
79616b8cff5SYuri Pankov s--;
79716b8cff5SYuri Pankov break;
79816b8cff5SYuri Pankov }
79916b8cff5SYuri Pankov e = 0;
80016b8cff5SYuri Pankov continue;
80116b8cff5SYuri Pankov case '}':
80216b8cff5SYuri Pankov case ']':
80316b8cff5SYuri Pankov if (e)
80416b8cff5SYuri Pankov s--;
80516b8cff5SYuri Pankov break;
80616b8cff5SYuri Pankov default:
80716b8cff5SYuri Pankov s--;
80816b8cff5SYuri Pankov break;
80916b8cff5SYuri Pankov }
81016b8cff5SYuri Pankov break;
81116b8cff5SYuri Pankov }
81216b8cff5SYuri Pankov *t = c;
81316b8cff5SYuri Pankov break;
81416b8cff5SYuri Pankov case '0': case '1': case '2': case '3':
81516b8cff5SYuri Pankov case '4': case '5': case '6': case '7':
81616b8cff5SYuri Pankov c = *s - '0';
81716b8cff5SYuri Pankov q = s + 2;
81816b8cff5SYuri Pankov while (s < q)
81916b8cff5SYuri Pankov {
82016b8cff5SYuri Pankov switch (*++s)
82116b8cff5SYuri Pankov {
82216b8cff5SYuri Pankov case '0': case '1': case '2': case '3':
82316b8cff5SYuri Pankov case '4': case '5': case '6': case '7':
82416b8cff5SYuri Pankov c = (c << 3) + *s - '0';
82516b8cff5SYuri Pankov break;
82616b8cff5SYuri Pankov default:
82716b8cff5SYuri Pankov q = --s;
82816b8cff5SYuri Pankov break;
82916b8cff5SYuri Pankov }
83016b8cff5SYuri Pankov }
83116b8cff5SYuri Pankov *t = c;
83216b8cff5SYuri Pankov break;
83316b8cff5SYuri Pankov default:
83416b8cff5SYuri Pankov *(s + 1) = 0;
83516b8cff5SYuri Pankov bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);
83616b8cff5SYuri Pankov }
83716b8cff5SYuri Pankov return t - b;
83816b8cff5SYuri Pankov }
83916b8cff5SYuri Pankov
84016b8cff5SYuri Pankov static void
matchoffprint(int off)84116b8cff5SYuri Pankov matchoffprint(int off)
84216b8cff5SYuri Pankov {
84316b8cff5SYuri Pankov switch (off)
84416b8cff5SYuri Pankov {
84516b8cff5SYuri Pankov case -2:
84616b8cff5SYuri Pankov printf("X");
84716b8cff5SYuri Pankov break;
84816b8cff5SYuri Pankov case -1:
84916b8cff5SYuri Pankov printf("?");
85016b8cff5SYuri Pankov break;
85116b8cff5SYuri Pankov default:
85216b8cff5SYuri Pankov printf("%d", off);
85316b8cff5SYuri Pankov break;
85416b8cff5SYuri Pankov }
85516b8cff5SYuri Pankov }
85616b8cff5SYuri Pankov
85716b8cff5SYuri Pankov static void
matchprint(regmatch_t * match,int nmatch,int nsub,char * ans,unsigned long test)85816b8cff5SYuri Pankov matchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test)
85916b8cff5SYuri Pankov {
86016b8cff5SYuri Pankov int i;
86116b8cff5SYuri Pankov
86216b8cff5SYuri Pankov for (; nmatch > nsub + 1; nmatch--)
86316b8cff5SYuri Pankov if ((match[nmatch-1].rm_so != -1 || match[nmatch-1].rm_eo != -1) && (!(test & TEST_IGNORE_POSITION) || match[nmatch-1].rm_so >= 0 && match[nmatch-1].rm_eo >= 0))
86416b8cff5SYuri Pankov break;
86516b8cff5SYuri Pankov for (i = 0; i < nmatch; i++)
86616b8cff5SYuri Pankov {
86716b8cff5SYuri Pankov printf("(");
86816b8cff5SYuri Pankov matchoffprint(match[i].rm_so);
86916b8cff5SYuri Pankov printf(",");
87016b8cff5SYuri Pankov matchoffprint(match[i].rm_eo);
87116b8cff5SYuri Pankov printf(")");
87216b8cff5SYuri Pankov }
87316b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE)))
87416b8cff5SYuri Pankov {
87516b8cff5SYuri Pankov if (ans)
87616b8cff5SYuri Pankov printf(" expected: %s", ans);
87716b8cff5SYuri Pankov printf("\n");
87816b8cff5SYuri Pankov }
87916b8cff5SYuri Pankov }
88016b8cff5SYuri Pankov
88116b8cff5SYuri Pankov static int
matchcheck(regmatch_t * match,int nmatch,int nsub,char * ans,char * re,char * s,int len,int flags,unsigned long test)88216b8cff5SYuri Pankov matchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test)
88316b8cff5SYuri Pankov {
88416b8cff5SYuri Pankov char* p;
88516b8cff5SYuri Pankov int i;
88616b8cff5SYuri Pankov int m;
88716b8cff5SYuri Pankov int n;
88816b8cff5SYuri Pankov
88916b8cff5SYuri Pankov if (streq(ans, "OK"))
89016b8cff5SYuri Pankov return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);
89116b8cff5SYuri Pankov for (i = 0, p = ans; i < nmatch && *p; i++)
89216b8cff5SYuri Pankov {
89316b8cff5SYuri Pankov if (*p == '{')
89416b8cff5SYuri Pankov {
89516b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
89616b8cff5SYuri Pankov char* x;
89716b8cff5SYuri Pankov
89816b8cff5SYuri Pankov if (!(x = sfstruse(state.disc.sp)))
89916b8cff5SYuri Pankov bad("out of space [discipline string]\n", NiL, NiL, 0, 0);
90016b8cff5SYuri Pankov if (strcmp(p, x))
90116b8cff5SYuri Pankov {
90216b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
90316b8cff5SYuri Pankov return 0;
90416b8cff5SYuri Pankov report("callout failed", NiL, re, s, len, NiL, flags, test);
90516b8cff5SYuri Pankov quote(p, -1, test);
90616b8cff5SYuri Pankov printf(" expected, ");
90716b8cff5SYuri Pankov quote(x, -1, test);
90816b8cff5SYuri Pankov printf(" returned\n");
90916b8cff5SYuri Pankov }
91016b8cff5SYuri Pankov #endif
91116b8cff5SYuri Pankov break;
91216b8cff5SYuri Pankov }
91316b8cff5SYuri Pankov if (*p++ != '(')
91416b8cff5SYuri Pankov bad("improper answer\n", re, s, -1, test);
91516b8cff5SYuri Pankov if (*p == '?')
91616b8cff5SYuri Pankov {
91716b8cff5SYuri Pankov m = -1;
91816b8cff5SYuri Pankov p++;
91916b8cff5SYuri Pankov }
92016b8cff5SYuri Pankov else if (*p == 'R' && !memcmp(p, "RE_DUP_MAX", 10))
92116b8cff5SYuri Pankov {
92216b8cff5SYuri Pankov m = RE_DUP_MAX;
92316b8cff5SYuri Pankov p += 10;
92416b8cff5SYuri Pankov if (*p == '+' || *p == '-')
92516b8cff5SYuri Pankov m += strtol(p, &p, 10);
92616b8cff5SYuri Pankov }
92716b8cff5SYuri Pankov else
92816b8cff5SYuri Pankov m = strtol(p, &p, 10);
92916b8cff5SYuri Pankov if (*p++ != ',')
93016b8cff5SYuri Pankov bad("improper answer\n", re, s, -1, test);
93116b8cff5SYuri Pankov if (*p == '?')
93216b8cff5SYuri Pankov {
93316b8cff5SYuri Pankov n = -1;
93416b8cff5SYuri Pankov p++;
93516b8cff5SYuri Pankov }
93616b8cff5SYuri Pankov else if (*p == 'R' && !memcmp(p, "RE_DUP_MAX", 10))
93716b8cff5SYuri Pankov {
93816b8cff5SYuri Pankov n = RE_DUP_MAX;
93916b8cff5SYuri Pankov p += 10;
94016b8cff5SYuri Pankov if (*p == '+' || *p == '-')
94116b8cff5SYuri Pankov n += strtol(p, &p, 10);
94216b8cff5SYuri Pankov }
94316b8cff5SYuri Pankov else
94416b8cff5SYuri Pankov n = strtol(p, &p, 10);
94516b8cff5SYuri Pankov if (*p++ != ')')
94616b8cff5SYuri Pankov bad("improper answer\n", re, s, -1, test);
94716b8cff5SYuri Pankov if (m!=match[i].rm_so || n!=match[i].rm_eo)
94816b8cff5SYuri Pankov {
94916b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
95016b8cff5SYuri Pankov {
95116b8cff5SYuri Pankov report("failed: match was", NiL, re, s, len, NiL, flags, test);
95216b8cff5SYuri Pankov matchprint(match, nmatch, nsub, ans, test);
95316b8cff5SYuri Pankov }
95416b8cff5SYuri Pankov return 0;
95516b8cff5SYuri Pankov }
95616b8cff5SYuri Pankov }
95716b8cff5SYuri Pankov for (; i < nmatch; i++)
95816b8cff5SYuri Pankov {
95916b8cff5SYuri Pankov if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)
96016b8cff5SYuri Pankov {
96116b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))
96216b8cff5SYuri Pankov {
96316b8cff5SYuri Pankov if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))
96416b8cff5SYuri Pankov {
96516b8cff5SYuri Pankov state.ignored++;
96616b8cff5SYuri Pankov return 0;
96716b8cff5SYuri Pankov }
96816b8cff5SYuri Pankov if (!(test & TEST_SUMMARY))
96916b8cff5SYuri Pankov {
97016b8cff5SYuri Pankov report("failed: match was", NiL, re, s, len, NiL, flags, test);
97116b8cff5SYuri Pankov matchprint(match, nmatch, nsub, ans, test);
97216b8cff5SYuri Pankov }
97316b8cff5SYuri Pankov }
97416b8cff5SYuri Pankov return 0;
97516b8cff5SYuri Pankov }
97616b8cff5SYuri Pankov }
97716b8cff5SYuri Pankov if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)
97816b8cff5SYuri Pankov {
97916b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
98016b8cff5SYuri Pankov {
98116b8cff5SYuri Pankov report("failed: overran match array", NiL, re, s, len, NiL, flags, test);
98216b8cff5SYuri Pankov matchprint(match, nmatch + 1, nsub, NiL, test);
98316b8cff5SYuri Pankov }
98416b8cff5SYuri Pankov return 0;
98516b8cff5SYuri Pankov }
98616b8cff5SYuri Pankov return 1;
98716b8cff5SYuri Pankov }
98816b8cff5SYuri Pankov
98916b8cff5SYuri Pankov static void
sigunblock(int s)99016b8cff5SYuri Pankov sigunblock(int s)
99116b8cff5SYuri Pankov {
99216b8cff5SYuri Pankov #ifdef SIG_SETMASK
99316b8cff5SYuri Pankov int op;
99416b8cff5SYuri Pankov sigset_t mask;
99516b8cff5SYuri Pankov
99616b8cff5SYuri Pankov sigemptyset(&mask);
99716b8cff5SYuri Pankov if (s)
99816b8cff5SYuri Pankov {
99916b8cff5SYuri Pankov sigaddset(&mask, s);
100016b8cff5SYuri Pankov op = SIG_UNBLOCK;
100116b8cff5SYuri Pankov }
100216b8cff5SYuri Pankov else op = SIG_SETMASK;
100316b8cff5SYuri Pankov sigprocmask(op, &mask, NiL);
100416b8cff5SYuri Pankov #else
100516b8cff5SYuri Pankov #ifdef sigmask
100616b8cff5SYuri Pankov sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
100716b8cff5SYuri Pankov #endif
100816b8cff5SYuri Pankov #endif
100916b8cff5SYuri Pankov }
101016b8cff5SYuri Pankov
101116b8cff5SYuri Pankov static void
gotcha(int sig)101216b8cff5SYuri Pankov gotcha(int sig)
101316b8cff5SYuri Pankov {
101416b8cff5SYuri Pankov int ret;
101516b8cff5SYuri Pankov
101616b8cff5SYuri Pankov signal(sig, gotcha);
101716b8cff5SYuri Pankov alarm(0);
101816b8cff5SYuri Pankov state.signals++;
101916b8cff5SYuri Pankov switch (sig)
102016b8cff5SYuri Pankov {
102116b8cff5SYuri Pankov case SIGALRM:
102216b8cff5SYuri Pankov ret = REG_EHUNG;
102316b8cff5SYuri Pankov break;
102416b8cff5SYuri Pankov case SIGBUS:
102516b8cff5SYuri Pankov ret = REG_EBUS;
102616b8cff5SYuri Pankov break;
102716b8cff5SYuri Pankov default:
102816b8cff5SYuri Pankov ret = REG_EFAULT;
102916b8cff5SYuri Pankov break;
103016b8cff5SYuri Pankov }
103116b8cff5SYuri Pankov sigunblock(sig);
103216b8cff5SYuri Pankov longjmp(state.gotcha, ret);
103316b8cff5SYuri Pankov }
103416b8cff5SYuri Pankov
103516b8cff5SYuri Pankov static char*
get_line(FILE * fp)103616b8cff5SYuri Pankov get_line(FILE* fp)
103716b8cff5SYuri Pankov {
103816b8cff5SYuri Pankov static char buf[32 * 1024];
103916b8cff5SYuri Pankov
104016b8cff5SYuri Pankov register char* s = buf;
104116b8cff5SYuri Pankov register char* e = &buf[sizeof(buf)];
104216b8cff5SYuri Pankov register char* b;
104316b8cff5SYuri Pankov
104416b8cff5SYuri Pankov for (;;)
104516b8cff5SYuri Pankov {
104616b8cff5SYuri Pankov if (!(b = fgets(s, e - s, fp)))
104716b8cff5SYuri Pankov return 0;
104816b8cff5SYuri Pankov state.lineno++;
104916b8cff5SYuri Pankov s += strlen(s);
105016b8cff5SYuri Pankov if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
105116b8cff5SYuri Pankov {
105216b8cff5SYuri Pankov *s = 0;
105316b8cff5SYuri Pankov break;
105416b8cff5SYuri Pankov }
105516b8cff5SYuri Pankov s--;
105616b8cff5SYuri Pankov }
105716b8cff5SYuri Pankov return buf;
105816b8cff5SYuri Pankov }
105916b8cff5SYuri Pankov
106016b8cff5SYuri Pankov static unsigned long
note(unsigned long level,char * msg,unsigned long skip,unsigned long test)106116b8cff5SYuri Pankov note(unsigned long level, char* msg, unsigned long skip, unsigned long test)
106216b8cff5SYuri Pankov {
106316b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)
106416b8cff5SYuri Pankov {
106516b8cff5SYuri Pankov printf("NOTE\t");
106616b8cff5SYuri Pankov if (msg)
106716b8cff5SYuri Pankov printf("%s: ", msg);
106816b8cff5SYuri Pankov printf("skipping lines %d", state.lineno);
106916b8cff5SYuri Pankov }
107016b8cff5SYuri Pankov return skip | level;
107116b8cff5SYuri Pankov }
107216b8cff5SYuri Pankov
107316b8cff5SYuri Pankov #define TABS(n) &ts[7-((n)&7)]
107416b8cff5SYuri Pankov
107516b8cff5SYuri Pankov static char ts[] = "\t\t\t\t\t\t\t";
107616b8cff5SYuri Pankov
107716b8cff5SYuri Pankov static unsigned long
extract(int * tabs,char * spec,char * re,char * s,char * ans,char * msg,char * accept,regmatch_t * match,int nmatch,int nsub,unsigned long skip,unsigned long level,unsigned long test)107816b8cff5SYuri Pankov extract(int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
107916b8cff5SYuri Pankov {
108016b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))
108116b8cff5SYuri Pankov {
108216b8cff5SYuri Pankov state.extracted = 1;
108316b8cff5SYuri Pankov if (test & TEST_OK)
108416b8cff5SYuri Pankov {
108516b8cff5SYuri Pankov state.passed++;
108616b8cff5SYuri Pankov if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
108716b8cff5SYuri Pankov {
108816b8cff5SYuri Pankov if (msg && strcmp(msg, "EXPECTED"))
108916b8cff5SYuri Pankov printf("NOTE\t%s\n", msg);
109016b8cff5SYuri Pankov return skip;
109116b8cff5SYuri Pankov }
109216b8cff5SYuri Pankov test &= ~(TEST_PASS|TEST_QUERY);
109316b8cff5SYuri Pankov }
109416b8cff5SYuri Pankov if (test & (TEST_QUERY|TEST_VERIFY))
109516b8cff5SYuri Pankov {
109616b8cff5SYuri Pankov if (test & TEST_BASELINE)
109716b8cff5SYuri Pankov test &= ~(TEST_BASELINE|TEST_PASS);
109816b8cff5SYuri Pankov else
109916b8cff5SYuri Pankov test |= TEST_PASS;
110016b8cff5SYuri Pankov skip |= level;
110116b8cff5SYuri Pankov }
110216b8cff5SYuri Pankov if (!(test & TEST_OK))
110316b8cff5SYuri Pankov {
110416b8cff5SYuri Pankov if (test & TEST_UNSPECIFIED)
110516b8cff5SYuri Pankov state.unspecified++;
110616b8cff5SYuri Pankov else
110716b8cff5SYuri Pankov state.errors++;
110816b8cff5SYuri Pankov }
110916b8cff5SYuri Pankov if (test & (TEST_PASS|TEST_SUMMARY))
111016b8cff5SYuri Pankov return skip;
111116b8cff5SYuri Pankov test &= ~TEST_DELIMIT;
111216b8cff5SYuri Pankov printf("%s%s", spec, TABS(*tabs++));
111316b8cff5SYuri Pankov if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))
111416b8cff5SYuri Pankov printf("SAME");
111516b8cff5SYuri Pankov else
111616b8cff5SYuri Pankov quote(re, -1, test);
111716b8cff5SYuri Pankov printf("%s", TABS(*tabs++));
111816b8cff5SYuri Pankov quote(s, -1, test);
111916b8cff5SYuri Pankov printf("%s", TABS(*tabs++));
112016b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || !accept && !match)
112116b8cff5SYuri Pankov printf("%s", ans);
112216b8cff5SYuri Pankov else if (accept)
112316b8cff5SYuri Pankov printf("%s", accept);
112416b8cff5SYuri Pankov else
112516b8cff5SYuri Pankov matchprint(match, nmatch, nsub, NiL, test);
112616b8cff5SYuri Pankov if (msg)
112716b8cff5SYuri Pankov printf("%s%s", TABS(*tabs++), msg);
112816b8cff5SYuri Pankov putchar('\n');
112916b8cff5SYuri Pankov }
113016b8cff5SYuri Pankov else if (test & TEST_QUERY)
113116b8cff5SYuri Pankov skip = note(level, msg, skip, test);
113216b8cff5SYuri Pankov else if (test & TEST_VERIFY)
113316b8cff5SYuri Pankov state.extracted = 1;
113416b8cff5SYuri Pankov return skip;
113516b8cff5SYuri Pankov }
113616b8cff5SYuri Pankov
113716b8cff5SYuri Pankov static int
catchfree(regex_t * preg,int flags,int * tabs,char * spec,char * re,char * s,char * ans,char * msg,char * accept,regmatch_t * match,int nmatch,int nsub,unsigned long skip,unsigned long level,unsigned long test)113816b8cff5SYuri Pankov catchfree(regex_t* preg, int flags, int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
113916b8cff5SYuri Pankov {
114016b8cff5SYuri Pankov int eret;
114116b8cff5SYuri Pankov
114216b8cff5SYuri Pankov if (!(test & TEST_CATCH))
114316b8cff5SYuri Pankov {
114416b8cff5SYuri Pankov regfree(preg);
114516b8cff5SYuri Pankov eret = 0;
114616b8cff5SYuri Pankov }
114716b8cff5SYuri Pankov else if (!(eret = setjmp(state.gotcha)))
114816b8cff5SYuri Pankov {
114916b8cff5SYuri Pankov alarm(HUNG);
115016b8cff5SYuri Pankov regfree(preg);
115116b8cff5SYuri Pankov alarm(0);
115216b8cff5SYuri Pankov }
115316b8cff5SYuri Pankov else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
115416b8cff5SYuri Pankov extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
115516b8cff5SYuri Pankov else
115616b8cff5SYuri Pankov {
115716b8cff5SYuri Pankov report("failed", "regfree", re, NiL, -1, msg, flags, test);
115816b8cff5SYuri Pankov error(preg, eret);
115916b8cff5SYuri Pankov }
116016b8cff5SYuri Pankov return eret;
116116b8cff5SYuri Pankov }
116216b8cff5SYuri Pankov
116316b8cff5SYuri Pankov static char*
expand(char * os,char * ot)116416b8cff5SYuri Pankov expand(char* os, char* ot)
116516b8cff5SYuri Pankov {
116616b8cff5SYuri Pankov char* s = os;
116716b8cff5SYuri Pankov char* t;
116816b8cff5SYuri Pankov int n = 0;
116916b8cff5SYuri Pankov int r;
117016b8cff5SYuri Pankov long m;
117116b8cff5SYuri Pankov
117216b8cff5SYuri Pankov for (;;)
117316b8cff5SYuri Pankov {
117416b8cff5SYuri Pankov switch (*s++)
117516b8cff5SYuri Pankov {
117616b8cff5SYuri Pankov case 0:
117716b8cff5SYuri Pankov break;
117816b8cff5SYuri Pankov case '{':
117916b8cff5SYuri Pankov n++;
118016b8cff5SYuri Pankov continue;
118116b8cff5SYuri Pankov case '}':
118216b8cff5SYuri Pankov n--;
118316b8cff5SYuri Pankov continue;
118416b8cff5SYuri Pankov case 'R':
118516b8cff5SYuri Pankov if (n == 1 && !memcmp(s, "E_DUP_MAX", 9))
118616b8cff5SYuri Pankov {
118716b8cff5SYuri Pankov s--;
118816b8cff5SYuri Pankov for (t = ot; os < s; *t++ = *os++);
118916b8cff5SYuri Pankov r = ((t - ot) >= 5 && t[-1] == '{' && t[-2] == '.' && t[-3] == '.' && t[-4] == '.') ? t[-5] : 0;
119016b8cff5SYuri Pankov os = ot;
119116b8cff5SYuri Pankov m = RE_DUP_MAX;
119216b8cff5SYuri Pankov if (*(s += 10) == '+' || *s == '-')
119316b8cff5SYuri Pankov m += strtol(s, &s, 10);
119416b8cff5SYuri Pankov if (r)
119516b8cff5SYuri Pankov {
119616b8cff5SYuri Pankov t -= 5;
119716b8cff5SYuri Pankov while (m-- > 0)
119816b8cff5SYuri Pankov *t++ = r;
119916b8cff5SYuri Pankov while (*s && *s++ != '}');
120016b8cff5SYuri Pankov }
120116b8cff5SYuri Pankov else
120216b8cff5SYuri Pankov t += snprintf(t, 32, "%ld", m);
120316b8cff5SYuri Pankov while (*t = *s++)
120416b8cff5SYuri Pankov t++;
120516b8cff5SYuri Pankov break;
120616b8cff5SYuri Pankov }
120716b8cff5SYuri Pankov continue;
120816b8cff5SYuri Pankov default:
120916b8cff5SYuri Pankov continue;
121016b8cff5SYuri Pankov }
121116b8cff5SYuri Pankov break;
121216b8cff5SYuri Pankov }
121316b8cff5SYuri Pankov return os;
121416b8cff5SYuri Pankov }
121516b8cff5SYuri Pankov
121616b8cff5SYuri Pankov int
main(int argc,char ** argv)121716b8cff5SYuri Pankov main(int argc, char** argv)
121816b8cff5SYuri Pankov {
121916b8cff5SYuri Pankov int flags;
122016b8cff5SYuri Pankov int cflags;
122116b8cff5SYuri Pankov int eflags;
122216b8cff5SYuri Pankov int nmatch;
1223*6b8702c2SRichard Lowe #if _REG_nexec
122416b8cff5SYuri Pankov int nexec;
1225*6b8702c2SRichard Lowe #endif
122616b8cff5SYuri Pankov int nstr;
122716b8cff5SYuri Pankov int cret;
122816b8cff5SYuri Pankov int eret;
122916b8cff5SYuri Pankov int nsub;
123016b8cff5SYuri Pankov int i;
123116b8cff5SYuri Pankov int j;
123216b8cff5SYuri Pankov int expected;
123316b8cff5SYuri Pankov int got;
123416b8cff5SYuri Pankov int locale;
123516b8cff5SYuri Pankov int subunitlen;
123616b8cff5SYuri Pankov int testno;
123716b8cff5SYuri Pankov unsigned long level;
123816b8cff5SYuri Pankov unsigned long skip;
123916b8cff5SYuri Pankov char* p;
124016b8cff5SYuri Pankov char* line;
124116b8cff5SYuri Pankov char* spec;
124216b8cff5SYuri Pankov char* re;
124316b8cff5SYuri Pankov char* s;
124416b8cff5SYuri Pankov char* ans;
124516b8cff5SYuri Pankov char* msg;
124616b8cff5SYuri Pankov char* fun;
124716b8cff5SYuri Pankov char* ppat;
124816b8cff5SYuri Pankov char* subunit;
124916b8cff5SYuri Pankov char* version;
125016b8cff5SYuri Pankov char* field[6];
125116b8cff5SYuri Pankov char* delim[6];
125216b8cff5SYuri Pankov FILE* fp;
125316b8cff5SYuri Pankov int tabs[6];
125416b8cff5SYuri Pankov char unit[64];
125516b8cff5SYuri Pankov regmatch_t match[100];
125616b8cff5SYuri Pankov regex_t preg;
125716b8cff5SYuri Pankov
125816b8cff5SYuri Pankov static char pat[32 * 1024];
125916b8cff5SYuri Pankov static char patbuf[32 * 1024];
126016b8cff5SYuri Pankov static char strbuf[32 * 1024];
126116b8cff5SYuri Pankov
126216b8cff5SYuri Pankov int nonosub = REG_NOSUB == 0;
1263*6b8702c2SRichard Lowe #if _REG_nexec
126416b8cff5SYuri Pankov int nonexec = 0;
1265*6b8702c2SRichard Lowe #endif
126616b8cff5SYuri Pankov
126716b8cff5SYuri Pankov unsigned long test = 0;
126816b8cff5SYuri Pankov
126916b8cff5SYuri Pankov static char* filter[] = { "-", 0 };
127016b8cff5SYuri Pankov
127116b8cff5SYuri Pankov state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
127216b8cff5SYuri Pankov p = unit;
127316b8cff5SYuri Pankov version = (char*)id + 10;
127416b8cff5SYuri Pankov while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
127516b8cff5SYuri Pankov p++;
127616b8cff5SYuri Pankov *p = 0;
127716b8cff5SYuri Pankov while ((p = *++argv) && *p == '-')
127816b8cff5SYuri Pankov for (;;)
127916b8cff5SYuri Pankov {
128016b8cff5SYuri Pankov switch (*++p)
128116b8cff5SYuri Pankov {
128216b8cff5SYuri Pankov case 0:
128316b8cff5SYuri Pankov break;
128416b8cff5SYuri Pankov case 'c':
128516b8cff5SYuri Pankov test |= TEST_CATCH;
128616b8cff5SYuri Pankov continue;
128716b8cff5SYuri Pankov case 'e':
128816b8cff5SYuri Pankov test |= TEST_IGNORE_ERROR;
128916b8cff5SYuri Pankov continue;
129016b8cff5SYuri Pankov case 'h':
129116b8cff5SYuri Pankov case '?':
129216b8cff5SYuri Pankov help(0);
129316b8cff5SYuri Pankov return 2;
129416b8cff5SYuri Pankov case '-':
129516b8cff5SYuri Pankov help(p[1] == 'h');
129616b8cff5SYuri Pankov return 2;
129716b8cff5SYuri Pankov case 'n':
1298*6b8702c2SRichard Lowe #if _REG_nexec
129916b8cff5SYuri Pankov nonexec = 1;
1300*6b8702c2SRichard Lowe #endif
130116b8cff5SYuri Pankov continue;
130216b8cff5SYuri Pankov case 'o':
130316b8cff5SYuri Pankov test |= TEST_IGNORE_OVER;
130416b8cff5SYuri Pankov continue;
130516b8cff5SYuri Pankov case 'p':
130616b8cff5SYuri Pankov test |= TEST_IGNORE_POSITION;
130716b8cff5SYuri Pankov continue;
130816b8cff5SYuri Pankov case 's':
130916b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
131016b8cff5SYuri Pankov if (!(state.stack = stkalloc(stkstd, 0)))
131116b8cff5SYuri Pankov fprintf(stderr, "%s: out of space [stack]", unit);
131216b8cff5SYuri Pankov state.disc.disc.re_resizef = resizef;
131316b8cff5SYuri Pankov state.disc.disc.re_resizehandle = (void*)stkstd;
131416b8cff5SYuri Pankov #endif
131516b8cff5SYuri Pankov continue;
131616b8cff5SYuri Pankov case 'x':
131716b8cff5SYuri Pankov nonosub = 1;
131816b8cff5SYuri Pankov continue;
131916b8cff5SYuri Pankov case 'v':
132016b8cff5SYuri Pankov test |= TEST_VERBOSE;
132116b8cff5SYuri Pankov continue;
132216b8cff5SYuri Pankov case 'A':
132316b8cff5SYuri Pankov test |= TEST_ACTUAL;
132416b8cff5SYuri Pankov continue;
132516b8cff5SYuri Pankov case 'B':
132616b8cff5SYuri Pankov test |= TEST_BASELINE;
132716b8cff5SYuri Pankov continue;
132816b8cff5SYuri Pankov case 'F':
132916b8cff5SYuri Pankov test |= TEST_FAIL;
133016b8cff5SYuri Pankov continue;
133116b8cff5SYuri Pankov case 'P':
133216b8cff5SYuri Pankov test |= TEST_PASS;
133316b8cff5SYuri Pankov continue;
133416b8cff5SYuri Pankov case 'S':
133516b8cff5SYuri Pankov test |= TEST_SUMMARY;
133616b8cff5SYuri Pankov continue;
133716b8cff5SYuri Pankov default:
133816b8cff5SYuri Pankov fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
133916b8cff5SYuri Pankov return 2;
134016b8cff5SYuri Pankov }
134116b8cff5SYuri Pankov break;
134216b8cff5SYuri Pankov }
134316b8cff5SYuri Pankov if (!*argv)
134416b8cff5SYuri Pankov argv = filter;
134516b8cff5SYuri Pankov locale = 0;
134616b8cff5SYuri Pankov while (state.file = *argv++)
134716b8cff5SYuri Pankov {
134816b8cff5SYuri Pankov if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
134916b8cff5SYuri Pankov {
135016b8cff5SYuri Pankov state.file = 0;
135116b8cff5SYuri Pankov fp = stdin;
135216b8cff5SYuri Pankov }
135316b8cff5SYuri Pankov else if (!(fp = fopen(state.file, "r")))
135416b8cff5SYuri Pankov {
135516b8cff5SYuri Pankov fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
135616b8cff5SYuri Pankov return 2;
135716b8cff5SYuri Pankov }
135816b8cff5SYuri Pankov testno = state.errors = state.ignored = state.lineno = state.passed =
135916b8cff5SYuri Pankov state.signals = state.unspecified = state.warnings = 0;
136016b8cff5SYuri Pankov skip = 0;
136116b8cff5SYuri Pankov level = 1;
136216b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
136316b8cff5SYuri Pankov {
136416b8cff5SYuri Pankov printf("TEST\t%s ", unit);
136516b8cff5SYuri Pankov if (s = state.file)
136616b8cff5SYuri Pankov {
136716b8cff5SYuri Pankov subunit = p = 0;
136816b8cff5SYuri Pankov for (;;)
136916b8cff5SYuri Pankov {
137016b8cff5SYuri Pankov switch (*s++)
137116b8cff5SYuri Pankov {
137216b8cff5SYuri Pankov case 0:
137316b8cff5SYuri Pankov break;
137416b8cff5SYuri Pankov case '/':
137516b8cff5SYuri Pankov subunit = s;
137616b8cff5SYuri Pankov continue;
137716b8cff5SYuri Pankov case '.':
137816b8cff5SYuri Pankov p = s - 1;
137916b8cff5SYuri Pankov continue;
138016b8cff5SYuri Pankov default:
138116b8cff5SYuri Pankov continue;
138216b8cff5SYuri Pankov }
138316b8cff5SYuri Pankov break;
138416b8cff5SYuri Pankov }
138516b8cff5SYuri Pankov if (!subunit)
138616b8cff5SYuri Pankov subunit = state.file;
138716b8cff5SYuri Pankov if (p < subunit)
138816b8cff5SYuri Pankov p = s - 1;
138916b8cff5SYuri Pankov subunitlen = p - subunit;
139016b8cff5SYuri Pankov printf("%-.*s ", subunitlen, subunit);
139116b8cff5SYuri Pankov }
139216b8cff5SYuri Pankov else
139316b8cff5SYuri Pankov subunit = 0;
139416b8cff5SYuri Pankov for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
139516b8cff5SYuri Pankov putchar(*s);
139616b8cff5SYuri Pankov if (test & TEST_CATCH)
139716b8cff5SYuri Pankov printf(", catch");
139816b8cff5SYuri Pankov if (test & TEST_IGNORE_ERROR)
139916b8cff5SYuri Pankov printf(", ignore error code mismatches");
140016b8cff5SYuri Pankov if (test & TEST_IGNORE_POSITION)
140116b8cff5SYuri Pankov printf(", ignore negative position mismatches");
140216b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
140316b8cff5SYuri Pankov if (state.stack)
140416b8cff5SYuri Pankov printf(", stack");
140516b8cff5SYuri Pankov #endif
140616b8cff5SYuri Pankov if (test & TEST_VERBOSE)
140716b8cff5SYuri Pankov printf(", verbose");
140816b8cff5SYuri Pankov printf("\n");
140916b8cff5SYuri Pankov #ifdef REG_VERSIONID
141016b8cff5SYuri Pankov if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
141116b8cff5SYuri Pankov s = pat;
141216b8cff5SYuri Pankov else
141316b8cff5SYuri Pankov #endif
141416b8cff5SYuri Pankov #ifdef REG_TEST_VERSION
141516b8cff5SYuri Pankov s = REG_TEST_VERSION;
141616b8cff5SYuri Pankov #else
141716b8cff5SYuri Pankov s = "regex";
141816b8cff5SYuri Pankov #endif
141916b8cff5SYuri Pankov printf("NOTE\t%s\n", s);
142016b8cff5SYuri Pankov if (elementsof(unsupported) > 1)
142116b8cff5SYuri Pankov {
142216b8cff5SYuri Pankov #if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
142316b8cff5SYuri Pankov i = 0;
142416b8cff5SYuri Pankov #else
142516b8cff5SYuri Pankov i = REG_EXTENDED != 0;
142616b8cff5SYuri Pankov #endif
142716b8cff5SYuri Pankov for (got = 0; i < elementsof(unsupported) - 1; i++)
142816b8cff5SYuri Pankov {
142916b8cff5SYuri Pankov if (!got)
143016b8cff5SYuri Pankov {
143116b8cff5SYuri Pankov got = 1;
143216b8cff5SYuri Pankov printf("NOTE\tunsupported: %s", unsupported[i]);
143316b8cff5SYuri Pankov }
143416b8cff5SYuri Pankov else
143516b8cff5SYuri Pankov printf(",%s", unsupported[i]);
143616b8cff5SYuri Pankov }
143716b8cff5SYuri Pankov if (got)
143816b8cff5SYuri Pankov printf("\n");
143916b8cff5SYuri Pankov }
144016b8cff5SYuri Pankov }
144116b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
144216b8cff5SYuri Pankov state.disc.disc.re_version = REG_VERSION;
144316b8cff5SYuri Pankov state.disc.disc.re_compf = compf;
144416b8cff5SYuri Pankov state.disc.disc.re_execf = execf;
144516b8cff5SYuri Pankov if (!(state.disc.sp = sfstropen()))
144616b8cff5SYuri Pankov bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
144716b8cff5SYuri Pankov preg.re_disc = &state.disc.disc;
144816b8cff5SYuri Pankov #endif
144916b8cff5SYuri Pankov if (test & TEST_CATCH)
145016b8cff5SYuri Pankov {
145116b8cff5SYuri Pankov signal(SIGALRM, gotcha);
145216b8cff5SYuri Pankov signal(SIGBUS, gotcha);
145316b8cff5SYuri Pankov signal(SIGSEGV, gotcha);
145416b8cff5SYuri Pankov }
145516b8cff5SYuri Pankov while (p = get_line(fp))
145616b8cff5SYuri Pankov {
145716b8cff5SYuri Pankov
145816b8cff5SYuri Pankov /* parse: */
145916b8cff5SYuri Pankov
146016b8cff5SYuri Pankov line = p;
146116b8cff5SYuri Pankov if (*p == ':' && !isspace(*(p + 1)))
146216b8cff5SYuri Pankov {
146316b8cff5SYuri Pankov while (*++p && *p != ':');
146416b8cff5SYuri Pankov if (!*p++)
146516b8cff5SYuri Pankov {
146616b8cff5SYuri Pankov if (test & TEST_BASELINE)
146716b8cff5SYuri Pankov printf("%s\n", line);
146816b8cff5SYuri Pankov continue;
146916b8cff5SYuri Pankov }
147016b8cff5SYuri Pankov }
147116b8cff5SYuri Pankov while (isspace(*p))
147216b8cff5SYuri Pankov p++;
147316b8cff5SYuri Pankov if (*p == 0 || *p == '#' || *p == 'T')
147416b8cff5SYuri Pankov {
147516b8cff5SYuri Pankov if (test & TEST_BASELINE)
147616b8cff5SYuri Pankov printf("%s\n", line);
147716b8cff5SYuri Pankov continue;
147816b8cff5SYuri Pankov }
147916b8cff5SYuri Pankov if (*p == ':' || *p == 'N')
148016b8cff5SYuri Pankov {
148116b8cff5SYuri Pankov if (test & TEST_BASELINE)
148216b8cff5SYuri Pankov printf("%s\n", line);
148316b8cff5SYuri Pankov else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
148416b8cff5SYuri Pankov {
148516b8cff5SYuri Pankov while (*++p && !isspace(*p));
148616b8cff5SYuri Pankov while (isspace(*p))
148716b8cff5SYuri Pankov p++;
148816b8cff5SYuri Pankov printf("NOTE %s\n", p);
148916b8cff5SYuri Pankov }
149016b8cff5SYuri Pankov continue;
149116b8cff5SYuri Pankov }
149216b8cff5SYuri Pankov j = 0;
149316b8cff5SYuri Pankov i = 0;
149416b8cff5SYuri Pankov field[i++] = p;
149516b8cff5SYuri Pankov for (;;)
149616b8cff5SYuri Pankov {
149716b8cff5SYuri Pankov switch (*p++)
149816b8cff5SYuri Pankov {
149916b8cff5SYuri Pankov case 0:
150016b8cff5SYuri Pankov p--;
150116b8cff5SYuri Pankov j = 0;
150216b8cff5SYuri Pankov goto checkfield;
150316b8cff5SYuri Pankov case '\t':
150416b8cff5SYuri Pankov *(delim[i] = p - 1) = 0;
150516b8cff5SYuri Pankov j = 1;
150616b8cff5SYuri Pankov checkfield:
150716b8cff5SYuri Pankov s = field[i - 1];
150816b8cff5SYuri Pankov if (streq(s, "NIL"))
150916b8cff5SYuri Pankov field[i - 1] = 0;
151016b8cff5SYuri Pankov else if (streq(s, "NULL"))
151116b8cff5SYuri Pankov *s = 0;
151216b8cff5SYuri Pankov while (*p == '\t')
151316b8cff5SYuri Pankov {
151416b8cff5SYuri Pankov p++;
151516b8cff5SYuri Pankov j++;
151616b8cff5SYuri Pankov }
151716b8cff5SYuri Pankov tabs[i - 1] = j;
151816b8cff5SYuri Pankov if (!*p)
151916b8cff5SYuri Pankov break;
152016b8cff5SYuri Pankov if (i >= elementsof(field))
152116b8cff5SYuri Pankov bad("too many fields\n", NiL, NiL, 0, 0);
152216b8cff5SYuri Pankov field[i++] = p;
152316b8cff5SYuri Pankov /*FALLTHROUGH*/
152416b8cff5SYuri Pankov default:
152516b8cff5SYuri Pankov continue;
152616b8cff5SYuri Pankov }
152716b8cff5SYuri Pankov break;
152816b8cff5SYuri Pankov }
152916b8cff5SYuri Pankov if (!(spec = field[0]))
153016b8cff5SYuri Pankov bad("NIL spec\n", NiL, NiL, 0, 0);
153116b8cff5SYuri Pankov
153216b8cff5SYuri Pankov /* interpret: */
153316b8cff5SYuri Pankov
153416b8cff5SYuri Pankov cflags = REG_TEST_DEFAULT;
153516b8cff5SYuri Pankov eflags = REG_EXEC_DEFAULT;
153616b8cff5SYuri Pankov test &= TEST_GLOBAL;
153716b8cff5SYuri Pankov state.extracted = 0;
153816b8cff5SYuri Pankov nmatch = 20;
153916b8cff5SYuri Pankov nsub = -1;
154016b8cff5SYuri Pankov for (p = spec; *p; p++)
154116b8cff5SYuri Pankov {
154216b8cff5SYuri Pankov if (isdigit(*p))
154316b8cff5SYuri Pankov {
154416b8cff5SYuri Pankov nmatch = strtol(p, &p, 10);
154516b8cff5SYuri Pankov if (nmatch >= elementsof(match))
154616b8cff5SYuri Pankov bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
154716b8cff5SYuri Pankov p--;
154816b8cff5SYuri Pankov continue;
154916b8cff5SYuri Pankov }
155016b8cff5SYuri Pankov switch (*p)
155116b8cff5SYuri Pankov {
155216b8cff5SYuri Pankov case 'A':
155316b8cff5SYuri Pankov test |= TEST_ARE;
155416b8cff5SYuri Pankov continue;
155516b8cff5SYuri Pankov case 'B':
155616b8cff5SYuri Pankov test |= TEST_BRE;
155716b8cff5SYuri Pankov continue;
155816b8cff5SYuri Pankov case 'C':
155916b8cff5SYuri Pankov if (!(test & TEST_QUERY) && !(skip & level))
156016b8cff5SYuri Pankov bad("locale must be nested\n", NiL, NiL, 0, 0);
156116b8cff5SYuri Pankov test &= ~TEST_QUERY;
156216b8cff5SYuri Pankov if (locale)
156316b8cff5SYuri Pankov bad("locale nesting not supported\n", NiL, NiL, 0, 0);
156416b8cff5SYuri Pankov if (i != 2)
156516b8cff5SYuri Pankov bad("locale field expected\n", NiL, NiL, 0, 0);
156616b8cff5SYuri Pankov if (!(skip & level))
156716b8cff5SYuri Pankov {
156816b8cff5SYuri Pankov #if defined(LC_COLLATE) && defined(LC_CTYPE)
156916b8cff5SYuri Pankov s = field[1];
157016b8cff5SYuri Pankov if (!s || streq(s, "POSIX"))
157116b8cff5SYuri Pankov s = "C";
157216b8cff5SYuri Pankov if ((ans = setlocale(LC_COLLATE, s)) && streq(ans, "POSIX"))
157316b8cff5SYuri Pankov ans = "C";
157416b8cff5SYuri Pankov if (!ans || !streq(ans, s) && streq(s, "C"))
157516b8cff5SYuri Pankov ans = 0;
157616b8cff5SYuri Pankov else if ((ans = setlocale(LC_CTYPE, s)) && streq(ans, "POSIX"))
157716b8cff5SYuri Pankov ans = "C";
157816b8cff5SYuri Pankov if (!ans || !streq(ans, s) && streq(s, "C"))
157916b8cff5SYuri Pankov skip = note(level, s, skip, test);
158016b8cff5SYuri Pankov else
158116b8cff5SYuri Pankov {
158216b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
158316b8cff5SYuri Pankov printf("NOTE \"%s\" locale\n", s);
158416b8cff5SYuri Pankov locale = level;
158516b8cff5SYuri Pankov }
158616b8cff5SYuri Pankov #else
158716b8cff5SYuri Pankov skip = note(level, skip, test, "locales not supported");
158816b8cff5SYuri Pankov #endif
158916b8cff5SYuri Pankov }
159016b8cff5SYuri Pankov cflags = NOTEST;
159116b8cff5SYuri Pankov continue;
159216b8cff5SYuri Pankov case 'E':
159316b8cff5SYuri Pankov test |= TEST_ERE;
159416b8cff5SYuri Pankov continue;
159516b8cff5SYuri Pankov case 'K':
159616b8cff5SYuri Pankov test |= TEST_KRE;
159716b8cff5SYuri Pankov continue;
159816b8cff5SYuri Pankov case 'L':
159916b8cff5SYuri Pankov test |= TEST_LRE;
160016b8cff5SYuri Pankov continue;
160116b8cff5SYuri Pankov case 'S':
160216b8cff5SYuri Pankov test |= TEST_SRE;
160316b8cff5SYuri Pankov continue;
160416b8cff5SYuri Pankov
160516b8cff5SYuri Pankov case 'a':
160616b8cff5SYuri Pankov cflags |= REG_LEFT|REG_RIGHT;
160716b8cff5SYuri Pankov continue;
160816b8cff5SYuri Pankov case 'b':
160916b8cff5SYuri Pankov eflags |= REG_NOTBOL;
161016b8cff5SYuri Pankov continue;
161116b8cff5SYuri Pankov case 'c':
161216b8cff5SYuri Pankov cflags |= REG_COMMENT;
161316b8cff5SYuri Pankov continue;
161416b8cff5SYuri Pankov case 'd':
161516b8cff5SYuri Pankov cflags |= REG_SHELL_DOT;
161616b8cff5SYuri Pankov continue;
161716b8cff5SYuri Pankov case 'e':
161816b8cff5SYuri Pankov eflags |= REG_NOTEOL;
161916b8cff5SYuri Pankov continue;
162016b8cff5SYuri Pankov case 'f':
162116b8cff5SYuri Pankov cflags |= REG_MULTIPLE;
162216b8cff5SYuri Pankov continue;
162316b8cff5SYuri Pankov case 'g':
162416b8cff5SYuri Pankov cflags |= NOTEST;
162516b8cff5SYuri Pankov continue;
162616b8cff5SYuri Pankov case 'h':
162716b8cff5SYuri Pankov cflags |= REG_MULTIREF;
162816b8cff5SYuri Pankov continue;
162916b8cff5SYuri Pankov case 'i':
163016b8cff5SYuri Pankov cflags |= REG_ICASE;
163116b8cff5SYuri Pankov continue;
163216b8cff5SYuri Pankov case 'j':
163316b8cff5SYuri Pankov cflags |= REG_SPAN;
163416b8cff5SYuri Pankov continue;
163516b8cff5SYuri Pankov case 'k':
163616b8cff5SYuri Pankov cflags |= REG_ESCAPE;
163716b8cff5SYuri Pankov continue;
163816b8cff5SYuri Pankov case 'l':
163916b8cff5SYuri Pankov cflags |= REG_LEFT;
164016b8cff5SYuri Pankov continue;
164116b8cff5SYuri Pankov case 'm':
164216b8cff5SYuri Pankov cflags |= REG_MINIMAL;
164316b8cff5SYuri Pankov continue;
164416b8cff5SYuri Pankov case 'n':
164516b8cff5SYuri Pankov cflags |= REG_NEWLINE;
164616b8cff5SYuri Pankov continue;
164716b8cff5SYuri Pankov case 'o':
164816b8cff5SYuri Pankov cflags |= REG_SHELL_GROUP;
164916b8cff5SYuri Pankov continue;
165016b8cff5SYuri Pankov case 'p':
165116b8cff5SYuri Pankov cflags |= REG_SHELL_PATH;
165216b8cff5SYuri Pankov continue;
165316b8cff5SYuri Pankov case 'q':
165416b8cff5SYuri Pankov cflags |= REG_DELIMITED;
165516b8cff5SYuri Pankov continue;
165616b8cff5SYuri Pankov case 'r':
165716b8cff5SYuri Pankov cflags |= REG_RIGHT;
165816b8cff5SYuri Pankov continue;
165916b8cff5SYuri Pankov case 's':
166016b8cff5SYuri Pankov cflags |= REG_SHELL_ESCAPED;
166116b8cff5SYuri Pankov continue;
166216b8cff5SYuri Pankov case 't':
166316b8cff5SYuri Pankov cflags |= REG_MUSTDELIM;
166416b8cff5SYuri Pankov continue;
166516b8cff5SYuri Pankov case 'u':
166616b8cff5SYuri Pankov test |= TEST_UNSPECIFIED;
166716b8cff5SYuri Pankov continue;
166816b8cff5SYuri Pankov case 'v':
166916b8cff5SYuri Pankov cflags |= REG_CLASS_ESCAPE;
167016b8cff5SYuri Pankov continue;
167116b8cff5SYuri Pankov case 'w':
167216b8cff5SYuri Pankov cflags |= REG_NOSUB;
167316b8cff5SYuri Pankov continue;
167416b8cff5SYuri Pankov case 'x':
167516b8cff5SYuri Pankov if (REG_LENIENT)
167616b8cff5SYuri Pankov cflags |= REG_LENIENT;
167716b8cff5SYuri Pankov else
167816b8cff5SYuri Pankov test |= TEST_LENIENT;
167916b8cff5SYuri Pankov continue;
168016b8cff5SYuri Pankov case 'y':
168116b8cff5SYuri Pankov eflags |= REG_LEFT;
168216b8cff5SYuri Pankov continue;
168316b8cff5SYuri Pankov case 'z':
168416b8cff5SYuri Pankov cflags |= REG_NULL;
168516b8cff5SYuri Pankov continue;
168616b8cff5SYuri Pankov
168716b8cff5SYuri Pankov case '$':
168816b8cff5SYuri Pankov test |= TEST_EXPAND;
168916b8cff5SYuri Pankov continue;
169016b8cff5SYuri Pankov
169116b8cff5SYuri Pankov case '/':
169216b8cff5SYuri Pankov test |= TEST_SUB;
169316b8cff5SYuri Pankov continue;
169416b8cff5SYuri Pankov
169516b8cff5SYuri Pankov case '=':
169616b8cff5SYuri Pankov test |= TEST_DECOMP;
169716b8cff5SYuri Pankov continue;
169816b8cff5SYuri Pankov
169916b8cff5SYuri Pankov case '?':
170016b8cff5SYuri Pankov test |= TEST_VERIFY;
170116b8cff5SYuri Pankov test &= ~(TEST_AND|TEST_OR);
170216b8cff5SYuri Pankov state.verify = state.passed;
170316b8cff5SYuri Pankov continue;
170416b8cff5SYuri Pankov case '&':
170516b8cff5SYuri Pankov test |= TEST_VERIFY|TEST_AND;
170616b8cff5SYuri Pankov test &= ~TEST_OR;
170716b8cff5SYuri Pankov continue;
170816b8cff5SYuri Pankov case '|':
170916b8cff5SYuri Pankov test |= TEST_VERIFY|TEST_OR;
171016b8cff5SYuri Pankov test &= ~TEST_AND;
171116b8cff5SYuri Pankov continue;
171216b8cff5SYuri Pankov case ';':
171316b8cff5SYuri Pankov test |= TEST_OR;
171416b8cff5SYuri Pankov test &= ~TEST_AND;
171516b8cff5SYuri Pankov continue;
171616b8cff5SYuri Pankov
171716b8cff5SYuri Pankov case '{':
171816b8cff5SYuri Pankov level <<= 1;
171916b8cff5SYuri Pankov if (skip & (level >> 1))
172016b8cff5SYuri Pankov {
172116b8cff5SYuri Pankov skip |= level;
172216b8cff5SYuri Pankov cflags = NOTEST;
172316b8cff5SYuri Pankov }
172416b8cff5SYuri Pankov else
172516b8cff5SYuri Pankov {
172616b8cff5SYuri Pankov skip &= ~level;
172716b8cff5SYuri Pankov test |= TEST_QUERY;
172816b8cff5SYuri Pankov }
172916b8cff5SYuri Pankov continue;
173016b8cff5SYuri Pankov case '}':
173116b8cff5SYuri Pankov if (level == 1)
173216b8cff5SYuri Pankov bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
173316b8cff5SYuri Pankov if ((skip & level) && !(skip & (level>>1)))
173416b8cff5SYuri Pankov {
173516b8cff5SYuri Pankov if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
173616b8cff5SYuri Pankov {
173716b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_FAIL))
173816b8cff5SYuri Pankov printf("}\n");
173916b8cff5SYuri Pankov else if (!(test & TEST_PASS))
174016b8cff5SYuri Pankov printf("-%d\n", state.lineno);
174116b8cff5SYuri Pankov }
174216b8cff5SYuri Pankov }
174316b8cff5SYuri Pankov #if defined(LC_COLLATE) && defined(LC_CTYPE)
174416b8cff5SYuri Pankov else if (locale & level)
174516b8cff5SYuri Pankov {
174616b8cff5SYuri Pankov locale = 0;
174716b8cff5SYuri Pankov if (!(skip & level))
174816b8cff5SYuri Pankov {
174916b8cff5SYuri Pankov s = "C";
175016b8cff5SYuri Pankov setlocale(LC_COLLATE, s);
175116b8cff5SYuri Pankov setlocale(LC_CTYPE, s);
175216b8cff5SYuri Pankov if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
175316b8cff5SYuri Pankov printf("NOTE \"%s\" locale\n", s);
175416b8cff5SYuri Pankov else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
175516b8cff5SYuri Pankov printf("}\n");
175616b8cff5SYuri Pankov }
175716b8cff5SYuri Pankov else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
175816b8cff5SYuri Pankov printf("}\n");
175916b8cff5SYuri Pankov }
176016b8cff5SYuri Pankov #endif
176116b8cff5SYuri Pankov level >>= 1;
176216b8cff5SYuri Pankov cflags = NOTEST;
176316b8cff5SYuri Pankov continue;
176416b8cff5SYuri Pankov
176516b8cff5SYuri Pankov default:
176616b8cff5SYuri Pankov bad("bad spec\n", spec, NiL, 0, test);
176716b8cff5SYuri Pankov break;
176816b8cff5SYuri Pankov
176916b8cff5SYuri Pankov }
177016b8cff5SYuri Pankov break;
177116b8cff5SYuri Pankov }
177216b8cff5SYuri Pankov if ((cflags|eflags) == NOTEST || (skip & level) && (test & TEST_BASELINE))
177316b8cff5SYuri Pankov {
177416b8cff5SYuri Pankov if (test & TEST_BASELINE)
177516b8cff5SYuri Pankov {
177616b8cff5SYuri Pankov while (i > 1)
177716b8cff5SYuri Pankov *delim[--i] = '\t';
177816b8cff5SYuri Pankov printf("%s\n", line);
177916b8cff5SYuri Pankov }
178016b8cff5SYuri Pankov continue;
178116b8cff5SYuri Pankov }
178216b8cff5SYuri Pankov if (test & TEST_OR)
178316b8cff5SYuri Pankov {
178416b8cff5SYuri Pankov if (!(test & TEST_VERIFY))
178516b8cff5SYuri Pankov {
178616b8cff5SYuri Pankov test &= ~TEST_OR;
178716b8cff5SYuri Pankov if (state.passed == state.verify && i > 1)
178816b8cff5SYuri Pankov printf("NOTE\t%s\n", field[1]);
178916b8cff5SYuri Pankov continue;
179016b8cff5SYuri Pankov }
179116b8cff5SYuri Pankov else if (state.passed > state.verify)
179216b8cff5SYuri Pankov continue;
179316b8cff5SYuri Pankov }
179416b8cff5SYuri Pankov else if (test & TEST_AND)
179516b8cff5SYuri Pankov {
179616b8cff5SYuri Pankov if (state.passed == state.verify)
179716b8cff5SYuri Pankov continue;
179816b8cff5SYuri Pankov state.passed = state.verify;
179916b8cff5SYuri Pankov }
180016b8cff5SYuri Pankov if (i < ((test & TEST_DECOMP) ? 3 : 4))
180116b8cff5SYuri Pankov bad("too few fields\n", NiL, NiL, 0, test);
180216b8cff5SYuri Pankov while (i < elementsof(field))
180316b8cff5SYuri Pankov field[i++] = 0;
180416b8cff5SYuri Pankov if (re = field[1])
180516b8cff5SYuri Pankov {
180616b8cff5SYuri Pankov if (streq(re, "SAME"))
180716b8cff5SYuri Pankov {
180816b8cff5SYuri Pankov re = ppat;
180916b8cff5SYuri Pankov test |= TEST_SAME;
181016b8cff5SYuri Pankov }
181116b8cff5SYuri Pankov else
181216b8cff5SYuri Pankov {
181316b8cff5SYuri Pankov if (test & TEST_EXPAND)
181416b8cff5SYuri Pankov escape(re);
181516b8cff5SYuri Pankov re = expand(re, patbuf);
181616b8cff5SYuri Pankov strcpy(ppat = pat, re);
181716b8cff5SYuri Pankov }
181816b8cff5SYuri Pankov }
181916b8cff5SYuri Pankov else
182016b8cff5SYuri Pankov ppat = 0;
182116b8cff5SYuri Pankov nstr = -1;
182216b8cff5SYuri Pankov if (s = field[2])
182316b8cff5SYuri Pankov {
182416b8cff5SYuri Pankov s = expand(s, strbuf);
182516b8cff5SYuri Pankov if (test & TEST_EXPAND)
182616b8cff5SYuri Pankov {
182716b8cff5SYuri Pankov nstr = escape(s);
182816b8cff5SYuri Pankov #if _REG_nexec
182916b8cff5SYuri Pankov if (nstr != strlen(s))
183016b8cff5SYuri Pankov nexec = nstr;
183116b8cff5SYuri Pankov #endif
183216b8cff5SYuri Pankov }
183316b8cff5SYuri Pankov }
183416b8cff5SYuri Pankov if (!(ans = field[(test & TEST_DECOMP) ? 2 : 3]))
183516b8cff5SYuri Pankov bad("NIL answer\n", NiL, NiL, 0, test);
183616b8cff5SYuri Pankov msg = field[4];
183716b8cff5SYuri Pankov fflush(stdout);
183816b8cff5SYuri Pankov if (test & TEST_SUB)
183916b8cff5SYuri Pankov #if _REG_subcomp
184016b8cff5SYuri Pankov cflags |= REG_DELIMITED;
184116b8cff5SYuri Pankov #else
184216b8cff5SYuri Pankov continue;
184316b8cff5SYuri Pankov #endif
184416b8cff5SYuri Pankov #if !_REG_decomp
184516b8cff5SYuri Pankov if (test & TEST_DECOMP)
184616b8cff5SYuri Pankov continue;
184716b8cff5SYuri Pankov #endif
184816b8cff5SYuri Pankov
184916b8cff5SYuri Pankov compile:
185016b8cff5SYuri Pankov
185116b8cff5SYuri Pankov if (state.extracted || (skip & level))
185216b8cff5SYuri Pankov continue;
185316b8cff5SYuri Pankov #if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
185416b8cff5SYuri Pankov #ifdef REG_EXTENDED
185516b8cff5SYuri Pankov if (REG_EXTENDED != 0 && (test & TEST_BRE))
185616b8cff5SYuri Pankov #else
185716b8cff5SYuri Pankov if (test & TEST_BRE)
185816b8cff5SYuri Pankov #endif
185916b8cff5SYuri Pankov {
186016b8cff5SYuri Pankov test &= ~TEST_BRE;
186116b8cff5SYuri Pankov flags = cflags;
186216b8cff5SYuri Pankov state.which = "BRE";
186316b8cff5SYuri Pankov }
186416b8cff5SYuri Pankov else
186516b8cff5SYuri Pankov #endif
186616b8cff5SYuri Pankov #ifdef REG_EXTENDED
186716b8cff5SYuri Pankov if (test & TEST_ERE)
186816b8cff5SYuri Pankov {
186916b8cff5SYuri Pankov test &= ~TEST_ERE;
187016b8cff5SYuri Pankov flags = cflags | REG_EXTENDED;
187116b8cff5SYuri Pankov state.which = "ERE";
187216b8cff5SYuri Pankov }
187316b8cff5SYuri Pankov else
187416b8cff5SYuri Pankov #endif
187516b8cff5SYuri Pankov #ifdef REG_AUGMENTED
187616b8cff5SYuri Pankov if (test & TEST_ARE)
187716b8cff5SYuri Pankov {
187816b8cff5SYuri Pankov test &= ~TEST_ARE;
187916b8cff5SYuri Pankov flags = cflags | REG_AUGMENTED;
188016b8cff5SYuri Pankov state.which = "ARE";
188116b8cff5SYuri Pankov }
188216b8cff5SYuri Pankov else
188316b8cff5SYuri Pankov #endif
188416b8cff5SYuri Pankov #ifdef REG_LITERAL
188516b8cff5SYuri Pankov if (test & TEST_LRE)
188616b8cff5SYuri Pankov {
188716b8cff5SYuri Pankov test &= ~TEST_LRE;
188816b8cff5SYuri Pankov flags = cflags | REG_LITERAL;
188916b8cff5SYuri Pankov state.which = "LRE";
189016b8cff5SYuri Pankov }
189116b8cff5SYuri Pankov else
189216b8cff5SYuri Pankov #endif
189316b8cff5SYuri Pankov #ifdef REG_SHELL
189416b8cff5SYuri Pankov if (test & TEST_SRE)
189516b8cff5SYuri Pankov {
189616b8cff5SYuri Pankov test &= ~TEST_SRE;
189716b8cff5SYuri Pankov flags = cflags | REG_SHELL;
189816b8cff5SYuri Pankov state.which = "SRE";
189916b8cff5SYuri Pankov }
190016b8cff5SYuri Pankov else
190116b8cff5SYuri Pankov #ifdef REG_AUGMENTED
190216b8cff5SYuri Pankov if (test & TEST_KRE)
190316b8cff5SYuri Pankov {
190416b8cff5SYuri Pankov test &= ~TEST_KRE;
190516b8cff5SYuri Pankov flags = cflags | REG_SHELL | REG_AUGMENTED;
190616b8cff5SYuri Pankov state.which = "KRE";
190716b8cff5SYuri Pankov }
190816b8cff5SYuri Pankov else
190916b8cff5SYuri Pankov #endif
191016b8cff5SYuri Pankov #endif
191116b8cff5SYuri Pankov {
191216b8cff5SYuri Pankov if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
191316b8cff5SYuri Pankov extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
191416b8cff5SYuri Pankov continue;
191516b8cff5SYuri Pankov }
191616b8cff5SYuri Pankov if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
191716b8cff5SYuri Pankov {
191816b8cff5SYuri Pankov printf("test %-3d %s ", state.lineno, state.which);
191916b8cff5SYuri Pankov quote(re, -1, test|TEST_DELIMIT);
192016b8cff5SYuri Pankov printf(" ");
192116b8cff5SYuri Pankov quote(s, nstr, test|TEST_DELIMIT);
192216b8cff5SYuri Pankov printf("\n");
192316b8cff5SYuri Pankov }
192416b8cff5SYuri Pankov
192516b8cff5SYuri Pankov nosub:
192616b8cff5SYuri Pankov fun = "regcomp";
192716b8cff5SYuri Pankov #if _REG_nexec
192816b8cff5SYuri Pankov if (nstr >= 0 && nstr != strlen(s))
192916b8cff5SYuri Pankov nexec = nstr;
193016b8cff5SYuri Pankov #endif
1931*6b8702c2SRichard Lowe
193216b8cff5SYuri Pankov if (state.extracted || (skip & level))
193316b8cff5SYuri Pankov continue;
193416b8cff5SYuri Pankov if (!(test & TEST_QUERY))
193516b8cff5SYuri Pankov testno++;
193616b8cff5SYuri Pankov #ifdef REG_DISCIPLINE
193716b8cff5SYuri Pankov if (state.stack)
193816b8cff5SYuri Pankov stkset(stkstd, state.stack, 0);
193916b8cff5SYuri Pankov flags |= REG_DISCIPLINE;
194016b8cff5SYuri Pankov state.disc.ordinal = 0;
194116b8cff5SYuri Pankov sfstrseek(state.disc.sp, 0, SEEK_SET);
194216b8cff5SYuri Pankov #endif
194316b8cff5SYuri Pankov if (!(test & TEST_CATCH))
194416b8cff5SYuri Pankov cret = regcomp(&preg, re, flags);
194516b8cff5SYuri Pankov else if (!(cret = setjmp(state.gotcha)))
194616b8cff5SYuri Pankov {
194716b8cff5SYuri Pankov alarm(HUNG);
194816b8cff5SYuri Pankov cret = regcomp(&preg, re, flags);
194916b8cff5SYuri Pankov alarm(0);
195016b8cff5SYuri Pankov }
195116b8cff5SYuri Pankov #if _REG_subcomp
195216b8cff5SYuri Pankov if (!cret && (test & TEST_SUB))
195316b8cff5SYuri Pankov {
195416b8cff5SYuri Pankov fun = "regsubcomp";
195516b8cff5SYuri Pankov p = re + preg.re_npat;
195616b8cff5SYuri Pankov if (!(test & TEST_CATCH))
195716b8cff5SYuri Pankov cret = regsubcomp(&preg, p, NiL, 0, 0);
195816b8cff5SYuri Pankov else if (!(cret = setjmp(state.gotcha)))
195916b8cff5SYuri Pankov {
196016b8cff5SYuri Pankov alarm(HUNG);
196116b8cff5SYuri Pankov cret = regsubcomp(&preg, p, NiL, 0, 0);
196216b8cff5SYuri Pankov alarm(0);
196316b8cff5SYuri Pankov }
196416b8cff5SYuri Pankov if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
196516b8cff5SYuri Pankov {
196616b8cff5SYuri Pankov if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
196716b8cff5SYuri Pankov continue;
196816b8cff5SYuri Pankov cret = REG_EFLAGS;
196916b8cff5SYuri Pankov }
197016b8cff5SYuri Pankov }
197116b8cff5SYuri Pankov #endif
197216b8cff5SYuri Pankov #if _REG_decomp
197316b8cff5SYuri Pankov if (!cret && (test & TEST_DECOMP))
197416b8cff5SYuri Pankov {
197516b8cff5SYuri Pankov char buf[128];
197616b8cff5SYuri Pankov
197716b8cff5SYuri Pankov if ((j = nmatch) > sizeof(buf))
197816b8cff5SYuri Pankov j = sizeof(buf);
197916b8cff5SYuri Pankov fun = "regdecomp";
198016b8cff5SYuri Pankov p = re + preg.re_npat;
198116b8cff5SYuri Pankov if (!(test & TEST_CATCH))
198216b8cff5SYuri Pankov i = regdecomp(&preg, -1, buf, j);
198316b8cff5SYuri Pankov else if (!(cret = setjmp(state.gotcha)))
198416b8cff5SYuri Pankov {
198516b8cff5SYuri Pankov alarm(HUNG);
198616b8cff5SYuri Pankov i = regdecomp(&preg, -1, buf, j);
198716b8cff5SYuri Pankov alarm(0);
198816b8cff5SYuri Pankov }
198916b8cff5SYuri Pankov if (!cret)
199016b8cff5SYuri Pankov {
199116b8cff5SYuri Pankov catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
199216b8cff5SYuri Pankov if (i > j)
199316b8cff5SYuri Pankov {
199416b8cff5SYuri Pankov if (i != (strlen(ans) + 1))
199516b8cff5SYuri Pankov {
199616b8cff5SYuri Pankov report("failed", fun, re, s, nstr, msg, flags, test);
199716b8cff5SYuri Pankov printf(" %d byte buffer supplied, %d byte buffer required\n", j, i);
199816b8cff5SYuri Pankov }
199916b8cff5SYuri Pankov }
200016b8cff5SYuri Pankov else if (strcmp(buf, ans))
200116b8cff5SYuri Pankov {
200216b8cff5SYuri Pankov report("failed", fun, re, s, nstr, msg, flags, test);
200316b8cff5SYuri Pankov quote(ans, -1, test|TEST_DELIMIT);
200416b8cff5SYuri Pankov printf(" expected, ");
200516b8cff5SYuri Pankov quote(buf, -1, test|TEST_DELIMIT);
200616b8cff5SYuri Pankov printf(" returned\n");
200716b8cff5SYuri Pankov }
200816b8cff5SYuri Pankov continue;
200916b8cff5SYuri Pankov }
201016b8cff5SYuri Pankov }
201116b8cff5SYuri Pankov #endif
201216b8cff5SYuri Pankov if (!cret)
201316b8cff5SYuri Pankov {
201416b8cff5SYuri Pankov if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
201516b8cff5SYuri Pankov {
201616b8cff5SYuri Pankov for (p = ans; *p; p++)
201716b8cff5SYuri Pankov if (*p == '(')
201816b8cff5SYuri Pankov nsub++;
201916b8cff5SYuri Pankov else if (*p == '{')
202016b8cff5SYuri Pankov nsub--;
202116b8cff5SYuri Pankov if (nsub >= 0)
202216b8cff5SYuri Pankov {
202316b8cff5SYuri Pankov if (test & TEST_IGNORE_OVER)
202416b8cff5SYuri Pankov {
202516b8cff5SYuri Pankov if (nmatch > nsub)
202616b8cff5SYuri Pankov nmatch = nsub + 1;
202716b8cff5SYuri Pankov }
202816b8cff5SYuri Pankov else if (nsub != preg.re_nsub)
202916b8cff5SYuri Pankov {
203016b8cff5SYuri Pankov if (nsub > preg.re_nsub)
203116b8cff5SYuri Pankov {
203216b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
203316b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
203416b8cff5SYuri Pankov else
203516b8cff5SYuri Pankov {
203616b8cff5SYuri Pankov report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
203716b8cff5SYuri Pankov printf("at least %d expected, %d returned\n", nsub, preg.re_nsub);
203816b8cff5SYuri Pankov state.errors++;
203916b8cff5SYuri Pankov }
204016b8cff5SYuri Pankov }
204116b8cff5SYuri Pankov else
204216b8cff5SYuri Pankov nsub = preg.re_nsub;
204316b8cff5SYuri Pankov }
204416b8cff5SYuri Pankov }
204516b8cff5SYuri Pankov }
204616b8cff5SYuri Pankov if (!(test & (TEST_DECOMP|TEST_SUB)) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
204716b8cff5SYuri Pankov {
204816b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
204916b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
205016b8cff5SYuri Pankov else if (!(test & TEST_LENIENT))
205116b8cff5SYuri Pankov {
205216b8cff5SYuri Pankov report("failed", fun, re, NiL, -1, msg, flags, test);
205316b8cff5SYuri Pankov printf("%s expected, OK returned\n", ans);
205416b8cff5SYuri Pankov }
205516b8cff5SYuri Pankov catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
205616b8cff5SYuri Pankov continue;
205716b8cff5SYuri Pankov }
205816b8cff5SYuri Pankov }
205916b8cff5SYuri Pankov else
206016b8cff5SYuri Pankov {
206116b8cff5SYuri Pankov if (test & TEST_LENIENT)
206216b8cff5SYuri Pankov /* we'll let it go this time */;
206316b8cff5SYuri Pankov else if (!*ans || ans[0]=='(' || cret == REG_BADPAT && streq(ans, "NOMATCH"))
206416b8cff5SYuri Pankov {
206516b8cff5SYuri Pankov got = 0;
206616b8cff5SYuri Pankov for (i = 1; i < elementsof(codes); i++)
206716b8cff5SYuri Pankov if (cret==codes[i].code)
206816b8cff5SYuri Pankov got = i;
206916b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
207016b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
207116b8cff5SYuri Pankov else
207216b8cff5SYuri Pankov {
207316b8cff5SYuri Pankov report("failed", fun, re, NiL, -1, msg, flags, test);
207416b8cff5SYuri Pankov printf("%s returned: ", codes[got].name);
207516b8cff5SYuri Pankov error(&preg, cret);
207616b8cff5SYuri Pankov }
207716b8cff5SYuri Pankov }
207816b8cff5SYuri Pankov else
207916b8cff5SYuri Pankov {
208016b8cff5SYuri Pankov expected = got = 0;
208116b8cff5SYuri Pankov for (i = 1; i < elementsof(codes); i++)
208216b8cff5SYuri Pankov {
208316b8cff5SYuri Pankov if (streq(ans, codes[i].name))
208416b8cff5SYuri Pankov expected = i;
208516b8cff5SYuri Pankov if (cret==codes[i].code)
208616b8cff5SYuri Pankov got = i;
208716b8cff5SYuri Pankov }
208816b8cff5SYuri Pankov if (!expected)
208916b8cff5SYuri Pankov {
209016b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
209116b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
209216b8cff5SYuri Pankov else
209316b8cff5SYuri Pankov {
209416b8cff5SYuri Pankov report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
209516b8cff5SYuri Pankov printf("%s expected, %s returned\n", ans, codes[got].name);
209616b8cff5SYuri Pankov }
209716b8cff5SYuri Pankov }
209816b8cff5SYuri Pankov else if (cret != codes[expected].code && cret != REG_BADPAT)
209916b8cff5SYuri Pankov {
210016b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
210116b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
210216b8cff5SYuri Pankov else if (test & TEST_IGNORE_ERROR)
210316b8cff5SYuri Pankov state.ignored++;
210416b8cff5SYuri Pankov else
210516b8cff5SYuri Pankov {
210616b8cff5SYuri Pankov report("should fail and did", fun, re, NiL, -1, msg, flags, test);
210716b8cff5SYuri Pankov printf("%s expected, %s returned: ", ans, codes[got].name);
210816b8cff5SYuri Pankov state.errors--;
210916b8cff5SYuri Pankov state.warnings++;
211016b8cff5SYuri Pankov error(&preg, cret);
211116b8cff5SYuri Pankov }
211216b8cff5SYuri Pankov }
211316b8cff5SYuri Pankov }
211416b8cff5SYuri Pankov goto compile;
211516b8cff5SYuri Pankov }
211616b8cff5SYuri Pankov
211716b8cff5SYuri Pankov #if _REG_nexec
211816b8cff5SYuri Pankov execute:
211916b8cff5SYuri Pankov if (nexec >= 0)
212016b8cff5SYuri Pankov fun = "regnexec";
212116b8cff5SYuri Pankov else
212216b8cff5SYuri Pankov #endif
212316b8cff5SYuri Pankov fun = "regexec";
212416b8cff5SYuri Pankov
212516b8cff5SYuri Pankov for (i = 0; i < elementsof(match); i++)
212616b8cff5SYuri Pankov match[i] = state.NOMATCH;
212716b8cff5SYuri Pankov
212816b8cff5SYuri Pankov #if _REG_nexec
212916b8cff5SYuri Pankov if (nexec >= 0)
213016b8cff5SYuri Pankov {
213116b8cff5SYuri Pankov eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
213216b8cff5SYuri Pankov s[nexec] = 0;
213316b8cff5SYuri Pankov }
213416b8cff5SYuri Pankov else
213516b8cff5SYuri Pankov #endif
213616b8cff5SYuri Pankov {
213716b8cff5SYuri Pankov if (!(test & TEST_CATCH))
213816b8cff5SYuri Pankov eret = regexec(&preg, s, nmatch, match, eflags);
213916b8cff5SYuri Pankov else if (!(eret = setjmp(state.gotcha)))
214016b8cff5SYuri Pankov {
214116b8cff5SYuri Pankov alarm(HUNG);
214216b8cff5SYuri Pankov eret = regexec(&preg, s, nmatch, match, eflags);
214316b8cff5SYuri Pankov alarm(0);
214416b8cff5SYuri Pankov }
214516b8cff5SYuri Pankov }
214616b8cff5SYuri Pankov #if _REG_subcomp
214716b8cff5SYuri Pankov if ((test & TEST_SUB) && !eret)
214816b8cff5SYuri Pankov {
214916b8cff5SYuri Pankov fun = "regsubexec";
215016b8cff5SYuri Pankov if (!(test & TEST_CATCH))
215116b8cff5SYuri Pankov eret = regsubexec(&preg, s, nmatch, match);
215216b8cff5SYuri Pankov else if (!(eret = setjmp(state.gotcha)))
215316b8cff5SYuri Pankov {
215416b8cff5SYuri Pankov alarm(HUNG);
215516b8cff5SYuri Pankov eret = regsubexec(&preg, s, nmatch, match);
215616b8cff5SYuri Pankov alarm(0);
215716b8cff5SYuri Pankov }
215816b8cff5SYuri Pankov }
215916b8cff5SYuri Pankov #endif
216016b8cff5SYuri Pankov if (flags & REG_NOSUB)
216116b8cff5SYuri Pankov {
216216b8cff5SYuri Pankov if (eret)
216316b8cff5SYuri Pankov {
216416b8cff5SYuri Pankov if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
216516b8cff5SYuri Pankov {
216616b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
216716b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
216816b8cff5SYuri Pankov else
216916b8cff5SYuri Pankov {
217016b8cff5SYuri Pankov report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
217116b8cff5SYuri Pankov error(&preg, eret);
217216b8cff5SYuri Pankov }
217316b8cff5SYuri Pankov }
217416b8cff5SYuri Pankov }
217516b8cff5SYuri Pankov else if (streq(ans, "NOMATCH"))
217616b8cff5SYuri Pankov {
217716b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
217816b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
217916b8cff5SYuri Pankov else
218016b8cff5SYuri Pankov {
218116b8cff5SYuri Pankov report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
218216b8cff5SYuri Pankov error(&preg, eret);
218316b8cff5SYuri Pankov }
218416b8cff5SYuri Pankov }
218516b8cff5SYuri Pankov }
218616b8cff5SYuri Pankov else if (eret)
218716b8cff5SYuri Pankov {
218816b8cff5SYuri Pankov if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
218916b8cff5SYuri Pankov {
219016b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
219116b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
219216b8cff5SYuri Pankov else
219316b8cff5SYuri Pankov {
219416b8cff5SYuri Pankov report("failed", fun, re, s, nstr, msg, flags, test);
219516b8cff5SYuri Pankov if (eret != REG_NOMATCH)
219616b8cff5SYuri Pankov error(&preg, eret);
219716b8cff5SYuri Pankov else if (*ans)
219816b8cff5SYuri Pankov printf("expected: %s\n", ans);
219916b8cff5SYuri Pankov else
220016b8cff5SYuri Pankov printf("\n");
220116b8cff5SYuri Pankov }
220216b8cff5SYuri Pankov }
220316b8cff5SYuri Pankov }
220416b8cff5SYuri Pankov else if (streq(ans, "NOMATCH"))
220516b8cff5SYuri Pankov {
220616b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
220716b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
220816b8cff5SYuri Pankov else
220916b8cff5SYuri Pankov {
221016b8cff5SYuri Pankov report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
221116b8cff5SYuri Pankov matchprint(match, nmatch, nsub, NiL, test);
221216b8cff5SYuri Pankov }
221316b8cff5SYuri Pankov }
221416b8cff5SYuri Pankov #if _REG_subcomp
221516b8cff5SYuri Pankov else if (test & TEST_SUB)
221616b8cff5SYuri Pankov {
221716b8cff5SYuri Pankov p = preg.re_sub->re_buf;
221816b8cff5SYuri Pankov if (strcmp(p, ans))
221916b8cff5SYuri Pankov {
222016b8cff5SYuri Pankov report("failed", fun, re, s, nstr, msg, flags, test);
222116b8cff5SYuri Pankov quote(ans, -1, test|TEST_DELIMIT);
222216b8cff5SYuri Pankov printf(" expected, ");
222316b8cff5SYuri Pankov quote(p, -1, test|TEST_DELIMIT);
222416b8cff5SYuri Pankov printf(" returned\n");
222516b8cff5SYuri Pankov }
222616b8cff5SYuri Pankov }
222716b8cff5SYuri Pankov #endif
222816b8cff5SYuri Pankov else if (!*ans)
222916b8cff5SYuri Pankov {
223016b8cff5SYuri Pankov if (match[0].rm_so != state.NOMATCH.rm_so)
223116b8cff5SYuri Pankov {
223216b8cff5SYuri Pankov if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
223316b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
223416b8cff5SYuri Pankov else
223516b8cff5SYuri Pankov {
223616b8cff5SYuri Pankov report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
223716b8cff5SYuri Pankov matchprint(match, nmatch, nsub, NiL, test);
223816b8cff5SYuri Pankov }
223916b8cff5SYuri Pankov }
224016b8cff5SYuri Pankov }
224116b8cff5SYuri Pankov else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
224216b8cff5SYuri Pankov {
224316b8cff5SYuri Pankov #if _REG_nexec
224416b8cff5SYuri Pankov if (nexec < 0 && !nonexec)
224516b8cff5SYuri Pankov {
224616b8cff5SYuri Pankov nexec = nstr >= 0 ? nstr : strlen(s);
224716b8cff5SYuri Pankov s[nexec] = '\n';
224816b8cff5SYuri Pankov testno++;
224916b8cff5SYuri Pankov goto execute;
225016b8cff5SYuri Pankov }
225116b8cff5SYuri Pankov #endif
225216b8cff5SYuri Pankov if (!(test & (TEST_DECOMP|TEST_SUB|TEST_VERIFY)) && !nonosub)
225316b8cff5SYuri Pankov {
225416b8cff5SYuri Pankov if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
225516b8cff5SYuri Pankov continue;
225616b8cff5SYuri Pankov flags |= REG_NOSUB;
225716b8cff5SYuri Pankov goto nosub;
225816b8cff5SYuri Pankov }
225916b8cff5SYuri Pankov if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
226016b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
226116b8cff5SYuri Pankov }
226216b8cff5SYuri Pankov else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
226316b8cff5SYuri Pankov skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
226416b8cff5SYuri Pankov if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
226516b8cff5SYuri Pankov continue;
226616b8cff5SYuri Pankov goto compile;
226716b8cff5SYuri Pankov }
226816b8cff5SYuri Pankov if (test & TEST_SUMMARY)
226916b8cff5SYuri Pankov printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
227016b8cff5SYuri Pankov else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
227116b8cff5SYuri Pankov {
227216b8cff5SYuri Pankov printf("TEST\t%s", unit);
227316b8cff5SYuri Pankov if (subunit)
227416b8cff5SYuri Pankov printf(" %-.*s", subunitlen, subunit);
227516b8cff5SYuri Pankov printf(", %d test%s", testno, testno == 1 ? "" : "s");
227616b8cff5SYuri Pankov if (state.ignored)
227716b8cff5SYuri Pankov printf(", %d ignored mismatche%s", state.ignored, state.ignored == 1 ? "" : "s");
227816b8cff5SYuri Pankov if (state.warnings)
227916b8cff5SYuri Pankov printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
228016b8cff5SYuri Pankov if (state.unspecified)
228116b8cff5SYuri Pankov printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
228216b8cff5SYuri Pankov if (state.signals)
228316b8cff5SYuri Pankov printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
228416b8cff5SYuri Pankov printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
228516b8cff5SYuri Pankov }
228616b8cff5SYuri Pankov if (fp != stdin)
228716b8cff5SYuri Pankov fclose(fp);
228816b8cff5SYuri Pankov }
228916b8cff5SYuri Pankov return 0;
229016b8cff5SYuri Pankov }
2291