1: /* Copyright (C) 1991-1993, 1996-1999, 2000 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: #if HAVE_CONFIG_H
20: # include <config.h>
21: #endif
22:
23: /* Enable GNU extensions in fnmatch.h. */
24: #ifndef _GNU_SOURCE
25: # define _GNU_SOURCE 1
26: #endif
27:
28: #include <errno.h>
29: #include <fnmatch.h>
30: #include <ctype.h>
31:
32: #if HAVE_STRING_H || defined _LIBC
33: # include <string.h>
34: #else
35: # include <strings.h>
36: #endif
37:
38: #if defined STDC_HEADERS || defined _LIBC
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
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:
58: #if defined _LIBC || !defined __GNU_LIBRARY__
59:
60:
61: # if defined STDC_HEADERS || !defined isascii
62: # define ISASCII(c) 1
63: # else
64: # define ISASCII(c) isascii(c)
65: # endif
66:
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. */
121:
122: # if !defined _LIBC && !defined getenv
123: extern char *getenv ();
124: # endif
125:
126: # ifndef errno
127: extern int errno;
128: # endif
129:
130: /* Match STRING against the filename pattern PATTERN, returning zero if
131: it matches, nonzero if not. */
132: static int
133: #ifdef _LIBC
134: internal_function
135: #endif
136: internal_fnmatch (const char *pattern, const char *string,
137: int no_leading_period, int flags)
138: {
139: register const char *p = pattern, *n = string;
140: register unsigned char c;
141:
142: /* Note that this evaluates C many times. */
143: # ifdef _LIBC
144: # define FOLD(c) ((flags & FNM_CASEFOLD) ? tolower (c) : (c))
145: # else
146: # define FOLD(c) ((flags & FNM_CASEFOLD) && ISUPPER (c) ? tolower (c) : (c))
147: # endif
148:
149: while ((c = *p++) != '\0')
150: {
151: c = FOLD (c);
152:
153: switch (c)
154: {
155: case '?':
156: if (*n == '\0')
157: return FNM_NOMATCH;
158: else if (*n == '/' && (flags & FNM_FILE_NAME))
159: return FNM_NOMATCH;
160: else if (*n == '.' && no_leading_period
161: && (n == string
162: || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
163: return FNM_NOMATCH;
164: break;
165:
166: case '\\':
167: if (!(flags & FNM_NOESCAPE))
168: {
169: c = *p++;
170: if (c == '\0')
171: /* Trailing \ loses. */
172: return FNM_NOMATCH;
173: c = FOLD (c);
174: }
175: if (FOLD ((unsigned char) *n) != c)
176: return FNM_NOMATCH;
177: break;
178:
179: case '*':
180: if (*n == '.' && no_leading_period
181: && (n == string
182: || (n[-1] == '/' && (flags & FNM_FILE_NAME))))
183: return FNM_NOMATCH;
184:
185: for (c = *p++; c == '?' || c == '*'; c = *p++)
186: {
187: if (*n == '/' && (flags & FNM_FILE_NAME))
188: /* A slash does not match a wildcard under FNM_FILE_NAME. */
189: return FNM_NOMATCH;
190: else if (c == '?')
191: {
192: /* A ? needs to match one character. */
193: if (*n == '\0')
194: /* There isn't another character; no match. */
195: return FNM_NOMATCH;
196: else
197: /* One character of the string is consumed in matching
198: this ? wildcard, so *??? won't match if there are
199: less than three characters. */
200: ++n;
201: }
202: }
203:
204: if (c == '\0')
205: /* The wildcard(s) is/are the last element of the pattern.
206: If the name is a file name and contains another slash
207: this does mean it cannot match. If the FNM_LEADING_DIR
208: flag is set and exactly one slash is following, we have
209: a match. */
210: {
211: int result = (flags & FNM_FILE_NAME) == 0 ? 0 : FNM_NOMATCH;
212:
213: if (flags & FNM_FILE_NAME)
214: {
215: const char *slashp = strchr (n, '/');
216:
217: if (flags & FNM_LEADING_DIR)
218: {
219: if (slashp != NULL
220: && strchr (slashp + 1, '/') == NULL)
221: result = 0;
222: }
223: else
224: {
225: if (slashp == NULL)
226: result = 0;
227: }
228: }
229:
230: return result;
231: }
232: else
233: {
234: const char *endp;
235:
236: endp = __strchrnul (n, (flags & FNM_FILE_NAME) ? '/' : '\0');
237:
238: if (c == '[')
239: {
240: int flags2 = ((flags & FNM_FILE_NAME)
241: ? flags : (flags & ~FNM_PERIOD));
242:
243: for (--p; n < endp; ++n)
244: if (internal_fnmatch (p, n,
245: (no_leading_period
246: && (n == string
247: || (n[-1] == '/'
248: && (flags
249: & FNM_FILE_NAME)))),
250: flags2)
251: == 0)
252: return 0;
253: }
254: else if (c == '/' && (flags & FNM_FILE_NAME))
255: {
256: while (*n != '\0' && *n != '/')
257: ++n;
258: if (*n == '/'
259: && (internal_fnmatch (p, n + 1, flags & FNM_PERIOD,
260: flags) == 0))
261: return 0;
262: }
263: else
264: {
265: int flags2 = ((flags & FNM_FILE_NAME)
266: ? flags : (flags & ~FNM_PERIOD));
267:
268: if (c == '\\' && !(flags & FNM_NOESCAPE))
269: c = *p;
270: c = FOLD (c);
271: for (--p; n < endp; ++n)
272: if (FOLD ((unsigned char) *n) == c
273: && (internal_fnmatch (p, n,
274: (no_leading_period
275: && (n == string
276: || (n[-1] == '/'
277: && (flags
278: & FNM_FILE_NAME)))),
279: flags2) == 0))
280: return 0;
281: }
282: }
283:
284: /* If we come here no match is possible with the wildcard. */
285: return FNM_NOMATCH;
286:
287: case '[':
288: {
289: /* Nonzero if the sense of the character class is inverted. */
290: static int posixly_correct;
291: register int not;
292: char cold;
293:
294: if (posixly_correct == 0)
295: posixly_correct = getenv ("POSIXLY_CORRECT") != NULL ? 1 : -1;
296:
297: if (*n == '\0')
298: return FNM_NOMATCH;
299:
300: if (*n == '.' && no_leading_period && (n == string
301: || (n[-1] == '/'
302: && (flags
303: & FNM_FILE_NAME))))
304: return FNM_NOMATCH;
305:
306: if (*n == '/' && (flags & FNM_FILE_NAME))
307: /* `/' cannot be matched. */
308: return FNM_NOMATCH;
309:
310: not = (*p == '!' || (posixly_correct < 0 && *p == '^'));
311: if (not)
312: ++p;
313:
314: c = *p++;
315: for (;;)
316: {
317: unsigned char fn = FOLD ((unsigned char) *n);
318:
319: if (!(flags & FNM_NOESCAPE) && c == '\\')
320: {
321: if (*p == '\0')
322: return FNM_NOMATCH;
323: c = FOLD ((unsigned char) *p);
324: ++p;
325:
326: if (c == fn)
327: goto matched;
328: }
329: else if (c == '[' && *p == ':')
330: {
331: /* Leave room for the null. */
332: char str[CHAR_CLASS_MAX_LENGTH + 1];
333: size_t c1 = 0;
334: # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
335: wctype_t wt;
336: # endif
337: const char *startp = p;
338:
339: for (;;)
340: {
341: if (c1 == CHAR_CLASS_MAX_LENGTH)
342: /* The name is too long and therefore the pattern
343: is ill-formed. */
344: return FNM_NOMATCH;
345:
346: c = *++p;
347: if (c == ':' && p[1] == ']')
348: {
349: p += 2;
350: break;
351: }
352: if (c < 'a' || c >= 'z')
353: {
354: /* This cannot possibly be a character class name.
355: Match it as a normal range. */
356: p = startp;
357: c = '[';
358: goto normal_bracket;
359: }
360: str[c1++] = c;
361: }
362: str[c1] = '\0';
363:
364: # if defined _LIBC || (defined HAVE_WCTYPE_H && defined HAVE_WCHAR_H)
365: wt = IS_CHAR_CLASS (str);
366: if (wt == 0)
367: /* Invalid character class name. */
368: return FNM_NOMATCH;
369:
370: if (__iswctype (__btowc ((unsigned char) *n), wt))
371: goto matched;
372: # else
373: if ((STREQ (str, "alnum") && ISALNUM ((unsigned char) *n))
374: || (STREQ (str, "alpha") && ISALPHA ((unsigned char) *n))
375: || (STREQ (str, "blank") && ISBLANK ((unsigned char) *n))
376: || (STREQ (str, "cntrl") && ISCNTRL ((unsigned char) *n))
377: || (STREQ (str, "digit") && ISDIGIT ((unsigned char) *n))
378: || (STREQ (str, "graph") && ISGRAPH ((unsigned char) *n))
379: || (STREQ (str, "lower") && ISLOWER ((unsigned char) *n))
380: || (STREQ (str, "print") && ISPRINT ((unsigned char) *n))
381: || (STREQ (str, "punct") && ISPUNCT ((unsigned char) *n))
382: || (STREQ (str, "space") && ISSPACE ((unsigned char) *n))
383: || (STREQ (str, "upper") && ISUPPER ((unsigned char) *n))
384: || (STREQ (str, "xdigit") && ISXDIGIT ((unsigned char) *n)))
385: goto matched;
386: # endif
387: }
388: else if (c == '\0')
389: /* [ (unterminated) loses. */
390: return FNM_NOMATCH;
391: else
392: {
393: c = FOLD (c);
394: normal_bracket:
395: if (c == fn)
396: goto matched;
397:
398: cold = c;
399: c = *p++;
400:
401: if (c == '-' && *p != ']')
402: {
403: /* It is a range. */
404: char lo[2];
405: char fc[2];
406: unsigned char cend = *p++;
407: if (!(flags & FNM_NOESCAPE) && cend == '\\')
408: cend = *p++;
409: if (cend == '\0')
410: return FNM_NOMATCH;
411:
412: lo[0] = cold;
413: lo[1] = '\0';
414: fc[0] = fn;
415: fc[1] = '\0';
416: if (strcoll (lo, fc) <= 0)
417: {
418: char hi[2];
419: hi[0] = FOLD (cend);
420: hi[1] = '\0';
421: if (strcoll (fc, hi) <= 0)
422: goto matched;
423: }
424:
425: c = *p++;
426: }
427: }
428:
429: if (c == ']')
430: break;
431: }
432:
433: if (!not)
434: return FNM_NOMATCH;
435: break;
436:
437: matched:
438: /* Skip the rest of the [...] that already matched. */
439: while (c != ']')
440: {
441: if (c == '\0')
442: /* [... (unterminated) loses. */
443: return FNM_NOMATCH;
444:
445: c = *p++;
446: if (!(flags & FNM_NOESCAPE) && c == '\\')
447: {
448: if (*p == '\0')
449: return FNM_NOMATCH;
450: /* XXX 1003.2d11 is unclear if this is right. */
451: ++p;
452: }
453: else if (c == '[' && *p == ':')
454: {
455: do
456: if (*++p == '\0')
457: return FNM_NOMATCH;
458: while (*p != ':' || p[1] == ']');
459: p += 2;
460: c = *p;
461: }
462: }
463: if (not)
464: return FNM_NOMATCH;
465: }
466: break;
467:
468: default:
469: if (c != FOLD ((unsigned char) *n))
470: return FNM_NOMATCH;
471: }
472:
473: ++n;
474: }
475:
476: if (*n == '\0')
477: return 0;
478:
479: if ((flags & FNM_LEADING_DIR) && *n == '/')
480: /* The FNM_LEADING_DIR flag says that "foo*" matches "foobar/frobozz". */
481: return 0;
482:
483: return FNM_NOMATCH;
484:
485: # undef FOLD
486: }
487:
488:
489: int
490: fnmatch (pattern, string, flags)
491: const char *pattern;
492: const char *string;
493: int flags;
494: {
495: return internal_fnmatch (pattern, string, flags & FNM_PERIOD, flags);
496: }
497:
498: #endif /* _LIBC or not __GNU_LIBRARY__. */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>