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/param.h>
43 { "a", "b", 0, FNM_NOMATCH
},
44 { "a", "A", 0, FNM_NOMATCH
},
48 { "*a", "b", 0, FNM_NOMATCH
},
49 { "*a*", "b", 0, FNM_NOMATCH
},
50 { "*a*b*", "ab", 0, 0 },
51 { "*a*b*", "qaqbq", 0, 0 },
52 { "*a*bb*", "qaqbqbbq", 0, 0 },
53 { "*a*bc*", "qaqbqbcq", 0, 0 },
54 { "*a*bb*", "qaqbqbb", 0, 0 },
55 { "*a*bc*", "qaqbqbc", 0, 0 },
56 { "*a*bb", "qaqbqbb", 0, 0 },
57 { "*a*bc", "qaqbqbc", 0, 0 },
58 { "*a*bb", "qaqbqbbq", 0, FNM_NOMATCH
},
59 { "*a*bc", "qaqbqbcq", 0, FNM_NOMATCH
},
60 { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH
},
61 { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0 },
62 { "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0 },
63 { ".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH
},
64 { ".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0 },
65 { ".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0 },
66 { "*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH
},
67 { "??????????*", "123456789", 0, FNM_NOMATCH
},
68 { "*??????????", "123456789", 0, FNM_NOMATCH
},
69 { "*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0 },
70 { "??????????*", "1234567890", 0, 0 },
71 { "*??????????", "1234567890", 0, 0 },
72 { "*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0 },
73 { "??????????*", "12345678901", 0, 0 },
74 { "*??????????", "12345678901", 0, 0 },
80 { "[[]", "x", 0, FNM_NOMATCH
},
81 { "[*]", "", 0, FNM_NOMATCH
},
82 { "[*]", "x", 0, FNM_NOMATCH
},
83 { "[?]", "x", 0, FNM_NOMATCH
},
84 { "*[*]*", "foo*foo", 0, 0 },
85 { "*[*]*", "foo", 0, FNM_NOMATCH
},
86 { "[0-9]", "0", 0, 0 },
87 { "[0-9]", "5", 0, 0 },
88 { "[0-9]", "9", 0, 0 },
89 { "[0-9]", "/", 0, FNM_NOMATCH
},
90 { "[0-9]", ":", 0, FNM_NOMATCH
},
91 { "[0-9]", "*", 0, FNM_NOMATCH
},
92 { "[!0-9]", "0", 0, FNM_NOMATCH
},
93 { "[!0-9]", "5", 0, FNM_NOMATCH
},
94 { "[!0-9]", "9", 0, FNM_NOMATCH
},
95 { "[!0-9]", "/", 0, 0 },
96 { "[!0-9]", ":", 0, 0 },
97 { "[!0-9]", "*", 0, 0 },
98 { "*[0-9]", "a0", 0, 0 },
99 { "*[0-9]", "a5", 0, 0 },
100 { "*[0-9]", "a9", 0, 0 },
101 { "*[0-9]", "a/", 0, FNM_NOMATCH
},
102 { "*[0-9]", "a:", 0, FNM_NOMATCH
},
103 { "*[0-9]", "a*", 0, FNM_NOMATCH
},
104 { "*[!0-9]", "a0", 0, FNM_NOMATCH
},
105 { "*[!0-9]", "a5", 0, FNM_NOMATCH
},
106 { "*[!0-9]", "a9", 0, FNM_NOMATCH
},
107 { "*[!0-9]", "a/", 0, 0 },
108 { "*[!0-9]", "a:", 0, 0 },
109 { "*[!0-9]", "a*", 0, 0 },
110 { "*[0-9]", "a00", 0, 0 },
111 { "*[0-9]", "a55", 0, 0 },
112 { "*[0-9]", "a99", 0, 0 },
113 { "*[0-9]", "a0a0", 0, 0 },
114 { "*[0-9]", "a5a5", 0, 0 },
115 { "*[0-9]", "a9a9", 0, 0 },
116 { "\\*", "*", 0, 0 },
117 { "\\?", "?", 0, 0 },
118 { "\\[x]", "[x]", 0, 0 },
119 { "\\[", "[", 0, 0 },
120 { "\\\\", "\\", 0, 0 },
121 { "*\\**", "foo*foo", 0, 0 },
122 { "*\\**", "foo", 0, FNM_NOMATCH
},
123 { "*\\\\*", "foo\\foo", 0, 0 },
124 { "*\\\\*", "foo", 0, FNM_NOMATCH
},
125 { "\\(", "(", 0, 0 },
126 { "\\a", "a", 0, 0 },
127 { "\\*", "a", 0, FNM_NOMATCH
},
128 { "\\?", "a", 0, FNM_NOMATCH
},
129 { "\\*", "\\*", 0, FNM_NOMATCH
},
130 { "\\?", "\\?", 0, FNM_NOMATCH
},
131 { "\\[x]", "\\[x]", 0, FNM_NOMATCH
},
132 { "\\[x]", "\\x", 0, FNM_NOMATCH
},
133 { "\\[", "\\[", 0, FNM_NOMATCH
},
134 { "\\(", "\\(", 0, FNM_NOMATCH
},
135 { "\\a", "\\a", 0, FNM_NOMATCH
},
136 { "\\", "\\", 0, FNM_NOMATCH
},
137 { "\\", "", 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
},
148 { ".*", "..", 0, 0 },
149 { ".*", ".a", 0, 0 },
150 { "[0-9]", ".", FNM_PERIOD
, FNM_NOMATCH
},
151 { "a*", "a.", 0, 0 },
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
,
178 { "*a", ".a/b", FNM_PATHNAME
| FNM_PERIOD
| FNM_LEADING_DIR
,
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\0"
189 "FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0";
190 static char result
[sizeof (flagnames
) + 3 * sizeof (int) + 2];
197 for (i
= 0; flagvalues
[i
] != 0; i
++) {
199 if (flags
& flagvalues
[i
]) {
204 flags
&= ~flagvalues
[i
];
211 sprintf(p
, "%d", flags
);
225 for (i
= 0; i
< sizeof (testcases
) / sizeof (struct testcase
); i
++) {
229 result
= fnmatch(t
->pattern
, t
->string
, flags
);
230 if (result
!= t
->result
)
232 if (strchr(t
->pattern
, '\\') == NULL
&&
233 !(flags
& FNM_NOESCAPE
)) {
234 flags
|= FNM_NOESCAPE
;
235 result
= fnmatch(t
->pattern
, t
->string
, flags
);
236 if (result
!= t
->result
)
240 if (strchr(t
->pattern
, '\\') != NULL
&&
241 strchr(t
->string
, '\\') == NULL
&&
242 t
->result
== FNM_NOMATCH
&&
243 !(flags
& (FNM_NOESCAPE
| FNM_LEADING_DIR
))) {
244 flags
|= FNM_NOESCAPE
;
245 result
= fnmatch(t
->pattern
, t
->string
, flags
);
246 if (result
!= t
->result
)
250 if ((t
->string
[0] != '.' || t
->pattern
[0] == '.' ||
251 t
->result
== FNM_NOMATCH
) &&
252 !(flags
& (FNM_PATHNAME
| FNM_PERIOD
))) {
254 result
= fnmatch(t
->pattern
, t
->string
, flags
);
255 if (result
!= t
->result
)
259 if ((strchr(t
->string
, '/') == NULL
||
260 t
->result
== FNM_NOMATCH
) &&
261 !(flags
& FNM_PATHNAME
)) {
262 flags
|= FNM_PATHNAME
;
263 result
= fnmatch(t
->pattern
, t
->string
, flags
);
264 if (result
!= t
->result
)
268 if ((((t
->string
[0] != '.' || t
->pattern
[0] == '.') &&
269 strstr(t
->string
, "/.") == NULL
) ||
270 t
->result
== FNM_NOMATCH
) &&
271 flags
& FNM_PATHNAME
&& !(flags
& FNM_PERIOD
)) {
273 result
= fnmatch(t
->pattern
, t
->string
, flags
);
274 if (result
!= t
->result
)
278 if ((((t
->string
[0] != '.' || t
->pattern
[0] == '.') &&
279 strchr(t
->string
, '/') == NULL
) ||
280 t
->result
== FNM_NOMATCH
) &&
281 !(flags
& (FNM_PATHNAME
| FNM_PERIOD
))) {
282 flags
|= FNM_PATHNAME
| FNM_PERIOD
;
283 result
= fnmatch(t
->pattern
, t
->string
, flags
);
284 if (result
!= t
->result
)
288 if ((strchr(t
->string
, '/') == NULL
||
290 !(flags
& FNM_LEADING_DIR
)) {
291 flags
|= FNM_LEADING_DIR
;
292 result
= fnmatch(t
->pattern
, t
->string
, flags
);
293 if (result
!= t
->result
)
297 if (t
->result
== 0 && !(flags
& FNM_CASEFOLD
)) {
298 flags
|= FNM_CASEFOLD
;
299 result
= fnmatch(t
->pattern
, t
->string
, flags
);
300 if (result
!= t
->result
)
304 if (strchr(t
->pattern
, '\\') == NULL
&&
306 !(flags
& (FNM_NOESCAPE
| FNM_CASEFOLD
))) {
307 flags
|= FNM_NOESCAPE
| FNM_CASEFOLD
;
308 result
= fnmatch(t
->pattern
, t
->string
, flags
);
309 if (result
!= t
->result
)
315 if (result
!= t
->result
) {
316 printf("fnmatch(\"%s\", \"%s\", %s) != %d (was %d)\n",
317 t
->pattern
, t
->string
, flags_to_string(flags
),