Mercurial > hgrepos > Python2 > PyMuPDF
comparison mupdf-source/thirdparty/curl/lib/curl_fnmatch.c @ 2:b50eed0cc0ef upstream
ADD: MuPDF v1.26.7: the MuPDF source as downloaded by a default build of PyMuPDF 1.26.4.
The directory name has changed: no version number in the expanded directory now.
| author | Franz Glasner <fzglas.hg@dom66.de> |
|---|---|
| date | Mon, 15 Sep 2025 11:43:07 +0200 |
| parents | |
| children |
comparison
equal
deleted
inserted
replaced
| 1:1d09e1dec1d9 | 2:b50eed0cc0ef |
|---|---|
| 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 */ |
