aboutsummaryrefslogtreecommitdiff
path: root/lib/curl_fnmatch.c
diff options
context:
space:
mode:
authorPatrick Monnerat <patrick@monnerat.net>2018-02-07 15:01:51 +0100
committerPatrick Monnerat <patrick@monnerat.net>2018-02-07 15:01:51 +0100
commita0984eae14b2840a470800bb1bfb18bd99dc302b (patch)
tree1d73afb809a358f9d33f9a70f1e7b48448d4f975 /lib/curl_fnmatch.c
parentff07089585300739212d0b3dab66b92d21cafb1d (diff)
fnmatch: optimize processing of consecutive *s and ?s pattern characters
Reported-By: Daniel Stenberg Fixes #2291 Closes #2293
Diffstat (limited to 'lib/curl_fnmatch.c')
-rw-r--r--lib/curl_fnmatch.c31
1 files changed, 18 insertions, 13 deletions
diff --git a/lib/curl_fnmatch.c b/lib/curl_fnmatch.c
index f303881d3..0179a4f71 100644
--- a/lib/curl_fnmatch.c
+++ b/lib/curl_fnmatch.c
@@ -256,7 +256,6 @@ static int loop(const unsigned char *pattern, const unsigned char *string,
unsigned char *p = (unsigned char *)pattern;
unsigned char *s = (unsigned char *)string;
unsigned char charset[CURLFNM_CHSET_SIZE] = { 0 };
- int rc = 0;
for(;;) {
unsigned char *pp;
@@ -265,18 +264,24 @@ static int loop(const unsigned char *pattern, const unsigned char *string,
case '*':
if(!maxstars)
return CURL_FNMATCH_NOMATCH;
- while(p[1] == '*') /* eliminate multiple stars */
- p++;
- if(*s == '\0' && p[1] == '\0')
- return CURL_FNMATCH_MATCH;
- rc = loop(p + 1, s, maxstars - 1); /* *.txt matches .txt <=>
- .txt matches .txt */
- if(rc == CURL_FNMATCH_MATCH)
- return CURL_FNMATCH_MATCH;
- if(!*s)
- return CURL_FNMATCH_NOMATCH;
- s++; /* let the star eat up one character */
- break;
+ /* Regroup consecutive stars and question marks. This can be done because
+ '*?*?*' can be expressed as '??*'. */
+ for(;;) {
+ if(*++p == '\0')
+ return CURL_FNMATCH_MATCH;
+ if(*p == '?') {
+ if(!*s++)
+ return CURL_FNMATCH_NOMATCH;
+ }
+ else if(*p != '*')
+ break;
+ }
+ /* Skip string characters until we find a match with pattern suffix. */
+ for(maxstars--; *s; s++) {
+ if(loop(p, s, maxstars) == CURL_FNMATCH_MATCH)
+ return CURL_FNMATCH_MATCH;
+ }
+ return CURL_FNMATCH_NOMATCH;
case '?':
if(!*s)
return CURL_FNMATCH_NOMATCH;