quickjs-tart

quickjs-based runtime for wallet-core logic
Log | Files | Refs | README | LICENSE

curl_fnmatch.c (10408B)


      1 /***************************************************************************
      2  *                                  _   _ ____  _
      3  *  Project                     ___| | | |  _ \| |
      4  *                             / __| | | | |_) | |
      5  *                            | (__| |_| |  _ <| |___
      6  *                             \___|\___/|_| \_\_____|
      7  *
      8  * Copyright (C) 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.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 */