c0856f991939655b48ab0336090ee785b6c5713e
[musl] / src / regex / fnmatch.c
1 #include <fnmatch.h>
2 #include <wctype.h>
3 #include <string.h>
4 #include <wchar.h>
5 #include <stdlib.h>
6 #include <limits.h>
7
8 static int next(const char **s)
9 {
10         wchar_t c;
11         int l = mbtowc(&c, *s, MB_LEN_MAX);
12         /* hack to allow literal matches of invalid byte sequences */
13         if (l < 0) return (unsigned char)*(*s)++ - 0x100;
14         *s += l;
15         return c;
16 }
17
18 #define BRACKET_ERROR  -0x100
19 #define BRACKET_NOCHAR -0x101
20
21 static int bracket_next(const char **s)
22 {
23         int c;
24         int type;
25         if (**s == '[') {
26                 type = *(*s+1);
27                 if (type == '.' || type == '=') {
28                         *s += 2;
29                         c = next(s);
30                         if (c <= 0) return BRACKET_ERROR;
31                         if (**s == type && *(*s+1) == ']') {
32                                 *s += 2;
33                                 return c;
34                         }
35                         for (; **s && (**s != type || *(*s+1) != ']'); (*s)++);
36                         if (!**s) return BRACKET_ERROR;
37                         *s += 2;
38                         return BRACKET_NOCHAR;
39                 }
40         }
41         c = next(s);
42         if (c <= 0) return BRACKET_ERROR;
43         return c;
44 }
45
46 #define __FNM_CONT 0x8000
47
48 int fnmatch(const char *p, const char *s, int flags)
49 {
50         int c, d, k;
51         int not;
52         int match;
53         int first;
54         int no_slash = (flags & FNM_PATHNAME) ? '/' : 0;
55         int no_period = (flags & FNM_PERIOD) && !(flags & __FNM_CONT) ? '.' : 0x100;
56
57         flags |= __FNM_CONT;
58
59         while ((c = *p++)) {
60                 switch (c) {
61                 case '?':
62                         k = next(&s);
63                         if (!k || k == no_period || k == no_slash)
64                                 return FNM_NOMATCH;
65                         break;
66                 case '\\':
67                         if (!(flags & FNM_NOESCAPE)) {
68                                 c = *p++;
69                                 goto literal;
70                         }
71                         if (*s++ != c) return FNM_NOMATCH;
72                         break;
73                 case '*':
74                         for (; *p == '*'; p++);
75                         if (*p && !*s) return FNM_NOMATCH;
76                         if (*s == no_period)
77                                 return FNM_NOMATCH;
78                         if (!*p && (!no_slash || !strchr(s, no_slash)))
79                                 return 0;
80                         for (; *s; s++)
81                                 if (!fnmatch(p, s, flags))
82                                         return 0;
83                                 else if (*s == no_slash)
84                                         break;
85                         return FNM_NOMATCH;
86                 case '[':
87                         not = (*p == '!' || *p == '^');
88                         if (not) p++;
89                         k = next(&s);
90                         if (!k || k == no_slash || k == no_period)
91                                 return FNM_NOMATCH;
92                         match = 0;
93                         first = 1;
94                         for (;;) {
95                                 if (!*p) return FNM_NOMATCH;
96                                 if (*p == ']' && !first) break;
97                                 first = 0;
98                                 if (*p == '[' && *(p+1) == ':') {
99                                         const char *z;
100                                         p += 2;
101                                         for (z=p; *z && (*z != ':' || *(z+1) != ']'); z++);
102                                         if (!*z || z-p > 32) { /* FIXME: symbolic const? */
103                                                 return FNM_NOMATCH;
104                                         } else {
105                                                 char class[33];
106                                                 memcpy(class, p, z-p);
107                                                 class[z-p] = 0;
108                                                 if (iswctype(k, wctype(class)))
109                                                         match = 1;
110                                         }
111                                         p = z+2;
112                                         continue;
113                                 }
114                                 c = bracket_next(&p);
115                                 if (c == BRACKET_ERROR)
116                                         return FNM_NOMATCH;
117                                 if (c == BRACKET_NOCHAR)
118                                         continue;
119                                 if (*p == '-' && *(p+1) != ']') {
120                                         p++;
121                                         d = bracket_next(&p);
122                                         if (d == BRACKET_ERROR)
123                                                 return FNM_NOMATCH;
124                                         if (d == BRACKET_NOCHAR)
125                                                 continue;
126                                         if (k >= c && k <= d)
127                                                 match = 1;
128                                         continue;
129                                 }
130                                 if (k == c) match = 1;
131                         }
132                         p++;
133                         if (not == match)
134                                 return FNM_NOMATCH;
135                         break;
136                 default:
137                 literal:
138                         if (*s++ != c)
139                                 return FNM_NOMATCH;
140                         if (c == no_slash && (flags & FNM_PERIOD)) {
141                                 no_period = '.';
142                                 continue;
143                         }
144                         break;
145                 }
146                 no_period = 0x100;
147         }
148         if (*s) return FNM_NOMATCH;
149         return 0;
150 }