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 * glob(3) test harness
24 * see help() for details
25 */
26
27 static const char id[] = "\n@(#)$Id: testglob (AT&T Research) 2012-06-23 $\0\n";
28
29 #if _PACKAGE_ast
30
31 #include <ast.h>
32
33 #define quniq(v,n) struniq(v,n)
34
35 #else
36
37 #define fmtident(s) ((char*)(s)+10)
38
39 static int
quniq(char ** argv,int n)40 quniq(char** argv, int n)
41 {
42 register char** ao;
43 register char** an;
44 register char** ae;
45
46 ao = an = argv;
47 ae = ao + n;
48 while (++an < ae) {
49 while (streq(*ao, *an))
50 if (++an >= ae)
51 return ao - argv + 1;
52 *++ao = *an;
53 }
54 return ao - argv + 1;
55 }
56
57 #endif
58
59 #include <sys/types.h>
60 #include <sys/stat.h>
61 #include <stdio.h>
62 #include <glob.h>
63 #include <ctype.h>
64 #include <setjmp.h>
65 #include <signal.h>
66 #include <unistd.h>
67
68 #ifdef __STDC__
69 #include <stdlib.h>
70 #include <locale.h>
71 #endif
72
73 #ifndef NiL
74 #ifdef __STDC__
75 #define NiL 0
76 #else
77 #define NiL (char*)0
78 #endif
79 #endif
80
81 #define H(x) fprintf(stderr,x)
82
83 static void
help(void)84 help(void)
85 {
86 H("NAME\n");
87 H(" testglob - glob(3) test harness\n");
88 H("\n");
89 H("SYNOPSIS\n");
90 H(" testglob [ options ] < testglob.dat\n");
91 H("\n");
92 H("DESCRIPTION\n");
93 H(" testglob reads glob(3) test specifications, one per line, from the\n");
94 H(" standard input and writes one output line for each failed test. A\n");
95 H(" summary line is written after all tests are done. Unsupported\n");
96 H(" features are noted before the first test, and tests requiring these\n");
97 H(" features are silently ignored. Each test is repeated with GLOB_LIST,\n");
98 H(" GLOB_STACK, and GLOB_LIST|GLOB_STACK set.\n");
99 H("\n");
100 H("OPTIONS\n");
101 H(" -c catch signals and non-terminating calls\n");
102 H(" -e ignore error code mismatches\n");
103 H(" -n do not repeat tests with GLOB_LIST, GLOB_STACK, or GLOB_LIST|GLOB_STACK\n");
104 H(" -v list each test line\n");
105 H("\n");
106 H("INPUT FORMAT\n");
107 H(" Input lines may be blank, a comment beginning with #, or a test\n");
108 H(" specification. A specification is five fields separated by one\n");
109 H(" or more tabs. NULL denotes the empty string and NIL denotes the\n");
110 H(" 0 pointer.\n");
111 H("\n");
112 H(" Field 1: the glob(3) flags to apply, one character per GLOB_feature\n");
113 H(" flag. The test is skipped if GLOB_feature is not supported by the\n");
114 H(" implementation. If the first character is not [SK] then the\n");
115 H(" specification is a global control line. One or more of [SK] may be\n");
116 H(" specified; the test will be repeated for each mode.\n");
117 H("\n");
118 H(" K GLOB_AUGMENTED augmented (ksh) patterns\n");
119 H(" S 0 basic shell patterns\n");
120 H("\n");
121 H(" a GLOB_APPEND append to previous result\n");
122 H(" b GLOB_BRACE enable {...} expansion\n");
123 H(" c GLOB_COMPLETE shell file completion\n");
124 H(" e GLOB_NOESCAPE \\ not special\n");
125 H(" E GLOB_ERR abort on error\n");
126 H(" i GLOB_ICASE ignore case\n");
127 H(" m GLOB_MARK append / to directories\n");
128 H(" n GLOB_NOCHECK no match returns original pattern\n");
129 H(" r GLOB_STARSTAR enable /**/ expansion\n");
130 H(" s GLOB_NOSORT don't sort\n");
131 H(" u standard unspecified behavior -- errors not counted\n");
132 H("\n");
133 H(" Field 1 control lines:\n");
134 H("\n");
135 H(" C set LC_COLLATE and LC_CTYPE to the locale in field 2\n");
136 H(" I set gl_fignore to the pattern in field 2\n");
137 H(" W workspace file/dir; tab indentation denotes directory level\n");
138 H("\n");
139 H(" { silent skip if failed until }\n");
140 H(" } end of skip\n");
141 H("\n");
142 H(" : comment comment copied to output\n");
143 H("\n");
144 H(" Field 2: a shell filename expansion pattern\n");
145 H("\n");
146 H(" Field 3: the expected glob() return value, OK for success, glob\n");
147 H(" return codes otherwise, with the GLOB_ prefix omitted\n");
148 H("\n");
149 H(" Field 4: optional space-separated matched file list\n");
150 H("\n");
151 H(" Field 5: optional comment appended to the report.\n");
152 H("\n");
153 H("CONTRIBUTORS\n");
154 H(" Glenn Fowler <gsf@research.att.com> (ksh strmatch, regex extensions)\n");
155 H(" David Korn <dgk@research.att.com> (ksh glob matcher)\n");
156 }
157
158 #ifndef elementsof
159 #define elementsof(x) (sizeof(x)/sizeof(x[0]))
160 #endif
161
162 #ifndef streq
163 #define streq(a,b) (*(a)==*(b)&&!strcmp(a,b))
164 #endif
165
166 #define LOOPED 2
167 #define NOTEST (~0)
168
169 static const char* unsupported[] = {
170 #ifndef GLOB_AUGMENTED
171 "AUGMENTED",
172 #endif
173 #ifndef GLOB_BRACE
174 "BRACE",
175 #endif
176 #ifndef GLOB_COMPLETE
177 "COMPLETE",
178 #endif
179 #ifndef GLOB_DISC
180 "DISC",
181 #endif
182 #ifndef GLOB_ICASE
183 "ICASE",
184 #endif
185 #ifndef GLOB_LIST
186 "LIST",
187 #endif
188 #ifndef GLOB_STACK
189 "STACK",
190 #endif
191 #ifndef GLOB_STARSTAR
192 "STARSTAR",
193 #endif
194 0
195 };
196
197 #ifndef GLOB_BRACE
198 #define GLOB_BRACE NOTEST
199 #endif
200 #ifndef GLOB_COMPLETE
201 #define GLOB_COMPLETE NOTEST
202 #endif
203 #ifndef GLOB_DISC
204 #define GLOB_DISC 0
205 #endif
206 #ifndef GLOB_ICASE
207 #define GLOB_ICASE NOTEST
208 #endif
209 #ifndef GLOB_LIST
210 #define GLOB_LIST 0
211 #endif
212 #ifndef GLOB_STACK
213 #define GLOB_STACK 0
214 #endif
215 #ifndef GLOB_STARSTAR
216 #define GLOB_STARSTAR 0
217 #endif
218
219 #define GLOB_UNKNOWN (-1)
220
221 #ifndef GLOB_ABORTED
222 #define GLOB_ABORTED (GLOB_UNKNOWN-1)
223 #endif
224 #ifndef GLOB_NOMATCH
225 #define GLOB_NOMATCH (GLOB_UNKNOWN-2)
226 #endif
227 #ifndef GLOB_NOSPACE
228 #define GLOB_NOSPACE (GLOB_UNKNOWN-3)
229 #endif
230 #ifndef GLOB_INTR
231 #define GLOB_INTR (GLOB_UNKNOWN-4)
232 #endif
233 #ifndef GLOB_APPERR
234 #define GLOB_APPERR (GLOB_UNKNOWN-5)
235 #endif
236 #ifndef GLOB_NOSYS
237 #define GLOB_NOSYS (GLOB_UNKNOWN-6)
238 #endif
239 #ifndef GLOB_ELOOP
240 #define GLOB_ELOOP (GLOB_UNKNOWN-7)
241 #endif
242 #ifndef GLOB_EBUS
243 #define GLOB_EBUS (GLOB_UNKNOWN-8)
244 #endif
245 #ifndef GLOB_EFAULT
246 #define GLOB_EFAULT (GLOB_UNKNOWN-9)
247 #endif
248
249 static const struct { int code; char* name; char* desc;} codes[] = {
250 GLOB_UNKNOWN, "UNKNOWN", "unknown",
251 0, "OK", "ok",
252 GLOB_ABORTED, "ABORTED", "glob aborted",
253 GLOB_NOMATCH, "NOMATCH", "no match",
254 GLOB_NOSPACE, "NOSPACE", "no space left",
255 GLOB_INTR, "INTR", "an interrupt occurred",
256 GLOB_APPERR, "APPERR", "aplication error",
257 GLOB_NOSYS, "NOSYS", "not a system call",
258 GLOB_ELOOP, "ELOOP", "recursin loop",
259 GLOB_EBUS, "EBUS", "bus error",
260 GLOB_EFAULT, "EFAULT", "memory fault",
261 };
262
263 static struct {
264 int errors;
265 struct {
266 int count;
267 int error;
268 int position;
269 } ignore;
270 int lineno;
271 int ret;
272 int signals;
273 int unspecified;
274 int warnings;
275 char* stack;
276 char* which;
277 jmp_buf gotcha;
278 } state;
279
280 static void
quote(char * s)281 quote(char* s)
282 {
283 unsigned char* u = (unsigned char*)s;
284 int c;
285
286 if (!u)
287 printf("NIL");
288 else if (!*u)
289 printf("NULL");
290 else {
291 printf("\"");
292 for (;;) {
293 switch (c = *u++) {
294 case 0:
295 break;;
296 case '\\':
297 printf("\\\\");
298 continue;
299 case '"':
300 printf("\\\"");
301 continue;
302 case '\n':
303 printf("\\n");
304 continue;
305 case '\r':
306 printf("\\r");
307 continue;
308 case '\t':
309 printf("\\t");
310 continue;
311 default:
312 if (!iscntrl(c) && isprint(c))
313 putchar(c);
314 else
315 printf("\\x%02x", c);
316 continue;
317 }
318 break;
319 }
320 printf("\"");
321 }
322 }
323
324 static void
report(char * comment,char * pat,char * msg,int flags,int unspecified)325 report(char* comment, char* pat, char* msg, int flags, int unspecified)
326 {
327 printf("%d: ", state.lineno);
328 #if GLOB_LIST
329 if (flags & GLOB_LIST)
330 printf("LIST: ");
331 #endif
332 #if GLOB_STACK
333 if (flags & GLOB_STACK)
334 printf("STACK: ");
335 #endif
336 if (unspecified) {
337 state.unspecified++;
338 printf(" unspecified behavior");
339 }
340 else
341 state.errors++;
342 if (pat)
343 quote(pat);
344 printf(" %s %s", state.which, comment);
345 if (msg && comment[strlen(comment)-1] != '\n')
346 printf(": %s: ", msg);
347 }
348
349 static int
note(int level,int skip,char * msg)350 note(int level, int skip, char* msg)
351 {
352 if (!skip) {
353 printf("NOTE\t");
354 if (msg)
355 printf("%s: ", msg);
356 printf("skipping lines %d", state.lineno);
357 }
358 return skip | level;
359 }
360
361 static void
bad(char * comment,char * pat)362 bad(char* comment, char* pat)
363 {
364 printf("bad test case ");
365 report(comment, pat, NiL, 0, 0);
366 exit(1);
367 }
368
369 static int
hex(int c)370 hex(int c)
371 {
372 return isdigit(c) ? (c - '0') : (c - (isupper(c) ? 'A' : 'a') + 10);
373 }
374
375 static void
escape(char * s)376 escape(char* s)
377 {
378 char* t;
379
380 for (t = s; *t = *s; s++, t++) {
381 if (*s != '\\')
382 continue;
383 switch (*++s) {
384
385 case 0:
386 *++t = 0;
387 break;
388 case '\\':
389 *t = '\\';
390 break;
391 case 'n':
392 *t = '\n';
393 break;
394 case 'r':
395 *t = '\r';
396 break;
397 case 't':
398 *t = '\t';
399 break;
400 case 'x':
401 if (!isxdigit(s[1]) || !isxdigit(s[2]))
402 bad("bad \\x\n", NiL);
403 *t = hex(*++s) << 4;
404 *t |= hex(*++s);
405 break;
406 default:
407 s--;
408 break;
409 }
410 }
411 }
412
413 static void
sigunblock(int s)414 sigunblock(int s)
415 {
416 #ifdef SIG_SETMASK
417 int op;
418 sigset_t mask;
419
420 sigemptyset(&mask);
421 if (s) {
422 sigaddset(&mask, s);
423 op = SIG_UNBLOCK;
424 }
425 else
426 op = SIG_SETMASK;
427 sigprocmask(op, &mask, NiL);
428 #else
429 #ifdef sigmask
430 sigsetmask(s ? (sigsetmask(0L) & ~sigmask(s)) : 0L);
431 #endif
432 #endif
433 }
434
435 static void
gotcha(int sig)436 gotcha(int sig)
437 {
438 signal(sig, gotcha);
439 alarm(0);
440 state.signals++;
441 switch (sig) {
442
443 case SIGALRM:
444 state.ret = GLOB_ELOOP;
445 break;
446 case SIGBUS:
447 state.ret = GLOB_EBUS;
448 break;
449 case SIGSEGV:
450 state.ret = GLOB_EFAULT;
451 break;
452 }
453 sigunblock(sig);
454 longjmp(state.gotcha, 1);
455 }
456
457 static int
qstrcmp(const void * a,const void * b)458 qstrcmp(const void* a, const void* b)
459 {
460 return strcmp(*(char**)a, *(char**)b);
461 }
462
463 static char*
getline(void)464 getline(void)
465 {
466 static char buf[32 * 1024];
467
468 register char* s = buf;
469 register char* e = &buf[sizeof(buf)];
470 register char* b;
471
472 for (;;) {
473 if (!(b = fgets(s, e - s, stdin)))
474 return 0;
475 state.lineno++;
476 s += strlen(s) - 1;
477 if (*s != '\n')
478 break;
479 if (s == b || *(s - 1) != '\\') {
480 *s = 0;
481 break;
482 }
483 s--;
484 }
485 return buf;
486 }
487
488 int
main(int argc,char ** argv)489 main(int argc, char** argv)
490 {
491 int flags;
492 int query;
493 int unspecified;
494 int kre;
495 int sre;
496 int okre;
497 int osre;
498 int ret;
499 int i;
500 int m;
501 int n;
502 int expected;
503 int got;
504 int ok;
505 int nmodes;
506 int extra;
507 char* spec;
508 char* pat;
509 char* p;
510 char* bp;
511 char* k;
512 char* s;
513 char* bs;
514 char* ans;
515 char* err;
516 char* msg;
517 char** v;
518 char* field[5];
519 char unit[64];
520 char pathbuf[1024];
521 char linkbuf[1024];
522 char* buf;
523 char* path;
524 char* pathmax;
525 char* work[16];
526 char* av[256];
527 glob_t gl;
528 struct stat st;
529 #if GLOB_DISC
530 char fignore[128];
531 #endif
532 #if GLOB_LIST
533 globlist_t* gi;
534 #endif
535
536 int catch = 0;
537 int cwd = 0;
538 int level = 1;
539 int locale = 0;
540 int skip = 0;
541 int testno = 0;
542 int verbose = 0;
543 int working = 0;
544
545 static int modes[] = {
546 0,
547 #if GLOB_LIST
548 GLOB_LIST,
549 #endif
550 #if GLOB_STACK
551 GLOB_STACK,
552 #endif
553 #if GLOB_LIST && GLOB_STACK
554 GLOB_LIST|GLOB_STACK,
555 #endif
556 };
557
558 nmodes = elementsof(modes);
559 printf("TEST\t%s", s = fmtident(id));
560 p = unit;
561 while (p < &unit[sizeof(unit)-1] && (*p = *s++) && !isspace(*p))
562 p++;
563 *p = 0;
564 while ((p = *++argv) && *p == '-')
565 for (;;) {
566 switch (*++p) {
567
568 case 0:
569 break;
570 case 'c':
571 catch = 1;
572 printf(", catch");
573 continue;
574 case 'e':
575 state.ignore.error = 1;
576 printf(", ignore error code mismatches");
577 continue;
578 case 'h':
579 case '?':
580 case '-':
581 printf(", help\n\n");
582 help();
583 return 2;
584 case 'n':
585 nmodes = 1;
586 continue;
587 case 'v':
588 verbose = 1;
589 printf(", verbose");
590 continue;
591 default:
592 printf(", invalid option %c", *p);
593 continue;
594 }
595 break;
596 }
597 if (p)
598 printf(", argument(s) ignored");
599 printf("\n");
600 if (elementsof(unsupported) > 1) {
601 printf("NOTE\tunsupported:");
602 got = ' ';
603 for (i = 0; i < elementsof(unsupported) - 1; i++) {
604 printf("%c%s", got, unsupported[i]);
605 got = ',';
606 }
607 printf("\n");
608 }
609 if (catch) {
610 signal(SIGALRM, gotcha);
611 signal(SIGBUS, gotcha);
612 signal(SIGSEGV, gotcha);
613 }
614 path = pathbuf + 1;
615 pathmax = &path[elementsof(pathbuf)-1];
616 path[0] = 0;
617 work[cwd] = path;
618 work[cwd + 1] = 0;
619 work[cwd + 2] = 0;
620 ok = 0;
621 extra = 0;
622 while (p = buf = getline()) {
623
624 /* parse: */
625
626 if (*p == 0 || *p == '#')
627 continue;
628 if (*p == ':') {
629 while (*++p == ' ');
630 printf("NOTE %s\n", p);
631 continue;
632 }
633 if (*p == 'W') {
634 while (*++p == '\t');
635 if (*p) {
636 i = p - buf;
637 if (i > (cwd + 1) || i >= elementsof(work))
638 bad("invalid workspace depth\n", NiL);
639 if (working) {
640 working = 0;
641 cwd = 1;
642 if (chdir("../.."))
643 bad("cannot chdir\n", "../..");
644 else if (verbose)
645 printf("test %-3d chdir ../..\n", state.lineno);
646 }
647 if (i > cwd) {
648 if (path[0] && access(path, F_OK)) {
649 if (verbose) {
650 printf("test %-3d mkdir ", state.lineno);
651 quote(path);
652 printf("\n");
653 }
654 if (mkdir(path, 0755))
655 bad("cannot create work directory\n", path);
656 }
657 }
658 else {
659 if (access(path, F_OK)) {
660 if (k) {
661 if (verbose) {
662 printf("test %-3d link ", state.lineno);
663 quote(path);
664 printf(" ");
665 quote(k);
666 printf("\n");
667 }
668 if (symlink(k, path))
669 bad("cannot create work link\n", path);
670 k = 0;
671 }
672 else if (!streq(work[cwd - 1], ".")) {
673 if (verbose) {
674 printf("test %-3d file ", state.lineno);
675 quote(path);
676 printf("\n");
677 }
678 if (close(creat(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)))
679 bad("cannot create work file\n", path);
680 }
681 }
682 cwd = i - 1;
683 }
684 s = work[cwd];
685 *(s - 1) = '/';
686 k = 0;
687 while (s < pathmax && *p) {
688 if (*p == '\t') {
689 k = linkbuf;
690 while (k < &linkbuf[sizeof(linkbuf) - 1] && (*k = *++p))
691 k++;
692 *k = 0;
693 k = linkbuf;
694 break;
695 }
696 *s++ = *p++;
697 }
698 *s++ = 0;
699 work[cwd = i] = s;
700 }
701 continue;
702 }
703 if (work[2]) {
704 if (!streq(work[cwd-1], ".") && access(path, F_OK))
705 if (k) {
706 if (verbose) {
707 printf("test %-3d link ", state.lineno);
708 quote(path);
709 printf(" ");
710 quote(k);
711 printf("\n");
712 }
713 if (symlink(k, path))
714 bad("cannot create work link\n", path);
715 }
716 else {
717 if (verbose) {
718 printf("test %-3d file ", state.lineno);
719 quote(path);
720 printf("\n");
721 }
722 if (close(creat(path, S_IRUSR|S_IWUSR|S_IRGRP|S_IROTH)))
723 bad("cannot create work file\n", path);
724 }
725 *(work[2] - 1) = 0;
726 if (!working)
727 working = 1;
728 else if (chdir("../.."))
729 bad("cannot chdir\n", "../..");
730 else if (verbose)
731 printf("test %-3d chdir ..\n", state.lineno);
732 if (chdir(path))
733 bad("cannot chdir\n", path);
734 else if (verbose) {
735 printf("test %-3d chdir ", state.lineno);
736 quote(path);
737 printf("\n");
738 }
739 work[2] = 0;
740 }
741 #if GLOB_DISC
742 fignore[0] = 0;
743 #endif
744 i = 0;
745 field[i++] = p;
746 for (;;) {
747 switch (*p++) {
748 case 0:
749 p--;
750 goto checkfield;
751 case '\t':
752 *(p - 1) = 0;
753 checkfield:
754 s = field[i - 1];
755 if (streq(s, "NIL"))
756 field[i - 1] = 0;
757 else if (streq(s, "NULL"))
758 *s = 0;
759 while (*p == '\t')
760 p++;
761 if (!*p)
762 break;
763 if (i >= elementsof(field))
764 bad("too many fields\n", NiL);
765 field[i++] = p;
766 /*FALLTHROUGH*/
767 default:
768 continue;
769 }
770 break;
771 }
772 if (!(spec = field[0]))
773 bad("NIL spec\n", NiL);
774
775 /* interpret: */
776
777 flags = 0;
778 query = unspecified = kre = sre = 0;
779 for (p = spec; *p; p++) {
780 switch (*p) {
781 case 'C':
782 if (!query && !(skip & level))
783 bad("locale query expected\n", NiL);
784 query = 0;
785 if (locale)
786 bad("locale nesting not supported\n", NiL);
787 if (i != 2)
788 bad("locale field expected\n", NiL);
789 if (!(skip & level)) {
790 #if defined(LC_COLLATE) && defined(LC_CTYPE)
791 s = field[1];
792 if (!s || streq(s, "POSIX"))
793 s = "C";
794 if (!(ans = setlocale(LC_COLLATE, s)) || streq(ans, "C") || streq(ans, "POSIX") || !(ans = setlocale(LC_CTYPE, s)) || streq(ans, "C") || streq(ans, "POSIX"))
795 skip = note(level, skip, s);
796 else {
797 printf("NOTE \"%s\" locale\n", s);
798 locale = level;
799 }
800 #else
801 skip = note(level, skip, "locales not supported");
802 #endif
803 }
804 flags |= NOTEST;
805 continue;
806 case 'E':
807 flags |= GLOB_ERR;
808 continue;
809 case 'I':
810 #if GLOB_DISC
811 if (field[1])
812 strncpy(fignore, field[1], sizeof(fignore) - 1);
813 else
814 fignore[0] = 0;
815 #endif
816 flags |= NOTEST;
817 continue;
818 case 'K':
819 kre = 1;
820 continue;
821 case 'S':
822 sre = 1;
823 continue;
824
825 case 'a':
826 flags |= GLOB_APPEND;
827 continue;
828 case 'b':
829 flags |= GLOB_BRACE;
830 continue;
831 case 'c':
832 flags |= GLOB_COMPLETE;
833 continue;
834 case 'e':
835 flags |= GLOB_NOESCAPE;
836 continue;
837 case 'i':
838 flags |= GLOB_ICASE;
839 continue;
840 case 'm':
841 flags |= GLOB_MARK;
842 continue;
843 case 'n':
844 flags |= GLOB_NOCHECK;
845 continue;
846 case 'r':
847 flags |= GLOB_STARSTAR;
848 continue;
849 case 's':
850 flags |= GLOB_NOSORT;
851 continue;
852 case 'u':
853 unspecified = 1;
854 continue;
855
856 case 'x':
857 #if GLOB_VERSION >= 20060717L
858 extra = 15;
859 #endif
860 continue;
861
862 case '{':
863 level <<= 1;
864 if (skip & (level >> 1)) {
865 skip |= level;
866 flags |= NOTEST;
867 }
868 else {
869 skip &= ~level;
870 query = 1;
871 }
872 continue;
873 case '}':
874 if (level == 1)
875 bad("invalid {...} nesting\n", NiL);
876 else {
877 if ((skip & level) && !(skip & (level>>1)))
878 printf("-%d\n", state.lineno);
879 #if defined(LC_COLLATE) && defined(LC_CTYPE)
880 else if (locale & level) {
881 locale = 0;
882 if (!(skip & level)) {
883 s = "C";
884 setlocale(LC_COLLATE, s);
885 setlocale(LC_CTYPE, s);
886 printf("NOTE \"%s\" locale\n", s);
887 }
888 }
889 #endif
890 level >>= 1;
891 }
892 flags |= NOTEST;
893 continue;
894 default:
895 bad("bad spec\n", spec);
896 break;
897
898 }
899 break;
900 }
901 if (flags == NOTEST || !sre && !kre)
902 continue;
903 if (i < 3)
904 bad("too few fields\n", NiL);
905 if (skip & level)
906 continue;
907 while (i < elementsof(field))
908 field[i++] = 0;
909 if (pat = field[1])
910 escape(pat);
911 if (ans = field[3])
912 escape(ans);
913 okre = kre;
914 osre = sre;
915 for (m = 0; m < nmodes; m++) {
916 if (modes[m]) {
917 if ((flags & modes[m]) == modes[m])
918 continue;
919 flags |= modes[m];
920 }
921 err = field[2];
922 msg = field[4];
923 kre = okre;
924 sre = osre;
925 fflush(stdout);
926
927 /* execute: */
928
929 if (sre) {
930 state.which = "SRE";
931 sre = 0;
932 #ifdef GLOB_AUGMENTED
933 flags &= ~GLOB_AUGMENTED;
934 #endif
935 }
936 #ifdef GLOB_AUGMENTED
937 else if (kre) {
938 state.which = "KRE";
939 kre = 0;
940 flags |= GLOB_AUGMENTED;
941 }
942 #endif
943 else
944 continue;
945 if (!m && !query && verbose) {
946 printf("test %-3d ", state.lineno);
947 quote(pat);
948 printf("\n");
949 }
950 if (!ok || !(flags & GLOB_APPEND)) {
951 if (ok) {
952 ok = 0;
953 globfree(&gl);
954 }
955 memset(&gl, 0, sizeof(gl));
956 }
957 #if GLOB_DISC
958 if (fignore[0]) {
959 gl.gl_fignore = (const char*)fignore;
960 flags |= GLOB_DISC;
961 }
962 else
963 gl.gl_fignore = 0;
964 #if GLOB_VERSION >= 20060717L
965 if (gl.gl_extra = extra)
966 flags |= GLOB_DISC;
967 #endif
968 #endif
969 if (!query)
970 testno++;
971 if (catch) {
972 if (setjmp(state.gotcha))
973 ret = state.ret;
974 else {
975 alarm(LOOPED);
976 ret = glob(pat, flags, 0, &gl);
977 alarm(0);
978 }
979 }
980 else
981 ret = glob(pat, flags, 0, &gl);
982 if (ret == 0) {
983 ok = 1;
984 if (!gl.gl_pathc)
985 ret = GLOB_NOMATCH;
986 }
987 expected = got = 0;
988 for (i = 1; i < elementsof(codes); i++) {
989 if (streq(err, codes[i].name))
990 expected = i;
991 if (ret == codes[i].code)
992 got = i;
993 }
994 if (expected != got) {
995 if (query)
996 skip = note(level, skip, msg);
997 else if (state.ignore.error)
998 state.ignore.count++;
999 else {
1000 report("return failed: ", pat, msg, flags, unspecified);
1001 printf("%s expected, %s returned", codes[expected].name, codes[got].name);
1002 if (!ret)
1003 printf(" with %d match%s", gl.gl_pathc, gl.gl_pathc == 1 ? "" : "es");
1004 printf("\n");
1005 }
1006 }
1007 else if (ret != GLOB_NOMATCH) {
1008 #if GLOB_LIST
1009 if (flags & GLOB_LIST) {
1010 n = 0;
1011 for (gi = gl.gl_list; gi; gi = gi->gl_next) {
1012 if (n >= (elementsof(av) - 1))
1013 break;
1014 av[n++] = gi->gl_path + extra;
1015 }
1016 av[n] = 0;
1017 v = av;
1018 }
1019 else
1020 #endif
1021 {
1022 n = gl.gl_pathc;
1023 v = gl.gl_pathv;
1024 }
1025 if (verbose) {
1026 printf(" ");
1027 for (i = 0; i < n; i++)
1028 printf(" %s", v[i]);
1029 printf("\n");
1030 }
1031 if (flags & (GLOB_LIST|GLOB_NOSORT)) {
1032 qsort(v, n, sizeof(*v), qstrcmp);
1033 if ((flags & GLOB_STARSTAR) && !(gl.gl_flags & GLOB_STARSTAR))
1034 v[n = quniq(v, n)] = 0;
1035 }
1036 if (!ans)
1037 ans = "";
1038 bs = s = ans;
1039 bp = p = "";
1040 for (i = 0; i < n; i++) {
1041 bp = p = v[i];
1042 bs = s;
1043 while (*p == *s && *s && *s != ' ') {
1044 p++;
1045 s++;
1046 }
1047 if (*p || *s && *s != ' ')
1048 break;
1049 while (*s == ' ')
1050 s++;
1051 }
1052 if (*p || *s) {
1053 if (!*p && i >= n)
1054 bp = 0;
1055 if (!*s)
1056 bs = s = 0;
1057 else {
1058 while (*s && *s != ' ')
1059 s++;
1060 if (*s == ' ')
1061 *s = 0;
1062 else
1063 s = 0;
1064 }
1065 report("match failed: ", pat, msg, flags, unspecified);
1066 quote(bs);
1067 printf(" expected, ");
1068 quote(bp);
1069 printf(" returned\n");
1070 if (s)
1071 *s = 0;
1072 }
1073 }
1074 if (flags & GLOB_APPEND)
1075 break;
1076 flags &= ~modes[m];
1077 }
1078 }
1079 printf("TEST\t%s, %d test%s", unit, testno, testno == 1 ? "" : "s");
1080 if (state.ignore.count)
1081 printf(", %d ignored mismatche%s", state.ignore.count, state.ignore.count == 1 ? "" : "s");
1082 if (state.warnings)
1083 printf(", %d warning%s", state.warnings, state.warnings == 1 ? "" : "s");
1084 if (state.unspecified)
1085 printf(", %d unspecified difference%s", state.unspecified, state.unspecified == 1 ? "" : "s");
1086 if (state.signals)
1087 printf(", %d signal%s", state.signals, state.signals == 1 ? "" : "s");
1088 printf(", %d error%s\n", state.errors, state.errors == 1 ? "" : "s");
1089 return 0;
1090 }
1091