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