{"thread":{"id":"35877","subject":"[PATCH/RESEND] attr: allow pattern escape using backslashes","startedAt":"2014-02-15T02:05:04Z","lastAt":"2014-02-18T19:38:34Z","messageCount":2,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"234841","messageId":"1392429904-11559-1-git-send-email-pclouds@gmail.com","threadId":"35877","inReplyTo":null,"subject":"[PATCH/RESEND] attr: allow pattern escape using backslashes","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2014-02-15T02:05:04Z","receivedAt":"2014-02-15T02:05:04Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Patterns in .gitattributes are separated by whitespaces, which makes\nit impossible to specify exact spaces in the pattern. '?' can be used\nas a workaround, but it matches other characters too. This patch makes\na space following a backslash part of the pattern, not a pattern\nseparator.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Last discussion is [1] although the thread went off topic, so no\n actual discussion.\n \n [1] http://thread.gmane.org/gmane.comp.version-control.git/212631\n\n Documentation/gitattributes.txt | 6 +++---\n attr.c                          | 8 +++++++-\n t/t0003-attributes.sh           | 5 +++++\n 3 files changed, 15 insertions(+), 4 deletions(-)\n\ndiff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\nindex 643c1ba..5d4d386 100644\n--- a/Documentation/gitattributes.txt\n+++ b/Documentation/gitattributes.txt\n@@ -20,9 +20,9 @@ Each line in `gitattributes` file is of form:\n \n \tpattern\tattr1 attr2 ...\n \n-That is, a pattern followed by an attributes list,\n-separated by whitespaces.  When the pattern matches the\n-path in question, the attributes listed on the line are given to\n+That is, a pattern followed by an attributes list, separated by\n+whitespaces that are not quoted by a backslash. When the pattern matches\n+the path in question, the attributes listed on the line are given to\n the path.\n \n Each attribute can be in one of these states for a given path:\ndiff --git a/attr.c b/attr.c\nindex 8d13d70..699716d 100644\n--- a/attr.c\n+++ b/attr.c\n@@ -209,7 +209,13 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,\n \tif (!*cp || *cp == '#')\n \t\treturn NULL;\n \tname = cp;\n-\tnamelen = strcspn(name, blank);\n+\tnamelen = 0;\n+\twhile (name[namelen] != '\\0' && !strchr(blank, name[namelen])) {\n+\t\tif (name[namelen] == '\\\\' && name[namelen + 1] != '\\0')\n+\t\t\tnamelen += 2;\n+\t\telse\n+\t\t\tnamelen++;\n+\t}\n \tif (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&\n \t    starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {\n \t\tif (!macro_ok) {\ndiff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh\nindex b9d7947..2f16805 100755\n--- a/t/t0003-attributes.sh\n+++ b/t/t0003-attributes.sh\n@@ -23,6 +23,7 @@ test_expect_success 'setup' '\n \t\techo \"offon -test test\"\n \t\techo \"no notest\"\n \t\techo \"A/e/F test=A/e/F\"\n+\t\techo \"A\\\\ b test=space\"\n \t) >.gitattributes &&\n \t(\n \t\techo \"g test=a/g\" &&\n@@ -195,6 +196,10 @@ test_expect_success 'root subdir attribute test' '\n \tattr_check subdir/a/i unspecified\n '\n \n+test_expect_success 'quoting in pattern' '\n+\tattr_check \"A b\" space\n+'\n+\n test_expect_success 'negative patterns' '\n \techo \"!f test=bar\" >.gitattributes &&\n \tgit check-attr test -- '\"'\"'!f'\"'\"' 2>errors &&\n-- \n1.8.5.2.240.g8478abd\n"},{"id":"235007","messageId":"xmqqy518dxdx.fsf@gitster.dls.corp.google.com","threadId":"35877","inReplyTo":"1392429904-11559-1-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH/RESEND] attr: allow pattern escape using backslashes","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2014-02-18T19:38:34Z","receivedAt":"2014-02-18T19:38:34Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Patterns in .gitattributes are separated by whitespaces, which makes\n> it impossible to specify exact spaces in the pattern. '?' can be used\n> as a workaround, but it matches other characters too. This patch makes\n> a space following a backslash part of the pattern, not a pattern\n> separator.\n>\n> Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n> ---\n>  Last discussion is [1] although the thread went off topic, so no\n>  actual discussion.\n\nThe only people who could get hurt with this patch are those who do\nhave a path that ends with a backslash (e.g. 'hello\\') and have been\nmatching it with a pattern that literally match with it, but even\nthen they should have been quoting it at the end of the pattern\n(e.g. as 'hello\\\\'), so the new parsing rule would not be confused,\nI would think.\n\nSo, I like it.  Thanks.\n\n>  \n>  [1] http://thread.gmane.org/gmane.comp.version-control.git/212631\n>\n>  Documentation/gitattributes.txt | 6 +++---\n>  attr.c                          | 8 +++++++-\n>  t/t0003-attributes.sh           | 5 +++++\n>  3 files changed, 15 insertions(+), 4 deletions(-)\n>\n> diff --git a/Documentation/gitattributes.txt b/Documentation/gitattributes.txt\n> index 643c1ba..5d4d386 100644\n> --- a/Documentation/gitattributes.txt\n> +++ b/Documentation/gitattributes.txt\n> @@ -20,9 +20,9 @@ Each line in `gitattributes` file is of form:\n>  \n>  \tpattern\tattr1 attr2 ...\n>  \n> -That is, a pattern followed by an attributes list,\n> -separated by whitespaces.  When the pattern matches the\n> -path in question, the attributes listed on the line are given to\n> +That is, a pattern followed by an attributes list, separated by\n> +whitespaces that are not quoted by a backslash. When the pattern matches\n> +the path in question, the attributes listed on the line are given to\n>  the path.\n>  \n>  Each attribute can be in one of these states for a given path:\n> diff --git a/attr.c b/attr.c\n> index 8d13d70..699716d 100644\n> --- a/attr.c\n> +++ b/attr.c\n> @@ -209,7 +209,13 @@ static struct match_attr *parse_attr_line(const char *line, const char *src,\n>  \tif (!*cp || *cp == '#')\n>  \t\treturn NULL;\n>  \tname = cp;\n> -\tnamelen = strcspn(name, blank);\n> +\tnamelen = 0;\n> +\twhile (name[namelen] != '\\0' && !strchr(blank, name[namelen])) {\n> +\t\tif (name[namelen] == '\\\\' && name[namelen + 1] != '\\0')\n> +\t\t\tnamelen += 2;\n> +\t\telse\n> +\t\t\tnamelen++;\n> +\t}\n>  \tif (strlen(ATTRIBUTE_MACRO_PREFIX) < namelen &&\n>  \t    starts_with(name, ATTRIBUTE_MACRO_PREFIX)) {\n>  \t\tif (!macro_ok) {\n> diff --git a/t/t0003-attributes.sh b/t/t0003-attributes.sh\n> index b9d7947..2f16805 100755\n> --- a/t/t0003-attributes.sh\n> +++ b/t/t0003-attributes.sh\n> @@ -23,6 +23,7 @@ test_expect_success 'setup' '\n>  \t\techo \"offon -test test\"\n>  \t\techo \"no notest\"\n>  \t\techo \"A/e/F test=A/e/F\"\n> +\t\techo \"A\\\\ b test=space\"\n>  \t) >.gitattributes &&\n>  \t(\n>  \t\techo \"g test=a/g\" &&\n> @@ -195,6 +196,10 @@ test_expect_success 'root subdir attribute test' '\n>  \tattr_check subdir/a/i unspecified\n>  '\n>  \n> +test_expect_success 'quoting in pattern' '\n> +\tattr_check \"A b\" space\n> +'\n> +\n>  test_expect_success 'negative patterns' '\n>  \techo \"!f test=bar\" >.gitattributes &&\n>  \tgit check-attr test -- '\"'\"'!f'\"'\"' 2>errors &&\n"}]}