1 #pragma prototyped noticed
2
3 /*
4 * regex(3) test harness
5 *
6 * build: cc -o testregex testregex.c
7 * help: testregex --man
8 * note: REG_* features are detected by #ifdef; if REG_* are enums
9 * then supply #define REG_foo REG_foo for each enum REG_foo
10 *
11 * Glenn Fowler <glenn.s.fowler@gmail.com>
12 * AT&T Research
13 *
14 * PLEASE: publish your tests so everyone can benefit
15 *
16 * The following license covers testregex.c and all associated test data.
17 *
18 * Permission is hereby granted, free of charge, to any person obtaining a
19 * copy of THIS SOFTWARE FILE (the "Software"), to deal in the Software
20 * without restriction, including without limitation the rights to use,
21 * copy, modify, merge, publish, distribute, and/or sell copies of the
22 * Software, and to permit persons to whom the Software is furnished to do
23 * so, subject to the following disclaimer:
24 *
25 * THIS SOFTWARE IS PROVIDED BY AT&T ``AS IS'' AND ANY EXPRESS OR IMPLIED
26 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
27 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 * IN NO EVENT SHALL AT&T BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 */
36
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*
compf(const regex_t * re,const char * xstr,size_t xlen,regdisc_t * disc)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
execf(const regex_t * re,void * data,const char * xstr,size_t xlen,const char * sstr,size_t slen,char ** snxt,regdisc_t * disc)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*
resizef(void * handle,void * data,size_t size)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
help(int html)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 glenn.s.fowler@gmail.com (ksh strmatch, regex extensions)\n");
294 T(" David Korn dgkorn@gmail.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
quote(char * s,int len,unsigned long test)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
report(char * comment,char * fun,char * re,char * s,int len,char * msg,int flags,unsigned long test)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
error(regex_t * preg,int code)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
bad(char * comment,char * re,char * s,int len,unsigned long test)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
escape(char * s)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
matchoffprint(int off)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
matchprint(regmatch_t * match,int nmatch,int nsub,char * ans,unsigned long test)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
matchcheck(regmatch_t * match,int nmatch,int nsub,char * ans,char * re,char * s,int len,int flags,unsigned long test)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
sigunblock(int s)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
gotcha(int sig)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*
get_line(FILE * fp)1036 get_line(FILE* fp)
1037 {
1038 static char buf[32 * 1024];
1039
1040 register char* s = buf;
1041 register char* e = &buf[sizeof(buf)];
1042 register char* b;
1043
1044 for (;;)
1045 {
1046 if (!(b = fgets(s, e - s, fp)))
1047 return 0;
1048 state.lineno++;
1049 s += strlen(s);
1050 if (s == b || *--s != '\n' || s == b || *(s - 1) != '\\')
1051 {
1052 *s = 0;
1053 break;
1054 }
1055 s--;
1056 }
1057 return buf;
1058 }
1059
1060 static unsigned long
note(unsigned long level,char * msg,unsigned long skip,unsigned long test)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
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)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
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)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*
expand(char * os,char * ot)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
main(int argc,char ** argv)1217 main(int argc, char** argv)
1218 {
1219 int flags;
1220 int cflags;
1221 int eflags;
1222 int nmatch;
1223 #if _REG_nexec
1224 int nexec;
1225 #endif
1226 int nstr;
1227 int cret;
1228 int eret;
1229 int nsub;
1230 int i;
1231 int j;
1232 int expected;
1233 int got;
1234 int locale;
1235 int subunitlen;
1236 int testno;
1237 unsigned long level;
1238 unsigned long skip;
1239 char* p;
1240 char* line;
1241 char* spec;
1242 char* re;
1243 char* s;
1244 char* ans;
1245 char* msg;
1246 char* fun;
1247 char* ppat;
1248 char* subunit;
1249 char* version;
1250 char* field[6];
1251 char* delim[6];
1252 FILE* fp;
1253 int tabs[6];
1254 char unit[64];
1255 regmatch_t match[100];
1256 regex_t preg;
1257
1258 static char pat[32 * 1024];
1259 static char patbuf[32 * 1024];
1260 static char strbuf[32 * 1024];
1261
1262 int nonosub = REG_NOSUB == 0;
1263 #if _REG_nexec
1264 int nonexec = 0;
1265 #endif
1266
1267 unsigned long test = 0;
1268
1269 static char* filter[] = { "-", 0 };
1270
1271 state.NOMATCH.rm_so = state.NOMATCH.rm_eo = -2;
1272 p = unit;
1273 version = (char*)id + 10;
1274 while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
1275 p++;
1276 *p = 0;
1277 while ((p = *++argv) && *p == '-')
1278 for (;;)
1279 {
1280 switch (*++p)
1281 {
1282 case 0:
1283 break;
1284 case 'c':
1285 test |= TEST_CATCH;
1286 continue;
1287 case 'e':
1288 test |= TEST_IGNORE_ERROR;
1289 continue;
1290 case 'h':
1291 case '?':
1292 help(0);
1293 return 2;
1294 case '-':
1295 help(p[1] == 'h');
1296 return 2;
1297 case 'n':
1298 #if _REG_nexec
1299 nonexec = 1;
1300 #endif
1301 continue;
1302 case 'o':
1303 test |= TEST_IGNORE_OVER;
1304 continue;
1305 case 'p':
1306 test |= TEST_IGNORE_POSITION;
1307 continue;
1308 case 's':
1309 #ifdef REG_DISCIPLINE
1310 if (!(state.stack = stkalloc(stkstd, 0)))
1311 fprintf(stderr, "%s: out of space [stack]", unit);
1312 state.disc.disc.re_resizef = resizef;
1313 state.disc.disc.re_resizehandle = (void*)stkstd;
1314 #endif
1315 continue;
1316 case 'x':
1317 nonosub = 1;
1318 continue;
1319 case 'v':
1320 test |= TEST_VERBOSE;
1321 continue;
1322 case 'A':
1323 test |= TEST_ACTUAL;
1324 continue;
1325 case 'B':
1326 test |= TEST_BASELINE;
1327 continue;
1328 case 'F':
1329 test |= TEST_FAIL;
1330 continue;
1331 case 'P':
1332 test |= TEST_PASS;
1333 continue;
1334 case 'S':
1335 test |= TEST_SUMMARY;
1336 continue;
1337 default:
1338 fprintf(stderr, "%s: %c: invalid option\n", unit, *p);
1339 return 2;
1340 }
1341 break;
1342 }
1343 if (!*argv)
1344 argv = filter;
1345 locale = 0;
1346 while (state.file = *argv++)
1347 {
1348 if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
1349 {
1350 state.file = 0;
1351 fp = stdin;
1352 }
1353 else if (!(fp = fopen(state.file, "r")))
1354 {
1355 fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
1356 return 2;
1357 }
1358 testno = state.errors = state.ignored = state.lineno = state.passed =
1359 state.signals = state.unspecified = state.warnings = 0;
1360 skip = 0;
1361 level = 1;
1362 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1363 {
1364 printf("TEST\t%s ", unit);
1365 if (s = state.file)
1366 {
1367 subunit = p = 0;
1368 for (;;)
1369 {
1370 switch (*s++)
1371 {
1372 case 0:
1373 break;
1374 case '/':
1375 subunit = s;
1376 continue;
1377 case '.':
1378 p = s - 1;
1379 continue;
1380 default:
1381 continue;
1382 }
1383 break;
1384 }
1385 if (!subunit)
1386 subunit = state.file;
1387 if (p < subunit)
1388 p = s - 1;
1389 subunitlen = p - subunit;
1390 printf("%-.*s ", subunitlen, subunit);
1391 }
1392 else
1393 subunit = 0;
1394 for (s = version; *s && (*s != ' ' || *(s + 1) != '$'); s++)
1395 putchar(*s);
1396 if (test & TEST_CATCH)
1397 printf(", catch");
1398 if (test & TEST_IGNORE_ERROR)
1399 printf(", ignore error code mismatches");
1400 if (test & TEST_IGNORE_POSITION)
1401 printf(", ignore negative position mismatches");
1402 #ifdef REG_DISCIPLINE
1403 if (state.stack)
1404 printf(", stack");
1405 #endif
1406 if (test & TEST_VERBOSE)
1407 printf(", verbose");
1408 printf("\n");
1409 #ifdef REG_VERSIONID
1410 if (regerror(REG_VERSIONID, NiL, pat, sizeof(pat)) > 0)
1411 s = pat;
1412 else
1413 #endif
1414 #ifdef REG_TEST_VERSION
1415 s = REG_TEST_VERSION;
1416 #else
1417 s = "regex";
1418 #endif
1419 printf("NOTE\t%s\n", s);
1420 if (elementsof(unsupported) > 1)
1421 {
1422 #if (REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL)) || !defined(REG_EXTENDED)
1423 i = 0;
1424 #else
1425 i = REG_EXTENDED != 0;
1426 #endif
1427 for (got = 0; i < elementsof(unsupported) - 1; i++)
1428 {
1429 if (!got)
1430 {
1431 got = 1;
1432 printf("NOTE\tunsupported: %s", unsupported[i]);
1433 }
1434 else
1435 printf(",%s", unsupported[i]);
1436 }
1437 if (got)
1438 printf("\n");
1439 }
1440 }
1441 #ifdef REG_DISCIPLINE
1442 state.disc.disc.re_version = REG_VERSION;
1443 state.disc.disc.re_compf = compf;
1444 state.disc.disc.re_execf = execf;
1445 if (!(state.disc.sp = sfstropen()))
1446 bad("out of space [discipline string stream]\n", NiL, NiL, 0, 0);
1447 preg.re_disc = &state.disc.disc;
1448 #endif
1449 if (test & TEST_CATCH)
1450 {
1451 signal(SIGALRM, gotcha);
1452 signal(SIGBUS, gotcha);
1453 signal(SIGSEGV, gotcha);
1454 }
1455 while (p = get_line(fp))
1456 {
1457
1458 /* parse: */
1459
1460 line = p;
1461 if (*p == ':' && !isspace(*(p + 1)))
1462 {
1463 while (*++p && *p != ':');
1464 if (!*p++)
1465 {
1466 if (test & TEST_BASELINE)
1467 printf("%s\n", line);
1468 continue;
1469 }
1470 }
1471 while (isspace(*p))
1472 p++;
1473 if (*p == 0 || *p == '#' || *p == 'T')
1474 {
1475 if (test & TEST_BASELINE)
1476 printf("%s\n", line);
1477 continue;
1478 }
1479 if (*p == ':' || *p == 'N')
1480 {
1481 if (test & TEST_BASELINE)
1482 printf("%s\n", line);
1483 else if (!(test & (TEST_ACTUAL|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1484 {
1485 while (*++p && !isspace(*p));
1486 while (isspace(*p))
1487 p++;
1488 printf("NOTE %s\n", p);
1489 }
1490 continue;
1491 }
1492 j = 0;
1493 i = 0;
1494 field[i++] = p;
1495 for (;;)
1496 {
1497 switch (*p++)
1498 {
1499 case 0:
1500 p--;
1501 j = 0;
1502 goto checkfield;
1503 case '\t':
1504 *(delim[i] = p - 1) = 0;
1505 j = 1;
1506 checkfield:
1507 s = field[i - 1];
1508 if (streq(s, "NIL"))
1509 field[i - 1] = 0;
1510 else if (streq(s, "NULL"))
1511 *s = 0;
1512 while (*p == '\t')
1513 {
1514 p++;
1515 j++;
1516 }
1517 tabs[i - 1] = j;
1518 if (!*p)
1519 break;
1520 if (i >= elementsof(field))
1521 bad("too many fields\n", NiL, NiL, 0, 0);
1522 field[i++] = p;
1523 /*FALLTHROUGH*/
1524 default:
1525 continue;
1526 }
1527 break;
1528 }
1529 if (!(spec = field[0]))
1530 bad("NIL spec\n", NiL, NiL, 0, 0);
1531
1532 /* interpret: */
1533
1534 cflags = REG_TEST_DEFAULT;
1535 eflags = REG_EXEC_DEFAULT;
1536 test &= TEST_GLOBAL;
1537 state.extracted = 0;
1538 nmatch = 20;
1539 nsub = -1;
1540 for (p = spec; *p; p++)
1541 {
1542 if (isdigit(*p))
1543 {
1544 nmatch = strtol(p, &p, 10);
1545 if (nmatch >= elementsof(match))
1546 bad("nmatch must be < 100\n", NiL, NiL, 0, 0);
1547 p--;
1548 continue;
1549 }
1550 switch (*p)
1551 {
1552 case 'A':
1553 test |= TEST_ARE;
1554 continue;
1555 case 'B':
1556 test |= TEST_BRE;
1557 continue;
1558 case 'C':
1559 if (!(test & TEST_QUERY) && !(skip & level))
1560 bad("locale must be nested\n", NiL, NiL, 0, 0);
1561 test &= ~TEST_QUERY;
1562 if (locale)
1563 bad("locale nesting not supported\n", NiL, NiL, 0, 0);
1564 if (i != 2)
1565 bad("locale field expected\n", NiL, NiL, 0, 0);
1566 if (!(skip & level))
1567 {
1568 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1569 s = field[1];
1570 if (!s || streq(s, "POSIX"))
1571 s = "C";
1572 if ((ans = setlocale(LC_COLLATE, s)) && streq(ans, "POSIX"))
1573 ans = "C";
1574 if (!ans || !streq(ans, s) && streq(s, "C"))
1575 ans = 0;
1576 else if ((ans = setlocale(LC_CTYPE, s)) && streq(ans, "POSIX"))
1577 ans = "C";
1578 if (!ans || !streq(ans, s) && streq(s, "C"))
1579 skip = note(level, s, skip, test);
1580 else
1581 {
1582 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1583 printf("NOTE \"%s\" locale\n", s);
1584 locale = level;
1585 }
1586 #else
1587 skip = note(level, skip, test, "locales not supported");
1588 #endif
1589 }
1590 cflags = NOTEST;
1591 continue;
1592 case 'E':
1593 test |= TEST_ERE;
1594 continue;
1595 case 'K':
1596 test |= TEST_KRE;
1597 continue;
1598 case 'L':
1599 test |= TEST_LRE;
1600 continue;
1601 case 'S':
1602 test |= TEST_SRE;
1603 continue;
1604
1605 case 'a':
1606 cflags |= REG_LEFT|REG_RIGHT;
1607 continue;
1608 case 'b':
1609 eflags |= REG_NOTBOL;
1610 continue;
1611 case 'c':
1612 cflags |= REG_COMMENT;
1613 continue;
1614 case 'd':
1615 cflags |= REG_SHELL_DOT;
1616 continue;
1617 case 'e':
1618 eflags |= REG_NOTEOL;
1619 continue;
1620 case 'f':
1621 cflags |= REG_MULTIPLE;
1622 continue;
1623 case 'g':
1624 cflags |= NOTEST;
1625 continue;
1626 case 'h':
1627 cflags |= REG_MULTIREF;
1628 continue;
1629 case 'i':
1630 cflags |= REG_ICASE;
1631 continue;
1632 case 'j':
1633 cflags |= REG_SPAN;
1634 continue;
1635 case 'k':
1636 cflags |= REG_ESCAPE;
1637 continue;
1638 case 'l':
1639 cflags |= REG_LEFT;
1640 continue;
1641 case 'm':
1642 cflags |= REG_MINIMAL;
1643 continue;
1644 case 'n':
1645 cflags |= REG_NEWLINE;
1646 continue;
1647 case 'o':
1648 cflags |= REG_SHELL_GROUP;
1649 continue;
1650 case 'p':
1651 cflags |= REG_SHELL_PATH;
1652 continue;
1653 case 'q':
1654 cflags |= REG_DELIMITED;
1655 continue;
1656 case 'r':
1657 cflags |= REG_RIGHT;
1658 continue;
1659 case 's':
1660 cflags |= REG_SHELL_ESCAPED;
1661 continue;
1662 case 't':
1663 cflags |= REG_MUSTDELIM;
1664 continue;
1665 case 'u':
1666 test |= TEST_UNSPECIFIED;
1667 continue;
1668 case 'v':
1669 cflags |= REG_CLASS_ESCAPE;
1670 continue;
1671 case 'w':
1672 cflags |= REG_NOSUB;
1673 continue;
1674 case 'x':
1675 if (REG_LENIENT)
1676 cflags |= REG_LENIENT;
1677 else
1678 test |= TEST_LENIENT;
1679 continue;
1680 case 'y':
1681 eflags |= REG_LEFT;
1682 continue;
1683 case 'z':
1684 cflags |= REG_NULL;
1685 continue;
1686
1687 case '$':
1688 test |= TEST_EXPAND;
1689 continue;
1690
1691 case '/':
1692 test |= TEST_SUB;
1693 continue;
1694
1695 case '=':
1696 test |= TEST_DECOMP;
1697 continue;
1698
1699 case '?':
1700 test |= TEST_VERIFY;
1701 test &= ~(TEST_AND|TEST_OR);
1702 state.verify = state.passed;
1703 continue;
1704 case '&':
1705 test |= TEST_VERIFY|TEST_AND;
1706 test &= ~TEST_OR;
1707 continue;
1708 case '|':
1709 test |= TEST_VERIFY|TEST_OR;
1710 test &= ~TEST_AND;
1711 continue;
1712 case ';':
1713 test |= TEST_OR;
1714 test &= ~TEST_AND;
1715 continue;
1716
1717 case '{':
1718 level <<= 1;
1719 if (skip & (level >> 1))
1720 {
1721 skip |= level;
1722 cflags = NOTEST;
1723 }
1724 else
1725 {
1726 skip &= ~level;
1727 test |= TEST_QUERY;
1728 }
1729 continue;
1730 case '}':
1731 if (level == 1)
1732 bad("invalid {...} nesting\n", NiL, NiL, 0, 0);
1733 if ((skip & level) && !(skip & (level>>1)))
1734 {
1735 if (!(test & (TEST_BASELINE|TEST_SUMMARY)))
1736 {
1737 if (test & (TEST_ACTUAL|TEST_FAIL))
1738 printf("}\n");
1739 else if (!(test & TEST_PASS))
1740 printf("-%d\n", state.lineno);
1741 }
1742 }
1743 #if defined(LC_COLLATE) && defined(LC_CTYPE)
1744 else if (locale & level)
1745 {
1746 locale = 0;
1747 if (!(skip & level))
1748 {
1749 s = "C";
1750 setlocale(LC_COLLATE, s);
1751 setlocale(LC_CTYPE, s);
1752 if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_SUMMARY)))
1753 printf("NOTE \"%s\" locale\n", s);
1754 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_PASS))
1755 printf("}\n");
1756 }
1757 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL))
1758 printf("}\n");
1759 }
1760 #endif
1761 level >>= 1;
1762 cflags = NOTEST;
1763 continue;
1764
1765 default:
1766 bad("bad spec\n", spec, NiL, 0, test);
1767 break;
1768
1769 }
1770 break;
1771 }
1772 if ((cflags|eflags) == NOTEST || (skip & level) && (test & TEST_BASELINE))
1773 {
1774 if (test & TEST_BASELINE)
1775 {
1776 while (i > 1)
1777 *delim[--i] = '\t';
1778 printf("%s\n", line);
1779 }
1780 continue;
1781 }
1782 if (test & TEST_OR)
1783 {
1784 if (!(test & TEST_VERIFY))
1785 {
1786 test &= ~TEST_OR;
1787 if (state.passed == state.verify && i > 1)
1788 printf("NOTE\t%s\n", field[1]);
1789 continue;
1790 }
1791 else if (state.passed > state.verify)
1792 continue;
1793 }
1794 else if (test & TEST_AND)
1795 {
1796 if (state.passed == state.verify)
1797 continue;
1798 state.passed = state.verify;
1799 }
1800 if (i < ((test & TEST_DECOMP) ? 3 : 4))
1801 bad("too few fields\n", NiL, NiL, 0, test);
1802 while (i < elementsof(field))
1803 field[i++] = 0;
1804 if (re = field[1])
1805 {
1806 if (streq(re, "SAME"))
1807 {
1808 re = ppat;
1809 test |= TEST_SAME;
1810 }
1811 else
1812 {
1813 if (test & TEST_EXPAND)
1814 escape(re);
1815 re = expand(re, patbuf);
1816 strcpy(ppat = pat, re);
1817 }
1818 }
1819 else
1820 ppat = 0;
1821 nstr = -1;
1822 if (s = field[2])
1823 {
1824 s = expand(s, strbuf);
1825 if (test & TEST_EXPAND)
1826 {
1827 nstr = escape(s);
1828 #if _REG_nexec
1829 if (nstr != strlen(s))
1830 nexec = nstr;
1831 #endif
1832 }
1833 }
1834 if (!(ans = field[(test & TEST_DECOMP) ? 2 : 3]))
1835 bad("NIL answer\n", NiL, NiL, 0, test);
1836 msg = field[4];
1837 fflush(stdout);
1838 if (test & TEST_SUB)
1839 #if _REG_subcomp
1840 cflags |= REG_DELIMITED;
1841 #else
1842 continue;
1843 #endif
1844 #if !_REG_decomp
1845 if (test & TEST_DECOMP)
1846 continue;
1847 #endif
1848
1849 compile:
1850
1851 if (state.extracted || (skip & level))
1852 continue;
1853 #if !(REG_TEST_DEFAULT & (REG_AUGMENTED|REG_EXTENDED|REG_SHELL))
1854 #ifdef REG_EXTENDED
1855 if (REG_EXTENDED != 0 && (test & TEST_BRE))
1856 #else
1857 if (test & TEST_BRE)
1858 #endif
1859 {
1860 test &= ~TEST_BRE;
1861 flags = cflags;
1862 state.which = "BRE";
1863 }
1864 else
1865 #endif
1866 #ifdef REG_EXTENDED
1867 if (test & TEST_ERE)
1868 {
1869 test &= ~TEST_ERE;
1870 flags = cflags | REG_EXTENDED;
1871 state.which = "ERE";
1872 }
1873 else
1874 #endif
1875 #ifdef REG_AUGMENTED
1876 if (test & TEST_ARE)
1877 {
1878 test &= ~TEST_ARE;
1879 flags = cflags | REG_AUGMENTED;
1880 state.which = "ARE";
1881 }
1882 else
1883 #endif
1884 #ifdef REG_LITERAL
1885 if (test & TEST_LRE)
1886 {
1887 test &= ~TEST_LRE;
1888 flags = cflags | REG_LITERAL;
1889 state.which = "LRE";
1890 }
1891 else
1892 #endif
1893 #ifdef REG_SHELL
1894 if (test & TEST_SRE)
1895 {
1896 test &= ~TEST_SRE;
1897 flags = cflags | REG_SHELL;
1898 state.which = "SRE";
1899 }
1900 else
1901 #ifdef REG_AUGMENTED
1902 if (test & TEST_KRE)
1903 {
1904 test &= ~TEST_KRE;
1905 flags = cflags | REG_SHELL | REG_AUGMENTED;
1906 state.which = "KRE";
1907 }
1908 else
1909 #endif
1910 #endif
1911 {
1912 if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
1913 extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test|TEST_OK);
1914 continue;
1915 }
1916 if ((test & (TEST_QUERY|TEST_VERBOSE|TEST_VERIFY)) == TEST_VERBOSE)
1917 {
1918 printf("test %-3d %s ", state.lineno, state.which);
1919 quote(re, -1, test|TEST_DELIMIT);
1920 printf(" ");
1921 quote(s, nstr, test|TEST_DELIMIT);
1922 printf("\n");
1923 }
1924
1925 nosub:
1926 fun = "regcomp";
1927 #if _REG_nexec
1928 if (nstr >= 0 && nstr != strlen(s))
1929 nexec = nstr;
1930 #endif
1931
1932 if (state.extracted || (skip & level))
1933 continue;
1934 if (!(test & TEST_QUERY))
1935 testno++;
1936 #ifdef REG_DISCIPLINE
1937 if (state.stack)
1938 stkset(stkstd, state.stack, 0);
1939 flags |= REG_DISCIPLINE;
1940 state.disc.ordinal = 0;
1941 sfstrseek(state.disc.sp, 0, SEEK_SET);
1942 #endif
1943 if (!(test & TEST_CATCH))
1944 cret = regcomp(&preg, re, flags);
1945 else if (!(cret = setjmp(state.gotcha)))
1946 {
1947 alarm(HUNG);
1948 cret = regcomp(&preg, re, flags);
1949 alarm(0);
1950 }
1951 #if _REG_subcomp
1952 if (!cret && (test & TEST_SUB))
1953 {
1954 fun = "regsubcomp";
1955 p = re + preg.re_npat;
1956 if (!(test & TEST_CATCH))
1957 cret = regsubcomp(&preg, p, NiL, 0, 0);
1958 else if (!(cret = setjmp(state.gotcha)))
1959 {
1960 alarm(HUNG);
1961 cret = regsubcomp(&preg, p, NiL, 0, 0);
1962 alarm(0);
1963 }
1964 if (!cret && *(p += preg.re_npat) && !(preg.re_sub->re_flags & REG_SUB_LAST))
1965 {
1966 if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
1967 continue;
1968 cret = REG_EFLAGS;
1969 }
1970 }
1971 #endif
1972 #if _REG_decomp
1973 if (!cret && (test & TEST_DECOMP))
1974 {
1975 char buf[128];
1976
1977 if ((j = nmatch) > sizeof(buf))
1978 j = sizeof(buf);
1979 fun = "regdecomp";
1980 p = re + preg.re_npat;
1981 if (!(test & TEST_CATCH))
1982 i = regdecomp(&preg, -1, buf, j);
1983 else if (!(cret = setjmp(state.gotcha)))
1984 {
1985 alarm(HUNG);
1986 i = regdecomp(&preg, -1, buf, j);
1987 alarm(0);
1988 }
1989 if (!cret)
1990 {
1991 catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
1992 if (i > j)
1993 {
1994 if (i != (strlen(ans) + 1))
1995 {
1996 report("failed", fun, re, s, nstr, msg, flags, test);
1997 printf(" %d byte buffer supplied, %d byte buffer required\n", j, i);
1998 }
1999 }
2000 else if (strcmp(buf, ans))
2001 {
2002 report("failed", fun, re, s, nstr, msg, flags, test);
2003 quote(ans, -1, test|TEST_DELIMIT);
2004 printf(" expected, ");
2005 quote(buf, -1, test|TEST_DELIMIT);
2006 printf(" returned\n");
2007 }
2008 continue;
2009 }
2010 }
2011 #endif
2012 if (!cret)
2013 {
2014 if (!(flags & REG_NOSUB) && nsub < 0 && *ans == '(')
2015 {
2016 for (p = ans; *p; p++)
2017 if (*p == '(')
2018 nsub++;
2019 else if (*p == '{')
2020 nsub--;
2021 if (nsub >= 0)
2022 {
2023 if (test & TEST_IGNORE_OVER)
2024 {
2025 if (nmatch > nsub)
2026 nmatch = nsub + 1;
2027 }
2028 else if (nsub != preg.re_nsub)
2029 {
2030 if (nsub > preg.re_nsub)
2031 {
2032 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2033 skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2034 else
2035 {
2036 report("re_nsub incorrect", fun, re, NiL, -1, msg, flags, test);
2037 printf("at least %d expected, %d returned\n", nsub, preg.re_nsub);
2038 state.errors++;
2039 }
2040 }
2041 else
2042 nsub = preg.re_nsub;
2043 }
2044 }
2045 }
2046 if (!(test & (TEST_DECOMP|TEST_SUB)) && *ans && *ans != '(' && !streq(ans, "OK") && !streq(ans, "NOMATCH"))
2047 {
2048 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2049 skip = extract(tabs, line, re, s, ans, msg, "OK", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2050 else if (!(test & TEST_LENIENT))
2051 {
2052 report("failed", fun, re, NiL, -1, msg, flags, test);
2053 printf("%s expected, OK returned\n", ans);
2054 }
2055 catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
2056 continue;
2057 }
2058 }
2059 else
2060 {
2061 if (test & TEST_LENIENT)
2062 /* we'll let it go this time */;
2063 else if (!*ans || ans[0]=='(' || cret == REG_BADPAT && streq(ans, "NOMATCH"))
2064 {
2065 got = 0;
2066 for (i = 1; i < elementsof(codes); i++)
2067 if (cret==codes[i].code)
2068 got = i;
2069 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2070 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2071 else
2072 {
2073 report("failed", fun, re, NiL, -1, msg, flags, test);
2074 printf("%s returned: ", codes[got].name);
2075 error(&preg, cret);
2076 }
2077 }
2078 else
2079 {
2080 expected = got = 0;
2081 for (i = 1; i < elementsof(codes); i++)
2082 {
2083 if (streq(ans, codes[i].name))
2084 expected = i;
2085 if (cret==codes[i].code)
2086 got = i;
2087 }
2088 if (!expected)
2089 {
2090 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2091 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2092 else
2093 {
2094 report("failed: invalid error code", NiL, re, NiL, -1, msg, flags, test);
2095 printf("%s expected, %s returned\n", ans, codes[got].name);
2096 }
2097 }
2098 else if (cret != codes[expected].code && cret != REG_BADPAT)
2099 {
2100 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2101 skip = extract(tabs, line, re, s, ans, msg, codes[got].name, NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2102 else if (test & TEST_IGNORE_ERROR)
2103 state.ignored++;
2104 else
2105 {
2106 report("should fail and did", fun, re, NiL, -1, msg, flags, test);
2107 printf("%s expected, %s returned: ", ans, codes[got].name);
2108 state.errors--;
2109 state.warnings++;
2110 error(&preg, cret);
2111 }
2112 }
2113 }
2114 goto compile;
2115 }
2116
2117 #if _REG_nexec
2118 execute:
2119 if (nexec >= 0)
2120 fun = "regnexec";
2121 else
2122 #endif
2123 fun = "regexec";
2124
2125 for (i = 0; i < elementsof(match); i++)
2126 match[i] = state.NOMATCH;
2127
2128 #if _REG_nexec
2129 if (nexec >= 0)
2130 {
2131 eret = regnexec(&preg, s, nexec, nmatch, match, eflags);
2132 s[nexec] = 0;
2133 }
2134 else
2135 #endif
2136 {
2137 if (!(test & TEST_CATCH))
2138 eret = regexec(&preg, s, nmatch, match, eflags);
2139 else if (!(eret = setjmp(state.gotcha)))
2140 {
2141 alarm(HUNG);
2142 eret = regexec(&preg, s, nmatch, match, eflags);
2143 alarm(0);
2144 }
2145 }
2146 #if _REG_subcomp
2147 if ((test & TEST_SUB) && !eret)
2148 {
2149 fun = "regsubexec";
2150 if (!(test & TEST_CATCH))
2151 eret = regsubexec(&preg, s, nmatch, match);
2152 else if (!(eret = setjmp(state.gotcha)))
2153 {
2154 alarm(HUNG);
2155 eret = regsubexec(&preg, s, nmatch, match);
2156 alarm(0);
2157 }
2158 }
2159 #endif
2160 if (flags & REG_NOSUB)
2161 {
2162 if (eret)
2163 {
2164 if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
2165 {
2166 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2167 skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, 0, skip, level, test|TEST_DELIMIT);
2168 else
2169 {
2170 report("REG_NOSUB failed", fun, re, s, nstr, msg, flags, test);
2171 error(&preg, eret);
2172 }
2173 }
2174 }
2175 else if (streq(ans, "NOMATCH"))
2176 {
2177 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2178 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2179 else
2180 {
2181 report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2182 error(&preg, eret);
2183 }
2184 }
2185 }
2186 else if (eret)
2187 {
2188 if (eret != REG_NOMATCH || !streq(ans, "NOMATCH"))
2189 {
2190 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2191 skip = extract(tabs, line, re, s, ans, msg, "NOMATCH", NiL, 0, nsub, skip, level, test|TEST_DELIMIT);
2192 else
2193 {
2194 report("failed", fun, re, s, nstr, msg, flags, test);
2195 if (eret != REG_NOMATCH)
2196 error(&preg, eret);
2197 else if (*ans)
2198 printf("expected: %s\n", ans);
2199 else
2200 printf("\n");
2201 }
2202 }
2203 }
2204 else if (streq(ans, "NOMATCH"))
2205 {
2206 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2207 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2208 else
2209 {
2210 report("should fail and didn't", fun, re, s, nstr, msg, flags, test);
2211 matchprint(match, nmatch, nsub, NiL, test);
2212 }
2213 }
2214 #if _REG_subcomp
2215 else if (test & TEST_SUB)
2216 {
2217 p = preg.re_sub->re_buf;
2218 if (strcmp(p, ans))
2219 {
2220 report("failed", fun, re, s, nstr, msg, flags, test);
2221 quote(ans, -1, test|TEST_DELIMIT);
2222 printf(" expected, ");
2223 quote(p, -1, test|TEST_DELIMIT);
2224 printf(" returned\n");
2225 }
2226 }
2227 #endif
2228 else if (!*ans)
2229 {
2230 if (match[0].rm_so != state.NOMATCH.rm_so)
2231 {
2232 if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2233 skip = extract(tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test);
2234 else
2235 {
2236 report("failed: no match but match array assigned", NiL, re, s, nstr, msg, flags, test);
2237 matchprint(match, nmatch, nsub, NiL, test);
2238 }
2239 }
2240 }
2241 else if (matchcheck(match, nmatch, nsub, ans, re, s, nstr, flags, test))
2242 {
2243 #if _REG_nexec
2244 if (nexec < 0 && !nonexec)
2245 {
2246 nexec = nstr >= 0 ? nstr : strlen(s);
2247 s[nexec] = '\n';
2248 testno++;
2249 goto execute;
2250 }
2251 #endif
2252 if (!(test & (TEST_DECOMP|TEST_SUB|TEST_VERIFY)) && !nonosub)
2253 {
2254 if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2255 continue;
2256 flags |= REG_NOSUB;
2257 goto nosub;
2258 }
2259 if (test & (TEST_BASELINE|TEST_PASS|TEST_VERIFY))
2260 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_OK);
2261 }
2262 else if (test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS|TEST_QUERY|TEST_SUMMARY|TEST_VERIFY))
2263 skip = extract(tabs, line, re, s, ans, msg, NiL, match, nmatch, nsub, skip, level, test|TEST_DELIMIT);
2264 if (catchfree(&preg, flags, tabs, line, re, s, ans, msg, NiL, NiL, 0, 0, skip, level, test))
2265 continue;
2266 goto compile;
2267 }
2268 if (test & TEST_SUMMARY)
2269 printf("tests=%-4d errors=%-4d warnings=%-2d ignored=%-2d unspecified=%-2d signals=%d\n", testno, state.errors, state.warnings, state.ignored, state.unspecified, state.signals);
2270 else if (!(test & (TEST_ACTUAL|TEST_BASELINE|TEST_FAIL|TEST_PASS)))
2271 {
2272 printf("TEST\t%s", unit);
2273 if (subunit)
2274 printf(" %-.*s", subunitlen, subunit);
2275 printf(", %d test%s", testno, testno == 1 ? "" : "s");
2276 if (state.ignored)
2277 printf(", %d ignored mismatche%s", state.ignored, state.ignored == 1 ? "" : "s");
2278 if (state.warnings)
2279 printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
2280 if (state.unspecified)
2281 printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
2282 if (state.signals)
2283 printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
2284 printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
2285 }
2286 if (fp != stdin)
2287 fclose(fp);
2288 }
2289 return 0;
2290 }
2291