Annotation of embedaddon/curl/lib/curl_fnmatch.c, revision 1.1.1.1
1.1 misho 1: /***************************************************************************
2: * _ _ ____ _
3: * Project ___| | | | _ \| |
4: * / __| | | | |_) | |
5: * | (__| |_| | _ <| |___
6: * \___|\___/|_| \_\_____|
7: *
8: * Copyright (C) 1998 - 2019, 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: #ifndef CURL_DISABLE_FTP
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: #define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
36: #define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
37:
38: #define CURLFNM_NEGATE CURLFNM_CHARSET_LEN
39:
40: #define CURLFNM_ALNUM (CURLFNM_CHARSET_LEN + 1)
41: #define CURLFNM_DIGIT (CURLFNM_CHARSET_LEN + 2)
42: #define CURLFNM_XDIGIT (CURLFNM_CHARSET_LEN + 3)
43: #define CURLFNM_ALPHA (CURLFNM_CHARSET_LEN + 4)
44: #define CURLFNM_PRINT (CURLFNM_CHARSET_LEN + 5)
45: #define CURLFNM_BLANK (CURLFNM_CHARSET_LEN + 6)
46: #define CURLFNM_LOWER (CURLFNM_CHARSET_LEN + 7)
47: #define CURLFNM_GRAPH (CURLFNM_CHARSET_LEN + 8)
48: #define CURLFNM_SPACE (CURLFNM_CHARSET_LEN + 9)
49: #define CURLFNM_UPPER (CURLFNM_CHARSET_LEN + 10)
50:
51: typedef enum {
52: CURLFNM_SCHS_DEFAULT = 0,
53: CURLFNM_SCHS_RIGHTBR,
54: CURLFNM_SCHS_RIGHTBRLEFTBR
55: } setcharset_state;
56:
57: typedef enum {
58: CURLFNM_PKW_INIT = 0,
59: CURLFNM_PKW_DDOT
60: } parsekey_state;
61:
62: typedef enum {
63: CCLASS_OTHER = 0,
64: CCLASS_DIGIT,
65: CCLASS_UPPER,
66: CCLASS_LOWER
67: } char_class;
68:
69: #define SETCHARSET_OK 1
70: #define SETCHARSET_FAIL 0
71:
72: static int parsekeyword(unsigned char **pattern, unsigned char *charset)
73: {
74: parsekey_state state = CURLFNM_PKW_INIT;
75: #define KEYLEN 10
76: char keyword[KEYLEN] = { 0 };
77: int found = FALSE;
78: int i;
79: unsigned char *p = *pattern;
80: for(i = 0; !found; i++) {
81: char c = *p++;
82: if(i >= KEYLEN)
83: return SETCHARSET_FAIL;
84: switch(state) {
85: case CURLFNM_PKW_INIT:
86: if(ISLOWER(c))
87: keyword[i] = c;
88: else if(c == ':')
89: state = CURLFNM_PKW_DDOT;
90: else
91: return SETCHARSET_FAIL;
92: break;
93: case CURLFNM_PKW_DDOT:
94: if(c == ']')
95: found = TRUE;
96: else
97: return SETCHARSET_FAIL;
98: }
99: }
100: #undef KEYLEN
101:
102: *pattern = p; /* move caller's pattern pointer */
103: if(strcmp(keyword, "digit") == 0)
104: charset[CURLFNM_DIGIT] = 1;
105: else if(strcmp(keyword, "alnum") == 0)
106: charset[CURLFNM_ALNUM] = 1;
107: else if(strcmp(keyword, "alpha") == 0)
108: charset[CURLFNM_ALPHA] = 1;
109: else if(strcmp(keyword, "xdigit") == 0)
110: charset[CURLFNM_XDIGIT] = 1;
111: else if(strcmp(keyword, "print") == 0)
112: charset[CURLFNM_PRINT] = 1;
113: else if(strcmp(keyword, "graph") == 0)
114: charset[CURLFNM_GRAPH] = 1;
115: else if(strcmp(keyword, "space") == 0)
116: charset[CURLFNM_SPACE] = 1;
117: else if(strcmp(keyword, "blank") == 0)
118: charset[CURLFNM_BLANK] = 1;
119: else if(strcmp(keyword, "upper") == 0)
120: charset[CURLFNM_UPPER] = 1;
121: else if(strcmp(keyword, "lower") == 0)
122: charset[CURLFNM_LOWER] = 1;
123: else
124: return SETCHARSET_FAIL;
125: return SETCHARSET_OK;
126: }
127:
128: /* Return the character class. */
129: static char_class charclass(unsigned char c)
130: {
131: if(ISUPPER(c))
132: return CCLASS_UPPER;
133: if(ISLOWER(c))
134: return CCLASS_LOWER;
135: if(ISDIGIT(c))
136: return CCLASS_DIGIT;
137: return CCLASS_OTHER;
138: }
139:
140: /* Include a character or a range in set. */
141: static void setcharorrange(unsigned char **pp, unsigned char *charset)
142: {
143: unsigned char *p = (*pp)++;
144: unsigned char c = *p++;
145:
146: charset[c] = 1;
147: if(ISALNUM(c) && *p++ == '-') {
148: char_class cc = charclass(c);
149: unsigned char endrange = *p++;
150:
151: if(endrange == '\\')
152: endrange = *p++;
153: if(endrange >= c && charclass(endrange) == cc) {
154: while(c++ != endrange)
155: if(charclass(c) == cc) /* Chars in class may be not consecutive. */
156: charset[c] = 1;
157: *pp = p;
158: }
159: }
160: }
161:
162: /* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
163: static int setcharset(unsigned char **p, unsigned char *charset)
164: {
165: setcharset_state state = CURLFNM_SCHS_DEFAULT;
166: bool something_found = FALSE;
167: unsigned char c;
168:
169: memset(charset, 0, CURLFNM_CHSET_SIZE);
170: for(;;) {
171: c = **p;
172: if(!c)
173: return SETCHARSET_FAIL;
174:
175: switch(state) {
176: case CURLFNM_SCHS_DEFAULT:
177: if(c == ']') {
178: if(something_found)
179: return SETCHARSET_OK;
180: something_found = TRUE;
181: state = CURLFNM_SCHS_RIGHTBR;
182: charset[c] = 1;
183: (*p)++;
184: }
185: else if(c == '[') {
186: unsigned char *pp = *p + 1;
187:
188: if(*pp++ == ':' && parsekeyword(&pp, charset))
189: *p = pp;
190: else {
191: charset[c] = 1;
192: (*p)++;
193: }
194: something_found = TRUE;
195: }
196: else if(c == '^' || c == '!') {
197: if(!something_found) {
198: if(charset[CURLFNM_NEGATE]) {
199: charset[c] = 1;
200: something_found = TRUE;
201: }
202: else
203: charset[CURLFNM_NEGATE] = 1; /* negate charset */
204: }
205: else
206: charset[c] = 1;
207: (*p)++;
208: }
209: else if(c == '\\') {
210: c = *(++(*p));
211: if(c)
212: setcharorrange(p, charset);
213: else
214: charset['\\'] = 1;
215: something_found = TRUE;
216: }
217: else {
218: setcharorrange(p, charset);
219: something_found = TRUE;
220: }
221: break;
222: case CURLFNM_SCHS_RIGHTBR:
223: if(c == '[') {
224: state = CURLFNM_SCHS_RIGHTBRLEFTBR;
225: charset[c] = 1;
226: (*p)++;
227: }
228: else if(c == ']') {
229: return SETCHARSET_OK;
230: }
231: else if(ISPRINT(c)) {
232: charset[c] = 1;
233: (*p)++;
234: state = CURLFNM_SCHS_DEFAULT;
235: }
236: else
237: /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
238: * nonsense warning 'statement not reached' at end of the fnc when
239: * compiling on Solaris */
240: goto fail;
241: break;
242: case CURLFNM_SCHS_RIGHTBRLEFTBR:
243: if(c == ']')
244: return SETCHARSET_OK;
245: state = CURLFNM_SCHS_DEFAULT;
246: charset[c] = 1;
247: (*p)++;
248: break;
249: }
250: }
251: fail:
252: return SETCHARSET_FAIL;
253: }
254:
255: static int loop(const unsigned char *pattern, const unsigned char *string,
256: int maxstars)
257: {
258: unsigned char *p = (unsigned char *)pattern;
259: unsigned char *s = (unsigned char *)string;
260: unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
261:
262: for(;;) {
263: unsigned char *pp;
264:
265: switch(*p) {
266: case '*':
267: if(!maxstars)
268: return CURL_FNMATCH_NOMATCH;
269: /* Regroup consecutive stars and question marks. This can be done because
270: '*?*?*' can be expressed as '??*'. */
271: for(;;) {
272: if(*++p == '\0')
273: return CURL_FNMATCH_MATCH;
274: if(*p == '?') {
275: if(!*s++)
276: return CURL_FNMATCH_NOMATCH;
277: }
278: else if(*p != '*')
279: break;
280: }
281: /* Skip string characters until we find a match with pattern suffix. */
282: for(maxstars--; *s; s++) {
283: if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH)
284: return CURL_FNMATCH_MATCH;
285: }
286: return CURL_FNMATCH_NOMATCH;
287: case '?':
288: if(!*s)
289: return CURL_FNMATCH_NOMATCH;
290: s++;
291: p++;
292: break;
293: case '\0':
294: return *s? CURL_FNMATCH_NOMATCH: CURL_FNMATCH_MATCH;
295: case '\\':
296: if(p[1])
297: p++;
298: if(*s++ != *p++)
299: return CURL_FNMATCH_NOMATCH;
300: break;
301: case '[':
302: pp = p + 1; /* Copy in case of syntax error in set. */
303: if(setcharset(&pp, charset)) {
304: int found = FALSE;
305: if(!*s)
306: return CURL_FNMATCH_NOMATCH;
307: if(charset[(unsigned int)*s])
308: found = TRUE;
309: else if(charset[CURLFNM_ALNUM])
310: found = ISALNUM(*s);
311: else if(charset[CURLFNM_ALPHA])
312: found = ISALPHA(*s);
313: else if(charset[CURLFNM_DIGIT])
314: found = ISDIGIT(*s);
315: else if(charset[CURLFNM_XDIGIT])
316: found = ISXDIGIT(*s);
317: else if(charset[CURLFNM_PRINT])
318: found = ISPRINT(*s);
319: else if(charset[CURLFNM_SPACE])
320: found = ISSPACE(*s);
321: else if(charset[CURLFNM_UPPER])
322: found = ISUPPER(*s);
323: else if(charset[CURLFNM_LOWER])
324: found = ISLOWER(*s);
325: else if(charset[CURLFNM_BLANK])
326: found = ISBLANK(*s);
327: else if(charset[CURLFNM_GRAPH])
328: found = ISGRAPH(*s);
329:
330: if(charset[CURLFNM_NEGATE])
331: found = !found;
332:
333: if(!found)
334: return CURL_FNMATCH_NOMATCH;
335: p = pp + 1;
336: s++;
337: break;
338: }
339: /* Syntax error in set; mismatch! */
340: return CURL_FNMATCH_NOMATCH;
341:
342: default:
343: if(*p++ != *s++)
344: return CURL_FNMATCH_NOMATCH;
345: break;
346: }
347: }
348: }
349:
350: /*
351: * @unittest: 1307
352: */
353: int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
354: {
355: (void)ptr; /* the argument is specified by the curl_fnmatch_callback
356: prototype, but not used by Curl_fnmatch() */
357: if(!pattern || !string) {
358: return CURL_FNMATCH_FAIL;
359: }
360: return loop((unsigned char *)pattern, (unsigned char *)string, 2);
361: }
362: #else
363: #include <fnmatch.h>
364: /*
365: * @unittest: 1307
366: */
367: int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
368: {
369: int rc;
370: (void)ptr; /* the argument is specified by the curl_fnmatch_callback
371: prototype, but not used by Curl_fnmatch() */
372: if(!pattern || !string) {
373: return CURL_FNMATCH_FAIL;
374: }
375: rc = fnmatch(pattern, string, 0);
376: switch(rc) {
377: case 0:
378: return CURL_FNMATCH_MATCH;
379: case FNM_NOMATCH:
380: return CURL_FNMATCH_NOMATCH;
381: default:
382: return CURL_FNMATCH_FAIL;
383: }
384: /* not reached */
385: }
386:
387: #endif
388:
389: #endif /* if FTP is disabled */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>