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 "\\*", "\\*", FNM_NOESCAPE, 0,
139 "\\?", "\\?", FNM_NOESCAPE, 0,
140 "\\", "\\", FNM_NOESCAPE, 0,
141 "\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH,
142 "\\\\", "\\\\", FNM_NOESCAPE, 0,
143 "*\\*", "foo\\foo", FNM_NOESCAPE, 0,
144 "*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH,
145 "*", ".", FNM_PERIOD, FNM_NOMATCH,
146 "?", ".", FNM_PERIOD, FNM_NOMATCH,
150 "[0-9]", ".", FNM_PERIOD, FNM_NOMATCH,
152 "a/a", "a/a", FNM_PATHNAME, 0,
153 "a/*", "a/a", FNM_PATHNAME, 0,
154 "*/a", "a/a", FNM_PATHNAME, 0,
155 "*/*", "a/a", FNM_PATHNAME, 0,
156 "a*b/*", "abbb/x", FNM_PATHNAME, 0,
157 "a*b/*", "abbb/.x", FNM_PATHNAME, 0,
158 "*", "a/a", FNM_PATHNAME, FNM_NOMATCH,
159 "*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH,
160 "b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
161 "b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
162 "b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
163 "b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
164 "a", "A", FNM_CASEFOLD, 0,
165 "A", "a", FNM_CASEFOLD, 0,
166 "[a]", "A", FNM_CASEFOLD, 0,
167 "[A]", "a", FNM_CASEFOLD, 0,
168 "a", "b", FNM_CASEFOLD, FNM_NOMATCH,
169 "a", "a/b", FNM_PATHNAME, FNM_NOMATCH,
170 "*", "a/b", FNM_PATHNAME, FNM_NOMATCH,
171 "*b", "a/b", FNM_PATHNAME, FNM_NOMATCH,
172 "a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
173 "*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
174 "*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
175 "*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
176 "*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
177 "*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
178 "a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
182 flags_to_string(int flags)
184 static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
185 FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
186 static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
187 static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
194 for (i = 0; flagvalues[i] != 0; i++) {
196 if (flags & flagvalues[i]) {
201 flags &= ~flagvalues[i];
208 sprintf(p, "%d", flags);
215 write_sh_tests(const char *progname, int num)
220 printf("# Generated by %s -s %d, do not edit.\n", progname, num);
221 printf("# $" "FreeBSD$\n");
222 printf("failures=\n");
223 printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
225 printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
226 printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
227 } else if (num == 2) {
228 printf("# We do not treat a backslash specially in this case,\n");
229 printf("# but this is not the case in all shells.\n");
230 printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
231 printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
233 n = sizeof(testcases) / sizeof(testcases[0]);
234 for (i = 0; i < n; i++) {
236 if (strchr(t->pattern, '\'') != NULL ||
237 strchr(t->string, '\'') != NULL)
239 if (num == 1 && t->flags == 0)
240 printf("test%smatch '%s' '%s'\n",
241 t->result == FNM_NOMATCH ? "no" : "",
242 t->pattern, t->string);
243 if (num == 2 && (t->flags == FNM_NOESCAPE ||
244 (t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
245 printf("netest%smatch '%s' '%s'\n",
246 t->result == FNM_NOMATCH ? "no" : "",
247 t->pattern, t->string);
249 printf("[ -z \"$failures\" ]\n");
254 main(int argc, char *argv[])
257 int opt, flags, result, extra, errors;
260 while ((opt = getopt(argc, argv, "s:")) != -1) {
263 return (write_sh_tests(argv[0], atoi(optarg)));
265 fprintf(stderr, "usage: %s [-s num]\n", argv[0]);
266 fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
270 n = sizeof(testcases) / sizeof(testcases[0]);
272 printf("1..%zu\n", n);
273 for (i = 0; i < n; i++) {
278 result = fnmatch(t->pattern, t->string, flags);
279 if (result != t->result)
281 if (strchr(t->pattern, '\\') == NULL &&
282 !(flags & FNM_NOESCAPE)) {
283 flags |= FNM_NOESCAPE;
284 result = fnmatch(t->pattern, t->string, flags);
285 if (result != t->result)
290 if (strchr(t->pattern, '\\') != NULL &&
291 strchr(t->string, '\\') == NULL &&
292 t->result == FNM_NOMATCH &&
293 !(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
294 flags |= FNM_NOESCAPE;
295 result = fnmatch(t->pattern, t->string, flags);
296 if (result != t->result)
301 if ((t->string[0] != '.' || t->pattern[0] == '.' ||
302 t->result == FNM_NOMATCH) &&
303 !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
305 result = fnmatch(t->pattern, t->string, flags);
306 if (result != t->result)
311 if ((strchr(t->string, '/') == NULL ||
312 t->result == FNM_NOMATCH) &&
313 !(flags & FNM_PATHNAME)) {
314 flags |= FNM_PATHNAME;
315 result = fnmatch(t->pattern, t->string, flags);
316 if (result != t->result)
321 if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
322 strstr(t->string, "/.") == NULL) ||
323 t->result == FNM_NOMATCH) &&
324 flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
326 result = fnmatch(t->pattern, t->string, flags);
327 if (result != t->result)
332 if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
333 strchr(t->string, '/') == NULL) ||
334 t->result == FNM_NOMATCH) &&
335 !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
336 flags |= FNM_PATHNAME | FNM_PERIOD;
337 result = fnmatch(t->pattern, t->string, flags);
338 if (result != t->result)
343 if ((strchr(t->string, '/') == NULL || t->result == 0)
344 && !(flags & FNM_LEADING_DIR)) {
345 flags |= FNM_LEADING_DIR;
346 result = fnmatch(t->pattern, t->string, flags);
347 if (result != t->result)
352 if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
353 flags |= FNM_CASEFOLD;
354 result = fnmatch(t->pattern, t->string, flags);
355 if (result != t->result)
360 if (strchr(t->pattern, '\\') == NULL &&
362 !(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
363 flags |= FNM_NOESCAPE | FNM_CASEFOLD;
364 result = fnmatch(t->pattern, t->string, flags);
365 if (result != t->result)
371 if (result == t->result)
372 printf("ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d (+%d)\n",
373 i + 1, t->pattern, t->string,
374 flags_to_string(flags),
377 printf("not ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d != %d\n",
378 i + 1, t->pattern, t->string,
379 flags_to_string(flags),