1 /***********************************************************************
2 * *
3 * This software is part of the ast package *
4 * Copyright (c) 1995-2012 AT&T Intellectual Property *
5 * and is licensed under the *
6 * Eclipse Public License, Version 1.0 *
7 * by AT&T Intellectual Property *
8 * *
9 * A copy of the License is available at *
10 * http://www.eclipse.org/org/documents/epl-v10.html *
11 * (with md5 checksum b35adb5213ca9657e911e9befb180842) *
12 * *
13 * Information and Software Systems Research *
14 * AT&T Research *
15 * Florham Park NJ *
16 * *
17 * Glenn Fowler <glenn.s.fowler@gmail.com> *
18 * *
19 ***********************************************************************/
20 #pragma prototyped
21
22 /*
23 * strmatch(3) test harness
24 * see testmatch --help for a description of the input format
25 */
26
27 #if OLD
28 #define LEGACY "old"
29 #else
30 #define LEGACY ""
31 #endif
32
33 static const char id[] = "\n@(#)$Id: test" LEGACY "match (AT&T Research) 2012-06-25 $\0\n";
34
35 #if _PACKAGE_ast
36 #include <ast.h>
37 #else
38 #define fmtident(s) ((char*)(s)+10)
39 #endif
40
41 #include <stdio.h>
42 #include <ctype.h>
43 #include <setjmp.h>
44 #include <signal.h>
45 #include <unistd.h>
46
47 #ifdef __STDC__
48 #include <stdlib.h>
49 #include <locale.h>
50 #endif
51
52 #ifndef NiL
53 #ifdef __STDC__
54 #define NiL 0
55 #else
56 #define NiL (char*)0
57 #endif
58 #endif
59
60 #define H(x) fprintf(stderr,x)
61
62 static void
help(void)63 help(void)
64 {
65 H("NAME\n");
66 H(" testmatch - strgrpmatch(3) test harness\n");
67 H("\n");
68 H("SYNOPSIS\n");
69 H(" testmatch [ options ] testmatch.dat\n");
70 H("\n");
71 H("DESCRIPTION\n");
72 H(" testmatch reads strgrpmatch(3) test specifications, one per line, from\n");
73 H(" the standard input and writes one output line for each failed test. A\n");
74 H(" summary line is written after all tests are done. Each successful\n");
75 H(" test is run again with no subexpression pointer array. Unsupported\n");
76 H(" features are noted before the first test, and tests requiring these\n");
77 H(" features are silently ignored.\n");
78 H("\n");
79 #if OLD
80 H(" This version tests the legacy ad-hoc implementation with roots in the\n");
81 H(" Bourne sh implementation.\n");
82 #else
83 H(" This version tests the AST <regex.h> implementation.\n");
84 #endif
85 H("\n");
86 H("OPTIONS\n");
87 H(" -c catch signals and non-terminating calls\n");
88 H(" -h list help\n");
89 H(" -v list each test line\n");
90 H("\n");
91 H("INPUT FORMAT\n");
92 H(" Input lines may be blank, a comment beginning with #, or a test\n");
93 H(" specification. A specification is five fields separated by one\n");
94 H(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
95 H(" 0 pointer.\n");
96 H("\n");
97 H(" Field 1: the strgrpmatch(3) flags to apply, one character per\n");
98 H(" STR_feature flag. The test is skipped if STR_feature is not supported\n");
99 H(" by the implementation. If the first character is not [SK] then the\n");
100 H(" specification is a global control line. Note that no distinction\n");
101 H(" is made between SRE and KRE tests. STR_MAXIMAL is set by default.\n");
102 H(" Specifications containing testre(1T) flags are silently ignored.\n");
103 H("\n");
104 H(" S 0 SRE (sh glob)\n");
105 H(" K 0 KRE (ksh glob)\n");
106 H("\n");
107 H(" a STR_LEFT|STR_RIGHT implicit ^...$\n");
108 H(" i STR_ICASE ignore case\n");
109 H(" l STR_LEFT implicit ^...\n");
110 H(" m ~STR_MAXIMAL minimal match (default is STR_MAXIMAL)\n");
111 H(" r STR_RIGHT implicit ...$\n");
112 H(" u standard unspecified behavior -- errors not counted\n");
113 H(" $ expand C \\c escapes in fields 2 and 3\n");
114 H("\n");
115 H(" Field 1 control lines:\n");
116 H("\n");
117 H(" C set LC_COLLATE and LC_CTYPE to locale in field 2\n");
118 H("\n");
119 H(" { silent skip if failed until }\n");
120 H(" } end of skip\n");
121 H("\n");
122 H(" : comment comment copied to output\n");
123 H("\n");
124 H(" number use number for nmatch (20 by default)\n");
125 H("\n");
126 H(" Field 2: the strgrpmatch expression pattern; SAME uses the pattern\n");
127 H(" from the previous specification.\n");
128 H("\n");
129 H(" Field 3: the string to match.\n");
130 H("\n");
131 H(" Field 4: the test outcome. This is either OK, NOMATCH, BADPAT, or\n");
132 H(" the match array, a list of (m,n) entries with m and n being first\n");
133 H(" and last+1 positions in the field 3 string, or NULL if subexpression\n");
134 H(" array is specified and success is expected. The match[]\n");
135 H(" subexpression pointer array is initialized to (-2,-2).\n");
136 H(" All array elements not equal to (-2,-2) must be specified\n");
137 H(" in the outcome. Unspecified endpoints are denoted by ?.\n");
138 H("\n");
139 H(" Field 5: optional comment appended to the report.\n");
140 H("\n");
141 H("CONTRIBUTORS\n");
142 H(" Glenn Fowler <gsf@research.att.com> (ksh strgrpmatch)\n");
143 H(" David Korn <dgk@research.att.com> (ksh glob matcher)\n");
144 }
145
146 #ifndef elementsof
147 #define elementsof(x) (sizeof(x)/sizeof(x[0]))
148 #endif
149
150 #ifndef streq
151 #define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
152 #endif
153
154 #define LOOPED 2
155 #define NOTEST (~0)
156
157 #if !defined(STR_ICASE) && !defined(STR_LEFT) && !defined(STR_MAXIMAL) && !defined(STR_RIGHT)
158 #define NOT_SUPPORTED 1
159 #endif
160
161 static const char* unsupported[] =
162 {
163 0,
164 #if NOT_SUPPORTED
165 "strmatch",
166 "strgrpmatch",
167 #endif
168 #ifndef STR_ICASE
169 "ICASE",
170 #endif
171 #ifndef STR_LEFT
172 "LEFT",
173 #endif
174 #ifndef STR_MAXIMAL
175 "MAXIMAL",
176 #endif
177 #ifndef STR_RIGHT
178 "RIGHT",
179 #endif
180 };
181
182 #ifndef STR_ICASE
183 #define STR_ICASE NOTEST
184 #endif
185 #ifndef STR_LEFT
186 #define STR_LEFT NOTEST
187 #endif
188 #ifndef STR_MAXIMAL
189 #define STR_MAXIMAL NOTEST
190 #endif
191 #ifndef STR_RIGHT
192 #define STR_RIGHT NOTEST
193 #endif
194
195 #if STR_ICASE==NOTEST && STR_LEFT==NOTEST && STR_MAXIMAL==NOTEST && STR_RIGHT==NOTEST
196 #define NOT_SUPPORTED 1
197 #endif
198
199 static struct
200 {
201 int errors;
202 struct
203 {
204 int count;
205 int error;
206 int position;
207 } ignore;
208 int lineno;
209 int ret;
210 int signals;
211 int unspecified;
212 int warnings;
213 char* file;
214 char* which;
215 jmp_buf gotcha;
216 } state;
217
218 static void
quote(char * s,int expand)219 quote(char* s, int expand)
220 {
221 unsigned char* u = (unsigned char*)s;
222 int c;
223
224 if (!u)
225 printf("NIL");
226 else if (!*u)
227 printf("NULL");
228 else if (expand)
229 {
230 printf("\"");
231 for (;;)
232 {
233 switch (c = *u++)
234 {
235 case 0:
236 break;;
237 case '\\':
238 printf("\\\\");
239 continue;
240 case '"':
241 printf("\\\"");
242 continue;
243 case '\a':
244 printf("\\a");
245 continue;
246 case '\b':
247 printf("\\b");
248 continue;
249 case '\f':
250 printf("\\f");
251 continue;
252 case '\n':
253 printf("\\n");
254 continue;
255 case '\r':
256 printf("\\r");
257 continue;
258 case '\t':
259 printf("\\t");
260 continue;
261 case '\v':
262 printf("\\v");
263 continue;
264 default:
265 if (!iscntrl(c) && isprint(c))
266 putchar(c);
267 else
268 printf("\\x%02x", c);
269 continue;
270 }
271 break;
272 }
273 printf("\"");
274 }
275 else
276 printf("%s", s);
277 }
278
279 static void
report(char * comment,char * fun,char * re,char * s,char * msg,int flags,int unspecified,int expand)280 report(char* comment, char* fun, char* re, char* s, char* msg, int flags, int unspecified, int expand)
281 {
282 if (state.file)
283 printf("%s:", state.file);
284 printf("%d:", state.lineno);
285 if (re)
286 {
287 printf(" ");
288 quote(re, expand);
289 if (s)
290 {
291 printf(" versus ");
292 quote(s, expand);
293 }
294 }
295 if (unspecified)
296 {
297 state.unspecified++;
298 printf(" unspecified behavior");
299 }
300 else
301 state.errors++;
302 printf(" %s", state.which);
303 if (fun)
304 printf(" %s", fun);
305 if (comment[strlen(comment)-1] == '\n')
306 printf(" %s", comment);
307 else
308 {
309 printf(" %s: ", comment);
310 if (msg)
311 printf("%s: ", msg);
312 }
313 }
314
315 static int
note(int level,int skip,char * msg)316 note(int level, int skip, char* msg)
317 {
318 if (!skip)
319 {
320 printf("NOTE\t");
321 if (msg)
322 printf("%s: ", msg);
323 printf("skipping lines %d", state.lineno);
324 }
325 return skip | level;
326 }
327
328 static void
bad(char * comment,char * re,char * s,int expand)329 bad(char* comment, char* re, char* s, int expand)
330 {
331 printf("bad test case ");
332 report(comment, NiL, re, s, NiL, 0, 0, expand);
333 exit(1);
334 }
335
336 static void
escape(char * s)337 escape(char* s)
338 {
339 char* e;
340 char* t;
341 char* q;
342 int c;
343
344 for (t = s; *t = *s; s++, t++)
345 if (*s == '\\')
346 switch (*++s)
347 {
348 case '\\':
349 break;
350 case 'a':
351 *t = '\a';
352 break;
353 case 'b':
354 *t = '\b';
355 break;
356 case 'c':
357 if (*t = *s)
358 s++;
359 *t &= 037;
360 break;
361 case 'e':
362 case 'E':
363 *t = 033;
364 break;
365 case 'f':
366 *t = '\f';
367 break;
368 case 'n':
369 *t = '\n';
370 break;
371 case 'r':
372 *t = '\r';
373 break;
374 case 's':
375 *t = ' ';
376 break;
377 case 't':
378 *t = '\t';
379 break;
380 case 'v':
381 *t = '\v';
382 break;
383 case 'u':
384 case 'x':
385 q = *s == 'u' ? (s + 5) : (char*)0;
386 c = 0;
387 e = s + 1;
388 while (!e || !q || s < q)
389 {
390 switch (*++s)
391 {
392 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
393 c = (c << 4) + *s - 'a' + 10;
394 continue;
395 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
396 c = (c << 4) + *s - 'A' + 10;
397 continue;
398 case '0': case '1': case '2': case '3': case '4':
399 case '5': case '6': case '7': case '8': case '9':
400 c = (c << 4) + *s - '0';
401 continue;
402 case '{':
403 case '[':
404 if (s != e)
405 {
406 s--;
407 break;
408 }
409 e = 0;
410 if (q && *(s + 1) == 'U' && *(s + 2) == '+')
411 s += 2;
412 continue;
413 case '}':
414 case ']':
415 if (e)
416 s--;
417 break;
418 default:
419 s--;
420 break;
421 }
422 break;
423 }
424 *t = c;
425 break;
426 case '0': case '1': case '2': case '3':
427 case '4': case '5': case '6': case '7':
428 c = *s - '0';
429 q = s + 2;
430 while (s < q)
431 switch (*++s)
432 {
433 case '0': case '1': case '2': case '3':
434 case '4': case '5': case '6': case '7':
435 c = (c << 3) + *s - '0';
436 break;
437 default:
438 q = --s;
439 break;
440 }
441 *t = c;
442 break;
443 default:
444 bad("invalid C \\ escape\n", NiL, NiL, 0);
445 }
446 }
447
448 static void
matchprint(ssize_t * match,int nmatch,char * ans)449 matchprint(ssize_t* match, int nmatch, char* ans)
450 {
451 int i;
452
453 for (; nmatch > 0; nmatch -= 2)
454 if (match[nmatch-2] != -2 && (!state.ignore.position || match[nmatch-2] >= 0 && match[nmatch-2] >= 0))
455 break;
456 for (i = 0; i < nmatch; i += 2)
457 {
458 printf("(");
459 if (match[i] == -1)
460 printf("?");
461 else
462 printf("%zd", match[i]);
463 printf(",");
464 if (match[i+1] == -1)
465 printf("?");
466 else
467 printf("%zd", match[i+1]);
468 printf(")");
469 }
470 if (ans)
471 printf(" expected: %s", ans);
472 printf("\n");
473 }
474
475 static int
matchcheck(int nmatch,ssize_t * match,char * ans,char * re,char * s,int flags,int query,int unspecified,int expand)476 matchcheck(int nmatch, ssize_t* match, char* ans, char* re, char* s, int flags, int query, int unspecified, int expand)
477 {
478 char* p;
479 int i;
480 ssize_t m;
481 ssize_t n;
482
483 for (i = 0, p = ans; i < nmatch && *p; i += 2)
484 {
485 if (*p++ != '(')
486 bad("improper answer\n", re, s, expand);
487 if (*p == '?')
488 {
489 m = -1;
490 p++;
491 }
492 else
493 m = strtol(p, &p, 10);
494 if (*p++ != ',')
495 bad("improper answer\n", re, s, expand);
496 if (*p == '?')
497 {
498 n = -1;
499 p++;
500 }
501 else
502 n = strtol(p, &p, 10);
503 if (*p++ != ')')
504 bad("improper answer\n", re, s, expand);
505 if (m!=match[i] || n!=match[i+1])
506 {
507 if (!query)
508 {
509 report("failed: match was", NiL, re, s, NiL, flags, unspecified, expand);
510 matchprint(match, nmatch, ans);
511 }
512 return 0;
513 }
514 }
515 for (; i < nmatch; i += 2)
516 {
517 if (match[i]!=-2 || match[i+1]!=-2)
518 {
519 if (!query)
520 {
521 if (state.ignore.position && (match[i]<0 || match[i+1]<0))
522 {
523 state.ignore.count++;
524 return 0;
525 }
526 report("failed: match was", NiL, re, s, NiL, flags, unspecified, expand);
527 matchprint(match, nmatch, ans);
528 }
529 return 0;
530 }
531 }
532 if (match[nmatch] != -2)
533 {
534 report("failed: overran match array", NiL, re, s, NiL, flags, unspecified, expand);
535 matchprint(match, nmatch + 1, NiL);
536 }
537 return 1;
538 }
539
540 static void
sigunblock(int s)541 sigunblock(int s)
542 {
543 #ifdef SIG_SETMASK
544 int op;
545 sigset_t mask;
546
547 sigemptyset(&mask);
548 if (s)
549 {
550 sigaddset(&mask, s);
551 op = SIG_UNBLOCK;
552 }
553 else op = SIG_SETMASK;
554 sigprocmask(op, &mask, NiL);
555 #else
556 #ifdef sigmask
557 sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
558 #endif
559 #endif
560 }
561
562 static void
gotcha(int sig)563 gotcha(int sig)
564 {
565 signal(sig, gotcha);
566 alarm(0);
567 state.signals++;
568 state.ret = 0;
569 sigunblock(sig);
570 longjmp(state.gotcha, 1);
571 }
572
573 static char*
getline(FILE * fp)574 getline(FILE* fp)
575 {
576 static char buf[32 * 1024];
577
578 register char* s = buf;
579 register char* e = &buf[sizeof(buf)];
580 register char* b;
581
582 for (;;)
583 {
584 if (!(b = fgets(s, e - s, fp)))
585 return 0;
586 state.lineno++;
587 s += strlen(s) - 1;
588 if (*s != '\n')
589 break;
590 if (s == b || *(s - 1) != '\\')
591 {
592 *s = 0;
593 break;
594 }
595 s--;
596 }
597 return buf;
598 }
599
600 int
main(int argc,char ** argv)601 main(int argc, char** argv)
602 {
603 int cflags;
604 int eflags;
605 int query;
606 int expand;
607 int unspecified;
608 int kre;
609 int sre;
610 int nmatch;
611 int rmatch;
612 int eret;
613 int i;
614 int sub;
615 int subunitlen;
616 int level = 1;
617 int locale = 0;
618 int skip = 0;
619 int testno = 0;
620 FILE* fp;
621 char* p;
622 char* spec;
623 char* re;
624 char* s;
625 char* ans;
626 char* msg;
627 char* fun;
628 char* subunit;
629 char* version;
630 char* field[6];
631 char unit[64];
632 ssize_t match[200];
633
634 int catch = 0;
635 int verbose = 0;
636
637 static char* filter[] = { "-", 0 };
638
639 version = fmtident(id);
640 p = unit;
641 while (p < &unit[sizeof(unit)-1] && (*p = *version++) && !isspace(*p))
642 p++;
643 *p = 0;
644 while ((p = *++argv) && *p == '-')
645 for (;;)
646 {
647 switch (*++p)
648 {
649 case 0:
650 break;
651 case 'c':
652 catch = 1;
653 continue;
654 case 'h':
655 case '?':
656 case '-':
657 help();
658 return 2;
659 case 'p':
660 state.ignore.position = 1;
661 continue;
662 case 'v':
663 verbose = 1;
664 continue;
665 default:
666 fprintf(stderr, "%s: -%c: invalid option", unit, *p);
667 continue;
668 }
669 break;
670 }
671 if (catch)
672 {
673 signal(SIGALRM, gotcha);
674 signal(SIGBUS, gotcha);
675 signal(SIGSEGV, gotcha);
676 }
677 if (!*argv)
678 argv = filter;
679 while (state.file = *argv++)
680 {
681 if (streq(state.file, "-") || streq(state.file, "/dev/stdin") || streq(state.file, "/dev/fd/0"))
682 {
683 state.file = 0;
684 fp = stdin;
685 }
686 else if (!(fp = fopen(state.file, "r")))
687 {
688 fprintf(stderr, "%s: %s: cannot read\n", unit, state.file);
689 return 2;
690 }
691 printf("TEST\t%s ", unit);
692 if (s = state.file)
693 {
694 subunit = p = 0;
695 for (;;)
696 {
697 switch (*s++)
698 {
699 case 0:
700 break;
701 case '/':
702 subunit = s;
703 continue;
704 case '.':
705 p = s - 1;
706 continue;
707 default:
708 continue;
709 }
710 break;
711 }
712 if (!subunit)
713 subunit = state.file;
714 if (p < subunit)
715 p = s - 1;
716 subunitlen = p - subunit;
717 if (subunitlen == strlen(unit) && !memcmp(subunit, unit, subunitlen))
718 subunit = 0;
719 else
720 printf("%-.*s ", subunitlen, subunit);
721 }
722 else
723 subunit = 0;
724 printf("%s", version);
725 if (catch)
726 printf(", catch");
727 if (verbose)
728 printf(", verbose");
729 for (i = 1; i < elementsof(unsupported); i++)
730 printf(", no%s", unsupported[i]);
731 printf("\n");
732 level = 1;
733 locale = skip = testno = 0;
734 state.ignore.count = state.lineno = state.signals = state.unspecified = state.warnings = 0;
735 while (p = getline(fp))
736 {
737
738 /* parse: */
739
740 if (*p == 0 || *p == '#')
741 continue;
742 if (*p == ':')
743 {
744 while (*++p == ' ');
745 printf("NOTE %s\n", p);
746 continue;
747 }
748 i = 0;
749 field[i++] = p;
750 for (;;)
751 {
752 switch (*p++)
753 {
754 case 0:
755 p--;
756 goto checkfield;
757 case '\t':
758 *(p - 1) = 0;
759 checkfield:
760 s = field[i - 1];
761 if (streq(s, "NIL"))
762 field[i - 1] = 0;
763 else if (streq(s, "NULL"))
764 *s = 0;
765 while (*p == '\t')
766 p++;
767 if (!*p)
768 break;
769 if (i >= elementsof(field))
770 bad("too many fields\n", NiL, NiL, 0);
771 field[i++] = p;
772 /*FALLTHROUGH*/
773 default:
774 continue;
775 }
776 break;
777 }
778 if (!(spec = field[0]))
779 bad("NIL spec\n", NiL, NiL, 0);
780
781 /* interpret: */
782
783 cflags = 0;
784 #if STR_MAXIMAL != NOTEST
785 eflags = STR_MAXIMAL;
786 #else
787 eflags = 0;
788 #endif
789 expand = query = unspecified = kre = sre = 0;
790 nmatch = 20;
791 for (p = spec; *p; p++)
792 {
793 if (isdigit(*p))
794 {
795 if ((nmatch = 2 * strtol(p, &p, 10)) >= elementsof(match))
796 bad("nmatch too large\n", spec, NiL, 0);
797 p--;
798 continue;
799 }
800 switch (*p)
801 {
802 case 'A':
803 continue;
804 case 'B':
805 continue;
806 case 'C':
807 if (!query && !(skip & level))
808 bad("locale query expected\n", NiL, NiL, 0);
809 query = 0;
810 #if OLD
811 if (!(skip & level))
812 skip = note(level, skip, "locales not supported by old strmatch()");
813 #else
814 if (locale)
815 bad("locale nesting not supported\n", NiL, NiL, 0);
816 if (i != 2)
817 bad("locale field expected\n", NiL, NiL, 0);
818 if (!(skip & level))
819 {
820 #if defined(LC_COLLATE) && defined(LC_CTYPE)
821 s = field[1];
822 if (!s || streq(s, "POSIX"))
823 s = "C";
824 if (!(ans = setlocale(LC_COLLATE, s)) || streq(ans, "C") || streq(ans, "POSIX") || !(ans = setlocale(LC_CTYPE, s)) || streq(ans, "C") || streq(ans, "POSIX"))
825 skip = note(level, skip, s);
826 else
827 {
828 printf("NOTE \"%s\" locale\n", s);
829 locale = level;
830 }
831 #else
832 skip = note(level, skip, "locales not supported");
833 #endif
834 }
835 #endif
836 cflags = NOTEST;
837 continue;
838 case 'E':
839 continue;
840 case 'K':
841 kre = 1;
842 continue;
843 case 'L':
844 continue;
845 case 'S':
846 sre = 1;
847 continue;
848
849 case 'a':
850 eflags |= STR_LEFT|STR_RIGHT;
851 continue;
852 case 'b':
853 cflags = NOTEST;
854 continue;
855 case 'c':
856 cflags = NOTEST;
857 continue;
858 case 'd':
859 cflags = NOTEST;
860 continue;
861 case 'e':
862 cflags = NOTEST;
863 continue;
864 case 'f':
865 continue;
866 case 'g':
867 cflags = NOTEST;
868 continue;
869 case 'h':
870 cflags = NOTEST;
871 continue;
872 case 'i':
873 eflags |= STR_ICASE;
874 continue;
875 case 'j':
876 cflags = NOTEST;
877 continue;
878 case 'k':
879 cflags = NOTEST;
880 continue;
881 case 'l':
882 eflags |= STR_LEFT;
883 continue;
884 case 'm':
885 #if STR_MAXIMAL != NOTEST
886 eflags &= ~STR_MAXIMAL;
887 #else
888 eflags = NOTEST;
889 #endif
890 continue;
891 case 'n':
892 cflags = NOTEST;
893 continue;
894 case 'o':
895 cflags = NOTEST;
896 continue;
897 case 'p':
898 cflags = NOTEST;
899 continue;
900 case 'r':
901 eflags |= STR_RIGHT;
902 continue;
903 case 's':
904 cflags = NOTEST;
905 continue;
906 case 'u':
907 unspecified = 1;
908 continue;
909 case 'v':
910 cflags = NOTEST;
911 continue;
912 case 'x':
913 cflags = NOTEST;
914 continue;
915 case 'y':
916 eflags = NOTEST;
917 continue;
918 case 'z':
919 cflags = NOTEST;
920 continue;
921
922 case '$':
923 expand = 1;
924 continue;
925 case '/':
926 cflags = NOTEST;
927 continue;
928
929 case '{':
930 level <<= 1;
931 if (skip & (level >> 1))
932 {
933 skip |= level;
934 cflags = NOTEST;
935 }
936 else
937 {
938 skip &= ~level;
939 query = 1;
940 }
941 continue;
942 case '}':
943 if (level == 1)
944 bad("invalid {...} nesting\n", NiL, NiL, 0);
945 else
946 {
947 if ((skip & level) && !(skip & (level>>1)))
948 printf("-%d\n", state.lineno);
949 #if defined(LC_COLLATE) && defined(LC_CTYPE)
950 else if (locale & level)
951 {
952 locale = 0;
953 if (!(skip & level))
954 {
955 s = "C";
956 setlocale(LC_COLLATE, s);
957 setlocale(LC_CTYPE, s);
958 printf("NOTE \"%s\" locale\n", s);
959 }
960 }
961 #endif
962 skip &= ~level;
963 level >>= 1;
964 }
965 cflags = NOTEST;
966 continue;
967
968 default:
969 bad("bad spec\n", spec, NiL, 0);
970 break;
971
972 }
973 break;
974 }
975 if ((cflags|eflags) == NOTEST || !sre && !kre)
976 continue;
977 if (i < 4)
978 bad("too few fields\n", NiL, NiL, 0);
979 while (i < elementsof(field))
980 field[i++] = 0;
981 if ((re = field[1]) && expand)
982 escape(re);
983 if ((s = field[2]) && expand)
984 escape(s);
985 if (!(ans = field[3]))
986 bad("NIL answer\n", NiL, NiL, 0);
987 msg = field[4];
988 fflush(stdout);
989
990 compile:
991
992 if (skip)
993 continue;
994 #if NOT_SUPPORTED == 0
995 if (sre)
996 {
997 state.which = "SRE";
998 sre = 0;
999 }
1000 else if (kre)
1001 {
1002 state.which = "KRE";
1003 kre = 0;
1004 }
1005 else
1006 continue;
1007 if (!query && verbose)
1008 printf("test %-3d %s \"%s\" \"%s\"\n", state.lineno, state.which, re, s);
1009 sub = 1;
1010
1011 nosub:
1012
1013 if (skip)
1014 continue;
1015 if (!query)
1016 testno++;
1017 for (i = 0; i < elementsof(match); i++)
1018 match[i] = -2;
1019 if (catch)
1020 {
1021 if (setjmp(state.gotcha))
1022 eret = state.ret;
1023 else
1024 {
1025 alarm(LOOPED);
1026 if (sub)
1027 {
1028 fun = "strgrpmatch";
1029 eret = (rmatch = strgrpmatch(s, re, match, nmatch / 2, eflags)) == 0;
1030 if (verbose)
1031 printf("[%s]", fun);
1032 }
1033 else
1034 {
1035 fun = "strmatch";
1036 eret = (rmatch = strmatch(s, re)) == 0;
1037 }
1038 alarm(0);
1039 }
1040 }
1041 else if (sub)
1042 {
1043 fun = "strgrpmatch";
1044 eret = (rmatch = strgrpmatch(s, re, match, nmatch / 2, eflags)) == 0;
1045 if (verbose)
1046 printf("[%s]", fun);
1047 }
1048 else
1049 {
1050 fun = "strmatch";
1051 eret = (rmatch = strmatch(s, re)) == 0;
1052 }
1053 #if OLD
1054 if (eret && streq(s, re))
1055 {
1056 note(level, skip, "old strmatch() does not fall back to literal match on error");
1057 printf("-EOF\n");
1058 goto skip;
1059 }
1060 #endif
1061 if (!sub)
1062 {
1063 if (eret)
1064 {
1065 if (!streq(ans, "NOMATCH") && *ans != 'E')
1066 {
1067 if (query)
1068 skip = note(level, skip, msg);
1069 else
1070 report("failed", fun, re, s, msg, nmatch, unspecified, expand);
1071 if (eret == 1)
1072 printf("OK expected, NOMATCH returned");
1073 else
1074 printf("OK expected, error %d returned", eret);
1075 printf("\n");
1076 }
1077 }
1078 else if (streq(ans, "NOMATCH") || *ans == 'E')
1079 {
1080 if (query)
1081 skip = note(level, skip, msg);
1082 else
1083 {
1084 report("failed", fun, re, s, msg, nmatch, unspecified, expand);
1085 printf("%s expected, OK returned", ans);
1086 printf("\n");
1087 }
1088 }
1089 }
1090 else if (eret)
1091 {
1092 if (!streq(ans, "NOMATCH") && *ans != 'E')
1093 {
1094 if (query)
1095 skip = note(level, skip, msg);
1096 else
1097 {
1098 report("failed", fun, re, s, msg, nmatch, unspecified, expand);
1099 if (eret == 1)
1100 printf("OK expected, NOMATCH returned");
1101 else
1102 printf("OK expected, error %d returned", eret);
1103 printf("\n");
1104 }
1105 }
1106 }
1107 else if (streq(ans, "NOMATCH") || *ans == 'E')
1108 {
1109 if (query)
1110 skip = note(level, skip, msg);
1111 else
1112 {
1113 report("should fail and didn't", fun, re, s, msg, nmatch, unspecified, expand);
1114 matchprint(match, nmatch, NiL);
1115 }
1116 }
1117 else if (!*ans)
1118 {
1119 if (match[0] != -2)
1120 {
1121 if (query)
1122 skip = note(level, skip, msg);
1123 else
1124 {
1125 report("failed: no match but match array assigned", NiL, re, s, msg, nmatch, unspecified, expand);
1126 matchprint(match, nmatch, NiL);
1127 }
1128 }
1129 }
1130 else if (!matchcheck(2 * rmatch, match, ans, re, s, nmatch, query, unspecified, expand))
1131 {
1132 if (eflags ^ (STR_LEFT|STR_RIGHT))
1133 continue;
1134 sub = 0;
1135 goto nosub;
1136 }
1137 else if (query)
1138 skip = note(level, skip, msg);
1139 goto compile;
1140 #endif
1141 }
1142 #if OLD
1143
1144 skip:
1145
1146 #endif
1147 printf("TEST\t%s", unit);
1148 if (subunit)
1149 printf(" %-.*s", subunitlen, subunit);
1150 printf(", %d test%s", testno, testno == 1 ? "" : "s");
1151 if (state.ignore.count)
1152 printf(", %d ignored mismatche%s", state.ignore.count, state.ignore.count == 1 ? "" : "s");
1153 if (state.warnings)
1154 printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
1155 if (state.unspecified)
1156 printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
1157 if (state.signals)
1158 printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
1159 printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
1160 if (fp != stdin)
1161 fclose(fp);
1162 }
1163 return 0;
1164 }
1165