Annotation of embedaddon/curl/lib/curl_fnmatch.c, revision 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>