So far, wildmatch() has always honoured directory boundary and there
was no way to turn it off. Make it behave more like fnmatch() by
requiring all callers that want the FNM_PATHNAME behaviour to pass
that in the equivalent flag WM_PATHNAME. Callers that do not specify
WM_PATHNAME will get wildcards like ? and * in their patterns matched
against '/', just like not passing FNM_PATHNAME to fnmatch().

Signed-off-by: Nguyễn Thái Ngọc Duy <pclo...@gmail.com>
---
 dir.c                |  2 +-
 t/t3070-wildmatch.sh | 27 +++++++++++++++++++++++++++
 test-wildmatch.c     |  6 ++++--
 wildmatch.c          | 13 +++++++++----
 wildmatch.h          |  1 +
 5 files changed, 42 insertions(+), 7 deletions(-)

diff --git a/dir.c b/dir.c
index 175a182..6ef0396 100644
--- a/dir.c
+++ b/dir.c
@@ -595,7 +595,7 @@ int match_pathname(const char *pathname, int pathlen,
        }
 
        return wildmatch(pattern, name,
-                        ignore_case ? WM_CASEFOLD : 0,
+                        WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0),
                         NULL) == 0;
 }
 
diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index af54c83..5c9601a 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -29,6 +29,18 @@ match() {
     fi
 }
 
+pathmatch() {
+    if [ $1 = 1 ]; then
+       test_expect_success "pathmatch:    match '$2' '$3'" "
+           test-wildmatch pathmatch '$2' '$3'
+       "
+    else
+       test_expect_success "pathmatch: no match '$2' '$3'" "
+           ! test-wildmatch pathmatch '$2' '$3'
+       "
+    fi
+}
+
 # Basic wildmat features
 match 1 1 foo foo
 match 0 0 foo bar
@@ -192,4 +204,19 @@ match 0 0 
'XXX/adobe/courier/bold/o/normal//12/120/75/75/X/70/iso8859/1' 'XXX/*/
 match 1 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txt' '**/*a*b*g*n*t'
 match 0 0 'abcd/abcdefg/abcdefghijk/abcdefghijklmnop.txtz' '**/*a*b*g*n*t'
 
+pathmatch 1 foo foo
+pathmatch 0 foo fo
+pathmatch 1 foo/bar foo/bar
+pathmatch 1 foo/bar 'foo/*'
+pathmatch 1 foo/bba/arr 'foo/*'
+pathmatch 1 foo/bba/arr 'foo/**'
+pathmatch 1 foo/bba/arr 'foo*'
+pathmatch 1 foo/bba/arr 'foo**'
+pathmatch 1 foo/bba/arr 'foo/*arr'
+pathmatch 1 foo/bba/arr 'foo/**arr'
+pathmatch 0 foo/bba/arr 'foo/*z'
+pathmatch 0 foo/bba/arr 'foo/**z'
+pathmatch 1 foo/bar 'foo?bar'
+pathmatch 1 foo/bar 'foo[/]bar'
+
 test_done
diff --git a/test-wildmatch.c b/test-wildmatch.c
index 4bb23b4..a5f4833 100644
--- a/test-wildmatch.c
+++ b/test-wildmatch.c
@@ -12,9 +12,11 @@ int main(int argc, char **argv)
                        argv[i] += 3;
        }
        if (!strcmp(argv[1], "wildmatch"))
-               return !!wildmatch(argv[3], argv[2], 0, NULL);
+               return !!wildmatch(argv[3], argv[2], WM_PATHNAME, NULL);
        else if (!strcmp(argv[1], "iwildmatch"))
-               return !!wildmatch(argv[3], argv[2], WM_CASEFOLD, NULL);
+               return !!wildmatch(argv[3], argv[2], WM_PATHNAME | WM_CASEFOLD, 
NULL);
+       else if (!strcmp(argv[1], "pathmatch"))
+               return !!wildmatch(argv[3], argv[2], 0, NULL);
        else if (!strcmp(argv[1], "fnmatch"))
                return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
        else
diff --git a/wildmatch.c b/wildmatch.c
index 1b5bbac..536470b 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -78,14 +78,17 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                        continue;
                case '?':
                        /* Match anything but '/'. */
-                       if (t_ch == '/')
+                       if ((flags & WM_PATHNAME) && t_ch == '/')
                                return WM_NOMATCH;
                        continue;
                case '*':
                        if (*++p == '*') {
                                const uchar *prev_p = p - 2;
                                while (*++p == '*') {}
-                               if ((prev_p < pattern || *prev_p == '/') &&
+                               if (!(flags & WM_PATHNAME))
+                                       /* without WM_PATHNAME, '*' == '**' */
+                                       match_slash = 1;
+                               else if ((prev_p < pattern || *prev_p == '/') &&
                                    (*p == '\0' || *p == '/' ||
                                     (p[0] == '\\' && p[1] == '/'))) {
                                        /*
@@ -104,7 +107,8 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                                } else
                                        return WM_ABORT_MALFORMED;
                        } else
-                               match_slash = 0;
+                               /* without WM_PATHNAME, '*' == '**' */
+                               match_slash = flags & WM_PATHNAME ? 0 : 1;
                        if (*p == '\0') {
                                /* Trailing "**" matches everything.  Trailing 
"*" matches
                                 * only if there are no more slash characters. 
*/
@@ -215,7 +219,8 @@ static int dowild(const uchar *p, const uchar *text, 
unsigned int flags)
                                } else if (t_ch == p_ch)
                                        matched = 1;
                        } while (prev_ch = p_ch, (p_ch = *++p) != ']');
-                       if (matched == negated || t_ch == '/')
+                       if (matched == negated ||
+                           ((flags & WM_PATHNAME) && t_ch == '/'))
                                return WM_NOMATCH;
                        continue;
                }
diff --git a/wildmatch.h b/wildmatch.h
index 1c814fd..4090c8f 100644
--- a/wildmatch.h
+++ b/wildmatch.h
@@ -2,6 +2,7 @@
 #define WILDMATCH_H
 
 #define WM_CASEFOLD 1
+#define WM_PATHNAME 2
 
 #define WM_ABORT_MALFORMED 2
 #define WM_NOMATCH 1
-- 
1.8.0.rc2.23.g1fb49df

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to