Subject: [PATCH v3 01/10] wildmatch: fix "**" special case

From: Nguyễn Thái Ngọc Duy <[email-masked]>
Date: Tue, 1 Jan 2013 09:44:02 +0700

"**" is adjusted to only be effective when surrounded by slashes, in
40bbee0 (wildmatch: adjust "**" behavior - 2012-10-15). Except that
the commit did it wrong:

1. when it checks for "the preceding slash unless ** is at the
   beginning", it compares to wrong pointer. It should have compared
   to the beginning of the pattern, not the text.

2. prev_p points to the character before "**", not the first "*". The
   correct comparison must be "prev_p < pattern" or
   "prev_p + 1 == pattern", not "prev_p == pattern".

3. The pattern must be surrounded by slashes unless it's at the
   beginning or the end of the pattern. We do two checks: one for the
   preceding slash and one the trailing slash. Both checks must be
   met. The use of "||" is wrong.

This patch fixes all above.

Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
---
 t/t3070-wildmatch.sh | 2 +-
 wildmatch.c          | 3 ++-
 2 files changed, 3 insertions(+), 2 deletions(-)

diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh
index d5bafef..af54c83 100755
--- a/t/t3070-wildmatch.sh
+++ b/t/t3070-wildmatch.sh
@@ -83,7 +83,7 @@ match 0 0 'deep/foo/bar/baz/' '**/bar/*'
 match 1 0 'deep/foo/bar/baz/' '**/bar/**'
 match 0 0 'deep/foo/bar' '**/bar/*'
 match 1 0 'deep/foo/bar/' '**/bar/**'
-match 1 0 'foo/bar/baz' '**/bar**'
+match 0 0 'foo/bar/baz' '**/bar**'
 match 1 0 'foo/bar/baz/x' '*/bar/**'
 match 0 0 'deep/foo/bar/baz/x' '*/bar/**'
 match 1 0 'deep/foo/bar/baz/x' '**/bar/*/*'
diff --git a/wildmatch.c b/wildmatch.c
index 3972e26..5f976e9 100644
--- a/wildmatch.c
+++ b/wildmatch.c
@@ -58,6 +58,7 @@ typedef unsigned char uchar;
 static int dowild(const uchar *p, const uchar *text, int force_lower_case)
 {
 	uchar p_ch;
+	const uchar *pattern = p;
 
 	for ( ; (p_ch = *p) != '\0'; text++, p++) {
 		int matched, special;
@@ -87,7 +88,7 @@ static int dowild(const uchar *p, const uchar *text, int force_lower_case)
 			if (*++p == '*') {
 				const uchar *prev_p = p - 2;
 				while (*++p == '*') {}
-				if ((prev_p == text || *prev_p == '/') ||
+				if ((prev_p < pattern || *prev_p == '/') &&
 				    (*p == '\0' || *p == '/' ||
 				     (p[0] == '\\' && p[1] == '/'))) {
 					/*
-- 
1.8.0.rc2.23.g1fb49df