]>
Commit | Line | Data |
---|---|---|
c84142e8 UD |
1 | /* Copyright (C) 1991, 1992, 1993, 1996, 1997 Free Software Foundation, Inc. |
2 | This file is part of the GNU C Library. | |
28f540f4 | 3 | |
c84142e8 UD |
4 | This library is free software; you can redistribute it and/or |
5 | modify it under the terms of the GNU Library General Public License as | |
6 | published by the Free Software Foundation; either version 2 of the | |
7 | License, or (at your option) any later version. | |
28f540f4 | 8 | |
c84142e8 UD |
9 | This library is distributed in the hope that it will be useful, |
10 | but WITHOUT ANY WARRANTY; without even the implied warranty of | |
11 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
12 | Library General Public License for more details. | |
28f540f4 | 13 | |
c84142e8 UD |
14 | You should have received a copy of the GNU Library General Public |
15 | License along with this library; see the file COPYING.LIB. If not, | |
16 | write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, | |
17 | Boston, MA 02111-1307, USA. */ | |
28f540f4 | 18 | |
ba1ffaa1 UD |
19 | #if HAVE_CONFIG_H |
20 | # include <config.h> | |
28f540f4 RM |
21 | #endif |
22 | ||
97aa195c RM |
23 | /* Enable GNU extensions in fnmatch.h. */ |
24 | #ifndef _GNU_SOURCE | |
ba1ffaa1 | 25 | # define _GNU_SOURCE 1 |
97aa195c RM |
26 | #endif |
27 | ||
28f540f4 RM |
28 | #include <errno.h> |
29 | #include <fnmatch.h> | |
30 | #include <ctype.h> | |
31 | ||
32 | ||
33 | /* Comment out all this code if we are using the GNU C Library, and are not | |
34 | actually compiling the library itself. This code is part of the GNU C | |
35 | Library, but also included in many other GNU distributions. Compiling | |
36 | and linking in this code is a waste when using the GNU C library | |
37 | (especially if it is a shared library). Rather than having every GNU | |
38 | program understand `configure --with-gnu-libc' and omit the object files, | |
39 | it is simpler to just do this in the source for each such file. */ | |
40 | ||
c84142e8 | 41 | #if defined _LIBC || !defined __GNU_LIBRARY__ |
28f540f4 RM |
42 | |
43 | ||
c84142e8 | 44 | # if defined STDC_HEADERS || !defined isascii |
ba1ffaa1 UD |
45 | # define ISASCII(c) 1 |
46 | # else | |
47 | # define ISASCII(c) isascii(c) | |
48 | # endif | |
49 | ||
50 | # define ISUPPER(c) (ISASCII (c) && isupper (c)) | |
51 | ||
52 | ||
53 | # ifndef errno | |
28f540f4 | 54 | extern int errno; |
ba1ffaa1 | 55 | # endif |
28f540f4 RM |
56 | |
57 | /* Match STRING against the filename pattern PATTERN, returning zero if | |
58 | it matches, nonzero if not. */ | |
59 | int | |
60 | fnmatch (pattern, string, flags) | |
61 | const char *pattern; | |
62 | const char *string; | |
63 | int flags; | |
64 | { | |
65 | register const char *p = pattern, *n = string; | |
66 | register char c; | |
67 | ||
6d52618b | 68 | /* Note that this evaluates C many times. */ |
ba1ffaa1 | 69 | # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) |
28f540f4 RM |
70 | |
71 | while ((c = *p++) != '\0') | |
72 | { | |
73 | c = FOLD (c); | |
74 | ||
75 | switch (c) | |
76 | { | |
77 | case '?': | |
78 | if (*n == '\0') | |
79 | return FNM_NOMATCH; | |
80 | else if ((flags & FNM_FILE_NAME) && *n == '/') | |
81 | return FNM_NOMATCH; | |
82 | else if ((flags & FNM_PERIOD) && *n == '.' && | |
83 | (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) | |
84 | return FNM_NOMATCH; | |
85 | break; | |
86 | ||
87 | case '\\': | |
88 | if (!(flags & FNM_NOESCAPE)) | |
89 | { | |
90 | c = *p++; | |
299a95b9 RM |
91 | if (c == '\0') |
92 | /* Trailing \ loses. */ | |
93 | return FNM_NOMATCH; | |
28f540f4 RM |
94 | c = FOLD (c); |
95 | } | |
96 | if (FOLD (*n) != c) | |
97 | return FNM_NOMATCH; | |
98 | break; | |
99 | ||
100 | case '*': | |
101 | if ((flags & FNM_PERIOD) && *n == '.' && | |
102 | (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) | |
103 | return FNM_NOMATCH; | |
104 | ||
4f54cdb1 RM |
105 | for (c = *p++; c == '?' || c == '*'; c = *p++) |
106 | { | |
107 | if ((flags & FNM_FILE_NAME) && *n == '/') | |
108 | /* A slash does not match a wildcard under FNM_FILE_NAME. */ | |
109 | return FNM_NOMATCH; | |
110 | else if (c == '?') | |
111 | { | |
112 | /* A ? needs to match one character. */ | |
113 | if (*n == '\0') | |
114 | /* There isn't another character; no match. */ | |
115 | return FNM_NOMATCH; | |
116 | else | |
117 | /* One character of the string is consumed in matching | |
118 | this ? wildcard, so *??? won't match if there are | |
119 | less than three characters. */ | |
120 | ++n; | |
121 | } | |
122 | } | |
28f540f4 RM |
123 | |
124 | if (c == '\0') | |
125 | return 0; | |
126 | ||
127 | { | |
128 | char c1 = (!(flags & FNM_NOESCAPE) && c == '\\') ? *p : c; | |
129 | c1 = FOLD (c1); | |
130 | for (--p; *n != '\0'; ++n) | |
131 | if ((c == '[' || FOLD (*n) == c1) && | |
132 | fnmatch (p, n, flags & ~FNM_PERIOD) == 0) | |
133 | return 0; | |
134 | return FNM_NOMATCH; | |
135 | } | |
136 | ||
137 | case '[': | |
138 | { | |
139 | /* Nonzero if the sense of the character class is inverted. */ | |
140 | register int not; | |
141 | ||
142 | if (*n == '\0') | |
143 | return FNM_NOMATCH; | |
144 | ||
145 | if ((flags & FNM_PERIOD) && *n == '.' && | |
146 | (n == string || ((flags & FNM_FILE_NAME) && n[-1] == '/'))) | |
147 | return FNM_NOMATCH; | |
148 | ||
149 | not = (*p == '!' || *p == '^'); | |
150 | if (not) | |
151 | ++p; | |
152 | ||
153 | c = *p++; | |
154 | for (;;) | |
155 | { | |
156 | register char cstart = c, cend = c; | |
157 | ||
158 | if (!(flags & FNM_NOESCAPE) && c == '\\') | |
299a95b9 RM |
159 | { |
160 | if (*p == '\0') | |
161 | return FNM_NOMATCH; | |
162 | cstart = cend = *p++; | |
163 | } | |
28f540f4 RM |
164 | |
165 | cstart = cend = FOLD (cstart); | |
166 | ||
167 | if (c == '\0') | |
168 | /* [ (unterminated) loses. */ | |
169 | return FNM_NOMATCH; | |
170 | ||
171 | c = *p++; | |
172 | c = FOLD (c); | |
173 | ||
174 | if ((flags & FNM_FILE_NAME) && c == '/') | |
175 | /* [/] can never match. */ | |
176 | return FNM_NOMATCH; | |
177 | ||
178 | if (c == '-' && *p != ']') | |
179 | { | |
180 | cend = *p++; | |
181 | if (!(flags & FNM_NOESCAPE) && cend == '\\') | |
182 | cend = *p++; | |
183 | if (cend == '\0') | |
184 | return FNM_NOMATCH; | |
185 | cend = FOLD (cend); | |
186 | ||
187 | c = *p++; | |
188 | } | |
189 | ||
190 | if (FOLD (*n) >= cstart && FOLD (*n) <= cend) | |
191 | goto matched; | |
192 | ||
193 | if (c == ']') | |
194 | break; | |
195 | } | |
196 | if (!not) | |
197 | return FNM_NOMATCH; | |
198 | break; | |
199 | ||
200 | matched:; | |
201 | /* Skip the rest of the [...] that already matched. */ | |
202 | while (c != ']') | |
203 | { | |
204 | if (c == '\0') | |
205 | /* [... (unterminated) loses. */ | |
206 | return FNM_NOMATCH; | |
207 | ||
208 | c = *p++; | |
209 | if (!(flags & FNM_NOESCAPE) && c == '\\') | |
299a95b9 RM |
210 | { |
211 | if (*p == '\0') | |
212 | return FNM_NOMATCH; | |
213 | /* XXX 1003.2d11 is unclear if this is right. */ | |
214 | ++p; | |
215 | } | |
28f540f4 RM |
216 | } |
217 | if (not) | |
218 | return FNM_NOMATCH; | |
219 | } | |
220 | break; | |
221 | ||
222 | default: | |
223 | if (c != FOLD (*n)) | |
224 | return FNM_NOMATCH; | |
225 | } | |
226 | ||
227 | ++n; | |
228 | } | |
229 | ||
230 | if (*n == '\0') | |
231 | return 0; | |
232 | ||
233 | if ((flags & FNM_LEADING_DIR) && *n == '/') | |
234 | /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ | |
235 | return 0; | |
236 | ||
237 | return FNM_NOMATCH; | |
ba1ffaa1 UD |
238 | |
239 | # undef FOLD | |
28f540f4 RM |
240 | } |
241 | ||
242 | #endif /* _LIBC or not __GNU_LIBRARY__. */ |