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