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