test-fnmatch.c revision 206711
1/*- 2 * Copyright (c) 2010 Jilles Tjoelker 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 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. 13 * 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 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/tools/regression/lib/libc/gen/test-fnmatch.c 206711 2010-04-16 22:29:24Z jilles $"); 29 30#include <errno.h> 31#include <stdio.h> 32#include <stdlib.h> 33#include <string.h> 34#include <fnmatch.h> 35 36struct testcase { 37 const char *pattern; 38 const char *string; 39 int flags; 40 int result; 41} testcases[] = { 42 "", "", 0, 0, 43 "a", "a", 0, 0, 44 "a", "b", 0, FNM_NOMATCH, 45 "a", "A", 0, FNM_NOMATCH, 46 "*", "a", 0, 0, 47 "*", "aa", 0, 0, 48 "*a", "a", 0, 0, 49 "*a", "b", 0, FNM_NOMATCH, 50 "*a*", "b", 0, FNM_NOMATCH, 51 "*a*b*", "ab", 0, 0, 52 "*a*b*", "qaqbq", 0, 0, 53 "*a*bb*", "qaqbqbbq", 0, 0, 54 "*a*bc*", "qaqbqbcq", 0, 0, 55 "*a*bb*", "qaqbqbb", 0, 0, 56 "*a*bc*", "qaqbqbc", 0, 0, 57 "*a*bb", "qaqbqbb", 0, 0, 58 "*a*bc", "qaqbqbc", 0, 0, 59 "*a*bb", "qaqbqbbq", 0, FNM_NOMATCH, 60 "*a*bc", "qaqbqbcq", 0, FNM_NOMATCH, 61 "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaa", 0, FNM_NOMATCH, 62 "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaa", 0, 0, 63 "*a*a*a*a*a*a*a*a*a*a*", "aaaaaaaaaaa", 0, 0, 64 ".*.*.*.*.*.*.*.*.*.*", ".........", 0, FNM_NOMATCH, 65 ".*.*.*.*.*.*.*.*.*.*", "..........", 0, 0, 66 ".*.*.*.*.*.*.*.*.*.*", "...........", 0, 0, 67 "*?*?*?*?*?*?*?*?*?*?*", "123456789", 0, FNM_NOMATCH, 68 "??????????*", "123456789", 0, FNM_NOMATCH, 69 "*??????????", "123456789", 0, FNM_NOMATCH, 70 "*?*?*?*?*?*?*?*?*?*?*", "1234567890", 0, 0, 71 "??????????*", "1234567890", 0, 0, 72 "*??????????", "1234567890", 0, 0, 73 "*?*?*?*?*?*?*?*?*?*?*", "12345678901", 0, 0, 74 "??????????*", "12345678901", 0, 0, 75 "*??????????", "12345678901", 0, 0, 76 "[x]", "x", 0, 0, 77 "[*]", "*", 0, 0, 78 "[?]", "?", 0, 0, 79 "[", "[", 0, 0, 80 "[[]", "[", 0, 0, 81 "[[]", "x", 0, FNM_NOMATCH, 82 "[*]", "", 0, FNM_NOMATCH, 83 "[*]", "x", 0, FNM_NOMATCH, 84 "[?]", "x", 0, FNM_NOMATCH, 85 "*[*]*", "foo*foo", 0, 0, 86 "*[*]*", "foo", 0, FNM_NOMATCH, 87 "[0-9]", "0", 0, 0, 88 "[0-9]", "5", 0, 0, 89 "[0-9]", "9", 0, 0, 90 "[0-9]", "/", 0, FNM_NOMATCH, 91 "[0-9]", ":", 0, FNM_NOMATCH, 92 "[0-9]", "*", 0, FNM_NOMATCH, 93 "[!0-9]", "0", 0, FNM_NOMATCH, 94 "[!0-9]", "5", 0, FNM_NOMATCH, 95 "[!0-9]", "9", 0, FNM_NOMATCH, 96 "[!0-9]", "/", 0, 0, 97 "[!0-9]", ":", 0, 0, 98 "[!0-9]", "*", 0, 0, 99 "*[0-9]", "a0", 0, 0, 100 "*[0-9]", "a5", 0, 0, 101 "*[0-9]", "a9", 0, 0, 102 "*[0-9]", "a/", 0, FNM_NOMATCH, 103 "*[0-9]", "a:", 0, FNM_NOMATCH, 104 "*[0-9]", "a*", 0, FNM_NOMATCH, 105 "*[!0-9]", "a0", 0, FNM_NOMATCH, 106 "*[!0-9]", "a5", 0, FNM_NOMATCH, 107 "*[!0-9]", "a9", 0, FNM_NOMATCH, 108 "*[!0-9]", "a/", 0, 0, 109 "*[!0-9]", "a:", 0, 0, 110 "*[!0-9]", "a*", 0, 0, 111 "*[0-9]", "a00", 0, 0, 112 "*[0-9]", "a55", 0, 0, 113 "*[0-9]", "a99", 0, 0, 114 "*[0-9]", "a0a0", 0, 0, 115 "*[0-9]", "a5a5", 0, 0, 116 "*[0-9]", "a9a9", 0, 0, 117 "\\*", "*", 0, 0, 118 "\\?", "?", 0, 0, 119 "\\[x]", "[x]", 0, 0, 120 "\\[", "[", 0, 0, 121 "\\\\", "\\", 0, 0, 122 "*\\**", "foo*foo", 0, 0, 123 "*\\**", "foo", 0, FNM_NOMATCH, 124 "*\\\\*", "foo\\foo", 0, 0, 125 "*\\\\*", "foo", 0, FNM_NOMATCH, 126 "\\(", "(", 0, 0, 127 "\\a", "a", 0, 0, 128 "\\*", "a", 0, FNM_NOMATCH, 129 "\\?", "a", 0, FNM_NOMATCH, 130 "\\*", "\\*", 0, FNM_NOMATCH, 131 "\\?", "\\?", 0, FNM_NOMATCH, 132 "\\[x]", "\\[x]", 0, FNM_NOMATCH, 133 "\\[x]", "\\x", 0, FNM_NOMATCH, 134 "\\[", "\\[", 0, FNM_NOMATCH, 135 "\\(", "\\(", 0, FNM_NOMATCH, 136 "\\a", "\\a", 0, FNM_NOMATCH, 137 "\\*", "\\*", FNM_NOESCAPE, 0, 138 "\\?", "\\?", FNM_NOESCAPE, 0, 139 "\\", "\\", FNM_NOESCAPE, 0, 140 "\\\\", "\\", FNM_NOESCAPE, FNM_NOMATCH, 141 "\\\\", "\\\\", FNM_NOESCAPE, 0, 142 "*\\*", "foo\\foo", FNM_NOESCAPE, 0, 143 "*\\*", "foo", FNM_NOESCAPE, FNM_NOMATCH, 144 "*", ".", FNM_PERIOD, FNM_NOMATCH, 145 "?", ".", FNM_PERIOD, FNM_NOMATCH, 146 ".*", ".", 0, 0, 147 ".*", "..", 0, 0, 148 ".*", ".a", 0, 0, 149 "[0-9]", ".", FNM_PERIOD, FNM_NOMATCH, 150 "a*", "a.", 0, 0, 151 "a/a", "a/a", FNM_PATHNAME, 0, 152 "a/*", "a/a", FNM_PATHNAME, 0, 153 "*/a", "a/a", FNM_PATHNAME, 0, 154 "*/*", "a/a", FNM_PATHNAME, 0, 155 "a*b/*", "abbb/x", FNM_PATHNAME, 0, 156 "a*b/*", "abbb/.x", FNM_PATHNAME, 0, 157 "*", "a/a", FNM_PATHNAME, FNM_NOMATCH, 158 "*/*", "a/a/a", FNM_PATHNAME, FNM_NOMATCH, 159 "b/*", "b/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH, 160 "b*/*", "a/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH, 161 "b/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0, 162 "b*/.*", "b/.x", FNM_PATHNAME | FNM_PERIOD, 0, 163 "a", "A", FNM_CASEFOLD, 0, 164 "A", "a", FNM_CASEFOLD, 0, 165 "[a]", "A", FNM_CASEFOLD, 0, 166 "[A]", "a", FNM_CASEFOLD, 0, 167 "a", "b", FNM_CASEFOLD, FNM_NOMATCH, 168 "a", "a/b", FNM_PATHNAME, FNM_NOMATCH, 169 "*", "a/b", FNM_PATHNAME, FNM_NOMATCH, 170 "*b", "a/b", FNM_PATHNAME, FNM_NOMATCH, 171 "a", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0, 172 "*", "a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0, 173 "*", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0, 174 "*a", ".a/b", FNM_PATHNAME | FNM_LEADING_DIR, 0, 175 "*", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH, 176 "*a", ".a/b", FNM_PATHNAME | FNM_PERIOD | FNM_LEADING_DIR, FNM_NOMATCH, 177 "a*b/*", "abbb/.x", FNM_PATHNAME | FNM_PERIOD, FNM_NOMATCH, 178}; 179 180static const char * 181flags_to_string(int flags) 182{ 183 static const int flagvalues[] = { FNM_NOESCAPE, FNM_PATHNAME, 184 FNM_PERIOD, FNM_LEADING_DIR, FNM_CASEFOLD, 0 }; 185 static const char flagnames[] = "FNM_NOESCAPE\0FNM_PATHNAME\0FNM_PERIOD\0FNM_LEADING_DIR\0FNM_CASEFOLD\0"; 186 static char result[sizeof(flagnames) + 3 * sizeof(int) + 2]; 187 char *p; 188 size_t i, len; 189 const char *fp; 190 191 p = result; 192 fp = flagnames; 193 for (i = 0; flagvalues[i] != 0; i++) { 194 len = strlen(fp); 195 if (flags & flagvalues[i]) { 196 if (p != result) 197 *p++ = '|'; 198 memcpy(p, fp, len); 199 p += len; 200 flags &= ~flagvalues[i]; 201 } 202 fp += len + 1; 203 } 204 if (p == result) 205 memcpy(p, "0", 2); 206 else if (flags != 0) 207 sprintf(p, "%d", flags); 208 else 209 *p = '\0'; 210 return result; 211} 212 213int 214main(int argc, char *argv[]) 215{ 216 size_t i, n; 217 int flags, result, extra, errors; 218 struct testcase *t; 219 220 n = sizeof(testcases) / sizeof(testcases[0]); 221 errors = 0; 222 printf("1..%zu\n", n); 223 for (i = 0; i < n; i++) { 224 t = &testcases[i]; 225 flags = t->flags; 226 extra = 0; 227 do { 228 result = fnmatch(t->pattern, t->string, flags); 229 if (result != t->result) 230 break; 231 if (strchr(t->pattern, '\\') == NULL && 232 !(flags & FNM_NOESCAPE)) { 233 flags |= FNM_NOESCAPE; 234 result = fnmatch(t->pattern, t->string, flags); 235 if (result != t->result) 236 break; 237 flags = t->flags; 238 extra++; 239 } 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) 247 break; 248 flags = t->flags; 249 extra++; 250 } 251 if ((t->string[0] != '.' || t->pattern[0] == '.' || 252 t->result == FNM_NOMATCH) && 253 !(flags & (FNM_PATHNAME | FNM_PERIOD))) { 254 flags |= FNM_PERIOD; 255 result = fnmatch(t->pattern, t->string, flags); 256 if (result != t->result) 257 break; 258 flags = t->flags; 259 extra++; 260 } 261 if ((strchr(t->string, '/') == NULL || 262 t->result == FNM_NOMATCH) && 263 !(flags & FNM_PATHNAME)) { 264 flags |= FNM_PATHNAME; 265 result = fnmatch(t->pattern, t->string, flags); 266 if (result != t->result) 267 break; 268 flags = t->flags; 269 extra++; 270 } 271 if ((((t->string[0] != '.' || t->pattern[0] == '.') && 272 strstr(t->string, "/.") == NULL) || 273 t->result == FNM_NOMATCH) && 274 flags & FNM_PATHNAME && !(flags & FNM_PERIOD)) { 275 flags |= FNM_PERIOD; 276 result = fnmatch(t->pattern, t->string, flags); 277 if (result != t->result) 278 break; 279 flags = t->flags; 280 extra++; 281 } 282 if ((((t->string[0] != '.' || t->pattern[0] == '.') && 283 strchr(t->string, '/') == NULL) || 284 t->result == FNM_NOMATCH) && 285 !(flags & (FNM_PATHNAME | FNM_PERIOD))) { 286 flags |= FNM_PATHNAME | FNM_PERIOD; 287 result = fnmatch(t->pattern, t->string, flags); 288 if (result != t->result) 289 break; 290 flags = t->flags; 291 extra++; 292 } 293 if ((strchr(t->string, '/') == NULL || t->result == 0) 294 && !(flags & FNM_LEADING_DIR)) { 295 flags |= FNM_LEADING_DIR; 296 result = fnmatch(t->pattern, t->string, flags); 297 if (result != t->result) 298 break; 299 flags = t->flags; 300 extra++; 301 } 302 if (t->result == 0 && !(flags & FNM_CASEFOLD)) { 303 flags |= FNM_CASEFOLD; 304 result = fnmatch(t->pattern, t->string, flags); 305 if (result != t->result) 306 break; 307 flags = t->flags; 308 extra++; 309 } 310 if (strchr(t->pattern, '\\') == NULL && 311 t->result == 0 && 312 !(flags & (FNM_NOESCAPE | FNM_CASEFOLD))) { 313 flags |= FNM_NOESCAPE | FNM_CASEFOLD; 314 result = fnmatch(t->pattern, t->string, flags); 315 if (result != t->result) 316 break; 317 flags = t->flags; 318 extra++; 319 } 320 } while (0); 321 if (result == t->result) 322 printf("ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d (+%d)\n", 323 i + 1, t->pattern, t->string, 324 flags_to_string(flags), 325 result, extra); 326 else { 327 printf("not ok %zu - fnmatch(\"%s\", \"%s\", %s) = %d != %d\n", 328 i + 1, t->pattern, t->string, 329 flags_to_string(flags), 330 result, t->result); 331 errors = 1; 332 } 333 } 334 335 return (errors); 336} 337