File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / curl / lib / curl_fnmatch.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Jun 3 10:01:15 2020 UTC (5 years ago) by misho
Branches: curl, MAIN
CVS tags: v7_70_0p4, HEAD
curl

    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>