aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2024-04-01 13:21:34 -0700
committerJunio C Hamano <gitster@pobox.com>2024-04-01 13:21:34 -0700
commit521df686e5a5d445e03280f48df966b77e23f160 (patch)
treefbd8b5eb9ef2b57c660aaa6ad9b8e799ec1530d0
parenta031815a7df317a4387151b1f4af1c85834458b1 (diff)
parente6895c3f971dc4d60f7a9fac6ef41a6593a37ba9 (diff)
downloadgit-521df686e5a5d445e03280f48df966b77e23f160.tar.gz
Merge branch 'ds/config-internal-whitespace-fix'
"git config" corrupted literal HT characters written in the configuration file as part of a value, which has been corrected. * ds/config-internal-whitespace-fix: config.txt: describe handling of whitespace further t1300: add more tests for whitespace and inline comments config: really keep value-internal whitespace verbatim config: minor addition of whitespace
-rw-r--r--Documentation/config.txt28
-rw-r--r--config.c15
-rwxr-xr-xt/t1300-config.sh114
3 files changed, 136 insertions, 21 deletions
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 782c2bab90..70b448b132 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -22,9 +22,10 @@ multivalued.
Syntax
~~~~~~
-The syntax is fairly flexible and permissive; whitespaces are mostly
-ignored. The '#' and ';' characters begin comments to the end of line,
-blank lines are ignored.
+The syntax is fairly flexible and permissive. Whitespace characters,
+which in this context are the space character (SP) and the horizontal
+tabulation (HT), are mostly ignored. The '#' and ';' characters begin
+comments to the end of line. Blank lines are ignored.
The file consists of sections and variables. A section begins with
the name of the section in square brackets and continues until the next
@@ -63,16 +64,17 @@ the variable is the boolean "true").
The variable names are case-insensitive, allow only alphanumeric characters
and `-`, and must start with an alphabetic character.
-A line that defines a value can be continued to the next line by
-ending it with a `\`; the backslash and the end-of-line are
-stripped. Leading whitespaces after 'name =', the remainder of the
-line after the first comment character '#' or ';', and trailing
-whitespaces of the line are discarded unless they are enclosed in
-double quotes. Internal whitespaces within the value are retained
-verbatim.
-
-Inside double quotes, double quote `"` and backslash `\` characters
-must be escaped: use `\"` for `"` and `\\` for `\`.
+Whitespace characters surrounding `name`, `=` and `value` are discarded.
+Internal whitespace characters within 'value' are retained verbatim.
+Comments starting with either `#` or `;` and extending to the end of line
+are discarded. A line that defines a value can be continued to the next
+line by ending it with a backslash (`\`); the backslash and the end-of-line
+characters are discarded.
+
+If `value` needs to contain leading or trailing whitespace characters,
+it must be enclosed in double quotation marks (`"`). Inside double quotation
+marks, double quote (`"`) and backslash (`\`) characters must be escaped:
+use `\"` for `"` and `\\` for `\`.
The following escape sequences (beside `\"` and `\\`) are recognized:
`\n` for newline character (NL), `\t` for horizontal tabulation (HT, TAB)
diff --git a/config.c b/config.c
index 3cfeb3d8bd..5072f12e62 100644
--- a/config.c
+++ b/config.c
@@ -817,7 +817,8 @@ static int get_next_char(struct config_source *cs)
static char *parse_value(struct config_source *cs)
{
- int quote = 0, comment = 0, space = 0;
+ int quote = 0, comment = 0;
+ size_t trim_len = 0;
strbuf_reset(&cs->value);
for (;;) {
@@ -827,13 +828,17 @@ static char *parse_value(struct config_source *cs)
cs->linenr--;
return NULL;
}
+ if (trim_len)
+ strbuf_setlen(&cs->value, trim_len);
return cs->value.buf;
}
if (comment)
continue;
if (isspace(c) && !quote) {
+ if (!trim_len)
+ trim_len = cs->value.len;
if (cs->value.len)
- space++;
+ strbuf_addch(&cs->value, c);
continue;
}
if (!quote) {
@@ -842,8 +847,8 @@ static char *parse_value(struct config_source *cs)
continue;
}
}
- for (; space; space--)
- strbuf_addch(&cs->value, ' ');
+ if (trim_len)
+ trim_len = 0;
if (c == '\\') {
c = get_next_char(cs);
switch (c) {
@@ -869,7 +874,7 @@ static char *parse_value(struct config_source *cs)
continue;
}
if (c == '"') {
- quote = 1-quote;
+ quote = 1 - quote;
continue;
}
strbuf_addch(&cs->value, c);
diff --git a/t/t1300-config.sh b/t/t1300-config.sh
index 31c3878687..f4bd69512e 100755
--- a/t/t1300-config.sh
+++ b/t/t1300-config.sh
@@ -11,6 +11,98 @@ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
+test_expect_success 'setup whitespace config' '
+ sed -e "s/^|//" \
+ -e "s/[$]$//" \
+ -e "s/X/ /g" >.git/config <<-\EOF
+ [section]
+ | solid = rock
+ | sparse = big XX blue
+ | sparseAndTail = big XX blue $
+ | sparseAndTailQuoted = "big XX blue "
+ | sparseAndBiggerTail = big XX blue X X
+ | sparseAndBiggerTailQuoted = "big XX blue X X"
+ | sparseAndBiggerTailQuotedPlus = "big XX blue X X"X $
+ | headAndTail = Xbig blue $
+ | headAndTailQuoted = "Xbig blue "
+ | headAndTailQuotedPlus = "Xbig blue " $
+ | annotated = big blueX# to be discarded
+ | annotatedQuoted = "big blue"X# to be discarded
+ EOF
+'
+
+test_expect_success 'no internal whitespace' '
+ echo "rock" >expect &&
+ git config --get section.solid >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal whitespace' '
+ echo "big QQ blue" | q_to_tab >expect &&
+ git config --get section.sparse >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and trailing whitespace' '
+ echo "big QQ blue" | q_to_tab >expect &&
+ git config --get section.sparseAndTail >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and trailing whitespace, all quoted' '
+ echo "big QQ blue " | q_to_tab >expect &&
+ git config --get section.sparseAndTailQuoted >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and more trailing whitespace' '
+ echo "big QQ blue" | q_to_tab >expect &&
+ git config --get section.sparseAndBiggerTail >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and more trailing whitespace, all quoted' '
+ echo "big QQ blue Q Q" | q_to_tab >expect &&
+ git config --get section.sparseAndBiggerTailQuoted >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'internal and more trailing whitespace, not all quoted' '
+ echo "big QQ blue Q Q" | q_to_tab >expect &&
+ git config --get section.sparseAndBiggerTailQuotedPlus >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'leading and trailing whitespace' '
+ echo "big blue" >expect &&
+ git config --get section.headAndTail >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'leading and trailing whitespace, all quoted' '
+ echo "Qbig blue " | q_to_tab >expect &&
+ git config --get section.headAndTailQuoted >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'leading and trailing whitespace, not all quoted' '
+ echo "Qbig blue " | q_to_tab >expect &&
+ git config --get section.headAndTailQuotedPlus >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inline comment' '
+ echo "big blue" >expect &&
+ git config --get section.annotated >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inline comment, quoted' '
+ echo "big blue" >expect &&
+ git config --get section.annotatedQuoted >actual &&
+ test_cmp expect actual
+'
+
test_expect_success 'clear default config' '
rm -f .git/config
'
@@ -1066,9 +1158,25 @@ test_expect_success '--null --get-regexp' '
test_cmp expect result
'
-test_expect_success 'inner whitespace kept verbatim' '
- git config section.val "foo bar" &&
- test_cmp_config "foo bar" section.val
+test_expect_success 'inner whitespace kept verbatim, spaces only' '
+ echo "foo bar" >expect &&
+ git config section.val "foo bar" &&
+ git config --get section.val >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inner whitespace kept verbatim, horizontal tabs only' '
+ echo "fooQQbar" | q_to_tab >expect &&
+ git config section.val "$(cat expect)" &&
+ git config --get section.val >actual &&
+ test_cmp expect actual
+'
+
+test_expect_success 'inner whitespace kept verbatim, horizontal tabs and spaces' '
+ echo "foo Q bar" | q_to_tab >expect &&
+ git config section.val "$(cat expect)" &&
+ git config --get section.val >actual &&
+ test_cmp expect actual
'
test_expect_success SYMLINKS 'symlinked configuration' '