2 * Copyright (c) 2010 Jilles Tjoelker
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
45 "a", "b", 0, FNM_NOMATCH,
46 "a", "A", 0, FNM_NOMATCH,
50 "*a", "b", 0, FNM_NOMATCH,
51 "*a*", "b", 0, FNM_NOMATCH,
53 "*a*b*", "qaqbq", 0, 0,
54 "*a*bb*", "qaqbqbbq", 0, 0,
55 "*a*bc*", "qaqbqbcq", 0, 0,
56 "*a*bb*", "qaqbqbb", 0, 0,
57 "*a*bc*", "qaqbqbc", 0, 0,
58 "*a*bb", "qaqbqbb", 0, 0,
59 "*a*bc", "qaqbqbc", 0, 0,
60 "*a*bb", "qaqbqbbq", 0, FNM_NOMATCH,
61 "*a*bc", "qaqbqbcq", 0, FNM_NOMATCH,
62 "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH,
63 "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0,
64 "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0,
65 ".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH,
66 ".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0,
67 ".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0,
68 "*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH,
69 "??????????*", "123456789", 0, FNM_NOMATCH,
70 "*??????????", "123456789", 0, FNM_NOMATCH,
71 "*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0,
72 "??????????*", "1234567890", 0, 0,
73 "*??????????", "1234567890", 0, 0,
74 "*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0,
75 "??????????*", "12345678901", 0, 0,
76 "*??????????", "12345678901", 0, 0,
82 "[[]", "x", 0, FNM_NOMATCH,
83 "[*]", "", 0, FNM_NOMATCH,
84 "[*]", "x", 0, FNM_NOMATCH,
85 "[?]", "x", 0, FNM_NOMATCH,
86 "*[*]*", "foo*foo", 0, 0,
87 "*[*]*", "foo", 0, FNM_NOMATCH,
91 "[0-9]", "/", 0, FNM_NOMATCH,
92 "[0-9]", ":", 0, FNM_NOMATCH,
93 "[0-9]", "*", 0, FNM_NOMATCH,
94 "[!0-9]", "0", 0, FNM_NOMATCH,
95 "[!0-9]", "5", 0, FNM_NOMATCH,
96 "[!0-9]", "9", 0, FNM_NOMATCH,
100 "*[0-9]", "a0", 0, 0,
101 "*[0-9]", "a5", 0, 0,
102 "*[0-9]", "a9", 0, 0,
103 "*[0-9]", "a/", 0, FNM_NOMATCH,
104 "*[0-9]", "a:", 0, FNM_NOMATCH,
105 "*[0-9]", "a*", 0, FNM_NOMATCH,
106 "*[!0-9]", "a0", 0, FNM_NOMATCH,
107 "*[!0-9]", "a5", 0, FNM_NOMATCH,
108 "*[!0-9]", "a9", 0, FNM_NOMATCH,
109 "*[!0-9]", "a/", 0, 0,
110 "*[!0-9]", "a:", 0, 0,
111 "*[!0-9]", "a*", 0, 0,
112 "*[0-9]", "a00", 0, 0,
113 "*[0-9]", "a55", 0, 0,
114 "*[0-9]", "a99", 0, 0,
115 "*[0-9]", "a0a0", 0, 0,
116 "*[0-9]", "a5a5", 0, 0,
117 "*[0-9]", "a9a9", 0, 0,
120 "\\[x]", "[x]", 0, 0,
123 "*\\**", "foo*foo", 0, 0,
124 "*\\**", "foo", 0, FNM_NOMATCH,
125 "*\\\\*", "foo\\foo", 0, 0,
126 "*\\\\*", "foo", 0, FNM_NOMATCH,
129 "\\*", "a", 0, FNM_NOMATCH,
130 "\\?", "a", 0, FNM_NOMATCH,
131 "\\*", "\\*", 0, FNM_NOMATCH,
132 "\\?", "\\?", 0, FNM_NOMATCH,
133 "\\[x]", "\\[x]", 0, FNM_NOMATCH,
134 "\\[x]", "\\x", 0, FNM_NOMATCH,
135 "\\[", "\\[", 0, FNM_NOMATCH,
136 "\\(", "\\(", 0, FNM_NOMATCH,
137 "\\a", "\\a", 0, FNM_NOMATCH,
138 "\\", "\\", 0, FNM_NOMATCH,
140 "\\*", "\\*", FNM_NOESCAPE, 0,
141 "\\?", "\\?", FNM_NOESCAPE, 0,
142 "\\", "\\", FNM_NOESCAPE, 0,
143 "\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH,
144 "\\\\", "\\\\", FNM_NOESCAPE, 0,
145 "*\\*", "foo\\foo", FNM_NOESCAPE, 0,
146 "*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH,
147 "*", ".", FNM_PERIOD, FNM_NOMATCH,
148 "?", ".", FNM_PERIOD, FNM_NOMATCH,
152 "[0-9]", ".", FNM_PERIOD, FNM_NOMATCH,
154 "a/a", "a/a", FNM_PATHNAME, 0,
155 "a/*", "a/a", FNM_PATHNAME, 0,
156 "*/a", "a/a", FNM_PATHNAME, 0,
157 "*/*", "a/a", FNM_PATHNAME, 0,
158 "a*b/*", "abbb/x", FNM_PATHNAME, 0,
159 "a*b/*", "abbb/.x", FNM_PATHNAME, 0,
160 "*", "a/a", FNM_PATHNAME, FNM_NOMATCH,
161 "*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH,
162 "b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
163 "b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
164 "b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
165 "b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
166 "a", "A", FNM_CASEFOLD, 0,
167 "A", "a", FNM_CASEFOLD, 0,
168 "[a]", "A", FNM_CASEFOLD, 0,
169 "[A]", "a", FNM_CASEFOLD, 0,
170 "a", "b", FNM_CASEFOLD, FNM_NOMATCH,
171 "a", "a/b", FNM_PATHNAME, FNM_NOMATCH,
172 "*", "a/b", FNM_PATHNAME, FNM_NOMATCH,
173 "*b", "a/b", FNM_PATHNAME, FNM_NOMATCH,
174 "a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
175 "*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
176 "*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
177 "*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
178 "*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
179 "*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
180 "a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
184 flags_to_string(int flags)
186 static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
187 FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
188 static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
189 static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
196 for (i = 0; flagvalues[i] != 0; i++) {
198 if (flags & flagvalues[i]) {
203 flags &= ~flagvalues[i];
210 sprintf(p, "%d", flags);
217 write_sh_tests(const char *progname, int num)
222 printf("# Generated by %s -s %d, do not edit.\n", progname, num);
223 printf("# $" "FreeBSD$\n");
224 printf("failures=\n");
225 printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
227 printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
228 printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
229 } else if (num == 2) {
230 printf("# We do not treat a backslash specially in this case,\n");
231 printf("# but this is not the case in all shells.\n");
232 printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
233 printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
235 n = sizeof(testcases) / sizeof(testcases[0]);
236 for (i = 0; i < n; i++) {
238 if (strchr(t->pattern, '\'') != NULL ||
239 strchr(t->string, '\'') != NULL)
241 if (t->flags == 0 && strcmp(t->pattern, "\\") == 0)
243 if (num == 1 && t->flags == 0)
244 printf("test%smatch '%s' '%s'\n",
245 t->result == FNM_NOMATCH ? "no" : "",
246 t->pattern, t->string);
247 if (num == 2 && (t->flags == FNM_NOESCAPE ||
248 (t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
249 printf("netest%smatch '%s' '%s'\n",
250 t->result == FNM_NOMATCH ? "no" : "",
251 t->pattern, t->string);
253 printf("[ -z \"$failures\" ]\n");
258 main(int argc, char *argv[])
261 int opt, flags, result, extra, errors;
264 while ((opt = getopt(argc, argv, "s:")) != -1) {
267 return (write_sh_tests(argv[0], atoi(optarg)));
269 fprintf(stderr, "usage: %s [-s num]\n", argv[0]);
270 fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
274 n = sizeof(testcases) / sizeof(testcases[0]);
276 printf("1..%zu\n", n);
277 for (i = 0; i < n; i++) {
282 result = fnmatch(t->pattern, t->string, flags);
283 if (result != t->result)
285 if (strchr(t->pattern, '\\') == NULL &&
286 !(flags & FNM_NOESCAPE)) {
287 flags |= FNM_NOESCAPE;
288 result = fnmatch(t->pattern, t->string, flags);
289 if (result != t->result)
294 if (strchr(t->pattern, '\\') != NULL &&
295 strchr(t->string, '\\') == NULL &&
296 t->result == FNM_NOMATCH &&
297 !(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
298 flags |= FNM_NOESCAPE;
299 result = fnmatch(t->pattern, t->string, flags);
300 if (result != t->result)
305 if ((t->string[0] != '.' || t->pattern[0] == '.' ||
306 t->result == FNM_NOMATCH) &&
307 !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
309 result = fnmatch(t->pattern, t->string, flags);
310 if (result != t->result)
315 if ((strchr(t->string, '/') == NULL ||
316 t->result == FNM_NOMATCH) &&
317 !(flags & FNM_PATHNAME)) {
318 flags |= FNM_PATHNAME;
319 result = fnmatch(t->pattern, t->string, flags);
320 if (result != t->result)
325 if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
326 strstr(t->string, "/.") == NULL) ||
327 t->result == FNM_NOMATCH) &&
328 flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
330 result = fnmatch(t->pattern, t->string, flags);
331 if (result != t->result)
336 if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
337 strchr(t->string, '/') == NULL) ||
338 t->result == FNM_NOMATCH) &&
339 !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
340 flags |= FNM_PATHNAME | FNM_PERIOD;
341 result = fnmatch(t->pattern, t->string, flags);
342 if (result != t->result)
347 if ((strchr(t->string, '/') == NULL || t->result == 0)
348 && !(flags & FNM_LEADING_DIR)) {
349 flags |= FNM_LEADING_DIR;
350 result = fnmatch(t->pattern, t->string, flags);
351 if (result != t->result)
356 if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
357 flags |= FNM_CASEFOLD;
358 result = fnmatch(t->pattern, t->string, flags);
359 if (result != t->result)
364 if (strchr(t->pattern, '\\') == NULL &&
366 !(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
367 flags |= FNM_NOESCAPE | FNM_CASEFOLD;
368 result = fnmatch(t->pattern, t->string, flags);
369 if (result != t->result)
375 if (result == t->result)
376 printf("ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d (+%d)\n",
377 i + 1, t->pattern, t->string,
378 flags_to_string(flags),
381 printf("not ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d != %d\n",
382 i + 1, t->pattern, t->string,
383 flags_to_string(flags),