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