wildmatch: support "no FNM_PATHNAME" mode
authorNguyễn Thái Ngọc Duy <pclouds@gmail.com>
Tue, 1 Jan 2013 02:44:07 +0000 (09:44 +0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 1 Jan 2013 23:32:37 +0000 (15:32 -0800)
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 <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
dir.c
t/t3070-wildmatch.sh
test-wildmatch.c
wildmatch.c
wildmatch.h

diff --git a/dir.c b/dir.c
index 175a1827ba90966bbaa19931ef6e193762d4c7c6..6ef03961f334462f4408825635cda29ffb48bd16 100644 (file)
--- 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;
 }
 
index af54c831111e6b74f892fefde220921eb5e83fa8..5c9601a0c83b525d936f22210237273165cef315 100755 (executable)
@@ -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
index 4bb23b4c92f5156dfeddaaf70e7c243518ce11e3..a5f4833770ef72379fe6a98c8557a355f3facb82 100644 (file)
@@ -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
index 1b5bbacf1afc5689864f67a99a66555e5730ef56..536470b79493784935c9c125473453bb3921b5d8 100644 (file)
@@ -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;
                }
index 1c814fd5ff2fb1d08c62792950a44dbc5539a579..4090c8f4bb0587d36ec01069f1e8d832ea46d7d6 100644 (file)
@@ -2,6 +2,7 @@
 #define WILDMATCH_H
 
 #define WM_CASEFOLD 1
+#define WM_PATHNAME 2
 
 #define WM_ABORT_MALFORMED 2
 #define WM_NOMATCH 1