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