wildmatch: support "no FNM_PATHNAME" mode
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>
This commit is contained in:
parent
0c528168da
commit
c41244e702
2
dir.c
2
dir.c
@ -595,7 +595,7 @@ int match_pathname(const char *pathname, int pathlen,
|
|||||||
}
|
}
|
||||||
|
|
||||||
return wildmatch(pattern, name,
|
return wildmatch(pattern, name,
|
||||||
ignore_case ? WM_CASEFOLD : 0,
|
WM_PATHNAME | (ignore_case ? WM_CASEFOLD : 0),
|
||||||
NULL) == 0;
|
NULL) == 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -29,6 +29,18 @@ match() {
|
|||||||
fi
|
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
|
# Basic wildmat features
|
||||||
match 1 1 foo foo
|
match 1 1 foo foo
|
||||||
match 0 0 foo bar
|
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 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'
|
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
|
test_done
|
||||||
|
@ -12,9 +12,11 @@ int main(int argc, char **argv)
|
|||||||
argv[i] += 3;
|
argv[i] += 3;
|
||||||
}
|
}
|
||||||
if (!strcmp(argv[1], "wildmatch"))
|
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"))
|
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"))
|
else if (!strcmp(argv[1], "fnmatch"))
|
||||||
return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
|
return !!fnmatch(argv[3], argv[2], FNM_PATHNAME);
|
||||||
else
|
else
|
||||||
|
13
wildmatch.c
13
wildmatch.c
@ -78,14 +78,17 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
|
|||||||
continue;
|
continue;
|
||||||
case '?':
|
case '?':
|
||||||
/* Match anything but '/'. */
|
/* Match anything but '/'. */
|
||||||
if (t_ch == '/')
|
if ((flags & WM_PATHNAME) && t_ch == '/')
|
||||||
return WM_NOMATCH;
|
return WM_NOMATCH;
|
||||||
continue;
|
continue;
|
||||||
case '*':
|
case '*':
|
||||||
if (*++p == '*') {
|
if (*++p == '*') {
|
||||||
const uchar *prev_p = p - 2;
|
const uchar *prev_p = p - 2;
|
||||||
while (*++p == '*') {}
|
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 == '/' ||
|
||||||
(p[0] == '\\' && p[1] == '/'))) {
|
(p[0] == '\\' && p[1] == '/'))) {
|
||||||
/*
|
/*
|
||||||
@ -104,7 +107,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
|
|||||||
} else
|
} else
|
||||||
return WM_ABORT_MALFORMED;
|
return WM_ABORT_MALFORMED;
|
||||||
} else
|
} else
|
||||||
match_slash = 0;
|
/* without WM_PATHNAME, '*' == '**' */
|
||||||
|
match_slash = flags & WM_PATHNAME ? 0 : 1;
|
||||||
if (*p == '\0') {
|
if (*p == '\0') {
|
||||||
/* Trailing "**" matches everything. Trailing "*" matches
|
/* Trailing "**" matches everything. Trailing "*" matches
|
||||||
* only if there are no more slash characters. */
|
* 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)
|
} else if (t_ch == p_ch)
|
||||||
matched = 1;
|
matched = 1;
|
||||||
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
|
} while (prev_ch = p_ch, (p_ch = *++p) != ']');
|
||||||
if (matched == negated || t_ch == '/')
|
if (matched == negated ||
|
||||||
|
((flags & WM_PATHNAME) && t_ch == '/'))
|
||||||
return WM_NOMATCH;
|
return WM_NOMATCH;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
#define WILDMATCH_H
|
#define WILDMATCH_H
|
||||||
|
|
||||||
#define WM_CASEFOLD 1
|
#define WM_CASEFOLD 1
|
||||||
|
#define WM_PATHNAME 2
|
||||||
|
|
||||||
#define WM_ABORT_MALFORMED 2
|
#define WM_ABORT_MALFORMED 2
|
||||||
#define WM_NOMATCH 1
|
#define WM_NOMATCH 1
|
||||||
|
Loading…
Reference in New Issue
Block a user