1 /***************************************************************************
3 * Project ___| | | | _ \| |
5 * | (__| |_| | _ <| |___
6 * \___|\___/|_| \_\_____|
8 * Copyright (C) 1998 - 2010, Daniel Stenberg, <daniel@haxx.se>, et al.
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 http://curl.haxx.se/docs/copyright.html.
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.
18 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
19 * KIND, either express or implied.
21 ***************************************************************************/
23 #include "curl_fnmatch.h"
26 #define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
27 #define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
29 #define CURLFNM_NEGATE CURLFNM_CHARSET_LEN
31 #define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1)
32 #define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2)
33 #define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3)
34 #define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4)
35 #define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5)
36 #define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6)
37 #define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7)
38 #define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8)
39 #define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
40 #define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
43 CURLFNM_LOOP_DEFAULT = 0,
44 CURLFNM_LOOP_BACKSLASH
48 CURLFNM_SCHS_DEFAULT = 0,
49 CURLFNM_SCHS_MAYRANGE,
50 CURLFNM_SCHS_MAYRANGE2,
52 CURLFNM_SCHS_RIGHTBRLEFTBR
60 #define SETCHARSET_OK 1
61 #define SETCHARSET_FAIL 0
63 static int parsekeyword(unsigned char **pattern, unsigned char *charset)
65 parsekey_state state = CURLFNM_PKW_INIT;
67 char keyword[KEYLEN] = { 0 };
70 register unsigned char *p = *pattern;
71 for(i = 0; !found; i++) {
74 return SETCHARSET_FAIL;
76 case CURLFNM_PKW_INIT:
77 if(ISALPHA(c) && ISLOWER(c))
80 state = CURLFNM_PKW_DDOT;
84 case CURLFNM_PKW_DDOT:
88 return SETCHARSET_FAIL;
93 *pattern = p; /* move caller's pattern pointer */
94 if(strcmp(keyword, "digit") == 0)
95 charset[CURLFNM_DIGIT] = 1;
96 else if(strcmp(keyword, "alnum") == 0)
97 charset[CURLFNM_ALNUM] = 1;
98 else if(strcmp(keyword, "alpha") == 0)
99 charset[CURLFNM_ALPHA] = 1;
100 else if(strcmp(keyword, "xdigit") == 0)
101 charset[CURLFNM_XDIGIT] = 1;
102 else if(strcmp(keyword, "print") == 0)
103 charset[CURLFNM_PRINT] = 1;
104 else if(strcmp(keyword, "graph") == 0)
105 charset[CURLFNM_GRAPH] = 1;
106 else if(strcmp(keyword, "space") == 0)
107 charset[CURLFNM_SPACE] = 1;
108 else if(strcmp(keyword, "blank") == 0)
109 charset[CURLFNM_BLANK] = 1;
110 else if(strcmp(keyword, "upper") == 0)
111 charset[CURLFNM_UPPER] = 1;
112 else if(strcmp(keyword, "lower") == 0)
113 charset[CURLFNM_LOWER] = 1;
115 return SETCHARSET_FAIL;
116 return SETCHARSET_OK;
119 /* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
120 static int setcharset(unsigned char **p, unsigned char *charset)
122 setcharset_state state = CURLFNM_SCHS_DEFAULT;
123 unsigned char rangestart = 0;
124 unsigned char lastchar = 0;
125 bool something_found = FALSE;
126 register unsigned char c;
130 case CURLFNM_SCHS_DEFAULT:
131 if(ISALNUM(c)) { /* ASCII value */
135 state = CURLFNM_SCHS_MAYRANGE;
136 something_found = TRUE;
140 return SETCHARSET_OK;
142 something_found = TRUE;
143 state = CURLFNM_SCHS_RIGHTBR;
149 if(c2 == ':') { /* there has to be a keyword */
151 if(parsekeyword(p, charset)) {
152 state = CURLFNM_SCHS_DEFAULT;
155 return SETCHARSET_FAIL;
161 something_found = TRUE;
163 else if(c == '?' || c == '*') {
164 something_found = TRUE;
168 else if(c == '^' || c == '!') {
169 if(!something_found) {
170 if(charset[CURLFNM_NEGATE]) {
175 charset[CURLFNM_NEGATE] = 1; /* negate charset */
184 something_found = TRUE;
185 state = CURLFNM_SCHS_MAYRANGE;
191 return SETCHARSET_FAIL;
194 return SETCHARSET_FAIL;
199 something_found = TRUE;
202 case CURLFNM_SCHS_MAYRANGE:
207 state = CURLFNM_SCHS_MAYRANGE2;
210 state = CURLFNM_SCHS_DEFAULT;
212 else if(ISALNUM(c)) {
223 return SETCHARSET_FAIL;
226 return SETCHARSET_OK;
229 return SETCHARSET_FAIL;
231 case CURLFNM_SCHS_MAYRANGE2:
235 return SETCHARSET_FAIL;
238 return SETCHARSET_OK;
244 state = CURLFNM_SCHS_DEFAULT;
248 return SETCHARSET_FAIL;
250 if(c >= rangestart) {
251 if((ISLOWER(c) && ISLOWER(rangestart)) ||
252 (ISDIGIT(c) && ISDIGIT(rangestart)) ||
253 (ISUPPER(c) && ISUPPER(rangestart))) {
254 charset[lastchar] = 0;
256 while(rangestart++ <= c)
257 charset[rangestart-1] = 1;
259 state = CURLFNM_SCHS_DEFAULT;
262 return SETCHARSET_FAIL;
265 case CURLFNM_SCHS_RIGHTBR:
267 state = CURLFNM_SCHS_RIGHTBRLEFTBR;
272 return SETCHARSET_OK;
275 return SETCHARSET_FAIL;
277 else if(ISPRINT(c)) {
280 state = CURLFNM_SCHS_DEFAULT;
283 return SETCHARSET_FAIL;
285 case CURLFNM_SCHS_RIGHTBRLEFTBR:
287 return SETCHARSET_OK;
290 state = CURLFNM_SCHS_DEFAULT;
297 return SETCHARSET_FAIL;
300 static int loop(const unsigned char *pattern, const unsigned char *string)
302 loop_state state = CURLFNM_LOOP_DEFAULT;
303 register unsigned char *p = (unsigned char *)pattern;
304 register unsigned char *s = (unsigned char *)string;
305 unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
310 case CURLFNM_LOOP_DEFAULT:
312 while(*(p+1) == '*') /* eliminate multiple stars */
314 if(*s == '\0' && *(p+1) == '\0')
315 return CURL_FNMATCH_MATCH;
316 rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
317 if(rc == CURL_FNMATCH_MATCH)
318 return CURL_FNMATCH_MATCH;
319 if(*s) /* let the star eat up one character */
322 return CURL_FNMATCH_NOMATCH;
330 return CURL_FNMATCH_NOMATCH;
332 return CURL_FNMATCH_FAIL; /* cannot deal with other character */
334 else if(*p == '\0') {
336 return CURL_FNMATCH_MATCH;
338 return CURL_FNMATCH_NOMATCH;
340 else if(*p == '\\') {
341 state = CURLFNM_LOOP_BACKSLASH;
345 unsigned char *pp = p+1; /* cannot handle with pointer to register */
346 if(setcharset(&pp, charset)) {
348 if(charset[(unsigned int)*s])
350 else if(charset[CURLFNM_ALNUM])
352 else if(charset[CURLFNM_ALPHA])
354 else if(charset[CURLFNM_DIGIT])
356 else if(charset[CURLFNM_XDIGIT])
357 found = ISXDIGIT(*s);
358 else if(charset[CURLFNM_PRINT])
360 else if(charset[CURLFNM_SPACE])
362 else if(charset[CURLFNM_UPPER])
364 else if(charset[CURLFNM_LOWER])
366 else if(charset[CURLFNM_BLANK])
368 else if(charset[CURLFNM_GRAPH])
371 if(charset[CURLFNM_NEGATE])
377 memset(charset, 0, CURLFNM_CHSET_SIZE);
380 return CURL_FNMATCH_NOMATCH;
383 return CURL_FNMATCH_FAIL;
387 return CURL_FNMATCH_NOMATCH;
390 case CURLFNM_LOOP_BACKSLASH:
393 state = CURLFNM_LOOP_DEFAULT;
395 return CURL_FNMATCH_NOMATCH;
398 return CURL_FNMATCH_FAIL;
404 int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
406 (void)ptr; /* the argument is specified by the curl_fnmatch_callback
407 prototype, but not used by Curl_fnmatch() */
408 if(!pattern || !string) {
409 return CURL_FNMATCH_FAIL;
411 return loop((unsigned char *)pattern, (unsigned char *)string);