Subject: Re: [PATCH alt-v3] Improve function dir.c:trim_trailing_spaces()

From: Junio C Hamano <[email-masked]>
Date: Mon, 02 Jun 2014 15:54:06 -0700

Pasha Bolokhov <[email-masked]> writes:

> Discard the unnecessary 'nr_spaces' variable, remove 'strlen()' and
> improve the 'if' structure. Switch to pointers instead of integers
>
> Slightly more rare occurrences of 'text  \    ' with a backslash
> in between spaces are handled correctly. Namely, the code in
> 8ba87adad6 does not reset 'last_space' when a backslash is
> encountered and the above line stays intact as a result.
> Add a test at the end of t/t0008-ignores.sh to exhibit this behavior
>
> Signed-off-by: Pasha Bolokhov <[email-masked]>
> ---
> Add /* fallthrough */ comment to switch(), remove TABs in test,
> and remove ":" command in file truncation in the test

8ba87adad6 does not seem to do anything to do with this change,
though.  Tentatively I've queued the following (but not merged to
anywhere nor pushed out).

Thanks.

-- >8 --
From: Pasha Bolokhov <[email-masked]>
Date: Mon, 2 Jun 2014 15:36:56 -0700
Subject: [PATCH] dir.c:trim_trailing_spaces(): fix for " \ " sequence

Discard the unnecessary 'nr_spaces' variable, remove 'strlen()' and
improve the 'if' structure.  Switch to pointers instead of integers
to control the loop.

Slightly more rare occurrences of 'text  \    ' with a backslash
in between spaces are handled correctly.  Namely, the code in
7e2e4b37 (dir: ignore trailing spaces in exclude patterns, 2014-02-09)
does not reset 'last_space' when a backslash is encountered and the above
line stays intact as a result.

Add a test at the end of t/t0008-ignores.sh to exhibit this behavior.

Signed-off-by: Pasha Bolokhov <[email-masked]>
Signed-off-by: Junio C Hamano <[email-masked]>
---
 dir.c              | 34 +++++++++++++++++++---------------
 t/t0008-ignores.sh | 23 +++++++++++++++++++++++
 2 files changed, 42 insertions(+), 15 deletions(-)

diff --git a/dir.c b/dir.c
index eb6f581..797805d 100644
--- a/dir.c
+++ b/dir.c
@@ -508,21 +508,25 @@ void clear_exclude_list(struct exclude_list *el)
 
 static void trim_trailing_spaces(char *buf)
 {
-	int i, last_space = -1, nr_spaces, len = strlen(buf);
-	for (i = 0; i < len; i++)
-		if (buf[i] == '\\')
-			i++;
-		else if (buf[i] == ' ') {
-			if (last_space == -1) {
-				last_space = i;
-				nr_spaces = 1;
-			} else
-				nr_spaces++;
-		} else
-			last_space = -1;
-
-	if (last_space != -1 && last_space + nr_spaces == len)
-		buf[last_space] = '\0';
+	char *p, *last_space = NULL;
+
+	for (p = buf; *p; p++)
+		switch (*p) {
+		case ' ':
+			if (!last_space)
+				last_space = p;
+			break;
+		case '\\':
+			p++;
+			if (!*p)
+				return;
+			/* fallthrough */
+		default:
+			last_space = NULL;
+		}
+
+	if (last_space)
+		*last_space = '\0';
 }
 
 int add_excludes_from_file_to_list(const char *fname,
diff --git a/t/t0008-ignores.sh b/t/t0008-ignores.sh
index 63beb99..5ef5ad3 100755
--- a/t/t0008-ignores.sh
+++ b/t/t0008-ignores.sh
@@ -806,4 +806,27 @@ test_expect_success !MINGW 'quoting allows trailing whitespace' '
 	test_cmp err.expect err
 '
 
+test_expect_success NOT_MINGW,NOT_CYGWIN 'correct handling of backslashes' '
+	rm -rf whitespace &&
+	mkdir whitespace &&
+	>"whitespace/trailing 1  " &&
+	>"whitespace/trailing 2 \\\\" &&
+	>"whitespace/trailing 3 \\\\" &&
+	>"whitespace/trailing 4   \\ " &&
+	>"whitespace/trailing 5 \\ \\ " &&
+	>"whitespace/trailing 6 \\a\\" &&
+	>whitespace/untracked &&
+	echo "whitespace/trailing 1 \\    " >ignore  &&
+	echo "whitespace/trailing 2 \\\\\\\\\\\\\\\\" >>ignore &&
+	echo "whitespace/trailing 3 \\\\\\\\\\\\\\\\ " >>ignore &&
+	echo "whitespace/trailing 4   \\\\\\\\\\\\    " >>ignore &&
+	echo "whitespace/trailing 5 \\\\\\\\ \\\\\\\\\\\\   " >>ignore &&
+	echo "whitespace/trailing 6 \\\\\\\\a\\\\\\\\" >>ignore &&
+	echo whitespace/untracked >expect &&
+	>err.expect &&
+	git ls-files -o -X ignore whitespace >actual 2>err &&
+	test_cmp expect actual &&
+	test_cmp err.expect err
+'
+
 test_done
-- 
2.0.0-511-g1433423