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