Skip to content

Commit e50d138

Browse files
authored
Merge pull request libgit2#5095 from pks-t/pks/ignore-escaped-trailing-space
ignore: handle escaped trailing whitespace
2 parents 4de6eb5 + d81e786 commit e50d138

File tree

2 files changed

+65
-3
lines changed

2 files changed

+65
-3
lines changed

src/attr_file.c

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -559,6 +559,21 @@ void git_attr_path__free(git_attr_path *info)
559559
* "cat-file.c" but not "mozilla-sha1/sha1.c".
560560
*/
561561

562+
/*
563+
* Determine the length of trailing spaces. Escaped spaces do not count as
564+
* trailing whitespace.
565+
*/
566+
static size_t trailing_space_length(const char *p, size_t len)
567+
{
568+
size_t n;
569+
for (n = len; n; n--) {
570+
if ((p[n-1] != ' ' && p[n-1] != '\t') ||
571+
(n > 1 && p[n-2] == '\\'))
572+
break;
573+
}
574+
return len - n;
575+
}
576+
562577
/*
563578
* This will return 0 if the spec was filled out,
564579
* GIT_ENOTFOUND if the fnmatch does not require matching, or
@@ -647,9 +662,10 @@ int git_attr_fnmatch__parse(
647662
return GIT_ENOTFOUND;
648663

649664
/* Remove trailing spaces. */
650-
while (pattern[spec->length - 1] == ' ' || pattern[spec->length - 1] == '\t')
651-
if (--spec->length == 0)
652-
return GIT_ENOTFOUND;
665+
spec->length -= trailing_space_length(pattern, spec->length);
666+
667+
if (spec->length == 0)
668+
return GIT_ENOTFOUND;
653669

654670
if (pattern[spec->length - 1] == '/') {
655671
spec->length--;

tests/attr/ignore.c

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,52 @@ void test_attr_ignore__ignore_space(void)
6161
assert_is_ignored(true, "NewFolder/NewFolder/File.txt");
6262
}
6363

64+
void test_attr_ignore__intermittent_space(void)
65+
{
66+
cl_git_rewritefile("attr/.gitignore", "foo bar\n");
67+
68+
assert_is_ignored(false, "foo");
69+
assert_is_ignored(false, "bar");
70+
assert_is_ignored(true, "foo bar");
71+
}
72+
73+
void test_attr_ignore__trailing_space(void)
74+
{
75+
cl_git_rewritefile(
76+
"attr/.gitignore",
77+
"foo \n"
78+
"bar \n"
79+
);
80+
81+
assert_is_ignored(true, "foo");
82+
assert_is_ignored(false, "foo ");
83+
assert_is_ignored(true, "bar");
84+
assert_is_ignored(false, "bar ");
85+
assert_is_ignored(false, "bar ");
86+
}
87+
88+
void test_attr_ignore__escaped_trailing_spaces(void)
89+
{
90+
cl_git_rewritefile(
91+
"attr/.gitignore",
92+
"foo\\ \n"
93+
"bar\\ \\ \n"
94+
"baz \\ \n"
95+
"qux\\ \n"
96+
);
97+
98+
assert_is_ignored(false, "foo");
99+
assert_is_ignored(true, "foo ");
100+
assert_is_ignored(false, "bar");
101+
assert_is_ignored(false, "bar ");
102+
assert_is_ignored(true, "bar ");
103+
assert_is_ignored(true, "baz ");
104+
assert_is_ignored(false, "baz ");
105+
assert_is_ignored(true, "qux ");
106+
assert_is_ignored(false, "qux");
107+
assert_is_ignored(false, "qux ");
108+
}
109+
64110
void test_attr_ignore__ignore_dir(void)
65111
{
66112
cl_git_rewritefile("attr/.gitignore", "dir/\n");

0 commit comments

Comments
 (0)