mirror of
https://github.com/moparisthebest/curl
synced 2024-08-13 17:03:50 -04:00
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
This commit is contained in:
parent
19abad095c
commit
fcaa1826bd
@ -53,8 +53,6 @@ typedef enum {
|
|||||||
|
|
||||||
typedef enum {
|
typedef enum {
|
||||||
CURLFNM_SCHS_DEFAULT = 0,
|
CURLFNM_SCHS_DEFAULT = 0,
|
||||||
CURLFNM_SCHS_MAYRANGE,
|
|
||||||
CURLFNM_SCHS_MAYRANGE2,
|
|
||||||
CURLFNM_SCHS_RIGHTBR,
|
CURLFNM_SCHS_RIGHTBR,
|
||||||
CURLFNM_SCHS_RIGHTBRLEFTBR
|
CURLFNM_SCHS_RIGHTBRLEFTBR
|
||||||
} setcharset_state;
|
} setcharset_state;
|
||||||
@ -64,6 +62,13 @@ typedef enum {
|
|||||||
CURLFNM_PKW_DDOT
|
CURLFNM_PKW_DDOT
|
||||||
} parsekey_state;
|
} parsekey_state;
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
CCLASS_OTHER = 0,
|
||||||
|
CCLASS_DIGIT,
|
||||||
|
CCLASS_UPPER,
|
||||||
|
CCLASS_LOWER
|
||||||
|
} char_class;
|
||||||
|
|
||||||
#define SETCHARSET_OK 1
|
#define SETCHARSET_OK 1
|
||||||
#define SETCHARSET_FAIL 0
|
#define SETCHARSET_FAIL 0
|
||||||
|
|
||||||
@ -123,14 +128,48 @@ static int parsekeyword(unsigned char **pattern, unsigned char *charset)
|
|||||||
return SETCHARSET_OK;
|
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) */
|
/* returns 1 (true) if pattern is OK, 0 if is bad ("p" is pattern pointer) */
|
||||||
static int setcharset(unsigned char **p, unsigned char *charset)
|
static int setcharset(unsigned char **p, unsigned char *charset)
|
||||||
{
|
{
|
||||||
setcharset_state state = CURLFNM_SCHS_DEFAULT;
|
setcharset_state state = CURLFNM_SCHS_DEFAULT;
|
||||||
unsigned char rangestart = 0;
|
|
||||||
unsigned char lastchar = 0;
|
|
||||||
bool something_found = FALSE;
|
bool something_found = FALSE;
|
||||||
unsigned char c;
|
unsigned char c;
|
||||||
|
|
||||||
|
memset(charset, 0, CURLFNM_CHSET_SIZE);
|
||||||
for(;;) {
|
for(;;) {
|
||||||
c = **p;
|
c = **p;
|
||||||
if(!c)
|
if(!c)
|
||||||
@ -138,14 +177,7 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
|||||||
|
|
||||||
switch(state) {
|
switch(state) {
|
||||||
case CURLFNM_SCHS_DEFAULT:
|
case CURLFNM_SCHS_DEFAULT:
|
||||||
if(ISALNUM(c)) { /* ASCII value */
|
if(c == ']') {
|
||||||
rangestart = c;
|
|
||||||
charset[c] = 1;
|
|
||||||
(*p)++;
|
|
||||||
state = CURLFNM_SCHS_MAYRANGE;
|
|
||||||
something_found = TRUE;
|
|
||||||
}
|
|
||||||
else if(c == ']') {
|
|
||||||
if(something_found)
|
if(something_found)
|
||||||
return SETCHARSET_OK;
|
return SETCHARSET_OK;
|
||||||
something_found = TRUE;
|
something_found = TRUE;
|
||||||
@ -169,11 +201,6 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
|||||||
}
|
}
|
||||||
something_found = TRUE;
|
something_found = TRUE;
|
||||||
}
|
}
|
||||||
else if(c == '?' || c == '*') {
|
|
||||||
something_found = TRUE;
|
|
||||||
charset[c] = 1;
|
|
||||||
(*p)++;
|
|
||||||
}
|
|
||||||
else if(c == '^' || c == '!') {
|
else if(c == '^' || c == '!') {
|
||||||
if(!something_found) {
|
if(!something_found) {
|
||||||
if(charset[CURLFNM_NEGATE]) {
|
if(charset[CURLFNM_NEGATE]) {
|
||||||
@ -189,81 +216,16 @@ static int setcharset(unsigned char **p, unsigned char *charset)
|
|||||||
}
|
}
|
||||||
else if(c == '\\') {
|
else if(c == '\\') {
|
||||||
c = *(++(*p));
|
c = *(++(*p));
|
||||||
if(ISPRINT((c))) {
|
if(c)
|
||||||
something_found = TRUE;
|
setcharorrange(p, charset);
|
||||||
state = CURLFNM_SCHS_MAYRANGE;
|
|
||||||
charset[c] = 1;
|
|
||||||
rangestart = c;
|
|
||||||
(*p)++;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return SETCHARSET_FAIL;
|
charset['\\'] = 1;
|
||||||
}
|
|
||||||
else {
|
|
||||||
charset[c] = 1;
|
|
||||||
(*p)++;
|
|
||||||
something_found = TRUE;
|
something_found = TRUE;
|
||||||
}
|
}
|
||||||
break;
|
else {
|
||||||
case CURLFNM_SCHS_MAYRANGE:
|
setcharorrange(p, charset);
|
||||||
if(c == '-') {
|
something_found = TRUE;
|
||||||
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;
|
break;
|
||||||
case CURLFNM_SCHS_RIGHTBR:
|
case CURLFNM_SCHS_RIGHTBR:
|
||||||
if(c == '[') {
|
if(c == '[') {
|
||||||
@ -383,13 +345,14 @@ static int loop(const unsigned char *pattern, const unsigned char *string,
|
|||||||
if(found) {
|
if(found) {
|
||||||
p = pp + 1;
|
p = pp + 1;
|
||||||
s++;
|
s++;
|
||||||
memset(charset, 0, CURLFNM_CHSET_SIZE);
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
return CURL_FNMATCH_NOMATCH;
|
return CURL_FNMATCH_NOMATCH;
|
||||||
}
|
}
|
||||||
else
|
else {
|
||||||
return CURL_FNMATCH_FAIL;
|
if(*p++ != *s++)
|
||||||
|
return CURL_FNMATCH_NOMATCH;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
if(*p++ != *s++)
|
if(*p++ != *s++)
|
||||||
|
@ -36,8 +36,8 @@ struct testcase {
|
|||||||
static const struct testcase tests[] = {
|
static const struct testcase tests[] = {
|
||||||
/* brackets syntax */
|
/* brackets syntax */
|
||||||
{ "\\[", "[", MATCH },
|
{ "\\[", "[", MATCH },
|
||||||
{ "[", "[", RE_ERR },
|
{ "[", "[", MATCH },
|
||||||
{ "[]", "[]", RE_ERR },
|
{ "[]", "[]", MATCH },
|
||||||
{ "[][]", "[", MATCH },
|
{ "[][]", "[", MATCH },
|
||||||
{ "[][]", "]", MATCH },
|
{ "[][]", "]", MATCH },
|
||||||
{ "[[]", "[", MATCH },
|
{ "[[]", "[", MATCH },
|
||||||
@ -49,6 +49,8 @@ static const struct testcase tests[] = {
|
|||||||
{ "[][[[]", "[", MATCH },
|
{ "[][[[]", "[", MATCH },
|
||||||
{ "[[]", "]", NOMATCH },
|
{ "[[]", "]", NOMATCH },
|
||||||
|
|
||||||
|
{ "[a@]", "a", MATCH },
|
||||||
|
|
||||||
{ "[a-z]", "a", MATCH },
|
{ "[a-z]", "a", MATCH },
|
||||||
{ "[a-z]", "A", NOMATCH },
|
{ "[a-z]", "A", NOMATCH },
|
||||||
{ "?[a-z]", "?Z", NOMATCH },
|
{ "?[a-z]", "?Z", NOMATCH },
|
||||||
@ -77,6 +79,7 @@ static const struct testcase tests[] = {
|
|||||||
{ "[][?*-]", "*", MATCH },
|
{ "[][?*-]", "*", MATCH },
|
||||||
{ "[][?*-]", "-", MATCH },
|
{ "[][?*-]", "-", MATCH },
|
||||||
{ "[]?*-]", "-", MATCH },
|
{ "[]?*-]", "-", MATCH },
|
||||||
|
{ "[\xFF]", "\xFF", MATCH },
|
||||||
{ "?/b/c", "a/b/c", MATCH },
|
{ "?/b/c", "a/b/c", MATCH },
|
||||||
{ "^_{}~", "^_{}~", MATCH },
|
{ "^_{}~", "^_{}~", MATCH },
|
||||||
{ "!#%+,-./01234567889", "!#%+,-./01234567889", MATCH },
|
{ "!#%+,-./01234567889", "!#%+,-./01234567889", MATCH },
|
||||||
@ -98,7 +101,9 @@ static const struct testcase tests[] = {
|
|||||||
{ "*[^a].t?t", "ba.txt", NOMATCH },
|
{ "*[^a].t?t", "ba.txt", NOMATCH },
|
||||||
{ "*[^a].t?t", "ab.txt", MATCH },
|
{ "*[^a].t?t", "ab.txt", MATCH },
|
||||||
{ "*[^a]", "", NOMATCH },
|
{ "*[^a]", "", NOMATCH },
|
||||||
{ "[!ÿ]", "", NOMATCH },
|
{ "[!\xFF]", "", NOMATCH },
|
||||||
|
{ "[!\xFF]", "\xFF", NOMATCH },
|
||||||
|
{ "[!\xFF]", "a", MATCH },
|
||||||
{ "[!?*[]", "?", NOMATCH },
|
{ "[!?*[]", "?", NOMATCH },
|
||||||
{ "[!!]", "!", NOMATCH },
|
{ "[!!]", "!", NOMATCH },
|
||||||
{ "[!!]", "x", MATCH },
|
{ "[!!]", "x", MATCH },
|
||||||
|
Loading…
Reference in New Issue
Block a user