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