|
1 |
|
2 https://bugzilla.redhat.com/show_bug.cgi?id=703390 |
|
3 |
|
4 http://svn.apache.org/viewvc/apr/apr/branches/1.4.x/strings/apr_fnmatch.c?r1=731029&r2=1098902 |
|
5 |
|
6 --- strings/apr_fnmatch.c.fnmatch |
|
7 +++ strings/apr_fnmatch.c |
|
8 @@ -1,50 +1,58 @@ |
|
9 -/* |
|
10 - * Copyright (c) 1989, 1993, 1994 |
|
11 - * The Regents of the University of California. All rights reserved. |
|
12 +/* Licensed to the Apache Software Foundation (ASF) under one or more |
|
13 + * contributor license agreements. See the NOTICE file distributed with |
|
14 + * this work for additional information regarding copyright ownership. |
|
15 + * The ASF licenses this file to You under the Apache License, Version 2.0 |
|
16 + * (the "License"); you may not use this file except in compliance with |
|
17 + * the License. You may obtain a copy of the License at |
|
18 * |
|
19 - * This code is derived from software contributed to Berkeley by |
|
20 - * Guido van Rossum. |
|
21 + * http://www.apache.org/licenses/LICENSE-2.0 |
|
22 * |
|
23 - * Redistribution and use in source and binary forms, with or without |
|
24 - * modification, are permitted provided that the following conditions |
|
25 - * are met: |
|
26 - * 1. Redistributions of source code must retain the above copyright |
|
27 - * notice, this list of conditions and the following disclaimer. |
|
28 - * 2. Redistributions in binary form must reproduce the above copyright |
|
29 - * notice, this list of conditions and the following disclaimer in the |
|
30 - * documentation and/or other materials provided with the distribution. |
|
31 - * 3. All advertising materials mentioning features or use of this software |
|
32 - * must display the following acknowledgement: |
|
33 - * This product includes software developed by the University of |
|
34 - * California, Berkeley and its contributors. |
|
35 - * 4. Neither the name of the University nor the names of its contributors |
|
36 - * may be used to endorse or promote products derived from this software |
|
37 - * without specific prior written permission. |
|
38 + * Unless required by applicable law or agreed to in writing, software |
|
39 + * distributed under the License is distributed on an "AS IS" BASIS, |
|
40 + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
41 + * See the License for the specific language governing permissions and |
|
42 + * limitations under the License. |
|
43 + */ |
|
44 + |
|
45 + |
|
46 +/* Derived from The Open Group Base Specifications Issue 7, IEEE Std 1003.1-2008 |
|
47 + * as described in; |
|
48 + * http://pubs.opengroup.org/onlinepubs/9699919799/functions/fnmatch.html |
|
49 + * |
|
50 + * Filename pattern matches defined in section 2.13, "Pattern Matching Notation" |
|
51 + * from chapter 2. "Shell Command Language" |
|
52 + * http://pubs.opengroup.org/onlinepubs/9699919799/utilities/V3_chap02.html#tag_18_13 |
|
53 + * where; 1. A bracket expression starting with an unquoted <circumflex> '^' |
|
54 + * character CONTINUES to specify a non-matching list; 2. an explicit <period> '.' |
|
55 + * in a bracket expression matching list, e.g. "[.abc]" does NOT match a leading |
|
56 + * <period> in a filename; 3. a <left-square-bracket> '[' which does not introduce |
|
57 + * a valid bracket expression is treated as an ordinary character; 4. a differing |
|
58 + * number of consecutive slashes within pattern and string will NOT match; |
|
59 + * 5. a trailing '\' in FNM_ESCAPE mode is treated as an ordinary '\' character. |
|
60 + * |
|
61 + * Bracket expansion defined in section 9.3.5, "RE Bracket Expression", |
|
62 + * from chapter 9, "Regular Expressions" |
|
63 + * http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap09.html#tag_09_03_05 |
|
64 + * with no support for collating symbols, equivalence class expressions or |
|
65 + * character class expressions. A partial range expression with a leading |
|
66 + * hyphen following a valid range expression will match only the ordinary |
|
67 + * <hyphen> and the ending character (e.g. "[a-m-z]" will match characters |
|
68 + * 'a' through 'm', a <hyphen> '-', or a 'z'). |
|
69 + * |
|
70 + * NOTE: Only POSIX/C single byte locales are correctly supported at this time. |
|
71 + * Notably, non-POSIX locales with FNM_CASEFOLD produce undefined results, |
|
72 + * particularly in ranges of mixed case (e.g. "[A-z]") or spanning alpha and |
|
73 + * nonalpha characters within a range. |
|
74 * |
|
75 - * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND |
|
76 - * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE |
|
77 - * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE |
|
78 - * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE |
|
79 - * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL |
|
80 - * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS |
|
81 - * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) |
|
82 - * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT |
|
83 - * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY |
|
84 - * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF |
|
85 - * SUCH DAMAGE. |
|
86 + * XXX comments below indicate porting required for multi-byte character sets |
|
87 + * and non-POSIX locale collation orders; requires mbr* APIs to track shift |
|
88 + * state of pattern and string (rewinding pattern and string repeatedly). |
|
89 + * |
|
90 + * Certain parts of the code assume 0x00-0x3F are unique with any MBCS (e.g. |
|
91 + * UTF-8, SHIFT-JIS, etc). Any implementation allowing '\' as an alternate |
|
92 + * path delimiter must be aware that 0x5C is NOT unique within SHIFT-JIS. |
|
93 */ |
|
94 |
|
95 -#if defined(LIBC_SCCS) && !defined(lint) |
|
96 -static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94"; |
|
97 -#endif /* LIBC_SCCS and not lint */ |
|
98 - |
|
99 -/* |
|
100 - * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6. |
|
101 - * Compares a filename or pathname to a pattern. |
|
102 - */ |
|
103 -#ifndef WIN32 |
|
104 -#include "apr_private.h" |
|
105 -#endif |
|
106 #include "apr_file_info.h" |
|
107 #include "apr_fnmatch.h" |
|
108 #include "apr_tables.h" |
|
109 @@ -55,196 +63,355 @@ static char sccsid[] = "@(#)fnmatch.c 8. |
|
110 # include <ctype.h> |
|
111 #endif |
|
112 |
|
113 -#define EOS '\0' |
|
114 - |
|
115 -static const char *rangematch(const char *, int, int); |
|
116 |
|
117 -APR_DECLARE(apr_status_t) apr_fnmatch(const char *pattern, const char *string, int flags) |
|
118 +/* Most MBCS/collation/case issues handled here. Wildcard '*' is not handled. |
|
119 + * EOS '\0' and the FNM_PATHNAME '/' delimiters are not advanced over, |
|
120 + * however the "\/" sequence is advanced to '/'. |
|
121 + * |
|
122 + * Both pattern and string are **char to support pointer increment of arbitrary |
|
123 + * multibyte characters for the given locale, in a later iteration of this code |
|
124 + */ |
|
125 +static APR_INLINE int fnmatch_ch(const char **pattern, const char **string, int flags) |
|
126 { |
|
127 - const char *stringstart; |
|
128 - char c, test; |
|
129 + const char * const mismatch = *pattern; |
|
130 + const int nocase = !!(flags & APR_FNM_CASE_BLIND); |
|
131 + const int escape = !(flags & APR_FNM_NOESCAPE); |
|
132 + const int slash = !!(flags & APR_FNM_PATHNAME); |
|
133 + int result = APR_FNM_NOMATCH; |
|
134 + const char *startch; |
|
135 + int negate; |
|
136 + |
|
137 + if (**pattern == '[') |
|
138 + { |
|
139 + ++*pattern; |
|
140 + |
|
141 + /* Handle negation, either leading ! or ^ operators (never both) */ |
|
142 + negate = ((**pattern == '!') || (**pattern == '^')); |
|
143 + if (negate) |
|
144 + ++*pattern; |
|
145 + |
|
146 + while (**pattern) |
|
147 + { |
|
148 + /* ']' is an ordinary character at the start of the range pattern */ |
|
149 + if ((**pattern == ']') && (*pattern > mismatch)) { |
|
150 + ++*pattern; |
|
151 + /* XXX: Fix for MBCS character width */ |
|
152 + ++*string; |
|
153 + return (result ^ negate); |
|
154 + } |
|
155 + |
|
156 + if (escape && (**pattern == '\\')) { |
|
157 + ++*pattern; |
|
158 + |
|
159 + /* Patterns must be terminated with ']', not EOS */ |
|
160 + if (!**pattern) |
|
161 + break; |
|
162 + } |
|
163 + |
|
164 + /* Patterns must be terminated with ']' not '/' */ |
|
165 + if (slash && (**pattern == '/')) |
|
166 + break; |
|
167 + |
|
168 + /* Look at only well-formed range patterns; ']' is allowed only if escaped, |
|
169 + * while '/' is not allowed at all in FNM_PATHNAME mode. |
|
170 + */ |
|
171 + /* XXX: Fix for locale/MBCS character width */ |
|
172 + if (((*pattern)[1] == '-') && (*pattern)[2] |
|
173 + && ((escape && ((*pattern)[2] != '\\')) |
|
174 + ? (((*pattern)[2] != ']') && (!slash || ((*pattern)[2] != '/'))) |
|
175 + : (((*pattern)[3]) && (!slash || ((*pattern)[3] != '/'))))) { |
|
176 + startch = *pattern; |
|
177 + *pattern += (escape && ((*pattern)[2] == '\\')) ? 3 : 2; |
|
178 + |
|
179 + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ |
|
180 + if ((**string >= *startch) && (**string <= **pattern)) |
|
181 + result = 0; |
|
182 + else if (nocase && (isupper(**string) || isupper(*startch) |
|
183 + || isupper(**pattern)) |
|
184 + && (tolower(**string) >= tolower(*startch)) |
|
185 + && (tolower(**string) <= tolower(**pattern))) |
|
186 + result = 0; |
|
187 + |
|
188 + ++*pattern; |
|
189 + continue; |
|
190 + } |
|
191 + |
|
192 + /* XXX: handle locale/MBCS comparison, advance by MBCS char width */ |
|
193 + if ((**string == **pattern)) |
|
194 + result = 0; |
|
195 + else if (nocase && (isupper(**string) || isupper(**pattern)) |
|
196 + && (tolower(**string) == tolower(**pattern))) |
|
197 + result = 0; |
|
198 |
|
199 - for (stringstart = string;;) { |
|
200 - switch (c = *pattern++) { |
|
201 - case EOS: |
|
202 - return (*string == EOS ? APR_SUCCESS : APR_FNM_NOMATCH); |
|
203 - case '?': |
|
204 - if (*string == EOS) { |
|
205 - return (APR_FNM_NOMATCH); |
|
206 - } |
|
207 - if (*string == '/' && (flags & APR_FNM_PATHNAME)) { |
|
208 - return (APR_FNM_NOMATCH); |
|
209 - } |
|
210 - if (*string == '.' && (flags & APR_FNM_PERIOD) && |
|
211 - (string == stringstart || |
|
212 - ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) { |
|
213 - return (APR_FNM_NOMATCH); |
|
214 - } |
|
215 - ++string; |
|
216 - break; |
|
217 - case '*': |
|
218 - c = *pattern; |
|
219 - /* Collapse multiple stars. */ |
|
220 - while (c == '*') { |
|
221 - c = *++pattern; |
|
222 - } |
|
223 - |
|
224 - if (*string == '.' && (flags & APR_FNM_PERIOD) && |
|
225 - (string == stringstart || |
|
226 - ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) { |
|
227 - return (APR_FNM_NOMATCH); |
|
228 - } |
|
229 - |
|
230 - /* Optimize for pattern with * at end or before /. */ |
|
231 - if (c == EOS) { |
|
232 - if (flags & APR_FNM_PATHNAME) { |
|
233 - return (strchr(string, '/') == NULL ? APR_SUCCESS : APR_FNM_NOMATCH); |
|
234 - } |
|
235 - else { |
|
236 - return (APR_SUCCESS); |
|
237 - } |
|
238 - } |
|
239 - else if (c == '/' && flags & APR_FNM_PATHNAME) { |
|
240 - if ((string = strchr(string, '/')) == NULL) { |
|
241 - return (APR_FNM_NOMATCH); |
|
242 - } |
|
243 - break; |
|
244 - } |
|
245 - |
|
246 - /* General case, use recursion. */ |
|
247 - while ((test = *string) != EOS) { |
|
248 - if (!apr_fnmatch(pattern, string, flags & ~APR_FNM_PERIOD)) { |
|
249 - return (APR_SUCCESS); |
|
250 - } |
|
251 - if (test == '/' && flags & APR_FNM_PATHNAME) { |
|
252 - break; |
|
253 - } |
|
254 - ++string; |
|
255 - } |
|
256 - return (APR_FNM_NOMATCH); |
|
257 - case '[': |
|
258 - if (*string == EOS) { |
|
259 - return (APR_FNM_NOMATCH); |
|
260 - } |
|
261 - if (*string == '/' && flags & APR_FNM_PATHNAME) { |
|
262 - return (APR_FNM_NOMATCH); |
|
263 - } |
|
264 - if (*string == '.' && (flags & APR_FNM_PERIOD) && |
|
265 - (string == stringstart || |
|
266 - ((flags & APR_FNM_PATHNAME) && *(string - 1) == '/'))) { |
|
267 - return (APR_FNM_NOMATCH); |
|
268 - } |
|
269 - if ((pattern = rangematch(pattern, *string, flags)) == NULL) { |
|
270 - return (APR_FNM_NOMATCH); |
|
271 - } |
|
272 - ++string; |
|
273 - break; |
|
274 - case '\\': |
|
275 - if (!(flags & APR_FNM_NOESCAPE)) { |
|
276 - if ((c = *pattern++) == EOS) { |
|
277 - c = '\\'; |
|
278 - --pattern; |
|
279 - } |
|
280 - } |
|
281 - /* FALLTHROUGH */ |
|
282 - default: |
|
283 - if (flags & APR_FNM_CASE_BLIND) { |
|
284 - if (apr_tolower(c) != apr_tolower(*string)) { |
|
285 - return (APR_FNM_NOMATCH); |
|
286 - } |
|
287 - } |
|
288 - else if (c != *string) { |
|
289 - return (APR_FNM_NOMATCH); |
|
290 - } |
|
291 - string++; |
|
292 - break; |
|
293 - } |
|
294 - /* NOTREACHED */ |
|
295 + ++*pattern; |
|
296 + } |
|
297 + |
|
298 + /* NOT a properly balanced [expr] pattern; Rewind to test '[' literal */ |
|
299 + *pattern = mismatch; |
|
300 + result = APR_FNM_NOMATCH; |
|
301 + } |
|
302 + else if (**pattern == '?') { |
|
303 + /* Optimize '?' match before unescaping **pattern */ |
|
304 + if (!**string || (slash && (**string == '/'))) |
|
305 + return APR_FNM_NOMATCH; |
|
306 + result = 0; |
|
307 + goto fnmatch_ch_success; |
|
308 } |
|
309 + else if (escape && (**pattern == '\\') && (*pattern)[1]) { |
|
310 + ++*pattern; |
|
311 + } |
|
312 + |
|
313 + /* XXX: handle locale/MBCS comparison, advance by the MBCS char width */ |
|
314 + if (**string == **pattern) |
|
315 + result = 0; |
|
316 + else if (nocase && (isupper(**string) || isupper(**pattern)) |
|
317 + && (tolower(**string) == tolower(**pattern))) |
|
318 + result = 0; |
|
319 + |
|
320 + /* Refuse to advance over trailing slash or nulls |
|
321 + */ |
|
322 + if (!**string || !**pattern || (slash && ((**string == '/') || (**pattern == '/')))) |
|
323 + return result; |
|
324 + |
|
325 +fnmatch_ch_success: |
|
326 + ++*pattern; |
|
327 + ++*string; |
|
328 + return result; |
|
329 } |
|
330 |
|
331 -static const char *rangematch(const char *pattern, int test, int flags) |
|
332 -{ |
|
333 - int negate, ok; |
|
334 - char c, c2; |
|
335 |
|
336 - /* |
|
337 - * A bracket expression starting with an unquoted circumflex |
|
338 - * character produces unspecified results (IEEE 1003.2-1992, |
|
339 - * 3.13.2). This implementation treats it like '!', for |
|
340 - * consistency with the regular expression syntax. |
|
341 - * J.T. Conklin ([email protected]) |
|
342 +APR_DECLARE(int) apr_fnmatch(const char *pattern, const char *string, int flags) |
|
343 +{ |
|
344 + static const char dummystring[2] = {' ', 0}; |
|
345 + const int escape = !(flags & APR_FNM_NOESCAPE); |
|
346 + const int slash = !!(flags & APR_FNM_PATHNAME); |
|
347 + const char *strendseg; |
|
348 + const char *dummyptr; |
|
349 + const char *matchptr; |
|
350 + int wild; |
|
351 + /* For '*' wild processing only; surpress 'used before initialization' |
|
352 + * warnings with dummy initialization values; |
|
353 */ |
|
354 - if ((negate = (*pattern == '!' || *pattern == '^'))) { |
|
355 - ++pattern; |
|
356 - } |
|
357 + const char *strstartseg = NULL; |
|
358 + const char *mismatch = NULL; |
|
359 + int matchlen = 0; |
|
360 + |
|
361 + while (*pattern) |
|
362 + { |
|
363 + /* Match balanced slashes, starting a new segment pattern |
|
364 + */ |
|
365 + if (slash && escape && (*pattern == '\\') && (pattern[1] == '/')) |
|
366 + ++pattern; |
|
367 + if (slash && (*pattern == '/') && (*string == '/')) { |
|
368 + ++pattern; |
|
369 + ++string; |
|
370 + } |
|
371 + |
|
372 + /* At the beginning of each segment, validate leading period behavior. |
|
373 + */ |
|
374 + if ((flags & APR_FNM_PERIOD) && (*string == '.')) |
|
375 + { |
|
376 + if (*pattern == '.') |
|
377 + ++pattern; |
|
378 + else if (escape && (*pattern == '\\') && (pattern[1] == '.')) |
|
379 + pattern += 2; |
|
380 + else |
|
381 + return APR_FNM_NOMATCH; |
|
382 + ++string; |
|
383 + } |
|
384 + |
|
385 + /* Determine the end of string segment |
|
386 + * |
|
387 + * Presumes '/' character is unique, not composite in any MBCS encoding |
|
388 + */ |
|
389 + if (slash) { |
|
390 + strendseg = strchr(string, '/'); |
|
391 + if (!strendseg) |
|
392 + strendseg = strchr(string, '\0'); |
|
393 + } |
|
394 + else { |
|
395 + strendseg = strchr(string, '\0'); |
|
396 + } |
|
397 + |
|
398 + /* Allow pattern '*' to be consumed even with no remaining string to match |
|
399 + */ |
|
400 + while (*pattern && !(slash && ((*pattern == '/') |
|
401 + || (escape && (*pattern == '\\') |
|
402 + && (pattern[1] == '/')))) |
|
403 + && ((string < strendseg) |
|
404 + || ((*pattern == '*') && (string == strendseg)))) |
|
405 + { |
|
406 + /* Reduce groups of '*' and '?' to n '?' matches |
|
407 + * followed by one '*' test for simplicity |
|
408 + */ |
|
409 + for (wild = 0; ((*pattern == '*') || (*pattern == '?')); ++pattern) |
|
410 + { |
|
411 + if (*pattern == '*') { |
|
412 + wild = 1; |
|
413 + } |
|
414 + else if (string < strendseg) { /* && (*pattern == '?') */ |
|
415 + /* XXX: Advance 1 char for MBCS locale */ |
|
416 + ++string; |
|
417 + } |
|
418 + else { /* (string >= strendseg) && (*pattern == '?') */ |
|
419 + return APR_FNM_NOMATCH; |
|
420 + } |
|
421 + } |
|
422 + |
|
423 + if (wild) |
|
424 + { |
|
425 + strstartseg = string; |
|
426 + mismatch = pattern; |
|
427 + |
|
428 + /* Count fixed (non '*') char matches remaining in pattern |
|
429 + * excluding '/' (or "\/") and '*' |
|
430 + */ |
|
431 + for (matchptr = pattern, matchlen = 0; 1; ++matchlen) |
|
432 + { |
|
433 + if ((*matchptr == '\0') |
|
434 + || (slash && ((*matchptr == '/') |
|
435 + || (escape && (*matchptr == '\\') |
|
436 + && (matchptr[1] == '/'))))) |
|
437 + { |
|
438 + /* Compare precisely this many trailing string chars, |
|
439 + * the resulting match needs no wildcard loop |
|
440 + */ |
|
441 + /* XXX: Adjust for MBCS */ |
|
442 + if (string + matchlen > strendseg) |
|
443 + return APR_FNM_NOMATCH; |
|
444 + |
|
445 + string = strendseg - matchlen; |
|
446 + wild = 0; |
|
447 + break; |
|
448 + } |
|
449 + |
|
450 + if (*matchptr == '*') |
|
451 + { |
|
452 + /* Ensure at least this many trailing string chars remain |
|
453 + * for the first comparison |
|
454 + */ |
|
455 + /* XXX: Adjust for MBCS */ |
|
456 + if (string + matchlen > strendseg) |
|
457 + return APR_FNM_NOMATCH; |
|
458 + |
|
459 + /* Begin first wild comparison at the current position */ |
|
460 + break; |
|
461 + } |
|
462 + |
|
463 + /* Skip forward in pattern by a single character match |
|
464 + * Use a dummy fnmatch_ch() test to count one "[range]" escape |
|
465 + */ |
|
466 + /* XXX: Adjust for MBCS */ |
|
467 + if (escape && (*matchptr == '\\') && matchptr[1]) { |
|
468 + matchptr += 2; |
|
469 + } |
|
470 + else if (*matchptr == '[') { |
|
471 + dummyptr = dummystring; |
|
472 + fnmatch_ch(&matchptr, &dummyptr, flags); |
|
473 + } |
|
474 + else { |
|
475 + ++matchptr; |
|
476 + } |
|
477 + } |
|
478 + } |
|
479 + |
|
480 + /* Incrementally match string against the pattern |
|
481 + */ |
|
482 + while (*pattern && (string < strendseg)) |
|
483 + { |
|
484 + /* Success; begin a new wild pattern search |
|
485 + */ |
|
486 + if (*pattern == '*') |
|
487 + break; |
|
488 + |
|
489 + if (slash && ((*string == '/') || (*pattern == '/') |
|
490 + || (escape && (*pattern == '\\') |
|
491 + && (pattern[1] == '/')))) |
|
492 + break; |
|
493 + |
|
494 + /* Compare ch's (the pattern is advanced over "\/" to the '/', |
|
495 + * but slashes will mismatch, and are not consumed) |
|
496 + */ |
|
497 + if (!fnmatch_ch(&pattern, &string, flags)) |
|
498 + continue; |
|
499 + |
|
500 + /* Failed to match, loop against next char offset of string segment |
|
501 + * until not enough string chars remain to match the fixed pattern |
|
502 + */ |
|
503 + if (wild) { |
|
504 + /* XXX: Advance 1 char for MBCS locale */ |
|
505 + string = ++strstartseg; |
|
506 + if (string + matchlen > strendseg) |
|
507 + return APR_FNM_NOMATCH; |
|
508 + |
|
509 + pattern = mismatch; |
|
510 + continue; |
|
511 + } |
|
512 + else |
|
513 + return APR_FNM_NOMATCH; |
|
514 + } |
|
515 + } |
|
516 + |
|
517 + if (*string && (!slash || (*string != '/'))) |
|
518 + return APR_FNM_NOMATCH; |
|
519 |
|
520 - for (ok = 0; (c = *pattern++) != ']';) { |
|
521 - if (c == '\\' && !(flags & APR_FNM_NOESCAPE)) { |
|
522 - c = *pattern++; |
|
523 - } |
|
524 - if (c == EOS) { |
|
525 - return (NULL); |
|
526 - } |
|
527 - if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') { |
|
528 - pattern += 2; |
|
529 - if (c2 == '\\' && !(flags & APR_FNM_NOESCAPE)) { |
|
530 - c2 = *pattern++; |
|
531 - } |
|
532 - if (c2 == EOS) { |
|
533 - return (NULL); |
|
534 - } |
|
535 - if ((c <= test && test <= c2) |
|
536 - || ((flags & APR_FNM_CASE_BLIND) |
|
537 - && ((apr_tolower(c) <= apr_tolower(test)) |
|
538 - && (apr_tolower(test) <= apr_tolower(c2))))) { |
|
539 - ok = 1; |
|
540 - } |
|
541 - } |
|
542 - else if ((c == test) |
|
543 - || ((flags & APR_FNM_CASE_BLIND) |
|
544 - && (apr_tolower(c) == apr_tolower(test)))) { |
|
545 - ok = 1; |
|
546 - } |
|
547 + if (*pattern && (!slash || ((*pattern != '/') |
|
548 + && (!escape || (*pattern != '\\') |
|
549 + || (pattern[1] != '/'))))) |
|
550 + return APR_FNM_NOMATCH; |
|
551 } |
|
552 - return (ok == negate ? NULL : pattern); |
|
553 + |
|
554 + /* pattern is at EOS; if string is also, declare success |
|
555 + */ |
|
556 + if (!*string) |
|
557 + return 0; |
|
558 + |
|
559 + /* pattern didn't match to the end of string */ |
|
560 + return APR_FNM_NOMATCH; |
|
561 } |
|
562 |
|
563 |
|
564 -/* This function is an Apache addition */ |
|
565 -/* return non-zero if pattern has any glob chars in it */ |
|
566 +/* This function is an Apache addition |
|
567 + * return non-zero if pattern has any glob chars in it |
|
568 + * @bug Function does not distinguish for FNM_PATHNAME mode, which renders |
|
569 + * a false positive for test[/]this (which is not a range, but |
|
570 + * seperate test[ and ]this segments and no glob.) |
|
571 + * @bug Function does not distinguish for non-FNM_ESCAPE mode. |
|
572 + * @bug Function does not parse []] correctly |
|
573 + * Solution may be to use fnmatch_ch() to walk the patterns? |
|
574 + */ |
|
575 APR_DECLARE(int) apr_fnmatch_test(const char *pattern) |
|
576 { |
|
577 int nesting; |
|
578 |
|
579 nesting = 0; |
|
580 while (*pattern) { |
|
581 - switch (*pattern) { |
|
582 - case '?': |
|
583 - case '*': |
|
584 - return 1; |
|
585 - |
|
586 - case '\\': |
|
587 - if (*++pattern == '\0') { |
|
588 - return 0; |
|
589 - } |
|
590 - break; |
|
591 - |
|
592 - case '[': /* '[' is only a glob if it has a matching ']' */ |
|
593 - ++nesting; |
|
594 - break; |
|
595 - |
|
596 - case ']': |
|
597 - if (nesting) { |
|
598 - return 1; |
|
599 - } |
|
600 - break; |
|
601 - } |
|
602 - ++pattern; |
|
603 - } |
|
604 + switch (*pattern) { |
|
605 + case '?': |
|
606 + case '*': |
|
607 + return 1; |
|
608 + |
|
609 + case '\\': |
|
610 + if (*++pattern == '\0') { |
|
611 + return 0; |
|
612 + } |
|
613 + break; |
|
614 + |
|
615 + case '[': /* '[' is only a glob if it has a matching ']' */ |
|
616 + ++nesting; |
|
617 + break; |
|
618 + |
|
619 + case ']': |
|
620 + if (nesting) { |
|
621 + return 1; |
|
622 + } |
|
623 + break; |
|
624 + } |
|
625 + ++pattern; } |
|
626 return 0; |
|
627 } |
|
628 |
|
629 + |
|
630 /* Find all files matching the specified pattern */ |
|
631 APR_DECLARE(apr_status_t) apr_match_glob(const char *pattern, |
|
632 apr_array_header_t **result, |