1206710Sjilles/*-
2206710Sjilles * Copyright (c) 2010 Jilles Tjoelker
3206710Sjilles * All rights reserved.
4206710Sjilles *
5206710Sjilles * Redistribution and use in source and binary forms, with or without
6206710Sjilles * modification, are permitted provided that the following conditions
7206710Sjilles * are met:
8206710Sjilles * 1. Redistributions of source code must retain the above copyright
9206710Sjilles *    notice, this list of conditions and the following disclaimer.
10206710Sjilles * 2. Redistributions in binary form must reproduce the above copyright
11206710Sjilles *    notice, this list of conditions and the following disclaimer in the
12206710Sjilles *    documentation and/or other materials provided with the distribution.
13206710Sjilles *
14206710Sjilles * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15206710Sjilles * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16206710Sjilles * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17206710Sjilles * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18206710Sjilles * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19206710Sjilles * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20206710Sjilles * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21206710Sjilles * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22206710Sjilles * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23206710Sjilles * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24206710Sjilles * SUCH DAMAGE.
25206710Sjilles */
26206710Sjilles
27206710Sjilles#include <sys/cdefs.h>
28206710Sjilles__FBSDID("$FreeBSD$");
29206710Sjilles
30206710Sjilles#include <errno.h>
31206710Sjilles#include <stdio.h>
32206710Sjilles#include <stdlib.h>
33206710Sjilles#include <string.h>
34207821Sjilles#include <unistd.h>
35206710Sjilles#include <fnmatch.h>
36206710Sjilles
37206710Sjillesstruct testcase {
38206710Sjilles	const char *pattern;
39206710Sjilles	const char *string;
40206710Sjilles	int flags;
41206710Sjilles	int result;
42206710Sjilles} testcases[] = {
43206710Sjilles	"", "", 0, 0,
44206710Sjilles	"a", "a", 0, 0,
45206710Sjilles	"a", "b", 0, FNM_NOMATCH,
46206710Sjilles	"a", "A", 0, FNM_NOMATCH,
47206710Sjilles	"*", "a", 0, 0,
48206710Sjilles	"*", "aa", 0, 0,
49206710Sjilles	"*a", "a", 0, 0,
50206710Sjilles	"*a", "b", 0, FNM_NOMATCH,
51206710Sjilles	"*a*", "b", 0, FNM_NOMATCH,
52206710Sjilles	"*a*b*", "ab", 0, 0,
53206710Sjilles	"*a*b*", "qaqbq", 0, 0,
54206710Sjilles	"*a*bb*", "qaqbqbbq", 0, 0,
55206710Sjilles	"*a*bc*", "qaqbqbcq", 0, 0,
56206710Sjilles	"*a*bb*", "qaqbqbb", 0, 0,
57206710Sjilles	"*a*bc*", "qaqbqbc", 0, 0,
58206710Sjilles	"*a*bb", "qaqbqbb", 0, 0,
59206710Sjilles	"*a*bc", "qaqbqbc", 0, 0,
60206710Sjilles	"*a*bb", "qaqbqbbq", 0, FNM_NOMATCH,
61206710Sjilles	"*a*bc", "qaqbqbcq", 0, FNM_NOMATCH,
62206710Sjilles	"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH,
63206710Sjilles	"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0,
64206710Sjilles	"*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0,
65206710Sjilles	".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH,
66206710Sjilles	".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0,
67206710Sjilles	".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0,
68206710Sjilles	"*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH,
69206710Sjilles	"??????????*", "123456789", 0, FNM_NOMATCH,
70206710Sjilles	"*??????????", "123456789", 0, FNM_NOMATCH,
71206710Sjilles	"*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0,
72206710Sjilles	"??????????*", "1234567890", 0, 0,
73206710Sjilles	"*??????????", "1234567890", 0, 0,
74206710Sjilles	"*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0,
75206710Sjilles	"??????????*", "12345678901", 0, 0,
76206710Sjilles	"*??????????", "12345678901", 0, 0,
77206710Sjilles	"[x]", "x", 0, 0,
78206710Sjilles	"[*]", "*", 0, 0,
79206710Sjilles	"[?]", "?", 0, 0,
80206710Sjilles	"[", "[", 0, 0,
81206710Sjilles	"[[]", "[", 0, 0,
82206710Sjilles	"[[]", "x", 0, FNM_NOMATCH,
83206710Sjilles	"[*]", "", 0, FNM_NOMATCH,
84206710Sjilles	"[*]", "x", 0, FNM_NOMATCH,
85206710Sjilles	"[?]", "x", 0, FNM_NOMATCH,
86206710Sjilles	"*[*]*", "foo*foo", 0, 0,
87206710Sjilles	"*[*]*", "foo", 0, FNM_NOMATCH,
88206710Sjilles	"[0-9]", "0", 0, 0,
89206710Sjilles	"[0-9]", "5", 0, 0,
90206710Sjilles	"[0-9]", "9", 0, 0,
91206710Sjilles	"[0-9]", "/", 0, FNM_NOMATCH,
92206710Sjilles	"[0-9]", ":", 0, FNM_NOMATCH,
93206710Sjilles	"[0-9]", "*", 0, FNM_NOMATCH,
94206710Sjilles	"[!0-9]", "0", 0, FNM_NOMATCH,
95206710Sjilles	"[!0-9]", "5", 0, FNM_NOMATCH,
96206710Sjilles	"[!0-9]", "9", 0, FNM_NOMATCH,
97206710Sjilles	"[!0-9]", "/", 0, 0,
98206710Sjilles	"[!0-9]", ":", 0, 0,
99206710Sjilles	"[!0-9]", "*", 0, 0,
100206710Sjilles	"*[0-9]", "a0", 0, 0,
101206710Sjilles	"*[0-9]", "a5", 0, 0,
102206710Sjilles	"*[0-9]", "a9", 0, 0,
103206710Sjilles	"*[0-9]", "a/", 0, FNM_NOMATCH,
104206710Sjilles	"*[0-9]", "a:", 0, FNM_NOMATCH,
105206710Sjilles	"*[0-9]", "a*", 0, FNM_NOMATCH,
106206710Sjilles	"*[!0-9]", "a0", 0, FNM_NOMATCH,
107206710Sjilles	"*[!0-9]", "a5", 0, FNM_NOMATCH,
108206710Sjilles	"*[!0-9]", "a9", 0, FNM_NOMATCH,
109206710Sjilles	"*[!0-9]", "a/", 0, 0,
110206710Sjilles	"*[!0-9]", "a:", 0, 0,
111206710Sjilles	"*[!0-9]", "a*", 0, 0,
112206710Sjilles	"*[0-9]", "a00", 0, 0,
113206710Sjilles	"*[0-9]", "a55", 0, 0,
114206710Sjilles	"*[0-9]", "a99", 0, 0,
115206710Sjilles	"*[0-9]", "a0a0", 0, 0,
116206710Sjilles	"*[0-9]", "a5a5", 0, 0,
117206710Sjilles	"*[0-9]", "a9a9", 0, 0,
118206710Sjilles	"\\*", "*", 0, 0,
119206710Sjilles	"\\?", "?", 0, 0,
120206710Sjilles	"\\[x]", "[x]", 0, 0,
121206710Sjilles	"\\[", "[", 0, 0,
122206710Sjilles	"\\\\", "\\", 0, 0,
123206710Sjilles	"*\\**", "foo*foo", 0, 0,
124206710Sjilles	"*\\**", "foo", 0, FNM_NOMATCH,
125206710Sjilles	"*\\\\*", "foo\\foo", 0, 0,
126206710Sjilles	"*\\\\*", "foo", 0, FNM_NOMATCH,
127206710Sjilles	"\\(", "(", 0, 0,
128206710Sjilles	"\\a", "a", 0, 0,
129206710Sjilles	"\\*", "a", 0, FNM_NOMATCH,
130206710Sjilles	"\\?", "a", 0, FNM_NOMATCH,
131206710Sjilles	"\\*", "\\*", 0, FNM_NOMATCH,
132206710Sjilles	"\\?", "\\?", 0, FNM_NOMATCH,
133206710Sjilles	"\\[x]", "\\[x]", 0, FNM_NOMATCH,
134206710Sjilles	"\\[x]", "\\x", 0, FNM_NOMATCH,
135206710Sjilles	"\\[", "\\[", 0, FNM_NOMATCH,
136206710Sjilles	"\\(", "\\(", 0, FNM_NOMATCH,
137206710Sjilles	"\\a", "\\a", 0, FNM_NOMATCH,
138254231Sjilles	"\\", "\\", 0, FNM_NOMATCH,
139254231Sjilles	"\\", "", 0, 0,
140206710Sjilles	"\\*", "\\*", FNM_NOESCAPE, 0,
141206710Sjilles	"\\?", "\\?", FNM_NOESCAPE, 0,
142206710Sjilles	"\\", "\\", FNM_NOESCAPE, 0,
143206710Sjilles	"\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH,
144206710Sjilles	"\\\\", "\\\\", FNM_NOESCAPE, 0,
145206710Sjilles	"*\\*", "foo\\foo", FNM_NOESCAPE, 0,
146206710Sjilles	"*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH,
147206710Sjilles	"*", ".", FNM_PERIOD, FNM_NOMATCH,
148206710Sjilles	"?", ".", FNM_PERIOD, FNM_NOMATCH,
149206710Sjilles	".*", ".", 0, 0,
150206710Sjilles	".*", "..", 0, 0,
151206710Sjilles	".*", ".a", 0, 0,
152206710Sjilles	"[0-9]", ".", FNM_PERIOD, FNM_NOMATCH,
153206710Sjilles	"a*", "a.", 0, 0,
154206710Sjilles	"a/a", "a/a", FNM_PATHNAME, 0,
155206710Sjilles	"a/*", "a/a", FNM_PATHNAME, 0,
156206710Sjilles	"*/a", "a/a", FNM_PATHNAME, 0,
157206710Sjilles	"*/*", "a/a", FNM_PATHNAME, 0,
158206710Sjilles	"a*b/*", "abbb/x", FNM_PATHNAME, 0,
159206710Sjilles	"a*b/*", "abbb/.x", FNM_PATHNAME, 0,
160206710Sjilles	"*", "a/a", FNM_PATHNAME, FNM_NOMATCH,
161206710Sjilles	"*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH,
162206710Sjilles	"b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
163206710Sjilles	"b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
164206710Sjilles	"b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
165206710Sjilles	"b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0,
166206710Sjilles	"a", "A", FNM_CASEFOLD, 0,
167206710Sjilles	"A", "a", FNM_CASEFOLD, 0,
168206710Sjilles	"[a]", "A", FNM_CASEFOLD, 0,
169206710Sjilles	"[A]", "a", FNM_CASEFOLD, 0,
170206710Sjilles	"a", "b", FNM_CASEFOLD, FNM_NOMATCH,
171206710Sjilles	"a", "a/b", FNM_PATHNAME, FNM_NOMATCH,
172206710Sjilles	"*", "a/b", FNM_PATHNAME, FNM_NOMATCH,
173206710Sjilles	"*b", "a/b", FNM_PATHNAME, FNM_NOMATCH,
174206710Sjilles	"a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
175206710Sjilles	"*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
176206710Sjilles	"*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
177206710Sjilles	"*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0,
178206710Sjilles	"*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
179206710Sjilles	"*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH,
180206711Sjilles	"a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH,
181206710Sjilles};
182206710Sjilles
183206710Sjillesstatic const char *
184206710Sjillesflags_to_string(int flags)
185206710Sjilles{
186206710Sjilles	static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME,
187206710Sjilles		FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 };
188206710Sjilles	static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
189206710Sjilles	static char result[sizeof(flagnames) + 3 * sizeof(int) + 2];
190206710Sjilles	char *p;
191206710Sjilles	size_t i, len;
192206710Sjilles	const char *fp;
193206710Sjilles
194206710Sjilles	p = result;
195206710Sjilles	fp = flagnames;
196206710Sjilles	for (i = 0; flagvalues[i] != 0; i++) {
197206710Sjilles		len = strlen(fp);
198206710Sjilles		if (flags & flagvalues[i]) {
199206710Sjilles			if (p != result)
200206710Sjilles				*p++ = '|';
201206710Sjilles			memcpy(p, fp, len);
202206710Sjilles			p += len;
203206710Sjilles			flags &= ~flagvalues[i];
204206710Sjilles		}
205206710Sjilles		fp += len + 1;
206206710Sjilles	}
207206710Sjilles	if (p == result)
208206710Sjilles		memcpy(p, "0", 2);
209206710Sjilles	else if (flags != 0)
210206710Sjilles		sprintf(p, "%d", flags);
211206710Sjilles	else
212206710Sjilles		*p = '\0';
213206710Sjilles	return result;
214206710Sjilles}
215206710Sjilles
216207821Sjillesstatic int
217207821Sjilleswrite_sh_tests(const char *progname, int num)
218207821Sjilles{
219207821Sjilles	size_t i, n;
220207821Sjilles	struct testcase *t;
221207821Sjilles
222207821Sjilles	printf("# Generated by %s -s %d, do not edit.\n", progname, num);
223207821Sjilles	printf("# $" "FreeBSD$\n");
224207821Sjilles	printf("failures=\n");
225207821Sjilles	printf("failed() { printf '%%s\\n' \"Failed: $1 '$2' '$3'\"; failures=x$failures; }\n");
226207821Sjilles	if (num == 1) {
227207821Sjilles		printf("testmatch() { eval \"case \\$2 in ''$1) ;; *) failed testmatch \\\"\\$@\\\";; esac\"; }\n");
228207821Sjilles		printf("testnomatch() { eval \"case \\$2 in ''$1) failed testnomatch \\\"\\$@\\\";; esac\"; }\n");
229207821Sjilles	} else if (num == 2) {
230207821Sjilles		printf("# We do not treat a backslash specially in this case,\n");
231207821Sjilles		printf("# but this is not the case in all shells.\n");
232207821Sjilles		printf("netestmatch() { case $2 in $1) ;; *) failed netestmatch \"$@\";; esac; }\n");
233207821Sjilles		printf("netestnomatch() { case $2 in $1) failed netestnomatch \"$@\";; esac; }\n");
234207821Sjilles	}
235207821Sjilles	n = sizeof(testcases) / sizeof(testcases[0]);
236207821Sjilles	for (i = 0; i < n; i++) {
237207821Sjilles		t = &testcases[i];
238207821Sjilles		if (strchr(t->pattern, '\'') != NULL ||
239207821Sjilles		    strchr(t->string, '\'') != NULL)
240207821Sjilles			continue;
241254231Sjilles		if (t->flags == 0 && strcmp(t->pattern, "\\") == 0)
242254231Sjilles			continue;
243207821Sjilles		if (num == 1 && t->flags == 0)
244207821Sjilles			printf("test%smatch '%s' '%s'\n",
245207821Sjilles			    t->result == FNM_NOMATCH ? "no" : "",
246207821Sjilles			    t->pattern, t->string);
247207821Sjilles		if (num == 2 && (t->flags == FNM_NOESCAPE ||
248207821Sjilles		    (t->flags == 0 && strchr(t->pattern, '\\') == NULL)))
249207821Sjilles			printf("netest%smatch '%s' '%s'\n",
250207821Sjilles			    t->result == FNM_NOMATCH ? "no" : "",
251207821Sjilles			    t->pattern, t->string);
252207821Sjilles	}
253207821Sjilles	printf("[ -z \"$failures\" ]\n");
254207821Sjilles	return 0;
255207821Sjilles}
256207821Sjilles
257206710Sjillesint
258206710Sjillesmain(int argc, char *argv[])
259206710Sjilles{
260206710Sjilles	size_t i, n;
261207821Sjilles	int opt, flags, result, extra, errors;
262206710Sjilles	struct testcase *t;
263206710Sjilles
264207821Sjilles	while ((opt = getopt(argc, argv, "s:")) != -1) {
265207821Sjilles		switch (opt) {
266207821Sjilles			case 's':
267207821Sjilles				return (write_sh_tests(argv[0], atoi(optarg)));
268207821Sjilles			default:
269207821Sjilles				fprintf(stderr, "usage: %s [-s num]\n", argv[0]);
270207821Sjilles				fprintf(stderr, "-s option writes tests for sh(1), num is 1 or 2\n");
271207821Sjilles				exit(1);
272207821Sjilles		}
273207821Sjilles	}
274206710Sjilles	n = sizeof(testcases) / sizeof(testcases[0]);
275206710Sjilles	errors = 0;
276206710Sjilles	printf("1..%zu\n", n);
277206710Sjilles	for (i = 0; i < n; i++) {
278206710Sjilles		t = &testcases[i];
279206710Sjilles		flags = t->flags;
280206710Sjilles		extra = 0;
281206710Sjilles		do {
282206710Sjilles			result = fnmatch(t->pattern, t->string, flags);
283206710Sjilles			if (result != t->result)
284206710Sjilles				break;
285206710Sjilles			if (strchr(t->pattern, '\\') == NULL &&
286206710Sjilles			    !(flags & FNM_NOESCAPE)) {
287206710Sjilles				flags |= FNM_NOESCAPE;
288206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
289206710Sjilles				if (result != t->result)
290206710Sjilles					break;
291206710Sjilles				flags = t->flags;
292206710Sjilles				extra++;
293206710Sjilles			}
294206710Sjilles			if (strchr(t->pattern, '\\') != NULL &&
295206710Sjilles			    strchr(t->string, '\\') == NULL &&
296206710Sjilles			    t->result == FNM_NOMATCH &&
297206710Sjilles			    !(flags & (FNM_NOESCAPE | FNM_LEADING_DIR))) {
298206710Sjilles				flags |= FNM_NOESCAPE;
299206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
300206710Sjilles				if (result != t->result)
301206710Sjilles					break;
302206710Sjilles				flags = t->flags;
303206710Sjilles				extra++;
304206710Sjilles			}
305206710Sjilles			if ((t->string[0] != '.' || t->pattern[0] == '.' ||
306206710Sjilles			    t->result == FNM_NOMATCH) &&
307206710Sjilles			    !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
308206710Sjilles				flags |= FNM_PERIOD;
309206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
310206710Sjilles				if (result != t->result)
311206710Sjilles					break;
312206710Sjilles				flags = t->flags;
313206710Sjilles				extra++;
314206710Sjilles			}
315206710Sjilles			if ((strchr(t->string, '/') == NULL ||
316206710Sjilles			    t->result == FNM_NOMATCH) &&
317206710Sjilles			    !(flags & FNM_PATHNAME)) {
318206710Sjilles				flags |= FNM_PATHNAME;
319206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
320206710Sjilles				if (result != t->result)
321206710Sjilles					break;
322206710Sjilles				flags = t->flags;
323206710Sjilles				extra++;
324206710Sjilles			}
325206710Sjilles			if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
326206710Sjilles			    strstr(t->string, "/.") == NULL) ||
327206710Sjilles			    t->result == FNM_NOMATCH) &&
328206710Sjilles			    flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) {
329206710Sjilles				flags |= FNM_PERIOD;
330206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
331206710Sjilles				if (result != t->result)
332206710Sjilles					break;
333206710Sjilles				flags = t->flags;
334206710Sjilles				extra++;
335206710Sjilles			}
336206710Sjilles			if ((((t->string[0] != '.' || t->pattern[0] == '.') &&
337206710Sjilles			    strchr(t->string, '/') == NULL) ||
338206710Sjilles			    t->result == FNM_NOMATCH) &&
339206710Sjilles			    !(flags & (FNM_PATHNAME | FNM_PERIOD))) {
340206710Sjilles				flags |= FNM_PATHNAME | FNM_PERIOD;
341206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
342206710Sjilles				if (result != t->result)
343206710Sjilles					break;
344206710Sjilles				flags = t->flags;
345206710Sjilles				extra++;
346206710Sjilles			}
347206710Sjilles			if ((strchr(t->string, '/') == NULL || t->result == 0)
348206710Sjilles			    && !(flags & FNM_LEADING_DIR)) {
349206710Sjilles				flags |= FNM_LEADING_DIR;
350206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
351206710Sjilles				if (result != t->result)
352206710Sjilles					break;
353206710Sjilles				flags = t->flags;
354206710Sjilles				extra++;
355206710Sjilles			}
356206710Sjilles			if (t->result == 0 && !(flags & FNM_CASEFOLD)) {
357206710Sjilles				flags |= FNM_CASEFOLD;
358206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
359206710Sjilles				if (result != t->result)
360206710Sjilles					break;
361206710Sjilles				flags = t->flags;
362206710Sjilles				extra++;
363206710Sjilles			}
364206710Sjilles			if (strchr(t->pattern, '\\') == NULL &&
365206710Sjilles			    t->result == 0 &&
366206710Sjilles			    !(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) {
367206710Sjilles				flags |= FNM_NOESCAPE | FNM_CASEFOLD;
368206710Sjilles				result = fnmatch(t->pattern, t->string, flags);
369206710Sjilles				if (result != t->result)
370206710Sjilles					break;
371206710Sjilles				flags = t->flags;
372206710Sjilles				extra++;
373206710Sjilles			}
374206710Sjilles		} while (0);
375206710Sjilles		if (result == t->result)
376206710Sjilles			printf("ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d (+%d)\n",
377206710Sjilles			    i + 1, t->pattern, t->string,
378206710Sjilles			    flags_to_string(flags),
379206710Sjilles			    result, extra);
380206710Sjilles		else {
381206710Sjilles			printf("not ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d != %d\n",
382206710Sjilles			    i + 1, t->pattern, t->string,
383206710Sjilles			    flags_to_string(flags),
384206710Sjilles			    result, t->result);
385206710Sjilles			errors = 1;
386206710Sjilles		}
387206710Sjilles	}
388206710Sjilles
389206710Sjilles	return (errors);
390206710Sjilles}
391