70de67caf120add1a5fc25fb8d98e0e1a09cdeba
[debian/sudo] / compat / regress / glob / globtest.c
1 /*      $OpenBSD: globtest.c,v 1.1 2008/10/01 23:04:36 millert Exp $    */
2
3 /*
4  * Public domain, 2008, Todd C. Miller <Todd.Miller@courtesan.com>
5  */
6
7 #include <config.h>
8
9 #include <stdio.h>
10 #include <stdlib.h>
11 #ifdef HAVE_STRING_H
12 # include <string.h>
13 #endif /* HAVE_STRING_H */
14 #ifdef HAVE_STRINGS_H
15 # include <strings.h>
16 #endif /* HAVE_STRINGS_H */
17 #ifdef HAVE_EXTENDED_GLOB
18 # include <glob.h>
19 #else
20 # include "compat/glob.h"
21 #endif
22 #include <errno.h>
23
24 #include "missing.h"
25
26 #define MAX_RESULTS     256
27
28 struct gl_entry {
29         int flags;
30         int nresults;
31         char pattern[1024];
32         char *results[MAX_RESULTS];
33 };
34
35 int test_glob(struct gl_entry *);
36
37 int
38 main(int argc, char **argv)
39 {
40         FILE *fp = stdin;
41         char buf[2048], *cp, *ep;
42         int errors = 0, tests = 0, lineno;
43         struct gl_entry entry;
44         size_t len;
45
46         if (argc > 1) {
47                 if ((fp = fopen(argv[1], "r")) == NULL) {
48                         perror(argv[1]);
49                         exit(1);
50                 }
51         }
52
53         /*
54          * Read in test file, which is formatted thusly:
55          *
56          * [pattern] <flags>
57          * result1
58          * result2
59          * result3
60          * ...
61          *
62          */
63         lineno = 0;
64         memset(&entry, 0, sizeof(entry));
65         while (fgets(buf, sizeof(buf), fp) != NULL) {
66                 lineno++;
67                 len = strlen(buf);
68                 if (len > 0) {
69                         if (buf[len - 1] != '\n') {
70                                 fprintf(stderr,
71                                     "globtest: missing newline at EOF\n");
72                                 exit(1);
73                         }
74                         buf[--len] = '\0';
75                 }
76                 if (len == 0)
77                         continue; /* blank line */
78
79                 if (buf[0] == '[') {
80                         /* check previous pattern */
81                         if (entry.pattern[0]) {
82                                 errors += test_glob(&entry);
83                                 tests++;
84                         }
85
86                         /* start new entry */
87                         if ((cp = strrchr(buf + 1, ']')) == NULL) {
88                                 fprintf(stderr,
89                                     "globtest: invalid entry on line %d\n",
90                                     lineno);
91                                 exit(1);
92                         }
93                         len = cp - buf - 1;
94                         if (len >= sizeof(entry.pattern)) {
95                                 fprintf(stderr,
96                                     "globtest: pattern too big on line %d\n",
97                                     lineno);
98                                 exit(1);
99                         }
100                         memcpy(entry.pattern, buf + 1, len);
101                         entry.pattern[len] = '\0';
102
103                         cp += 2;
104                         if (*cp++ != '<') {
105                                 fprintf(stderr,
106                                     "globtest: invalid entry on line %d\n",
107                                     lineno);
108                                 exit(1);
109                         }
110                         ep = strchr(cp, '>');
111                         if (ep == NULL) {
112                                 fprintf(stderr,
113                                     "globtest: invalid entry on line %d\n",
114                                     lineno);
115                                 exit(1);
116                         }
117                         *ep = '\0';
118                         entry.flags = 0;
119                         for ((cp = strtok(cp, "|")); cp != NULL; (cp = strtok(NULL, "|"))) {
120                                 if (strcmp(cp, "GLOB_APPEND") == 0)
121                                         entry.flags |= GLOB_APPEND;
122                                 else if (strcmp(cp, "GLOB_DOOFFS") == 0)
123                                         entry.flags |= GLOB_DOOFFS;
124                                 else if (strcmp(cp, "GLOB_ERR") == 0)
125                                         entry.flags |= GLOB_ERR;
126                                 else if (strcmp(cp, "GLOB_MARK") == 0)
127                                         entry.flags |= GLOB_MARK;
128                                 else if (strcmp(cp, "GLOB_NOCHECK") == 0)
129                                         entry.flags |= GLOB_NOCHECK;
130                                 else if (strcmp(cp, "GLOB_NOSORT") == 0)
131                                         entry.flags |= GLOB_NOSORT;
132                                 else if (strcmp(cp, "GLOB_NOESCAPE") == 0)
133                                         entry.flags |= GLOB_NOESCAPE;
134                                 else if (strcmp(cp, "GLOB_BRACE") == 0)
135                                         entry.flags |= GLOB_BRACE;
136                                 else if (strcmp(cp, "GLOB_TILDE") == 0)
137                                         entry.flags |= GLOB_TILDE;
138                                 else if (strcmp(cp, "NONE") != 0) {
139                                         fprintf(stderr,
140                                             "globtest: invalid flags on line %d\n",
141                                             lineno);
142                                         exit(1);
143                                 }
144                         }
145                         entry.nresults = 0;
146                         continue;
147                 }
148                 if (!entry.pattern[0]) {
149                         fprintf(stderr, "globtest: missing entry on line %d\n",
150                             lineno);
151                         exit(1);
152                 }
153
154                 if (entry.nresults + 1 > MAX_RESULTS) {
155                         fprintf(stderr,
156                             "globtest: too many results for %s, max %d\n",
157                             entry.pattern, MAX_RESULTS);
158                         exit(1);
159                 }
160                 entry.results[entry.nresults++] = strdup(buf);
161         }
162         if (entry.pattern[0]) {
163                 errors += test_glob(&entry); /* test last pattern */
164                 tests++;
165         }
166         if (tests != 0) {
167                 printf("glob: %d test%s run, %d errors, %d%% success rate\n",
168                     tests, tests == 1 ? "" : "s", errors,
169                     (tests - errors) * 100 / tests);
170         }
171         exit(errors);
172 }
173
174 int test_glob(struct gl_entry *entry)
175 {
176         glob_t gl;
177         char **ap;
178         int nmatches = 0, i = 0;
179
180         if (glob(entry->pattern, entry->flags, NULL, &gl) != 0) {
181                 fprintf(stderr, "glob failed: %s: %s\n", entry->pattern,
182                     strerror(errno));
183                 exit(1);
184         }
185
186         for (ap = gl.gl_pathv; *ap != NULL; ap++)
187                 nmatches++;
188
189         if (nmatches != entry->nresults)
190                 goto mismatch;
191
192         for (i = 0; i < entry->nresults; i++) {
193                 if (strcmp(gl.gl_pathv[i], entry->results[i]) != 0)
194                         goto mismatch;
195                 free(entry->results[i]);
196         }
197         return 0;
198  mismatch:
199         if (nmatches != entry->nresults) {
200                 fprintf(stderr,
201                     "globtest: mismatch in number of results (found %d, expected %d) for pattern %s\n",
202                     nmatches, entry->nresults, entry->pattern);
203         } else {
204                 fprintf(stderr, "globtest: mismatch for pattern %s, flags 0x%x "
205                     "(found \"%s\", expected \"%s\")\n", entry->pattern, entry->flags,
206                     gl.gl_pathv[i], entry->results[i]);
207                 while (i < entry->nresults)
208                         free(entry->results[i++]);
209         }
210         return 1;
211 }