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