VirtualBox

source: vbox/trunk/src/libs/curl-7.64.0/lib/curl_fnmatch.c@ 86011

Last change on this file since 86011 was 85671, checked in by vboxsync, 4 years ago

Export out internal curl copy to make it a lot simpler to build VBox (OSE) on Windows. bugref:9814

  • Property svn:eol-style set to native
File size: 10.3 KB
Line 
1/***************************************************************************
2 * _ _ ____ _
3 * Project ___| | | | _ \| |
4 * / __| | | | |_) | |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
7 *
8 * Copyright (C) 1998 - 2018, Daniel Stenberg, <daniel@haxx.se>, et al.
9 *
10 * This software is licensed as described in the file COPYING, which
11 * you should have received as part of this distribution. The terms
12 * are also available at https://curl.haxx.se/docs/copyright.html.
13 *
14 * You may opt to use, copy, modify, merge, publish, distribute and/or sell
15 * copies of the Software, and permit persons to whom the Software is
16 * furnished to do so, under the terms of the COPYING file.
17 *
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
20 *
21 ***************************************************************************/
22
23#include "curl_setup.h"
24
25#include <curl/curl.h>
26
27#include "curl_fnmatch.h"
28#include "curl_memory.h"
29
30/* The last #include file should be: */
31#include "memdebug.h"
32
33#ifndef HAVE_FNMATCH
34
35/*
36 * TODO:
37 *
38 * Make this function match POSIX. Test 1307 includes a set of test patterns
39 * that returns different results with a POSIX fnmatch() than with this
40 * implementation and this is considered a bug where POSIX is the guiding
41 * light.
42 */
43
44#define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
45#define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
46
47#define CURLFNM_NEGATE CURLFNM_CHARSET_LEN
48
49#define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1)
50#define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2)
51#define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3)
52#define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4)
53#define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5)
54#define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6)
55#define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7)
56#define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8)
57#define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
58#define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
59
60typedef enum {
61 CURLFNM_SCHS_DEFAULT = 0,
62 CURLFNM_SCHS_RIGHTBR,
63 CURLFNM_SCHS_RIGHTBRLEFTBR
64} setcharset_state;
65
66typedef enum {
67 CURLFNM_PKW_INIT = 0,
68 CURLFNM_PKW_DDOT
69} parsekey_state;
70
71typedef enum {
72 CCLASS_OTHER = 0,
73 CCLASS_DIGIT,
74 CCLASS_UPPER,
75 CCLASS_LOWER
76} char_class;
77
78#define SETCHARSET_OK 1
79#define SETCHARSET_FAIL 0
80
81static int parsekeyword(unsigned char **pattern, unsigned char *charset)
82{
83 parsekey_state state = CURLFNM_PKW_INIT;
84#define KEYLEN 10
85 char keyword[KEYLEN] = { 0 };
86 int found = FALSE;
87 int i;
88 unsigned char *p = *pattern;
89 for(i = 0; !found; i++) {
90 char c = *p++;
91 if(i >= KEYLEN)
92 return SETCHARSET_FAIL;
93 switch(state) {
94 case CURLFNM_PKW_INIT:
95 if(ISLOWER(c))
96 keyword[i] = c;
97 else if(c == ':')
98 state = CURLFNM_PKW_DDOT;
99 else
100 return SETCHARSET_FAIL;
101 break;
102 case CURLFNM_PKW_DDOT:
103 if(c == ']')
104 found = TRUE;
105 else
106 return SETCHARSET_FAIL;
107 }
108 }
109#undef KEYLEN
110
111 *pattern = p; /* move caller's pattern pointer */
112 if(strcmp(keyword, "digit") == 0)
113 charset[CURLFNM_DIGIT] = 1;
114 else if(strcmp(keyword, "alnum") == 0)
115 charset[CURLFNM_ALNUM] = 1;
116 else if(strcmp(keyword, "alpha") == 0)
117 charset[CURLFNM_ALPHA] = 1;
118 else if(strcmp(keyword, "xdigit") == 0)
119 charset[CURLFNM_XDIGIT] = 1;
120 else if(strcmp(keyword, "print") == 0)
121 charset[CURLFNM_PRINT] = 1;
122 else if(strcmp(keyword, "graph") == 0)
123 charset[CURLFNM_GRAPH] = 1;
124 else if(strcmp(keyword, "space") == 0)
125 charset[CURLFNM_SPACE] = 1;
126 else if(strcmp(keyword, "blank") == 0)
127 charset[CURLFNM_BLANK] = 1;
128 else if(strcmp(keyword, "upper") == 0)
129 charset[CURLFNM_UPPER] = 1;
130 else if(strcmp(keyword, "lower") == 0)
131 charset[CURLFNM_LOWER] = 1;
132 else
133 return SETCHARSET_FAIL;
134 return SETCHARSET_OK;
135}
136
137/* Return the character class. */
138static char_class charclass(unsigned char c)
139{
140 if(ISUPPER(c))
141 return CCLASS_UPPER;
142 if(ISLOWER(c))
143 return CCLASS_LOWER;
144 if(ISDIGIT(c))
145 return CCLASS_DIGIT;
146 return CCLASS_OTHER;
147}
148
149/* Include a character or a range in set. */
150static void setcharorrange(unsigned char **pp, unsigned char *charset)
151{
152 unsigned char *p = (*pp)++;
153 unsigned char c = *p++;
154
155 charset[c] = 1;
156 if(ISALNUM(c) && *p++ == '-') {
157 char_class cc = charclass(c);
158 unsigned char endrange = *p++;
159
160 if(endrange == '\\')
161 endrange = *p++;
162 if(endrange >= c && charclass(endrange) == cc) {
163 while(c++ != endrange)
164 if(charclass(c) == cc) /* Chars in class may be not consecutive. */
165 charset[c] = 1;
166 *pp = p;
167 }
168 }
169}
170
171/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
172static int setcharset(unsigned char **p, unsigned char *charset)
173{
174 setcharset_state state = CURLFNM_SCHS_DEFAULT;
175 bool something_found = FALSE;
176 unsigned char c;
177
178 memset(charset, 0, CURLFNM_CHSET_SIZE);
179 for(;;) {
180 c = **p;
181 if(!c)
182 return SETCHARSET_FAIL;
183
184 switch(state) {
185 case CURLFNM_SCHS_DEFAULT:
186 if(c == ']') {
187 if(something_found)
188 return SETCHARSET_OK;
189 something_found = TRUE;
190 state = CURLFNM_SCHS_RIGHTBR;
191 charset[c] = 1;
192 (*p)++;
193 }
194 else if(c == '[') {
195 unsigned char *pp = *p + 1;
196
197 if(*pp++ == ':' && parsekeyword(&pp, charset))
198 *p = pp;
199 else {
200 charset[c] = 1;
201 (*p)++;
202 }
203 something_found = TRUE;
204 }
205 else if(c == '^' || c == '!') {
206 if(!something_found) {
207 if(charset[CURLFNM_NEGATE]) {
208 charset[c] = 1;
209 something_found = TRUE;
210 }
211 else
212 charset[CURLFNM_NEGATE] = 1; /* negate charset */
213 }
214 else
215 charset[c] = 1;
216 (*p)++;
217 }
218 else if(c == '\\') {
219 c = *(++(*p));
220 if(c)
221 setcharorrange(p, charset);
222 else
223 charset['\\'] = 1;
224 something_found = TRUE;
225 }
226 else {
227 setcharorrange(p, charset);
228 something_found = TRUE;
229 }
230 break;
231 case CURLFNM_SCHS_RIGHTBR:
232 if(c == '[') {
233 state = CURLFNM_SCHS_RIGHTBRLEFTBR;
234 charset[c] = 1;
235 (*p)++;
236 }
237 else if(c == ']') {
238 return SETCHARSET_OK;
239 }
240 else if(ISPRINT(c)) {
241 charset[c] = 1;
242 (*p)++;
243 state = CURLFNM_SCHS_DEFAULT;
244 }
245 else
246 /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
247 * nonsense warning 'statement not reached' at end of the fnc when
248 * compiling on Solaris */
249 goto fail;
250 break;
251 case CURLFNM_SCHS_RIGHTBRLEFTBR:
252 if(c == ']')
253 return SETCHARSET_OK;
254 state = CURLFNM_SCHS_DEFAULT;
255 charset[c] = 1;
256 (*p)++;
257 break;
258 }
259 }
260fail:
261 return SETCHARSET_FAIL;
262}
263
264static int loop(const unsigned char *pattern, const unsigned char *string,
265 int maxstars)
266{
267 unsigned char *p = (unsigned char *)pattern;
268 unsigned char *s = (unsigned char *)string;
269 unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
270
271 for(;;) {
272 unsigned char *pp;
273
274 switch(*p) {
275 case '*':
276 if(!maxstars)
277 return CURL_FNMATCH_NOMATCH;
278 /* Regroup consecutive stars and question marks. This can be done because
279 '*?*?*' can be expressed as '??*'. */
280 for(;;) {
281 if(*++p == '\0')
282 return CURL_FNMATCH_MATCH;
283 if(*p == '?') {
284 if(!*s++)
285 return CURL_FNMATCH_NOMATCH;
286 }
287 else if(*p != '*')
288 break;
289 }
290 /* Skip string characters until we find a match with pattern suffix. */
291 for(maxstars--; *s; s++) {
292 if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH)
293 return CURL_FNMATCH_MATCH;
294 }
295 return CURL_FNMATCH_NOMATCH;
296 case '?':
297 if(!*s)
298 return CURL_FNMATCH_NOMATCH;
299 s++;
300 p++;
301 break;
302 case '\0':
303 return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH;
304 case '\\':
305 if(p[1])
306 p++;
307 if(*s++ != *p++)
308 return CURL_FNMATCH_NOMATCH;
309 break;
310 case '[':
311 pp = p + 1; /* Copy in case of syntax error in set. */
312 if(setcharset(&pp, charset)) {
313 int found = FALSE;
314 if(!*s)
315 return CURL_FNMATCH_NOMATCH;
316 if(charset[(unsigned int)*s])
317 found = TRUE;
318 else if(charset[CURLFNM_ALNUM])
319 found = ISALNUM(*s);
320 else if(charset[CURLFNM_ALPHA])
321 found = ISALPHA(*s);
322 else if(charset[CURLFNM_DIGIT])
323 found = ISDIGIT(*s);
324 else if(charset[CURLFNM_XDIGIT])
325 found = ISXDIGIT(*s);
326 else if(charset[CURLFNM_PRINT])
327 found = ISPRINT(*s);
328 else if(charset[CURLFNM_SPACE])
329 found = ISSPACE(*s);
330 else if(charset[CURLFNM_UPPER])
331 found = ISUPPER(*s);
332 else if(charset[CURLFNM_LOWER])
333 found = ISLOWER(*s);
334 else if(charset[CURLFNM_BLANK])
335 found = ISBLANK(*s);
336 else if(charset[CURLFNM_GRAPH])
337 found = ISGRAPH(*s);
338
339 if(charset[CURLFNM_NEGATE])
340 found = !found;
341
342 if(!found)
343 return CURL_FNMATCH_NOMATCH;
344 p = pp + 1;
345 s++;
346 break;
347 }
348 /* Syntax error in set; mismatch! */
349 return CURL_FNMATCH_NOMATCH;
350
351 default:
352 if(*p++ != *s++)
353 return CURL_FNMATCH_NOMATCH;
354 break;
355 }
356 }
357}
358
359/*
360 * @unittest: 1307
361 */
362int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
363{
364 (void)ptr; /* the argument is specified by the curl_fnmatch_callback
365 prototype, but not used by Curl_fnmatch() */
366 if(!pattern || !string) {
367 return CURL_FNMATCH_FAIL;
368 }
369 return loop((unsigned char *)pattern, (unsigned char *)string, 2);
370}
371#else
372#include <fnmatch.h>
373/*
374 * @unittest: 1307
375 */
376int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
377{
378 int rc;
379 (void)ptr; /* the argument is specified by the curl_fnmatch_callback
380 prototype, but not used by Curl_fnmatch() */
381 if(!pattern || !string) {
382 return CURL_FNMATCH_FAIL;
383 }
384 rc = fnmatch(pattern, string, 0);
385 switch(rc) {
386 case 0:
387 return CURL_FNMATCH_MATCH;
388 case FNM_NOMATCH:
389 return CURL_FNMATCH_NOMATCH;
390 default:
391 return CURL_FNMATCH_FAIL;
392 }
393 /* not reached */
394}
395
396#endif
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette