summaryrefslogtreecommitdiff
path: root/lib/curl_fnmatch.c
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2018-01-29 16:21:50 +0100
committerPatrick Monnerat <patrick@monnerat.net>2018-01-31 01:17:35 +0100
commitfcaa1826bd34c2a7ea7e71bfd2cfdcf5fe3506c1 (patch)
tree7dcb95b7bdc77fdba342b9b61994ccc0b6376d6a /lib/curl_fnmatch.c
parent19abad095caafb2279f8aeb5d39cd038dcece938 (diff)
downloadcurl-fcaa1826bd34c2a7ea7e71bfd2cfdcf5fe3506c1.tar.gz
fnmatch: accept an alphanum to be followed by a non-alphanum in char set
Also be more tolerant about set pattern syntax. Update unit test 1307 accordingly. Bug: https://curl.haxx.se/mail/lib-2018-01/0114.html
Diffstat (limited to 'lib/curl_fnmatch.c')
-rw-r--r--lib/curl_fnmatch.c143
1 files changed, 53 insertions, 90 deletions
diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c
index 5b6d28c06..bb50a2684 100644
--- a/lib/curl_fnmatch.c
+++ b/lib/curl_fnmatch.c
@@ -53,8 +53,6 @@ typedef enum {
typedef enum {
CURLFNM_SCHS_DEFAULT = 0,
- CURLFNM_SCHS_MAYRANGE,
- CURLFNM_SCHS_MAYRANGE2,
CURLFNM_SCHS_RIGHTBR,
CURLFNM_SCHS_RIGHTBRLEFTBR
} setcharset_state;
@@ -64,6 +62,13 @@ typedef enum {
CURLFNM_PKW_DDOT
} parsekey_state;
+typedef enum {
+ CCLASS_OTHER = 0,
+ CCLASS_DIGIT,
+ CCLASS_UPPER,
+ CCLASS_LOWER
+} char_class;
+
#define SETCHARSET_OK 1
#define SETCHARSET_FAIL 0
@@ -123,14 +128,48 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
return SETCHARSET_OK;
}
+/* Return the character class. */
+static char_class charclass(unsigned char c)
+{
+ if(ISUPPER(c))
+ return CCLASS_UPPER;
+ if(ISLOWER(c))
+ return CCLASS_LOWER;
+ if(ISDIGIT(c))
+ return CCLASS_DIGIT;
+ return CCLASS_OTHER;
+}
+
+/* Include a character or a range in set. */
+static void setcharorrange(unsigned char **pp, unsigned char *charset)
+{
+ unsigned char *p = (*pp)++;
+ unsigned char c = *p++;
+
+ charset[c] = 1;
+ if(ISALNUM(c) && *p++ == '-') {
+ char_class cc = charclass(c);
+ unsigned char endrange = *p++;
+
+ if(endrange == '\\')
+ endrange = *p++;
+ if(endrange >= c && charclass(endrange) == cc) {
+ while(c++ != endrange)
+ if(charclass(c) == cc) /* Chars in class may be not consecutive. */
+ charset[c] = 1;
+ *pp = p;
+ }
+ }
+}
+
/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
static int setcharset(unsigned char **p, unsigned char *charset)
{
setcharset_state state = CURLFNM_SCHS_DEFAULT;
- unsigned char rangestart = 0;
- unsigned char lastchar = 0;
bool something_found = FALSE;
unsigned char c;
+
+ memset(charset, 0, CURLFNM_CHSET_SIZE);
for(;;) {
c = **p;
if(!c)
@@ -138,14 +177,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
switch(state) {
case CURLFNM_SCHS_DEFAULT:
- if(ISALNUM(c)) { /* ASCII value */
- rangestart = c;
- charset[c] = 1;
- (*p)++;
- state = CURLFNM_SCHS_MAYRANGE;
- something_found = TRUE;
- }
- else if(c == ']') {
+ if(c == ']') {
if(something_found)
return SETCHARSET_OK;
something_found = TRUE;
@@ -169,11 +201,6 @@ static int setcharset(unsigned char **p, unsigned char *charset)
}
something_found = TRUE;
}
- else if(c == '?' || c == '*') {
- something_found = TRUE;
- charset[c] = 1;
- (*p)++;
- }
else if(c == '^' || c == '!') {
if(!something_found) {
if(charset[CURLFNM_NEGATE]) {
@@ -189,82 +216,17 @@ static int setcharset(unsigned char **p, unsigned char *charset)
}
else if(c == '\\') {
c = *(++(*p));
- if(ISPRINT((c))) {
- something_found = TRUE;
- state = CURLFNM_SCHS_MAYRANGE;
- charset[c] = 1;
- rangestart = c;
- (*p)++;
- }
+ if(c)
+ setcharorrange(p, charset);
else
- return SETCHARSET_FAIL;
+ charset['\\'] = 1;
+ something_found = TRUE;
}
else {
- charset[c] = 1;
- (*p)++;
+ setcharorrange(p, charset);
something_found = TRUE;
}
break;
- case CURLFNM_SCHS_MAYRANGE:
- if(c == '-') {
- charset[c] = 1;
- (*p)++;
- lastchar = '-';
- state = CURLFNM_SCHS_MAYRANGE2;
- }
- else if(c == '[') {
- state = CURLFNM_SCHS_DEFAULT;
- }
- else if(ISALNUM(c)) {
- charset[c] = 1;
- (*p)++;
- }
- else if(c == '\\') {
- c = *(++(*p));
- if(ISPRINT(c)) {
- charset[c] = 1;
- (*p)++;
- }
- else
- return SETCHARSET_FAIL;
- }
- else if(c == ']') {
- return SETCHARSET_OK;
- }
- else
- return SETCHARSET_FAIL;
- break;
- case CURLFNM_SCHS_MAYRANGE2:
- if(c == ']') {
- return SETCHARSET_OK;
- }
- else if(c == '\\') {
- c = *(++(*p));
- if(ISPRINT(c)) {
- charset[c] = 1;
- state = CURLFNM_SCHS_DEFAULT;
- (*p)++;
- }
- else
- return SETCHARSET_FAIL;
- }
- else if(c >= rangestart) {
- if((ISLOWER(c) && ISLOWER(rangestart)) ||
- (ISDIGIT(c) && ISDIGIT(rangestart)) ||
- (ISUPPER(c) && ISUPPER(rangestart))) {
- charset[lastchar] = 0;
- rangestart++;
- while(rangestart++ <= c)
- charset[rangestart-1] = 1;
- (*p)++;
- state = CURLFNM_SCHS_DEFAULT;
- }
- else
- return SETCHARSET_FAIL;
- }
- else
- return SETCHARSET_FAIL;
- break;
case CURLFNM_SCHS_RIGHTBR:
if(c == '[') {
state = CURLFNM_SCHS_RIGHTBRLEFTBR;
@@ -383,13 +345,14 @@ static int loop(const unsigned char *pattern, const unsigned char *string,
if(found) {
p = pp + 1;
s++;
- memset(charset, 0, CURLFNM_CHSET_SIZE);
}
else
return CURL_FNMATCH_NOMATCH;
}
- else
- return CURL_FNMATCH_FAIL;
+ else {
+ if(*p++ != *s++)
+ return CURL_FNMATCH_NOMATCH;
+ }
}
else {
if(*p++ != *s++)