rename
[libc-test] / src / functional / fnmatch.c
diff --git a/src/functional/fnmatch.c b/src/functional/fnmatch.c
new file mode 100644 (file)
index 0000000..33f508f
--- /dev/null
@@ -0,0 +1,138 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <fnmatch.h>
+#include <unistd.h>
+#include "test.h"
+
+/* adapted from dietlibc's test-newfnmatch.c */
+
+/* xlat / printflags adapted from http://www.liacs.nl/~wichert/strace/ */
+#define FLAG(f) { f, #f }
+
+struct xlat {
+       int val;
+       char *str;
+} fnmatch_flags[] = {
+       FLAG(FNM_NOESCAPE),
+       FLAG(FNM_PATHNAME),
+       FLAG(FNM_PERIOD),
+       {0, NULL},
+};
+
+static char *flagstr(const struct xlat *map, int flags)
+{
+       static char buf[1000];
+       char *sep;
+
+       if (!flags) {
+               sprintf(buf, "0");
+               return buf;
+       }
+       sep = "";
+       for (; map->str; map++) {
+               if (map->val && (flags & map->val) == map->val) {
+                       sprintf(buf, "%s%s", sep, map->str);
+                       sep = "|";
+                       flags &= ~(map->val);
+               }
+       }
+       if (flags)
+               sprintf(buf, "%sunknown=%#x", sep, flags);
+       return buf;
+}
+
+/* tests harness adapted from glibc testfnm.c */
+struct {
+       const char *pattern;
+       const char *string;
+       int flags;
+       int expected;
+} tests[] = {
+       /* begin dietlibc tests */
+       { "*.c", "foo.c", 0, 0 },
+       { "*.c", ".c", 0, 0 },
+       { "*.a", "foo.c", 0, FNM_NOMATCH },
+       { "*.c", ".foo.c", 0, 0 },
+       { "*.c", ".foo.c", FNM_PERIOD, FNM_NOMATCH },
+       { "*.c", "foo.c", FNM_PERIOD, 0 },
+       { "a\\*.c", "a*.c", FNM_NOESCAPE, FNM_NOMATCH },
+       { "a\\*.c", "ax.c", 0, FNM_NOMATCH },
+       { "a[xy].c", "ax.c", 0, 0 },
+       { "a[!y].c", "ax.c", 0, 0 },
+       { "a[a/z]*.c", "a/x.c", FNM_PATHNAME, FNM_NOMATCH },
+       { "a/*.c", "a/x.c", FNM_PATHNAME, 0 },
+       { "a*.c", "a/x.c", FNM_PATHNAME, FNM_NOMATCH },
+       { "*/foo", "/foo", FNM_PATHNAME, 0 },
+       { "-O[01]", "-O1", 0, 0 },
+       { "[[?*\\]", "\\", 0, 0 },
+       { "[]?*\\]", "]", 0, 0 },
+       /* initial right-bracket tests */
+       { "[!]a-]", "b", 0, 0 },
+       { "[]-_]", "^", 0, 0 }, /* range: ']', '^', '_' */
+       { "[!]-_]", "X", 0, 0 },
+       { "??", "-", 0, FNM_NOMATCH },
+       /* begin glibc tests */
+       { "*LIB*", "lib", FNM_PERIOD, FNM_NOMATCH },
+       { "a[/]b", "a/b", 0, 0 },
+       { "a[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+       { "[a-z]/[a-z]", "a/b", 0, 0 },
+       { "*", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+       { "*[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+       { "*[b]", "a/b", FNM_PATHNAME, FNM_NOMATCH },
+       { "[*]/b", "a/b", 0, FNM_NOMATCH },
+       { "[*]/b", "*/b", 0, 0 },
+       { "[?]/b", "a/b", 0, FNM_NOMATCH },
+       { "[?]/b", "?/b", 0, 0 },
+       { "[[a]/b", "a/b", 0, 0 },
+       { "[[a]/b", "[/b", 0, 0 },
+       { "\\*/b", "a/b", 0, FNM_NOMATCH },
+       { "\\*/b", "*/b", 0, 0 },
+       { "\\?/b", "a/b", 0, FNM_NOMATCH },
+       { "\\?/b", "?/b", 0, 0 },
+       { "[/b", "[/b", 0, 0 },
+       { "\\[/b", "[/b", 0, 0 },
+       { "??""/b", "aa/b", 0, 0 },
+       { "???b", "aa/b", 0, 0 },
+       { "???b", "aa/b", FNM_PATHNAME, FNM_NOMATCH },
+       { "?a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "a/?b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "*a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "a/*b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "[.]a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "a/[.]b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "*/?", "a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { "?/*", "a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { ".*/?", ".a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { "*/.?", "a/.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { "*/*", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
+       { "*?*/*", "a/.b", FNM_PERIOD, 0 },
+       { "*[.]/b", "a./b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { "*[[:alpha:]]/*[[:alnum:]]", "a/b", FNM_PATHNAME, 0 },
+       /* These three tests should result in error according to SUSv3.
+        * See XCU 2.13.1, XBD 9.3.5, & fnmatch() */
+       { "*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME, -FNM_NOMATCH },
+       { "*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME, -FNM_NOMATCH },
+       { "*[![:digit:]]*/[![:d-d]", "a/[", FNM_PATHNAME, -FNM_NOMATCH },
+       { "a?b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { "a*b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+       { "a[.]b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
+};
+
+int main(void)
+{
+       int i;
+
+       for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
+               int r, x;
+
+               r = fnmatch(tests[i].pattern, tests[i].string, tests[i].flags);
+               x = tests[i].expected;
+               if (r != x && (r != FNM_NOMATCH || x != -FNM_NOMATCH)) {
+                       error("fnmatch(\"%s\", \"%s\", %s) failed, got %d want %d\n",
+                               tests[i].pattern, tests[i].string,
+                               flagstr(fnmatch_flags, tests[i].flags),
+                               r, x);
+               }
+       }
+       return test_status;
+}