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