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>