wildmatch: properly fold case everywhere

Case folding is not done correctly when matching against the [:upper:]
character class and uppercased character ranges (e.g. A-Z).
Specifically, an uppercase letter fails to match against any of them
when case folding is requested because plain characters in the pattern
and the whole string are preemptively lowercased to handle the base case
fast.

That optimization is kept and ISLOWER() is used in the [:upper:] case
when case folding is requested, while matching against a character range
is retried with toupper() if the character was lowercase, as the bounds
of the range itself cannot be modified (in a case-insensitive context,
[A-_] is not equivalent to [a-_]).

Signed-off-by: Anthony Ramine <n.oxyde@gmail.com>
Reviewed-by: Duy Nguyen <pclouds@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Anthony Ramine 2013-05-30 12:19:10 +02:00 коммит произвёл Junio C Hamano
Родитель edca415256
Коммит b79c0c3755
2 изменённых файлов: 56 добавлений и 6 удалений

Просмотреть файл

@ -6,20 +6,20 @@ test_description='wildmatch tests'
match() { match() {
if [ $1 = 1 ]; then if [ $1 = 1 ]; then
test_expect_success "wildmatch: match '$3' '$4'" " test_expect_success "wildmatch: match '$3' '$4'" "
test-wildmatch wildmatch '$3' '$4' test-wildmatch wildmatch '$3' '$4'
" "
else else
test_expect_success "wildmatch: no match '$3' '$4'" " test_expect_success "wildmatch: no match '$3' '$4'" "
! test-wildmatch wildmatch '$3' '$4' ! test-wildmatch wildmatch '$3' '$4'
" "
fi fi
if [ $2 = 1 ]; then if [ $2 = 1 ]; then
test_expect_success "fnmatch: match '$3' '$4'" " test_expect_success "fnmatch: match '$3' '$4'" "
test-wildmatch fnmatch '$3' '$4' test-wildmatch fnmatch '$3' '$4'
" "
elif [ $2 = 0 ]; then elif [ $2 = 0 ]; then
test_expect_success "fnmatch: no match '$3' '$4'" " test_expect_success "fnmatch: no match '$3' '$4'" "
! test-wildmatch fnmatch '$3' '$4' ! test-wildmatch fnmatch '$3' '$4'
" "
# else # else
@ -29,13 +29,25 @@ match() {
fi fi
} }
imatch() {
if [ $1 = 1 ]; then
test_expect_success "iwildmatch: match '$2' '$3'" "
test-wildmatch iwildmatch '$2' '$3'
"
else
test_expect_success "iwildmatch: no match '$2' '$3'" "
! test-wildmatch iwildmatch '$2' '$3'
"
fi
}
pathmatch() { pathmatch() {
if [ $1 = 1 ]; then if [ $1 = 1 ]; then
test_expect_success "pathmatch: match '$2' '$3'" " test_expect_success "pathmatch: match '$2' '$3'" "
test-wildmatch pathmatch '$2' '$3' test-wildmatch pathmatch '$2' '$3'
" "
else else
test_expect_success "pathmatch: no match '$2' '$3'" " test_expect_success "pathmatch: no match '$2' '$3'" "
! test-wildmatch pathmatch '$2' '$3' ! test-wildmatch pathmatch '$2' '$3'
" "
fi fi
@ -235,4 +247,35 @@ pathmatch 1 abcXdefXghi '*X*i'
pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i' pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
pathmatch 1 ab/cXd/efXg/hi '*Xg*i' pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
# Case-sensitivy features
match 0 x 'a' '[A-Z]'
match 1 x 'A' '[A-Z]'
match 0 x 'A' '[a-z]'
match 1 x 'a' '[a-z]'
match 0 x 'a' '[[:upper:]]'
match 1 x 'A' '[[:upper:]]'
match 0 x 'A' '[[:lower:]]'
match 1 x 'a' '[[:lower:]]'
match 0 x 'A' '[B-Za]'
match 1 x 'a' '[B-Za]'
match 0 x 'A' '[B-a]'
match 1 x 'a' '[B-a]'
match 0 x 'z' '[Z-y]'
match 1 x 'Z' '[Z-y]'
imatch 1 'a' '[A-Z]'
imatch 1 'A' '[A-Z]'
imatch 1 'A' '[a-z]'
imatch 1 'a' '[a-z]'
imatch 1 'a' '[[:upper:]]'
imatch 1 'A' '[[:upper:]]'
imatch 1 'A' '[[:lower:]]'
imatch 1 'a' '[[:lower:]]'
imatch 1 'A' '[B-Za]'
imatch 1 'a' '[B-Za]'
imatch 1 'A' '[B-a]'
imatch 1 'a' '[B-a]'
imatch 1 'z' '[Z-y]'
imatch 1 'Z' '[Z-y]'
test_done test_done

Просмотреть файл

@ -196,6 +196,11 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} }
if (t_ch <= p_ch && t_ch >= prev_ch) if (t_ch <= p_ch && t_ch >= prev_ch)
matched = 1; matched = 1;
else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch)) {
uchar t_ch_upper = toupper(t_ch);
if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch)
matched = 1;
}
p_ch = 0; /* This makes "prev_ch" get set to 0. */ p_ch = 0; /* This makes "prev_ch" get set to 0. */
} else if (p_ch == '[' && p[1] == ':') { } else if (p_ch == '[' && p[1] == ':') {
const uchar *s; const uchar *s;
@ -245,6 +250,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
} else if (CC_EQ(s,i, "upper")) { } else if (CC_EQ(s,i, "upper")) {
if (ISUPPER(t_ch)) if (ISUPPER(t_ch))
matched = 1; matched = 1;
else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch))
matched = 1;
} else if (CC_EQ(s,i, "xdigit")) { } else if (CC_EQ(s,i, "xdigit")) {
if (ISXDIGIT(t_ch)) if (ISXDIGIT(t_ch))
matched = 1; matched = 1;