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