Subject: Re: [PATCH/RESEND] attr: allow pattern escape using backslashes

From: Junio C Hamano <[email-masked]>
Date: Tue, 18 Feb 2014 11:38:34 -0800

Nguyễn Thái Ngọc Duy  <[email-masked]> writes:

> Patterns in .gitattributes are separated by whitespaces, which makes
> it impossible to specify exact spaces in the pattern. '?' can be used
> as a workaround, but it matches other characters too. This patch makes
> a space following a backslash part of the pattern, not a pattern
> separator.
>
> Signed-off-by: Nguyễn Thái Ngọc Duy <[email-masked]>
> ---
>  Last discussion is [1] although the thread went off topic, so no
>  actual discussion.

The only people who could get hurt with this patch are those who do
have a path that ends with a backslash (e.g. 'hello\') and have been
matching it with a pattern that literally match with it, but even
then they should have been quoting it at the end of the pattern
(e.g. as 'hello\\'), so the new parsing rule would not be confused,
I would think.

So, I like it.  Thanks.

>  
>  [1] http://thread.gmane.org/gmane.comp.version-control.git/212631
>
>  Documentation/gitattributes.txt | 6 +++---
>  attr.c                          | 8 +++++++-
>  t/t0003-attributes.sh           | 5 +++++
>  3 files changed, 15 insertions(+), 4 deletions(-)
>
> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt
> index 643c1ba..5d4d386 100644
> --- a/Documentation/gitattributes.txt
> +++ b/Documentation/gitattributes.txt
> @@ -20,9 +20,9 @@ Each line in `gitattributes` file is of form:
>  
>  	pattern	attr1 attr2 ...
>  
> -That is, a pattern followed by an attributes list,
> -separated by whitespaces.  When the pattern matches the
> -path in question, the attributes listed on the line are given to
> +That is, a pattern followed by an attributes list, separated by
> +whitespaces that are not quoted by a backslash. When the pattern matches
> +the path in question, the attributes listed on the line are given to
>  the path.
>  
>  Each attribute can be in one of these states for a given path:
> diff --git a/attr.c b/attr.c
> index 8d13d70..699716d 100644
> --- a/attr.c
> +++ b/attr.c
> @@ -209,7 +209,13 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,
>  	if (!*cp || *cp == '#')
>  		return NULL;
>  	name = cp;
> -	namelen = strcspn(name, blank);
> +	namelen = 0;
> +	while (name[namelen] != '\0' && !strchr(blank, name[namelen])) {
> +		if (name[namelen] == '\\' && name[namelen + 1] != '\0')
> +			namelen += 2;
> +		else
> +			namelen++;
> +	}
>  	if (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&
>  	    starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {
>  		if (!macro_ok) {
> diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh
> index b9d7947..2f16805 100755
> --- a/t/t0003-attributes.sh
> +++ b/t/t0003-attributes.sh
> @@ -23,6 +23,7 @@ test_expect_success 'setup' '
>  		echo "offon -test test"
>  		echo "no notest"
>  		echo "A/e/F test=A/e/F"
> +		echo "A\\ b test=space"
>  	) >.gitattributes &&
>  	(
>  		echo "g test=a/g" &&
> @@ -195,6 +196,10 @@ test_expect_success 'root subdir attribute test' '
>  	attr_check subdir/a/i unspecified
>  '
>  
> +test_expect_success 'quoting in pattern' '
> +	attr_check "A b" space
> +'
> +
>  test_expect_success 'negative patterns' '
>  	echo "!f test=bar" >.gitattributes &&
>  	git check-attr test -- '"'"'!f'"'"' 2>errors &&