2 * regex(3) test harness
4 * build: cc -o testregex testregex.c
5 * help: testregex --man
6 * note: REG_* features are detected by #ifdef; if REG_* are enums
7 * then supply #define REG_foo REG_foo for each enum REG_foo
9 * Glenn Fowler <gsf@research.att.com>
12 * PLEASE: publish your tests so everyone can benefit
14 * Permission is hereby granted, free of charge, to any person obtaining a
15 * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
16 * without restriction, including without limitation the rights to use,
17 * copy, modify, merge, publish, distribute, and/or sell copies of the
18 * Software, and to permit persons to whom the Software is furnished to do
19 * so, subject to the following disclaimer:
21 * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
22 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
23 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
24 * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
33 static const char id[] = "\n@(#)$Id: testregex (AT&T Research) 2005-05-20 $\0\n";
38 #include <sys/types.h>
62 #define TEST_ARE 0x00000001
63 #define TEST_BRE 0x00000002
64 #define TEST_ERE 0x00000004
65 #define TEST_KRE 0x00000008
66 #define TEST_LRE 0x00000010
67 #define TEST_SRE 0x00000020
69 #define TEST_EXPAND 0x00000040
70 #define TEST_LENIENT 0x00000080
72 #define TEST_QUERY 0x00000100
73 #define TEST_SUB 0x00000200
74 #define TEST_UNSPECIFIED 0x00000400
75 #define TEST_VERIFY 0x00000800
76 #define TEST_AND 0x00001000
77 #define TEST_OR 0x00002000
79 #define TEST_DELIMIT 0x00010000
80 #define TEST_OK 0x00020000
81 #define TEST_SAME 0x00040000
83 #define TEST_ACTUAL 0x00100000
84 #define TEST_BASELINE 0x00200000
85 #define TEST_FAIL 0x00400000
86 #define TEST_PASS 0x00800000
87 #define TEST_SUMMARY 0x01000000
89 #define TEST_IGNORE_ERROR 0x02000000
90 #define TEST_IGNORE_OVER 0x04000000
91 #define TEST_IGNORE_POSITION 0x08000000
93 #define TEST_CATCH 0x10000000
94 #define TEST_VERBOSE 0x20000000
96 #define TEST_GLOBAL (TEST_ACTUAL|TEST_AND|TEST_BASELINE|TEST_CATCH|TEST_FAIL|TEST_IGNORE_ERROR|TEST_IGNORE_OVER|TEST_IGNORE_POSITION|TEST_OR|TEST_PASS|TEST_SUMMARY|TEST_VERBOSE)
103 typedef struct Disc_s
111 compf(const regex_t* re, const char* xstr, size_t xlen, regdisc_t* disc)
113 Disc_t* dp = (Disc_t*)disc;
115 return (void*)++dp->ordinal;
119 execf(const regex_t* re, void* data, const char* xstr, size_t xlen, const char* sstr, size_t slen, char** snxt, regdisc_t* disc)
121 Disc_t* dp = (Disc_t*)disc;
123 sfprintf(dp->sp, "{%-.*s}(%d:%d)", xlen, xstr, (int)data, slen);
128 resizef(void* handle, void* data, size_t size)
132 return stkalloc((Sfio_t*)handle, size);
145 #define H(x) do{if(html)fprintf(stderr,x);}while(0)
146 #define T(x) fprintf(stderr,x)
151 H("<!DOCTYPE HTML PUBLIC \"-//IETF//DTD HTML//EN\">\n");
154 H("<TITLE>testregex man document</TITLE>\n");
156 H("<BODY bgcolor=white>\n");
159 T(" testregex - regex(3) test harness\n");
162 T(" testregex [ options ]\n");
165 T(" testregex reads regex(3) test specifications, one per line, from the\n");
166 T(" standard input and writes one output line for each failed test. A\n");
167 T(" summary line is written after all tests are done. Each successful\n");
168 T(" test is run again with REG_NOSUB. Unsupported features are noted\n");
169 T(" before the first test, and tests requiring these features are\n");
170 T(" silently ignored.\n");
173 T(" -c catch signals and non-terminating calls\n");
174 T(" -e ignore error return mismatches\n");
175 T(" -h list help on standard error\n");
176 T(" -n do not repeat successful tests with regnexec()\n");
177 T(" -o ignore match[] overrun errors\n");
178 T(" -p ignore negative position mismatches\n");
179 T(" -s use stack instead of malloc\n");
180 T(" -x do not repeat successful tests with REG_NOSUB\n");
181 T(" -v list each test line\n");
182 T(" -A list failed test lines with actual answers\n");
183 T(" -B list all test lines with actual answers\n");
184 T(" -F list failed test lines\n");
185 T(" -P list passed test lines\n");
186 T(" -S output one summary line\n");
189 T(" Input lines may be blank, a comment beginning with #, or a test\n");
190 T(" specification. A specification is five fields separated by one\n");
191 T(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
194 T(" Field 1: the regex(3) flags to apply, one character per REG_feature\n");
195 T(" flag. The test is skipped if REG_feature is not supported by the\n");
196 T(" implementation. If the first character is not [BEASKL] then the\n");
197 T(" specification is a global control line. One or more of [BEASKL] may be\n");
198 T(" specified; the test will be repeated for each mode.\n");
200 T(" B basic BRE (grep, ed, sed)\n");
201 T(" E REG_EXTENDED ERE (egrep)\n");
202 T(" A REG_AUGMENTED ARE (egrep with negation)\n");
203 T(" S REG_SHELL SRE (sh glob)\n");
204 T(" K REG_SHELL|REG_AUGMENTED KRE (ksh glob)\n");
205 T(" L REG_LITERAL LRE (fgrep)\n");
207 T(" a REG_LEFT|REG_RIGHT implicit ^...$\n");
208 T(" b REG_NOTBOL lhs does not match ^\n");
209 T(" c REG_COMMENT ignore space and #...\\n\n");
210 T(" d REG_SHELL_DOT explicit leading . match\n");
211 T(" e REG_NOTEOL rhs does not match $\n");
212 T(" f REG_MULTIPLE multiple \\n separated patterns\n");
213 T(" g FNM_LEADING_DIR testfnmatch only -- match until /\n");
214 T(" h REG_MULTIREF multiple digit backref\n");
215 T(" i REG_ICASE ignore case\n");
216 T(" j REG_SPAN . matches \\n\n");
217 T(" k REG_ESCAPE \\ to ecape [...] delimiter\n");
218 T(" l REG_LEFT implicit ^...\n");
219 T(" m REG_MINIMAL minimal match\n");
220 T(" n REG_NEWLINE explicit \\n match\n");
221 T(" o REG_ENCLOSED (|&) magic inside [@|&](...)\n");
222 T(" p REG_SHELL_PATH explicit / match\n");
223 T(" q REG_DELIMITED delimited pattern\n");
224 T(" r REG_RIGHT implicit ...$\n");
225 T(" s REG_SHELL_ESCAPED \\ not special\n");
226 T(" t REG_MUSTDELIM all delimiters must be specified\n");
227 T(" u standard unspecified behavior -- errors not counted\n");
228 T(" w REG_NOSUB no subexpression match array\n");
229 T(" x REG_LENIENT let some errors slide\n");
230 T(" y REG_LEFT regexec() implicit ^...\n");
231 T(" z REG_NULL NULL subexpressions ok\n");
232 T(" $ expand C \\c escapes in fields 2 and 3\n");
233 T(" / field 2 is a regsubcomp() expression\n");
235 T(" Field 1 control lines:\n");
237 T(" C set LC_COLLATE and LC_CTYPE to locale in field 2\n");
239 T(" ?test ... output field 5 if passed and != EXPECTED, silent otherwise\n");
240 T(" &test ... output field 5 if current and previous passed\n");
241 T(" |test ... output field 5 if current passed and previous failed\n");
242 T(" ; ... output field 2 if previous failed\n");
243 T(" {test ... skip if failed until }\n");
244 T(" } end of skip\n");
246 T(" : comment comment copied as output NOTE\n");
247 T(" :comment:test :comment: ignored\n");
248 T(" N[OTE] comment comment copied as output NOTE\n");
249 T(" T[EST] comment comment\n");
251 T(" number use number for nmatch (20 by default)\n");
253 T(" Field 2: the regular expression pattern; SAME uses the pattern from\n");
254 T(" the previous specification.\n");
256 T(" Field 3: the string to match.\n");
258 T(" Field 4: the test outcome. This is either one of the posix error\n");
259 T(" codes (with REG_ omitted) or the match array, a list of (m,n)\n");
260 T(" entries with m and n being first and last+1 positions in the\n");
261 T(" field 3 string, or NULL if REG_NOSUB is in effect and success\n");
262 T(" is expected. BADPAT is acceptable in place of any regcomp(3)\n");
263 T(" error code. The match[] array is initialized to (-2,-2) before\n");
264 T(" each test. All array elements from 0 to nmatch-1 must be specified\n");
265 T(" in the outcome. Unspecified endpoints (offset -1) are denoted by ?.\n");
266 T(" Unset endpoints (offset -2) are denoted by X. {x}(o:n) denotes a\n");
267 T(" matched (?{...}) expression, where x is the text enclosed by {...},\n");
268 T(" o is the expression ordinal counting from 1, and n is the length of\n");
269 T(" the unmatched portion of the subject string. If x starts with a\n");
270 T(" number then that is the return value of re_execf(), otherwise 0 is\n");
273 T(" Field 5: optional comment appended to the report.\n");
276 T(" If a regex implementation misbehaves with memory then all bets are off.\n");
279 T(" Glenn Fowler gsf@research.att.com (ksh strmatch, regex extensions)\n");
280 T(" David Korn dgk@research.att.com (ksh glob matcher)\n");
281 T(" Doug McIlroy mcilroy@dartmouth.edu (ast regex/testre in C++)\n");
282 T(" Tom Lord lord@regexps.com (rx tests)\n");
283 T(" Henry Spencer henry@zoo.toronto.edu (original public regex)\n");
284 T(" Andrew Hume andrew@research.att.com (gre tests)\n");
285 T(" John Maddock John_Maddock@compuserve.com (regex++ tests)\n");
286 T(" Philip Hazel ph10@cam.ac.uk (pcre tests)\n");
287 T(" Ville Laurikari vl@iki.fi (libtre tests)\n");
294 #define elementsof(x) (sizeof(x)/sizeof(x[0]))
298 #define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
304 #ifndef REG_TEST_DEFAULT
305 #define REG_TEST_DEFAULT 0
308 #ifndef REG_EXEC_DEFAULT
309 #define REG_EXEC_DEFAULT 0
312 static const char* unsupported[] =
318 #ifndef REG_AUGMENTED
328 #ifndef REG_DELIMITED
331 #ifndef REG_DISCIPLINE
358 #ifndef REG_MUSTDELIM
376 #ifndef REG_SHELL_DOT
379 #ifndef REG_SHELL_ESCAPED
382 #ifndef REG_SHELL_GROUP
385 #ifndef REG_SHELL_PATH
391 #if REG_NOSUB & REG_TEST_DEFAULT
404 #define REG_COMMENT NOTEST
406 #ifndef REG_DELIMITED
407 #define REG_DELIMITED NOTEST
410 #define REG_ESCAPE NOTEST
413 #define REG_ICASE NOTEST
416 #define REG_LEFT NOTEST
419 #define REG_LENIENT 0
422 #define REG_MINIMAL NOTEST
425 #define REG_MULTIPLE NOTEST
428 #define REG_MULTIREF NOTEST
430 #ifndef REG_MUSTDELIM
431 #define REG_MUSTDELIM NOTEST
434 #define REG_NEWLINE NOTEST
437 #define REG_NOTBOL NOTEST
440 #define REG_NOTEOL NOTEST
443 #define REG_NULL NOTEST
446 #define REG_RIGHT NOTEST
448 #ifndef REG_SHELL_DOT
449 #define REG_SHELL_DOT NOTEST
451 #ifndef REG_SHELL_ESCAPED
452 #define REG_SHELL_ESCAPED NOTEST
454 #ifndef REG_SHELL_GROUP
455 #define REG_SHELL_GROUP NOTEST
457 #ifndef REG_SHELL_PATH
458 #define REG_SHELL_PATH NOTEST
461 #define REG_SPAN NOTEST
464 #define REG_UNKNOWN (-1)
467 #define REG_ENEWLINE (REG_UNKNOWN-1)
471 #define REG_ENULL (REG_UNKNOWN-2)
473 #define REG_ENULL REG_EMPTY
477 #define REG_ECOUNT (REG_UNKNOWN-3)
480 #define REG_BADESC (REG_UNKNOWN-4)
483 #define REG_EMEM (REG_UNKNOWN-5)
486 #define REG_EHUNG (REG_UNKNOWN-6)
489 #define REG_EBUS (REG_UNKNOWN-7)
492 #define REG_EFAULT (REG_UNKNOWN-8)
495 #define REG_EFLAGS (REG_UNKNOWN-9)
498 #define REG_EDELIM (REG_UNKNOWN-9)
501 static const struct { int code; char* name; } codes[] =
503 {REG_UNKNOWN, "UNKNOWN"},
504 {REG_NOMATCH, "NOMATCH"},
505 {REG_BADPAT, "BADPAT"},
506 {REG_ECOLLATE, "ECOLLATE"},
507 {REG_ECTYPE, "ECTYPE"},
508 {REG_EESCAPE, "EESCAPE"},
509 {REG_ESUBREG, "ESUBREG"},
510 {REG_EBRACK, "EBRACK"},
511 {REG_EPAREN, "EPAREN"},
512 {REG_EBRACE, "EBRACE"},
513 {REG_BADBR, "BADBR"},
514 {REG_ERANGE, "ERANGE"},
515 {REG_ESPACE, "ESPACE"},
516 {REG_BADRPT, "BADRPT"},
517 {REG_ENEWLINE, "ENEWLINE"},
518 {REG_ENULL, "ENULL"},
519 {REG_ECOUNT, "ECOUNT"},
520 {REG_BADESC, "BADESC"},
522 {REG_EHUNG, "EHUNG"},
524 {REG_EFAULT, "EFAULT"},
525 {REG_EFLAGS, "EFLAGS"},
526 {REG_EDELIM, "EDELIM"},
545 #ifdef REG_DISCIPLINE
551 quote(char* s, int len, unsigned long test)
553 unsigned char* u = (unsigned char*)s;
559 else if (!*u && len <= 1)
561 else if (test & TEST_EXPAND)
564 len = strlen((char*)u);
566 if (test & TEST_DELIMIT)
575 if (test & TEST_DELIMIT)
605 if (!iscntrl(c) && isprint(c))
608 printf("\\x%02x", c);
611 if (test & TEST_DELIMIT)
619 report(char* comment, char* fun, char* re, char* s, int len, char* msg, int flags, unsigned long test)
622 printf("%s:", state.file);
623 printf("%d:", state.lineno);
627 quote(re, -1, test|TEST_DELIMIT);
631 quote(s, len, test|TEST_DELIMIT);
634 if (test & TEST_UNSPECIFIED)
637 printf(" unspecified behavior");
642 printf(" %s", state.which);
643 if (flags & REG_NOSUB)
647 if (comment[strlen(comment)-1] == '\n')
648 printf(" %s", comment);
651 printf(" %s: ", comment);
658 error(regex_t* preg, int code)
669 msg = "memory fault";
672 msg = "did not terminate";
675 regerror(code, preg, msg = buf, sizeof buf);
682 bad(char* comment, char* re, char* s, int len, unsigned long test)
684 printf("bad test case ");
685 report(comment, NiL, re, s, len, NiL, 0, test);
698 for (b = t = s; (*t = *s); s++, t++)
741 q = c == 'u' ? (s + 5) : (char*)0;
743 while (!e || !q || s < q)
747 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
748 c = (c << 4) + *s - 'a' + 10;
750 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
751 c = (c << 4) + *s - 'A' + 10;
753 case '0': case '1': case '2': case '3': case '4':
754 case '5': case '6': case '7': case '8': case '9':
755 c = (c << 4) + *s - '0';
779 case '0': case '1': case '2': case '3':
780 case '4': case '5': case '6': case '7':
787 case '0': case '1': case '2': case '3':
788 case '4': case '5': case '6': case '7':
789 c = (c << 3) + *s - '0';
800 bad("invalid C \\ escape\n", s - 1, NiL, 0, 0);
806 matchoffprint(int off)
823 matchprint(regmatch_t* match, int nmatch, int nsub, char* ans, unsigned long test)
827 for (; nmatch > nsub + 1; nmatch--)
828 if ((match[nmatch-1].rm_so != -1 || match[nmatch-1].rm_eo != -1) && (!(test & TEST_IGNORE_POSITION) || (match[nmatch-1].rm_so >= 0 && match[nmatch-1].rm_eo >= 0)))
830 for (i = 0; i < nmatch; i++)
833 matchoffprint(match[i].rm_so);
835 matchoffprint(match[i].rm_eo);
838 if (!(test & (TEST_ACTUAL|TEST_BASELINE)))
841 printf(" expected: %s", ans);
847 matchcheck(regmatch_t* match, int nmatch, int nsub, char* ans, char* re, char* s, int len, int flags, unsigned long test)
854 if (streq(ans, "OK"))
855 return test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY);
856 for (i = 0, p = ans; i < nmatch && *p; i++)
860 #ifdef REG_DISCIPLINE
863 x = sfstruse(state.disc.sp);
866 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
868 report("callout failed", NiL, re, s, len, NiL, flags, test);
870 printf(" expected, ");
872 printf(" returned\n");
878 bad("improper answer\n", re, s, -1, test);
885 m = strtol(p, &p, 10);
887 bad("improper answer\n", re, s, -1, test);
894 n = strtol(p, &p, 10);
896 bad("improper answer\n", re, s, -1, test);
897 if (m!=match[i].rm_so || n!=match[i].rm_eo)
899 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
901 report("failed: match was", NiL, re, s, len, NiL, flags, test);
902 matchprint(match, nmatch, nsub, ans, test);
907 for (; i < nmatch; i++)
909 if (match[i].rm_so!=-1 || match[i].rm_eo!=-1)
911 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_VERIFY)))
913 if ((test & TEST_IGNORE_POSITION) && (match[i].rm_so<0 || match[i].rm_eo<0))
918 if (!(test & TEST_SUMMARY))
920 report("failed: match was", NiL, re, s, len, NiL, flags, test);
921 matchprint(match, nmatch, nsub, ans, test);
927 if (!(test & TEST_IGNORE_OVER) && match[nmatch].rm_so != state.NOMATCH.rm_so)
929 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY)))
931 report("failed: overran match array", NiL, re, s, len, NiL, flags, test);
932 matchprint(match, nmatch + 1, nsub, NiL, test);
952 else op = SIG_SETMASK;
953 sigprocmask(op, &mask, NiL);
956 sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
982 longjmp(state.gotcha, ret);
988 static char buf[32 * 1024];
990 register char* s = buf;
991 register char* e = &buf[sizeof(buf)];
996 if (!(b = fgets(s, e - s, fp)))
1000 if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
1010 static unsigned long
1011 note(unsigned long level, char* msg, unsigned long skip, unsigned long test)
1013 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)) && !skip)
1017 printf("%s: ", msg);
1018 printf("skipping lines %d", state.lineno);
1020 return skip | level;
1023 #define TABS(n) &ts[7-((n)&7)]
1025 static char ts[] = "\t\t\t\t\t\t\t";
1027 static unsigned long
1028 extract(int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
1030 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_OK|TEST_PASS|TEST_SUMMARY))
1032 state.extracted = 1;
1036 if ((test & TEST_VERIFY) && !(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1038 if (msg && strcmp(msg, "EXPECTED"))
1039 printf("NOTE\t%s\n", msg);
1042 test &= ~(TEST_PASS|TEST_QUERY);
1044 if (test & (TEST_QUERY|TEST_VERIFY))
1046 if (test & TEST_BASELINE)
1047 test &= ~(TEST_BASELINE|TEST_PASS);
1052 if (!(test & TEST_OK))
1054 if (test & TEST_UNSPECIFIED)
1055 state.unspecified++;
1059 if (test & (TEST_PASS|TEST_SUMMARY))
1061 test &= ~TEST_DELIMIT;
1062 printf("%s%s", spec, TABS(*tabs++));
1063 if ((test & (TEST_BASELINE|TEST_SAME)) == (TEST_BASELINE|TEST_SAME))
1066 quote(re, -1, test);
1067 printf("%s", TABS(*tabs++));
1069 printf("%s", TABS(*tabs++));
1070 if (!(test & (TEST_ACTUAL|TEST_BASELINE)) || (!accept && !match))
1073 printf("%s", accept);
1075 matchprint(match, nmatch, nsub, NiL, test);
1077 printf("%s%s", TABS(*tabs++), msg);
1080 else if (test & TEST_QUERY)
1081 skip = note(level, msg, skip, test);
1082 else if (test & TEST_VERIFY)
1083 state.extracted = 1;
1088 catchfree(regex_t* preg, int flags, int* tabs, char* spec, char* re, char* s, char* ans, char* msg, char* accept, regmatch_t* match, int nmatch, int nsub, unsigned long skip, unsigned long level, unsigned long test)
1092 if (!(test & TEST_CATCH))
1097 else if (!(eret = setjmp(state.gotcha)))
1103 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1104 extract(tabs, spec, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
1107 report("failed", "regfree", re, NiL, -1, msg, flags, test);
1114 old_main(int unused_param_argc, char** argv)
1132 unsigned long level;
1143 char* subunit = NULL;
1150 regmatch_t match[100];
1153 static char pat[32 * 1024];
1155 int nonosub = REG_NOSUB == 0;
1158 unsigned long test = 0;
1160 static char* filter[] = { "-", 0 };
1162 state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
1164 version = (char*)id + 10;
1165 while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
1168 while ((p = *++argv) && *p == '-')
1179 test |= TEST_IGNORE_ERROR;
1192 test |= TEST_IGNORE_OVER;
1195 test |= TEST_IGNORE_POSITION;
1198 #ifdef REG_DISCIPLINE
1199 if (!(state.stack = stkalloc(stkstd, 0)))
1200 fprintf(stderr, "%s: out of space [stack]", unit);
1201 state.disc.disc.re_resizef = resizef;
1202 state.disc.disc.re_resizehandle = (void*)stkstd;
1209 test |= TEST_VERBOSE;
1212 test |= TEST_ACTUAL;
1215 test |= TEST_BASELINE;
1224 test |= TEST_SUMMARY;
1227 fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
1235 while ((state.file = *argv++))
1237 if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
1242 else if (!(fp = fopen(state.file, "r")))
1244 fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
1247 testno = state.errors = state.ignored = state.lineno = state.passed =
1248 state.signals = state.unspecified = state.warnings = 0;
1251 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1253 printf("TEST\t%s ", unit);
1254 if ((s = state.file))
1275 subunit = state.file;
1278 subunitlen = p - subunit;
1279 printf("%-.*s ", subunitlen, subunit);
1283 for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
1285 if (test & TEST_CATCH)
1287 if (test & TEST_IGNORE_ERROR)
1288 printf(", ignore error code mismatches");
1289 if (test & TEST_IGNORE_POSITION)
1290 printf(", ignore negative position mismatches");
1291 #ifdef REG_DISCIPLINE
1295 if (test & TEST_VERBOSE)
1296 printf(", verbose");
1298 #ifdef REG_VERSIONID
1299 if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
1303 #ifdef REG_TEST_VERSION
1304 s = REG_TEST_VERSION;
1308 printf("NOTE\t%s\n", s);
1309 if (elementsof(unsupported) > 1)
1311 #if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
1314 i = REG_EXTENDED != 0;
1316 for (got = 0; i < elementsof(unsupported) - 1; i++)
1321 printf("NOTE\tunsupported: %s", unsupported[i]);
1324 printf(",%s", unsupported[i]);
1330 #ifdef REG_DISCIPLINE
1331 state.disc.disc.re_version = REG_VERSION;
1332 state.disc.disc.re_compf = compf;
1333 state.disc.disc.re_execf = execf;
1334 if (!(state.disc.sp = sfstropen()))
1335 bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
1336 preg.re_disc = &state.disc.disc;
1338 if (test & TEST_CATCH)
1340 signal(SIGALRM, gotcha);
1341 signal(SIGBUS, gotcha);
1342 signal(SIGSEGV, gotcha);
1344 while ((p = my_getline(fp)))
1350 if (*p == ':' && !isspace(*(p + 1)))
1352 while (*++p && *p != ':');
1355 if (test & TEST_BASELINE)
1356 printf("%s\n", line);
1362 if (*p == 0 || *p == '#' || *p == 'T')
1364 if (test & TEST_BASELINE)
1365 printf("%s\n", line);
1368 if (*p == ':' || *p == 'N')
1370 if (test & TEST_BASELINE)
1371 printf("%s\n", line);
1372 else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1374 while (*++p && !isspace(*p));
1377 printf("NOTE %s\n", p);
1393 *(delim[i] = p - 1) = 0;
1397 if (streq(s, "NIL"))
1399 else if (streq(s, "NULL"))
1409 if (i >= elementsof(field))
1410 bad("too many fields\n", NiL, NiL, 0, 0);
1418 if (!(spec = field[0]))
1419 bad("NIL spec\n", NiL, NiL, 0, 0);
1423 cflags = REG_TEST_DEFAULT;
1424 eflags = REG_EXEC_DEFAULT;
1425 test &= TEST_GLOBAL;
1426 state.extracted = 0;
1429 for (p = spec; *p; p++)
1433 nmatch = strtol(p, &p, 10);
1434 if (nmatch >= elementsof(match))
1435 bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
1448 if (!(test & TEST_QUERY) && !(skip & level))
1449 bad("locale must be nested\n", NiL, NiL, 0, 0);
1450 test &= ~TEST_QUERY;
1452 bad("locale nesting not supported\n", NiL, NiL, 0, 0);
1454 bad("locale field expected\n", NiL, NiL, 0, 0);
1455 if (!(skip & level))
1457 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1459 if (!s || streq(s, "POSIX"))
1461 if (!(ans = setlocale(LC_COLLATE, s)) || streq(ans, "C") || streq(ans, "POSIX") || !(ans = setlocale(LC_CTYPE, s)) || streq(ans, "C") || streq(ans, "POSIX"))
1462 skip = note(level, s, skip, test);
1465 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1466 printf("NOTE \"%s\" locale\n", s);
1470 skip = note(level, skip, test, "locales not supported");
1489 cflags |= REG_LEFT|REG_RIGHT;
1492 eflags |= REG_NOTBOL;
1495 cflags |= REG_COMMENT;
1498 cflags |= REG_SHELL_DOT;
1501 eflags |= REG_NOTEOL;
1504 cflags |= REG_MULTIPLE;
1510 cflags |= REG_MULTIREF;
1513 cflags |= REG_ICASE;
1519 cflags |= REG_ESCAPE;
1525 cflags |= REG_MINIMAL;
1528 cflags |= REG_NEWLINE;
1531 cflags |= REG_SHELL_GROUP;
1534 cflags |= REG_SHELL_PATH;
1537 cflags |= REG_DELIMITED;
1540 cflags |= REG_RIGHT;
1543 cflags |= REG_SHELL_ESCAPED;
1546 cflags |= REG_MUSTDELIM;
1549 test |= TEST_UNSPECIFIED;
1552 cflags |= REG_NOSUB;
1556 cflags |= REG_LENIENT;
1558 test |= TEST_LENIENT;
1568 test |= TEST_EXPAND;
1576 test |= TEST_VERIFY;
1577 test &= ~(TEST_AND|TEST_OR);
1578 state.verify = state.passed;
1581 test |= TEST_VERIFY|TEST_AND;
1585 test |= TEST_VERIFY|TEST_OR;
1595 if (skip & (level >> 1))
1608 bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
1609 if ((skip & level) && !(skip & (level>>1)))
1611 if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
1613 if (test & (TEST_ACTUAL|TEST_FAIL))
1615 else if (!(test & TEST_PASS))
1616 printf("-%d\n", state.lineno);
1619 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1620 else if (locale & level)
1623 if (!(skip & level))
1626 setlocale(LC_COLLATE, s);
1627 setlocale(LC_CTYPE, s);
1628 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1629 printf("NOTE \"%s\" locale\n", s);
1630 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
1633 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
1642 bad("bad spec\n", spec, NiL, 0, test);
1648 if ((cflags|eflags) == NOTEST || ((skip & level) && (test & TEST_BASELINE)))
1650 if (test & TEST_BASELINE)
1654 printf("%s\n", line);
1660 if (!(test & TEST_VERIFY))
1663 if (state.passed == state.verify && i > 1)
1664 printf("NOTE\t%s\n", field[1]);
1667 else if (state.passed > state.verify)
1670 else if (test & TEST_AND)
1672 if (state.passed == state.verify)
1674 state.passed = state.verify;
1677 bad("too few fields\n", NiL, NiL, 0, test);
1678 while (i < elementsof(field))
1680 if ((re = field[1]))
1682 if (streq(re, "SAME"))
1689 if (test & TEST_EXPAND)
1691 strcpy(ppat = pat, re);
1697 if ((s = field[2]) && (test & TEST_EXPAND))
1701 if (nstr != strlen(s))
1705 if (!(ans = field[3]))
1706 bad("NIL answer\n", NiL, NiL, 0, test);
1709 if (test & TEST_SUB)
1711 cflags |= REG_DELIMITED;
1718 if (state.extracted || (skip & level))
1720 #if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
1722 if (REG_EXTENDED != 0 && (test & TEST_BRE))
1724 if (test & TEST_BRE)
1729 state.which = "BRE";
1734 if (test & TEST_ERE)
1737 flags = cflags | REG_EXTENDED;
1738 state.which = "ERE";
1742 #ifdef REG_AUGMENTED
1743 if (test & TEST_ARE)
1746 flags = cflags | REG_AUGMENTED;
1747 state.which = "ARE";
1752 if (test & TEST_LRE)
1755 flags = cflags | REG_LITERAL;
1756 state.which = "LRE";
1761 if (test & TEST_SRE)
1764 flags = cflags | REG_SHELL;
1765 state.which = "SRE";
1768 #ifdef REG_AUGMENTED
1769 if (test & TEST_KRE)
1772 flags = cflags | REG_SHELL | REG_AUGMENTED;
1773 state.which = "KRE";
1779 if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
1780 extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
1783 if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
1785 printf("test %-3d %s ", state.lineno, state.which);
1786 quote(re, -1, test|TEST_DELIMIT);
1788 quote(s, nstr, test|TEST_DELIMIT);
1795 if (nstr >= 0 && nstr != strlen(s))
1801 if (state.extracted || (skip & level))
1803 if (!(test & TEST_QUERY))
1805 #ifdef REG_DISCIPLINE
1807 stkset(stkstd, state.stack, 0);
1808 flags |= REG_DISCIPLINE;
1809 state.disc.ordinal = 0;
1810 sfstrseek(state.disc.sp, 0, SEEK_SET);
1812 if (!(test & TEST_CATCH))
1813 cret = regcomp(&preg, re, flags);
1814 else if (!(cret = setjmp(state.gotcha)))
1817 cret = regcomp(&preg, re, flags);
1821 if (!cret && (test & TEST_SUB))
1824 p = re + preg.re_npat;
1825 if (!(test & TEST_CATCH))
1826 cret = regsubcomp(&preg, p, NiL, 0, 0);
1827 else if (!(cret = setjmp(state.gotcha)))
1830 cret = regsubcomp(&preg, p, NiL, 0, 0);
1833 if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
1835 if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
1843 if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
1845 for (p = ans; *p; p++)
1852 if (test & TEST_IGNORE_OVER)
1857 else if (nsub != preg.re_nsub)
1859 if (nsub > preg.re_nsub)
1861 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1862 skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1865 report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
1866 printf("at least %d expected, %zd returned\n", nsub, preg.re_nsub);
1871 nsub = preg.re_nsub;
1875 if (!(test & TEST_SUB) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
1877 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1878 skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1879 else if (!(test & TEST_LENIENT))
1881 report("failed", fun, re, NiL, -1, msg, flags, test);
1882 printf("%s expected, OK returned\n", ans);
1884 catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
1890 if (test & TEST_LENIENT)
1891 /* we'll let it go this time */;
1892 else if (!*ans || ans[0]=='(' || (cret == REG_BADPAT && streq(ans, "NOMATCH")))
1895 for (i = 1; i < elementsof(codes); i++)
1896 if (cret==codes[i].code)
1898 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1899 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1902 report("failed", fun, re, NiL, -1, msg, flags, test);
1903 printf("%s returned: ", codes[got].name);
1910 for (i = 1; i < elementsof(codes); i++)
1912 if (streq(ans, codes[i].name))
1914 if (cret==codes[i].code)
1919 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1920 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1923 report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
1924 printf("%s expected, %s returned\n", ans, codes[got].name);
1927 else if (cret != codes[expected].code && cret != REG_BADPAT)
1929 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1930 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1931 else if (test & TEST_IGNORE_ERROR)
1935 report("should fail and did", fun, re, NiL, -1, msg, flags, test);
1936 printf("%s expected, %s returned: ", ans, codes[got].name);
1954 for (i = 0; i < elementsof(match); i++)
1955 match[i] = state.NOMATCH;
1960 eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
1966 if (!(test & TEST_CATCH))
1967 eret = regexec(&preg, s, nmatch, match, eflags);
1968 else if (!(eret = setjmp(state.gotcha)))
1971 eret = regexec(&preg, s, nmatch, match, eflags);
1976 if ((test & TEST_SUB) && !eret)
1979 if (!(test & TEST_CATCH))
1980 eret = regsubexec(&preg, s, nmatch, match);
1981 else if (!(eret = setjmp(state.gotcha)))
1984 eret = regsubexec(&preg, s, nmatch, match);
1989 if (flags & REG_NOSUB)
1993 if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
1995 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
1996 skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
1999 report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
2004 else if (streq(ans, "NOMATCH"))
2006 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2007 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2010 report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2017 if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
2019 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2020 skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
2023 report("failed", fun, re, s, nstr, msg, flags, test);
2024 if (eret != REG_NOMATCH)
2027 printf("expected: %s\n", ans);
2033 else if (streq(ans, "NOMATCH"))
2035 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2036 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2039 report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2040 matchprint(match, nmatch, nsub, NiL, test);
2044 else if (test & TEST_SUB)
2046 p = preg.re_sub->re_buf;
2049 report("failed", fun, re, s, nstr, msg, flags, test);
2050 quote(ans, -1, test|TEST_DELIMIT);
2051 printf(" expected, ");
2052 quote(p, -1, test|TEST_DELIMIT);
2053 printf(" returned\n");
2059 if (match[0].rm_so != state.NOMATCH.rm_so)
2061 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2062 skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
2065 report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
2066 matchprint(match, nmatch, nsub, NiL, test);
2070 else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
2073 if (nexec < 0 && !nonexec)
2075 nexec = nstr >= 0 ? nstr : strlen(s);
2081 if (!(test & (TEST_SUB|TEST_VERIFY)) && !nonosub)
2083 if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2088 if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
2089 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
2091 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2092 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2093 if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2097 if (test & TEST_SUMMARY)
2098 printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
2099 else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
2101 printf("TEST\t%s", unit);
2103 printf(" %-.*s", subunitlen, subunit);
2104 printf(", %d test%s", testno, testno == 1 ? "" : "s");
2106 printf(", %d ignored mismatch%s", state.ignored, state.ignored == 1 ? "" : "es");
2108 printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
2109 if (state.unspecified)
2110 printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
2112 printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
2113 printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
2121 int main(int argc, char **argv)
2123 static char *param[][4] = {
2124 { NULL, "basic.dat" , NULL },
2125 { NULL, "categorize.dat" , NULL },
2126 { NULL, "forcedassoc.dat" , NULL },
2127 { NULL, "-c", "interpretation.dat", NULL },
2128 { NULL, "leftassoc.dat" , NULL },
2129 { NULL, "-c", "nullsubexpr.dat" , NULL },
2130 { NULL, "repetition.dat" , NULL },
2131 { NULL, "rightassoc.dat" , NULL },
2136 return old_main(argc, argv);
2139 for (i = 0; i < sizeof(param) / sizeof(param[0]); i++) {
2140 param[i][0] = argv[0];
2141 printf("Testing %s\n", param[i][1][0] != '-' ? param[i][1] : param[i][2]);
2142 r |= old_main(3 /* not used */, param[i]);