curl_fnmatch.c
Go to the documentation of this file.
00001 /***************************************************************************
00002  *                                  _   _ ____  _
00003  *  Project                     ___| | | |  _ \| |
00004  *                             / __| | | | |_) | |
00005  *                            | (__| |_| |  _ <| |___
00006  *                             \___|\___/|_| \_\_____|
00007  *
00008  * Copyright (C) 1998 - 2016, Daniel Stenberg, <daniel@haxx.se>, et al.
00009  *
00010  * This software is licensed as described in the file COPYING, which
00011  * you should have received as part of this distribution. The terms
00012  * are also available at https://curl.haxx.se/docs/copyright.html.
00013  *
00014  * You may opt to use, copy, modify, merge, publish, distribute and/or sell
00015  * copies of the Software, and permit persons to whom the Software is
00016  * furnished to do so, under the terms of the COPYING file.
00017  *
00018  * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
00019  * KIND, either express or implied.
00020  *
00021  ***************************************************************************/
00022 
00023 #include "curl_setup.h"
00024 
00025 #include <curl/curl.h>
00026 
00027 #include "curl_fnmatch.h"
00028 #include "curl_memory.h"
00029 
00030 /* The last #include file should be: */
00031 #include "memdebug.h"
00032 
00033 #define CURLFNM_CHARSET_LEN (sizeof(char) * 256)
00034 #define CURLFNM_CHSET_SIZE (CURLFNM_CHARSET_LEN + 15)
00035 
00036 #define CURLFNM_NEGATE  CURLFNM_CHARSET_LEN
00037 
00038 #define CURLFNM_ALNUM   (CURLFNM_CHARSET_LEN + 1)
00039 #define CURLFNM_DIGIT   (CURLFNM_CHARSET_LEN + 2)
00040 #define CURLFNM_XDIGIT  (CURLFNM_CHARSET_LEN + 3)
00041 #define CURLFNM_ALPHA   (CURLFNM_CHARSET_LEN + 4)
00042 #define CURLFNM_PRINT   (CURLFNM_CHARSET_LEN + 5)
00043 #define CURLFNM_BLANK   (CURLFNM_CHARSET_LEN + 6)
00044 #define CURLFNM_LOWER   (CURLFNM_CHARSET_LEN + 7)
00045 #define CURLFNM_GRAPH   (CURLFNM_CHARSET_LEN + 8)
00046 #define CURLFNM_SPACE   (CURLFNM_CHARSET_LEN + 9)
00047 #define CURLFNM_UPPER   (CURLFNM_CHARSET_LEN + 10)
00048 
00049 typedef enum {
00050   CURLFNM_LOOP_DEFAULT = 0,
00051   CURLFNM_LOOP_BACKSLASH
00052 } loop_state;
00053 
00054 typedef enum {
00055   CURLFNM_SCHS_DEFAULT = 0,
00056   CURLFNM_SCHS_MAYRANGE,
00057   CURLFNM_SCHS_MAYRANGE2,
00058   CURLFNM_SCHS_RIGHTBR,
00059   CURLFNM_SCHS_RIGHTBRLEFTBR
00060 } setcharset_state;
00061 
00062 typedef enum {
00063   CURLFNM_PKW_INIT = 0,
00064   CURLFNM_PKW_DDOT
00065 } parsekey_state;
00066 
00067 #define SETCHARSET_OK     1
00068 #define SETCHARSET_FAIL   0
00069 
00070 static int parsekeyword(unsigned char **pattern, unsigned char *charset)
00071 {
00072   parsekey_state state = CURLFNM_PKW_INIT;
00073 #define KEYLEN 10
00074   char keyword[KEYLEN] = { 0 };
00075   int found = FALSE;
00076   int i;
00077   unsigned char *p = *pattern;
00078   for(i = 0; !found; i++) {
00079     char c = *p++;
00080     if(i >= KEYLEN)
00081       return SETCHARSET_FAIL;
00082     switch(state) {
00083     case CURLFNM_PKW_INIT:
00084       if(ISALPHA(c) && ISLOWER(c))
00085         keyword[i] = c;
00086       else if(c == ':')
00087         state = CURLFNM_PKW_DDOT;
00088       else
00089         return 0;
00090       break;
00091     case CURLFNM_PKW_DDOT:
00092       if(c == ']')
00093         found = TRUE;
00094       else
00095         return SETCHARSET_FAIL;
00096     }
00097   }
00098 #undef KEYLEN
00099 
00100   *pattern = p; /* move caller's pattern pointer */
00101   if(strcmp(keyword, "digit") == 0)
00102     charset[CURLFNM_DIGIT] = 1;
00103   else if(strcmp(keyword, "alnum") == 0)
00104     charset[CURLFNM_ALNUM] = 1;
00105   else if(strcmp(keyword, "alpha") == 0)
00106     charset[CURLFNM_ALPHA] = 1;
00107   else if(strcmp(keyword, "xdigit") == 0)
00108     charset[CURLFNM_XDIGIT] = 1;
00109   else if(strcmp(keyword, "print") == 0)
00110     charset[CURLFNM_PRINT] = 1;
00111   else if(strcmp(keyword, "graph") == 0)
00112     charset[CURLFNM_GRAPH] = 1;
00113   else if(strcmp(keyword, "space") == 0)
00114     charset[CURLFNM_SPACE] = 1;
00115   else if(strcmp(keyword, "blank") == 0)
00116     charset[CURLFNM_BLANK] = 1;
00117   else if(strcmp(keyword, "upper") == 0)
00118     charset[CURLFNM_UPPER] = 1;
00119   else if(strcmp(keyword, "lower") == 0)
00120     charset[CURLFNM_LOWER] = 1;
00121   else
00122     return SETCHARSET_FAIL;
00123   return SETCHARSET_OK;
00124 }
00125 
00126 /* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
00127 static int setcharset(unsigned char **p, unsigned char *charset)
00128 {
00129   setcharset_state state = CURLFNM_SCHS_DEFAULT;
00130   unsigned char rangestart = 0;
00131   unsigned char lastchar   = 0;
00132   bool something_found = FALSE;
00133   unsigned char c;
00134   for(;;) {
00135     c = **p;
00136     switch(state) {
00137     case CURLFNM_SCHS_DEFAULT:
00138       if(ISALNUM(c)) { /* ASCII value */
00139         rangestart = c;
00140         charset[c] = 1;
00141         (*p)++;
00142         state = CURLFNM_SCHS_MAYRANGE;
00143         something_found = TRUE;
00144       }
00145       else if(c == ']') {
00146         if(something_found)
00147           return SETCHARSET_OK;
00148         else
00149           something_found = TRUE;
00150         state = CURLFNM_SCHS_RIGHTBR;
00151         charset[c] = 1;
00152         (*p)++;
00153       }
00154       else if(c == '[') {
00155         char c2 = *((*p)+1);
00156         if(c2 == ':') { /* there has to be a keyword */
00157           (*p) += 2;
00158           if(parsekeyword(p, charset)) {
00159             state = CURLFNM_SCHS_DEFAULT;
00160           }
00161           else
00162             return SETCHARSET_FAIL;
00163         }
00164         else {
00165           charset[c] = 1;
00166           (*p)++;
00167         }
00168         something_found = TRUE;
00169       }
00170       else if(c == '?' || c == '*') {
00171         something_found = TRUE;
00172         charset[c] = 1;
00173         (*p)++;
00174       }
00175       else if(c == '^' || c == '!') {
00176         if(!something_found) {
00177           if(charset[CURLFNM_NEGATE]) {
00178             charset[c] = 1;
00179             something_found = TRUE;
00180           }
00181           else
00182             charset[CURLFNM_NEGATE] = 1; /* negate charset */
00183         }
00184         else
00185           charset[c] = 1;
00186         (*p)++;
00187       }
00188       else if(c == '\\') {
00189         c = *(++(*p));
00190         if(ISPRINT((c))) {
00191           something_found = TRUE;
00192           state = CURLFNM_SCHS_MAYRANGE;
00193           charset[c] = 1;
00194           rangestart = c;
00195           (*p)++;
00196         }
00197         else
00198           return SETCHARSET_FAIL;
00199       }
00200       else if(c == '\0') {
00201         return SETCHARSET_FAIL;
00202       }
00203       else {
00204         charset[c] = 1;
00205         (*p)++;
00206         something_found = TRUE;
00207       }
00208       break;
00209     case CURLFNM_SCHS_MAYRANGE:
00210       if(c == '-') {
00211         charset[c] = 1;
00212         (*p)++;
00213         lastchar = '-';
00214         state = CURLFNM_SCHS_MAYRANGE2;
00215       }
00216       else if(c == '[') {
00217         state = CURLFNM_SCHS_DEFAULT;
00218       }
00219       else if(ISALNUM(c)) {
00220         charset[c] = 1;
00221         (*p)++;
00222       }
00223       else if(c == '\\') {
00224         c = *(++(*p));
00225         if(ISPRINT(c)) {
00226           charset[c] = 1;
00227           (*p)++;
00228         }
00229         else
00230           return SETCHARSET_FAIL;
00231       }
00232       else if(c == ']') {
00233         return SETCHARSET_OK;
00234       }
00235       else
00236         return SETCHARSET_FAIL;
00237       break;
00238     case CURLFNM_SCHS_MAYRANGE2:
00239       if(c == '\\') {
00240         c = *(++(*p));
00241         if(!ISPRINT(c))
00242           return SETCHARSET_FAIL;
00243       }
00244       if(c == ']') {
00245         return SETCHARSET_OK;
00246       }
00247       else if(c == '\\') {
00248         c = *(++(*p));
00249         if(ISPRINT(c)) {
00250           charset[c] = 1;
00251           state = CURLFNM_SCHS_DEFAULT;
00252           (*p)++;
00253         }
00254         else
00255           return SETCHARSET_FAIL;
00256       }
00257       if(c >= rangestart) {
00258         if((ISLOWER(c) && ISLOWER(rangestart)) ||
00259            (ISDIGIT(c) && ISDIGIT(rangestart)) ||
00260            (ISUPPER(c) && ISUPPER(rangestart))) {
00261           charset[lastchar] = 0;
00262           rangestart++;
00263           while(rangestart++ <= c)
00264             charset[rangestart-1] = 1;
00265           (*p)++;
00266           state = CURLFNM_SCHS_DEFAULT;
00267         }
00268         else
00269           return SETCHARSET_FAIL;
00270       }
00271       break;
00272     case CURLFNM_SCHS_RIGHTBR:
00273       if(c == '[') {
00274         state = CURLFNM_SCHS_RIGHTBRLEFTBR;
00275         charset[c] = 1;
00276         (*p)++;
00277       }
00278       else if(c == ']') {
00279         return SETCHARSET_OK;
00280       }
00281       else if(c == '\0') {
00282         return SETCHARSET_FAIL;
00283       }
00284       else if(ISPRINT(c)) {
00285         charset[c] = 1;
00286         (*p)++;
00287         state = CURLFNM_SCHS_DEFAULT;
00288       }
00289       else
00290         /* used 'goto fail' instead of 'return SETCHARSET_FAIL' to avoid a
00291          * nonsense warning 'statement not reached' at end of the fnc when
00292          * compiling on Solaris */
00293         goto fail;
00294       break;
00295     case CURLFNM_SCHS_RIGHTBRLEFTBR:
00296       if(c == ']') {
00297         return SETCHARSET_OK;
00298       }
00299       else {
00300         state  = CURLFNM_SCHS_DEFAULT;
00301         charset[c] = 1;
00302         (*p)++;
00303       }
00304       break;
00305     }
00306   }
00307 fail:
00308   return SETCHARSET_FAIL;
00309 }
00310 
00311 static int loop(const unsigned char *pattern, const unsigned char *string)
00312 {
00313   loop_state state = CURLFNM_LOOP_DEFAULT;
00314   unsigned char *p = (unsigned char *)pattern;
00315   unsigned char *s = (unsigned char *)string;
00316   unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
00317   int rc = 0;
00318 
00319   for(;;) {
00320     switch(state) {
00321     case CURLFNM_LOOP_DEFAULT:
00322       if(*p == '*') {
00323         while(*(p+1) == '*') /* eliminate multiple stars */
00324           p++;
00325         if(*s == '\0' && *(p+1) == '\0')
00326           return CURL_FNMATCH_MATCH;
00327         rc = loop(p + 1, s); /* *.txt matches .txt <=> .txt matches .txt */
00328         if(rc == CURL_FNMATCH_MATCH)
00329           return CURL_FNMATCH_MATCH;
00330         if(*s) /* let the star eat up one character */
00331           s++;
00332         else
00333           return CURL_FNMATCH_NOMATCH;
00334       }
00335       else if(*p == '?') {
00336         if(ISPRINT(*s)) {
00337           s++;
00338           p++;
00339         }
00340         else if(*s == '\0')
00341           return CURL_FNMATCH_NOMATCH;
00342         else
00343           return CURL_FNMATCH_FAIL; /* cannot deal with other character */
00344       }
00345       else if(*p == '\0') {
00346         if(*s == '\0')
00347           return CURL_FNMATCH_MATCH;
00348         else
00349           return CURL_FNMATCH_NOMATCH;
00350       }
00351       else if(*p == '\\') {
00352         state = CURLFNM_LOOP_BACKSLASH;
00353         p++;
00354       }
00355       else if(*p == '[') {
00356         unsigned char *pp = p+1; /* cannot handle with pointer to register */
00357         if(setcharset(&pp, charset)) {
00358           int found = FALSE;
00359           if(charset[(unsigned int)*s])
00360             found = TRUE;
00361           else if(charset[CURLFNM_ALNUM])
00362             found = ISALNUM(*s);
00363           else if(charset[CURLFNM_ALPHA])
00364             found = ISALPHA(*s);
00365           else if(charset[CURLFNM_DIGIT])
00366             found = ISDIGIT(*s);
00367           else if(charset[CURLFNM_XDIGIT])
00368             found = ISXDIGIT(*s);
00369           else if(charset[CURLFNM_PRINT])
00370             found = ISPRINT(*s);
00371           else if(charset[CURLFNM_SPACE])
00372             found = ISSPACE(*s);
00373           else if(charset[CURLFNM_UPPER])
00374             found = ISUPPER(*s);
00375           else if(charset[CURLFNM_LOWER])
00376             found = ISLOWER(*s);
00377           else if(charset[CURLFNM_BLANK])
00378             found = ISBLANK(*s);
00379           else if(charset[CURLFNM_GRAPH])
00380             found = ISGRAPH(*s);
00381 
00382           if(charset[CURLFNM_NEGATE])
00383             found = !found;
00384 
00385           if(found) {
00386             p = pp+1;
00387             s++;
00388             memset(charset, 0, CURLFNM_CHSET_SIZE);
00389           }
00390           else
00391             return CURL_FNMATCH_NOMATCH;
00392         }
00393         else
00394           return CURL_FNMATCH_FAIL;
00395       }
00396       else {
00397         if(*p++ != *s++)
00398           return CURL_FNMATCH_NOMATCH;
00399       }
00400       break;
00401     case CURLFNM_LOOP_BACKSLASH:
00402       if(ISPRINT(*p)) {
00403         if(*p++ == *s++)
00404           state = CURLFNM_LOOP_DEFAULT;
00405         else
00406           return CURL_FNMATCH_NOMATCH;
00407       }
00408       else
00409         return CURL_FNMATCH_FAIL;
00410       break;
00411     }
00412   }
00413 }
00414 
00415 /*
00416  * @unittest: 1307
00417  */
00418 int Curl_fnmatch(void *ptr, const char *pattern, const char *string)
00419 {
00420   (void)ptr; /* the argument is specified by the curl_fnmatch_callback
00421                 prototype, but not used by Curl_fnmatch() */
00422   if(!pattern || !string) {
00423     return CURL_FNMATCH_FAIL;
00424   }
00425   return loop((unsigned char *)pattern, (unsigned char *)string);
00426 }


rc_visard_driver
Author(s): Heiko Hirschmueller , Christian Emmerich , Felix Ruess
autogenerated on Thu Jun 6 2019 20:43:02