e822456cedeb7915bdfb778027fbf0c2a4cd7491
[libc-test] / src / functional / fnmatch.c
1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <fnmatch.h>
4 #include <unistd.h>
5 #include "test.h"
6
7 /* adapted from dietlibc's test-newfnmatch.c */
8
9 /* xlat / printflags adapted from http://www.liacs.nl/~wichert/strace/ */
10 #define FLAG(f) { f, #f }
11
12 struct xlat {
13         int val;
14         char *str;
15 } fnmatch_flags[] = {
16         FLAG(FNM_NOESCAPE),
17         FLAG(FNM_PATHNAME),
18         FLAG(FNM_PERIOD),
19         {0, NULL},
20 };
21
22 static char *flagstr(const struct xlat *map, int flags)
23 {
24         static char buf[1000];
25         char *sep;
26
27         if (!flags) {
28                 sprintf(buf, "0");
29                 return buf;
30         }
31         sep = "";
32         for (; map->str; map++) {
33                 if (map->val && (flags & map->val) == map->val) {
34                         sprintf(buf, "%s%s", sep, map->str);
35                         sep = "|";
36                         flags &= ~(map->val);
37                 }
38         }
39         if (flags)
40                 sprintf(buf, "%sunknown=%#x", sep, flags);
41         return buf;
42 }
43
44 /* tests harness adapted from glibc testfnm.c */
45 struct {
46         const char *pattern;
47         const char *string;
48         int flags;
49         int expected;
50 } tests[] = {
51         /* begin dietlibc tests */
52         { "*.c", "foo.c", 0, 0 },
53         { "*.c", ".c", 0, 0 },
54         { "*.a", "foo.c", 0, FNM_NOMATCH },
55         { "*.c", ".foo.c", 0, 0 },
56         { "*.c", ".foo.c", FNM_PERIOD, FNM_NOMATCH },
57         { "*.c", "foo.c", FNM_PERIOD, 0 },
58         { "a\\*.c", "a*.c", FNM_NOESCAPE, FNM_NOMATCH },
59         { "a\\*.c", "ax.c", 0, FNM_NOMATCH },
60         { "a[xy].c", "ax.c", 0, 0 },
61         { "a[!y].c", "ax.c", 0, 0 },
62         { "a[a/z]*.c", "a/x.c", FNM_PATHNAME, FNM_NOMATCH },
63         { "a/*.c", "a/x.c", FNM_PATHNAME, 0 },
64         { "a*.c", "a/x.c", FNM_PATHNAME, FNM_NOMATCH },
65         { "*/foo", "/foo", FNM_PATHNAME, 0 },
66         { "-O[01]", "-O1", 0, 0 },
67         { "[[?*\\]", "\\", 0, 0 },
68         { "[]?*\\]", "]", 0, 0 },
69         /* initial right-bracket tests */
70         { "[!]a-]", "b", 0, 0 },
71         { "[]-_]", "^", 0, 0 }, /* range: ']', '^', '_' */
72         { "[!]-_]", "X", 0, 0 },
73         { "??", "-", 0, FNM_NOMATCH },
74         /* begin glibc tests */
75         { "*LIB*", "lib", FNM_PERIOD, FNM_NOMATCH },
76         { "a[/]b", "a/b", 0, 0 },
77         { "a[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
78         { "[a-z]/[a-z]", "a/b", 0, 0 },
79         { "*", "a/b", FNM_PATHNAME, FNM_NOMATCH },
80         { "*[/]b", "a/b", FNM_PATHNAME, FNM_NOMATCH },
81         { "*[b]", "a/b", FNM_PATHNAME, FNM_NOMATCH },
82         { "[*]/b", "a/b", 0, FNM_NOMATCH },
83         { "[*]/b", "*/b", 0, 0 },
84         { "[?]/b", "a/b", 0, FNM_NOMATCH },
85         { "[?]/b", "?/b", 0, 0 },
86         { "[[a]/b", "a/b", 0, 0 },
87         { "[[a]/b", "[/b", 0, 0 },
88         { "\\*/b", "a/b", 0, FNM_NOMATCH },
89         { "\\*/b", "*/b", 0, 0 },
90         { "\\?/b", "a/b", 0, FNM_NOMATCH },
91         { "\\?/b", "?/b", 0, 0 },
92         { "[/b", "[/b", 0, 0 },
93         { "\\[/b", "[/b", 0, 0 },
94         { "??""/b", "aa/b", 0, 0 },
95         { "???b", "aa/b", 0, 0 },
96         { "???b", "aa/b", FNM_PATHNAME, FNM_NOMATCH },
97         { "?a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
98         { "a/?b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
99         { "*a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
100         { "a/*b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
101         { "[.]a/b", ".a/b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
102         { "a/[.]b", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
103         { "*/?", "a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
104         { "?/*", "a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
105         { ".*/?", ".a/b", FNM_PATHNAME|FNM_PERIOD, 0 },
106         { "*/.?", "a/.b", FNM_PATHNAME|FNM_PERIOD, 0 },
107         { "*/*", "a/.b", FNM_PATHNAME|FNM_PERIOD, FNM_NOMATCH },
108         { "*?*/*", "a/.b", FNM_PERIOD, 0 },
109         { "*[.]/b", "a./b", FNM_PATHNAME|FNM_PERIOD, 0 },
110         { "*[[:alpha:]]/*[[:alnum:]]", "a/b", FNM_PATHNAME, 0 },
111         /* These three tests should result in error according to SUSv3.
112          * See XCU 2.13.1, XBD 9.3.5, & fnmatch() */
113         { "*[![:digit:]]*/[![:d-d]", "a/b", FNM_PATHNAME, -FNM_NOMATCH },
114         { "*[![:digit:]]*/[[:d-d]", "a/[", FNM_PATHNAME, -FNM_NOMATCH },
115         { "*[![:digit:]]*/[![:d-d]", "a/[", FNM_PATHNAME, -FNM_NOMATCH },
116         { "a?b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
117         { "a*b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
118         { "a[.]b", "a.b", FNM_PATHNAME|FNM_PERIOD, 0 },
119 };
120
121 int main(void)
122 {
123         int i;
124
125         for (i = 0; i < sizeof(tests) / sizeof(*tests); i++) {
126                 int r, x;
127
128                 r = fnmatch(tests[i].pattern, tests[i].string, tests[i].flags);
129                 x = tests[i].expected;
130                 if (r != x && (r != FNM_NOMATCH || x != -FNM_NOMATCH)) {
131                         t_error("fnmatch(\"%s\", \"%s\", %s) failed, got %d want %d\n",
132                                 tests[i].pattern, tests[i].string,
133                                 flagstr(fnmatch_flags, tests[i].flags),
134                                 r, x);
135                 }
136         }
137         return t_status;
138 }