diff options
Diffstat (limited to 'win32/fnmatch.c')
-rw-r--r-- | win32/fnmatch.c | 484 |
1 files changed, 484 insertions, 0 deletions
diff --git a/win32/fnmatch.c b/win32/fnmatch.c new file mode 100644 index 000000000..de456e526 --- /dev/null +++ b/win32/fnmatch.c | |||
@@ -0,0 +1,484 @@ | |||
1 | /* Copyright (C) 1991, 92, 93, 96, 97, 98, 99 Free Software Foundation, Inc. | ||
2 | This file is part of the GNU C Library. | ||
3 | |||
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. | ||
8 | |||
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. | ||
13 | |||
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. */ | ||
18 | |||
19 | #include <platform.h> | ||
20 | |||
21 | #if HAVE_CONFIG_H | ||
22 | # include <config.h> | ||
23 | #endif | ||
24 | |||
25 | /* Enable GNU extensions in fnmatch.h. */ | ||
26 | #ifndef _GNU_SOURCE | ||
27 | # define _GNU_SOURCE 1 | ||
28 | #endif | ||
29 | |||
30 | #include <errno.h> | ||
31 | #include <fnmatch.h> | ||
32 | #include <ctype.h> | ||
33 | |||
34 | #if HAVE_STRING_H || defined _LIBC | ||
35 | # include <string.h> | ||
36 | #else | ||
37 | # include <strings.h> | ||
38 | #endif | ||
39 | |||
40 | #if defined STDC_HEADERS || defined _LIBC | ||
41 | # include <stdlib.h> | ||
42 | #endif | ||
43 | |||
44 | /* For platform which support the ISO C amendement 1 functionality we | ||
45 | support user defined character classes. */ | ||
46 | #if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) | ||
47 | /* Solaris 2.5 has a bug: <wchar.h> must be included before <wctype.h>. */ | ||
48 | # include <wchar.h> | ||
49 | # include <wctype.h> | ||
50 | #endif | ||
51 | |||
52 | /* Comment out all this code if we are using the GNU C Library, and are not | ||
53 | actually compiling the library itself. This code is part of the GNU C | ||
54 | Library, but also included in many other GNU distributions. Compiling | ||
55 | and linking in this code is a waste when using the GNU C library | ||
56 | (especially if it is a shared library). Rather than having every GNU | ||
57 | program understand `configure --with-gnu-libc' and omit the object files, | ||
58 | it is simpler to just do this in the source for each such file. */ | ||
59 | |||
60 | #if defined _LIBC || !defined __GNU_LIBRARY__ | ||
61 | |||
62 | |||
63 | # if defined STDC_HEADERS || !defined isascii | ||
64 | # define ISASCII(c) 1 | ||
65 | # else | ||
66 | # define ISASCII(c) isascii(c) | ||
67 | # endif | ||
68 | |||
69 | # ifdef isblank | ||
70 | # define ISBLANK(c) (ISASCII (c) && isblank (c)) | ||
71 | # else | ||
72 | # define ISBLANK(c) ((c) == ' ' || (c) == '\t') | ||
73 | # endif | ||
74 | # ifdef isgraph | ||
75 | # define ISGRAPH(c) (ISASCII (c) && isgraph (c)) | ||
76 | # else | ||
77 | # define ISGRAPH(c) (ISASCII (c) && isprint (c) && !isspace (c)) | ||
78 | # endif | ||
79 | |||
80 | # define ISPRINT(c) (ISASCII (c) && isprint (c)) | ||
81 | # define ISDIGIT(c) (ISASCII (c) && isdigit (c)) | ||
82 | # define ISALNUM(c) (ISASCII (c) && isalnum (c)) | ||
83 | # define ISALPHA(c) (ISASCII (c) && isalpha (c)) | ||
84 | # define ISCNTRL(c) (ISASCII (c) && iscntrl (c)) | ||
85 | # define ISLOWER(c) (ISASCII (c) && islower (c)) | ||
86 | # define ISPUNCT(c) (ISASCII (c) && ispunct (c)) | ||
87 | # define ISSPACE(c) (ISASCII (c) && isspace (c)) | ||
88 | # define ISUPPER(c) (ISASCII (c) && isupper (c)) | ||
89 | # define ISXDIGIT(c) (ISASCII (c) && isxdigit (c)) | ||
90 | |||
91 | # define STREQ(s1, s2) ((strcmp (s1, s2) == 0)) | ||
92 | |||
93 | # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) | ||
94 | /* The GNU C library provides support for user-defined character classes | ||
95 | and the functions from ISO C amendement 1. */ | ||
96 | # ifdef CHARCLASS_NAME_MAX | ||
97 | # define CHAR_CLASS_MAX_LENGTH CHARCLASS_NAME_MAX | ||
98 | # else | ||
99 | /* This shouldn't happen but some implementation might still have this | ||
100 | problem. Use a reasonable default value. */ | ||
101 | # define CHAR_CLASS_MAX_LENGTH 256 | ||
102 | # endif | ||
103 | |||
104 | # ifdef _LIBC | ||
105 | # define IS_CHAR_CLASS(string) __wctype (string) | ||
106 | # else | ||
107 | # define IS_CHAR_CLASS(string) wctype (string) | ||
108 | # endif | ||
109 | # else | ||
110 | # define CHAR_CLASS_MAX_LENGTH 6 /* Namely, `xdigit'. */ | ||
111 | |||
112 | # define IS_CHAR_CLASS(string) \ | ||
113 | (STREQ (string, "alpha") || STREQ (string, "upper") \ | ||
114 | || STREQ (string, "lower") || STREQ (string, "digit") \ | ||
115 | || STREQ (string, "alnum") || STREQ (string, "xdigit") \ | ||
116 | || STREQ (string, "space") || STREQ (string, "print") \ | ||
117 | || STREQ (string, "punct") || STREQ (string, "graph") \ | ||
118 | || STREQ (string, "cntrl") || STREQ (string, "blank")) | ||
119 | # endif | ||
120 | |||
121 | /* Avoid depending on library functions or files | ||
122 | whose names are inconsistent. */ | ||
123 | |||
124 | # if !defined _LIBC && !defined getenv | ||
125 | extern char *getenv (const char *); | ||
126 | # endif | ||
127 | |||
128 | # ifndef errno | ||
129 | extern int errno; | ||
130 | # endif | ||
131 | |||
132 | /* This function doesn't exist on most systems. */ | ||
133 | |||
134 | # if !defined HAVE___STRCHRNUL && !defined _LIBC && 0 | ||
135 | static char * | ||
136 | __strchrnul (const char *s, int c) | ||
137 | { | ||
138 | char *result = strchr (s, c); | ||
139 | if (result == NULL) | ||
140 | result = strchr (s, '\0'); | ||
141 | return result; | ||
142 | } | ||
143 | # else | ||
144 | # define __strchrnul strchrnul | ||
145 | # endif | ||
146 | |||
147 | # ifndef internal_function | ||
148 | /* Inside GNU libc we mark some function in a special way. In other | ||
149 | environments simply ignore the marking. */ | ||
150 | # define internal_function | ||
151 | # endif | ||
152 | |||
153 | /* Match STRING against the filename pattern PATTERN, returning zero if | ||
154 | it matches, nonzero if not. */ | ||
155 | static int internal_fnmatch __P ((const char *pattern, const char *string, | ||
156 | int no_leading_period, int flags)) | ||
157 | internal_function; | ||
158 | static int | ||
159 | internal_function | ||
160 | internal_fnmatch (const char *pattern, const char *string, | ||
161 | int no_leading_period, int flags) | ||
162 | { | ||
163 | register const char *p = pattern, *n = string; | ||
164 | register unsigned char c; | ||
165 | |||
166 | /* Note that this evaluates C many times. */ | ||
167 | # ifdef _LIBC | ||
168 | # define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c)) | ||
169 | # else | ||
170 | # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c)) | ||
171 | # endif | ||
172 | |||
173 | while ((c = *p++) != '\0') | ||
174 | { | ||
175 | c = FOLD (c); | ||
176 | |||
177 | switch (c) | ||
178 | { | ||
179 | case '?': | ||
180 | if (*n == '\0') | ||
181 | return FNM_NOMATCH; | ||
182 | else if (*n == '/' && (flags & FNM_FILE_NAME)) | ||
183 | return FNM_NOMATCH; | ||
184 | else if (*n == '.' && no_leading_period | ||
185 | && (n == string | ||
186 | || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) | ||
187 | return FNM_NOMATCH; | ||
188 | break; | ||
189 | |||
190 | case '\\': | ||
191 | if (!(flags & FNM_NOESCAPE)) | ||
192 | { | ||
193 | c = *p++; | ||
194 | if (c == '\0') | ||
195 | /* Trailing \ loses. */ | ||
196 | return FNM_NOMATCH; | ||
197 | c = FOLD (c); | ||
198 | } | ||
199 | if (FOLD ((unsigned char) *n) != c) | ||
200 | return FNM_NOMATCH; | ||
201 | break; | ||
202 | |||
203 | case '*': | ||
204 | if (*n == '.' && no_leading_period | ||
205 | && (n == string | ||
206 | || (n[-1] == '/' && (flags & FNM_FILE_NAME)))) | ||
207 | return FNM_NOMATCH; | ||
208 | |||
209 | for (c = *p++; c == '?' || c == '*'; c = *p++) | ||
210 | { | ||
211 | if (*n == '/' && (flags & FNM_FILE_NAME)) | ||
212 | /* A slash does not match a wildcard under FNM_FILE_NAME. */ | ||
213 | return FNM_NOMATCH; | ||
214 | else if (c == '?') | ||
215 | { | ||
216 | /* A ? needs to match one character. */ | ||
217 | if (*n == '\0') | ||
218 | /* There isn't another character; no match. */ | ||
219 | return FNM_NOMATCH; | ||
220 | else | ||
221 | /* One character of the string is consumed in matching | ||
222 | this ? wildcard, so *??? won't match if there are | ||
223 | less than three characters. */ | ||
224 | ++n; | ||
225 | } | ||
226 | } | ||
227 | |||
228 | if (c == '\0') | ||
229 | /* The wildcard(s) is/are the last element of the pattern. | ||
230 | If the name is a file name and contains another slash | ||
231 | this does mean it cannot match. */ | ||
232 | return ((flags & FNM_FILE_NAME) && strchr (n, '/') != NULL | ||
233 | ? FNM_NOMATCH : 0); | ||
234 | else | ||
235 | { | ||
236 | const char *endp; | ||
237 | |||
238 | endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0'); | ||
239 | |||
240 | if (c == '[') | ||
241 | { | ||
242 | int flags2 = ((flags & FNM_FILE_NAME) | ||
243 | ? flags : (flags & ~FNM_PERIOD)); | ||
244 | |||
245 | for (--p; n < endp; ++n) | ||
246 | if (internal_fnmatch (p, n, | ||
247 | (no_leading_period | ||
248 | && (n == string | ||
249 | || (n[-1] == '/' | ||
250 | && (flags | ||
251 | & FNM_FILE_NAME)))), | ||
252 | flags2) | ||
253 | == 0) | ||
254 | return 0; | ||
255 | } | ||
256 | else if (c == '/' && (flags & FNM_FILE_NAME)) | ||
257 | { | ||
258 | while (*n != '\0' && *n != '/') | ||
259 | ++n; | ||
260 | if (*n == '/' | ||
261 | && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD, | ||
262 | flags) == 0)) | ||
263 | return 0; | ||
264 | } | ||
265 | else | ||
266 | { | ||
267 | int flags2 = ((flags & FNM_FILE_NAME) | ||
268 | ? flags : (flags & ~FNM_PERIOD)); | ||
269 | |||
270 | if (c == '\\' && !(flags & FNM_NOESCAPE)) | ||
271 | c = *p; | ||
272 | c = FOLD (c); | ||
273 | for (--p; n < endp; ++n) | ||
274 | if (FOLD ((unsigned char) *n) == c | ||
275 | && (internal_fnmatch (p, n, | ||
276 | (no_leading_period | ||
277 | && (n == string | ||
278 | || (n[-1] == '/' | ||
279 | && (flags | ||
280 | & FNM_FILE_NAME)))), | ||
281 | flags2) == 0)) | ||
282 | return 0; | ||
283 | } | ||
284 | } | ||
285 | |||
286 | /* If we come here no match is possible with the wildcard. */ | ||
287 | return FNM_NOMATCH; | ||
288 | |||
289 | case '[': | ||
290 | { | ||
291 | /* Nonzero if the sense of the character class is inverted. */ | ||
292 | static int posixly_correct; | ||
293 | register int not; | ||
294 | char cold; | ||
295 | |||
296 | if (posixly_correct == 0) | ||
297 | posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1; | ||
298 | |||
299 | if (*n == '\0') | ||
300 | return FNM_NOMATCH; | ||
301 | |||
302 | if (*n == '.' && no_leading_period && (n == string | ||
303 | || (n[-1] == '/' | ||
304 | && (flags | ||
305 | & FNM_FILE_NAME)))) | ||
306 | return FNM_NOMATCH; | ||
307 | |||
308 | if (*n == '/' && (flags & FNM_FILE_NAME)) | ||
309 | /* `/' cannot be matched. */ | ||
310 | return FNM_NOMATCH; | ||
311 | |||
312 | not = (*p == '!' || (posixly_correct < 0 && *p == '^')); | ||
313 | if (not) | ||
314 | ++p; | ||
315 | |||
316 | c = *p++; | ||
317 | for (;;) | ||
318 | { | ||
319 | unsigned char fn = FOLD ((unsigned char) *n); | ||
320 | |||
321 | if (!(flags & FNM_NOESCAPE) && c == '\\') | ||
322 | { | ||
323 | if (*p == '\0') | ||
324 | return FNM_NOMATCH; | ||
325 | c = FOLD ((unsigned char) *p); | ||
326 | ++p; | ||
327 | |||
328 | if (c == fn) | ||
329 | goto matched; | ||
330 | } | ||
331 | else if (c == '[' && *p == ':') | ||
332 | { | ||
333 | /* Leave room for the null. */ | ||
334 | char str[CHAR_CLASS_MAX_LENGTH + 1]; | ||
335 | size_t c1 = 0; | ||
336 | # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) | ||
337 | wctype_t wt; | ||
338 | # endif | ||
339 | const char *startp = p; | ||
340 | |||
341 | for (;;) | ||
342 | { | ||
343 | if (c1 == CHAR_CLASS_MAX_LENGTH) | ||
344 | /* The name is too long and therefore the pattern | ||
345 | is ill-formed. */ | ||
346 | return FNM_NOMATCH; | ||
347 | |||
348 | c = *++p; | ||
349 | if (c == ':' && p[1] == ']') | ||
350 | { | ||
351 | p += 2; | ||
352 | break; | ||
353 | } | ||
354 | if (c < 'a' || c >= 'z') | ||
355 | { | ||
356 | /* This cannot possibly be a character class name. | ||
357 | Match it as a normal range. */ | ||
358 | p = startp; | ||
359 | c = '['; | ||
360 | goto normal_bracket; | ||
361 | } | ||
362 | str[c1++] = c; | ||
363 | } | ||
364 | str[c1] = '\0'; | ||
365 | |||
366 | # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H) | ||
367 | wt = IS_CHAR_CLASS (str); | ||
368 | if (wt == 0) | ||
369 | /* Invalid character class name. */ | ||
370 | return FNM_NOMATCH; | ||
371 | |||
372 | if (__iswctype (__btowc ((unsigned char) *n), wt)) | ||
373 | goto matched; | ||
374 | # else | ||
375 | if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n)) | ||
376 | || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n)) | ||
377 | || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n)) | ||
378 | || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n)) | ||
379 | || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n)) | ||
380 | || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n)) | ||
381 | || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n)) | ||
382 | || (STREQ (str, "print") && ISPRINT ((unsigned char) *n)) | ||
383 | || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n)) | ||
384 | || (STREQ (str, "space") && ISSPACE ((unsigned char) *n)) | ||
385 | || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n)) | ||
386 | || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n))) | ||
387 | goto matched; | ||
388 | # endif | ||
389 | } | ||
390 | else if (c == '\0') | ||
391 | /* [ (unterminated) loses. */ | ||
392 | return FNM_NOMATCH; | ||
393 | else | ||
394 | { | ||
395 | normal_bracket: | ||
396 | if (FOLD (c) == fn) | ||
397 | goto matched; | ||
398 | |||
399 | cold = c; | ||
400 | c = *p++; | ||
401 | |||
402 | if (c == '-' && *p != ']') | ||
403 | { | ||
404 | /* It is a range. */ | ||
405 | unsigned char cend = *p++; | ||
406 | if (!(flags & FNM_NOESCAPE) && cend == '\\') | ||
407 | cend = *p++; | ||
408 | if (cend == '\0') | ||
409 | return FNM_NOMATCH; | ||
410 | |||
411 | if (cold <= fn && fn <= FOLD (cend)) | ||
412 | goto matched; | ||
413 | |||
414 | c = *p++; | ||
415 | } | ||
416 | } | ||
417 | |||
418 | if (c == ']') | ||
419 | break; | ||
420 | } | ||
421 | |||
422 | if (!not) | ||
423 | return FNM_NOMATCH; | ||
424 | break; | ||
425 | |||
426 | matched: | ||
427 | /* Skip the rest of the [...] that already matched. */ | ||
428 | while (c != ']') | ||
429 | { | ||
430 | if (c == '\0') | ||
431 | /* [... (unterminated) loses. */ | ||
432 | return FNM_NOMATCH; | ||
433 | |||
434 | c = *p++; | ||
435 | if (!(flags & FNM_NOESCAPE) && c == '\\') | ||
436 | { | ||
437 | if (*p == '\0') | ||
438 | return FNM_NOMATCH; | ||
439 | /* XXX 1003.2d11 is unclear if this is right. */ | ||
440 | ++p; | ||
441 | } | ||
442 | else if (c == '[' && *p == ':') | ||
443 | { | ||
444 | do | ||
445 | if (*++p == '\0') | ||
446 | return FNM_NOMATCH; | ||
447 | while (*p != ':' || p[1] == ']'); | ||
448 | p += 2; | ||
449 | c = *p; | ||
450 | } | ||
451 | } | ||
452 | if (not) | ||
453 | return FNM_NOMATCH; | ||
454 | } | ||
455 | break; | ||
456 | |||
457 | default: | ||
458 | if (c != FOLD ((unsigned char) *n)) | ||
459 | return FNM_NOMATCH; | ||
460 | } | ||
461 | |||
462 | ++n; | ||
463 | } | ||
464 | |||
465 | if (*n == '\0') | ||
466 | return 0; | ||
467 | |||
468 | if ((flags & FNM_LEADING_DIR) && *n == '/') | ||
469 | /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */ | ||
470 | return 0; | ||
471 | |||
472 | return FNM_NOMATCH; | ||
473 | |||
474 | # undef FOLD | ||
475 | } | ||
476 | |||
477 | |||
478 | int | ||
479 | fnmatch (const char *pattern, const char *string, int flags) | ||
480 | { | ||
481 | return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags); | ||
482 | } | ||
483 | |||
484 | #endif /* _LIBC or not __GNU_LIBRARY__. */ | ||