wildmatch: make /**/ match zero or more directories

"foo/**/bar" matches "foo/x/bar", "foo/x/y/bar"... but not "foo/bar". We make a special case, when foo/**/ is detected (and "foo/" part is already matched), try matching "bar" with the rest of the string. "Match one or more directories" semantics can be easily achieved using "foo/*/**/bar". This also makes "**/foo" match "foo" in addition to "x/foo", "x/y/foo".. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Nguyễn Thái Ngọc Duy committed Oct 15, 2012 at 13:26 UTC 4c251e5cb5c245ee3bb98c7cedbe944df93e45f4
2 files changed +19 -1
t/t3070-wildmatch.sh
+7 -1
@@ -63,11 +63,17 @@ match 1 1 ']' ']'
63 match 0 0 'foo/baz/bar' 'foo*bar'
64 match 0 0 'foo/baz/bar' 'foo**bar'
65 match 0 1 'foobazbar' 'foo**bar'
66 +match 1 1 'foo/baz/bar' 'foo/**/bar'
67 +match 1 0 'foo/baz/bar' 'foo/**/**/bar'
68 +match 1 0 'foo/b/a/z/bar' 'foo/**/bar'
69 +match 1 0 'foo/b/a/z/bar' 'foo/**/**/bar'
70 +match 1 0 'foo/bar' 'foo/**/bar'
71 +match 1 0 'foo/bar' 'foo/**/**/bar'
72 match 0 0 'foo/bar' 'foo?bar'
73 match 0 0 'foo/bar' 'foo[/]bar'
74 match 0 0 'foo/bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
75 match 1 1 'foo-bar' 'f[^eiu][^eiu][^eiu][^eiu][^eiu]r'
70 -match 0 0 'foo' '**/foo'
76 +match 1 0 'foo' '**/foo'
77 match 1 x '/foo' '**/foo'
78 match 1 0 'bar/baz/foo' '**/foo'
79 match 0 0 'bar/baz/foo' '*/foo'
wildmatch.c
+12
@@ -90,6 +90,18 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
90 if ((prev_p == text || *prev_p == '/') ||
91 (*p == '\0' || *p == '/' ||
92 (p[0] == '\\' && p[1] == '/'))) {
93 + /*
94 + * Assuming we already match 'foo/' and are at
95 + * <star star slash>, just assume it matches
96 + * nothing and go ahead match the rest of the
97 + * pattern with the remaining string. This
98 + * helps make foo/<*><*>/bar (<> because
99 + * otherwise it breaks C comment syntax) match
100 + * both foo/bar and foo/a/bar.
101 + */
102 + if (p[0] == '/' &&
103 + dowild(p + 1, text, force_lower_case) == MATCH)
104 + return MATCH;
105 special = TRUE;
106 } else
107 return ABORT_MALFORMED;