Skip to content

Commit b79c0c3

Browse files
noxgitster
authored andcommitted
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 <[email protected]> Reviewed-by: Duy Nguyen <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent edca415 commit b79c0c3

File tree

2 files changed

+56
-6
lines changed

2 files changed

+56
-6
lines changed

t/t3070-wildmatch.sh

Lines changed: 49 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,20 @@ test_description='wildmatch tests'
66

77
match() {
88
if [ $1 = 1 ]; then
9-
test_expect_success "wildmatch: match '$3' '$4'" "
9+
test_expect_success "wildmatch: match '$3' '$4'" "
1010
test-wildmatch wildmatch '$3' '$4'
1111
"
1212
else
13-
test_expect_success "wildmatch: no match '$3' '$4'" "
13+
test_expect_success "wildmatch: no match '$3' '$4'" "
1414
! test-wildmatch wildmatch '$3' '$4'
1515
"
1616
fi
1717
if [ $2 = 1 ]; then
18-
test_expect_success "fnmatch: match '$3' '$4'" "
18+
test_expect_success "fnmatch: match '$3' '$4'" "
1919
test-wildmatch fnmatch '$3' '$4'
2020
"
2121
elif [ $2 = 0 ]; then
22-
test_expect_success "fnmatch: no match '$3' '$4'" "
22+
test_expect_success "fnmatch: no match '$3' '$4'" "
2323
! test-wildmatch fnmatch '$3' '$4'
2424
"
2525
# else
@@ -29,13 +29,25 @@ match() {
2929
fi
3030
}
3131

32+
imatch() {
33+
if [ $1 = 1 ]; then
34+
test_expect_success "iwildmatch: match '$2' '$3'" "
35+
test-wildmatch iwildmatch '$2' '$3'
36+
"
37+
else
38+
test_expect_success "iwildmatch: no match '$2' '$3'" "
39+
! test-wildmatch iwildmatch '$2' '$3'
40+
"
41+
fi
42+
}
43+
3244
pathmatch() {
3345
if [ $1 = 1 ]; then
34-
test_expect_success "pathmatch: match '$2' '$3'" "
46+
test_expect_success "pathmatch: match '$2' '$3'" "
3547
test-wildmatch pathmatch '$2' '$3'
3648
"
3749
else
38-
test_expect_success "pathmatch: no match '$2' '$3'" "
50+
test_expect_success "pathmatch: no match '$2' '$3'" "
3951
! test-wildmatch pathmatch '$2' '$3'
4052
"
4153
fi
@@ -235,4 +247,35 @@ pathmatch 1 abcXdefXghi '*X*i'
235247
pathmatch 1 ab/cXd/efXg/hi '*/*X*/*/*i'
236248
pathmatch 1 ab/cXd/efXg/hi '*Xg*i'
237249

250+
# Case-sensitivy features
251+
match 0 x 'a' '[A-Z]'
252+
match 1 x 'A' '[A-Z]'
253+
match 0 x 'A' '[a-z]'
254+
match 1 x 'a' '[a-z]'
255+
match 0 x 'a' '[[:upper:]]'
256+
match 1 x 'A' '[[:upper:]]'
257+
match 0 x 'A' '[[:lower:]]'
258+
match 1 x 'a' '[[:lower:]]'
259+
match 0 x 'A' '[B-Za]'
260+
match 1 x 'a' '[B-Za]'
261+
match 0 x 'A' '[B-a]'
262+
match 1 x 'a' '[B-a]'
263+
match 0 x 'z' '[Z-y]'
264+
match 1 x 'Z' '[Z-y]'
265+
266+
imatch 1 'a' '[A-Z]'
267+
imatch 1 'A' '[A-Z]'
268+
imatch 1 'A' '[a-z]'
269+
imatch 1 'a' '[a-z]'
270+
imatch 1 'a' '[[:upper:]]'
271+
imatch 1 'A' '[[:upper:]]'
272+
imatch 1 'A' '[[:lower:]]'
273+
imatch 1 'a' '[[:lower:]]'
274+
imatch 1 'A' '[B-Za]'
275+
imatch 1 'a' '[B-Za]'
276+
imatch 1 'A' '[B-a]'
277+
imatch 1 'a' '[B-a]'
278+
imatch 1 'z' '[Z-y]'
279+
imatch 1 'Z' '[Z-y]'
280+
238281
test_done

wildmatch.c

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,11 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
196196
}
197197
if (t_ch <= p_ch && t_ch >= prev_ch)
198198
matched = 1;
199+
else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch)) {
200+
uchar t_ch_upper = toupper(t_ch);
201+
if (t_ch_upper <= p_ch && t_ch_upper >= prev_ch)
202+
matched = 1;
203+
}
199204
p_ch = 0; /* This makes "prev_ch" get set to 0. */
200205
} else if (p_ch == '[' && p[1] == ':') {
201206
const uchar *s;
@@ -245,6 +250,8 @@ static int dowild(const uchar *p, const uchar *text, unsigned int flags)
245250
} else if (CC_EQ(s,i, "upper")) {
246251
if (ISUPPER(t_ch))
247252
matched = 1;
253+
else if ((flags & WM_CASEFOLD) && ISLOWER(t_ch))
254+
matched = 1;
248255
} else if (CC_EQ(s,i, "xdigit")) {
249256
if (ISXDIGIT(t_ch))
250257
matched = 1;

0 commit comments

Comments
 (0)