Add core.quotepath configuration variable.
authorJunio C Hamano <gitster@pobox.com>
Sun, 24 Jun 2007 22:11:24 +0000 (15:11 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sun, 24 Jun 2007 22:11:42 +0000 (15:11 -0700)
We always quote "unusual" byte values in a pathname using
C-string style, to make it safer for parsing scripts that do not
handle NUL separated records well (or just too lazy to bother).
The absolute minimum bytes that need to be quoted for this
purpose are TAB, LF (and other control characters), double quote
and backslash.

However, we have also always quoted the bytes in high 8-bit
range; this was partly because we were lazy and partly because
we were being cautious.

This introduces an internal "quote_path_fully" variable, and
core.quotepath configuration variable to control it.  When set
to false, it does not quote bytes in high 8-bit range anymore
but passes them intact.

The variable defaults to "true" to retain the traditional
behaviour for now.

Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/config.txt
cache.h
config.c
environment.c
quote.c
t/t3902-quoted.sh [new file with mode: 0755]

index a2057d9..34b1c97 100644 (file)
@@ -117,6 +117,18 @@ core.fileMode::
        the working copy are ignored; useful on broken filesystems like FAT.
        See gitlink:git-update-index[1]. True by default.
 
+core.quotepath::
+       The commands that output paths (e.g. `ls-files`,
+       `diff`), when not given the `-z` option, will quote
+       "unusual" characters in the pathname by enclosing the
+       pathname in a double-quote pair and with backslashes the
+       same way strings in C source code are quoted.  If this
+       variable is set to false, the bytes higher than 0x80 are
+       not quoted but output as verbatim.  Note that double
+       quote, backslash and control characters are always
+       quoted without `-z` regardless of the setting of this
+       variable.
+
 core.autocrlf::
        If true, makes git convert `CRLF` at the end of lines in text files to
        `LF` when reading from the filesystem, and convert in reverse when
diff --git a/cache.h b/cache.h
index ed83d92..6776357 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -292,6 +292,7 @@ extern int delete_ref(const char *, const unsigned char *sha1);
 
 /* Environment bits from configuration mechanism */
 extern int trust_executable_bit;
+extern int quote_path_fully;
 extern int has_symlinks;
 extern int assume_unchanged;
 extern int prefer_symlink_refs;
index e323153..4de8926 100644 (file)
--- a/config.c
+++ b/config.c
@@ -271,6 +271,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.quotepath")) {
+               quote_path_fully = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "core.symlinks")) {
                has_symlinks = git_config_bool(var, value);
                return 0;
index 8b9b89d..1c2773f 100644 (file)
@@ -12,6 +12,7 @@
 char git_default_email[MAX_GITNAME];
 char git_default_name[MAX_GITNAME];
 int trust_executable_bit = 1;
+int quote_path_fully = 1;
 int has_symlinks = 1;
 int assume_unchanged;
 int prefer_symlink_refs;
diff --git a/quote.c b/quote.c
index aa44009..d88bf75 100644 (file)
--- a/quote.c
+++ b/quote.c
@@ -188,7 +188,8 @@ static int quote_c_style_counted(const char *name, int namelen,
 #define EMITQ() EMIT('\\')
 
        const char *sp;
-       int ch, count = 0, needquote = 0;
+       unsigned char ch;
+       int count = 0, needquote = 0;
 
        if (!no_dq)
                EMIT('"');
@@ -197,7 +198,7 @@ static int quote_c_style_counted(const char *name, int namelen,
                if (!ch)
                        break;
                if ((ch < ' ') || (ch == '"') || (ch == '\\') ||
-                   (ch >= 0177)) {
+                   (quote_path_fully && (ch >= 0177))) {
                        needquote = 1;
                        switch (ch) {
                        case '\a': EMITQ(); ch = 'a'; break;
diff --git a/t/t3902-quoted.sh b/t/t3902-quoted.sh
new file mode 100755 (executable)
index 0000000..63f950b
--- /dev/null
@@ -0,0 +1,126 @@
+#!/bin/sh
+#
+# Copyright (c) 2006 Junio C Hamano
+#
+
+test_description='quoted output'
+
+. ./test-lib.sh
+
+FN='濱野'
+GN='純'
+HT='   '
+LF='
+'
+DQ='"'
+
+for_each_name () {
+       for name in \
+           Name "Name and a${LF}LF" "Name and an${HT}HT" "Name${DQ}" \
+           "$FN$HT$GN" "$FN$LF$GN" "$FN $GN" "$FN$GN" "$FN$DQ$GN" \
+           "With SP in it"
+       do
+               eval "$1"
+       done
+}
+
+test_expect_success setup '
+
+       for_each_name "echo initial >\"\$name\""
+       git add . &&
+       git commit -q -m Initial &&
+
+       for_each_name "echo second >\"\$name\"" &&
+       git commit -a -m Second
+
+       for_each_name "echo modified >\"\$name\""
+
+'
+
+cat >expect.quoted <<\EOF
+Name
+"Name and a\nLF"
+"Name and an\tHT"
+"Name\""
+With SP in it
+"\346\277\261\351\207\216\t\347\264\224"
+"\346\277\261\351\207\216\n\347\264\224"
+"\346\277\261\351\207\216 \347\264\224"
+"\346\277\261\351\207\216\"\347\264\224"
+"\346\277\261\351\207\216\347\264\224"
+EOF
+
+cat >expect.raw <<\EOF
+Name
+"Name and a\nLF"
+"Name and an\tHT"
+"Name\""
+With SP in it
+"濱野\t純"
+"濱野\n純"
+濱野 純
+"濱野\"純"
+濱野純
+EOF
+
+test_expect_success 'check fully quoted output from ls-files' '
+
+       git ls-files >current && diff -u expect.quoted current
+
+'
+
+test_expect_success 'check fully quoted output from diff-files' '
+
+       git diff --name-only >current &&
+       diff -u expect.quoted current
+
+'
+
+test_expect_success 'check fully quoted output from diff-index' '
+
+       git diff --name-only HEAD >current &&
+       diff -u expect.quoted current
+
+'
+
+test_expect_success 'check fully quoted output from diff-tree' '
+
+       git diff --name-only HEAD^ HEAD >current &&
+       diff -u expect.quoted current
+
+'
+
+test_expect_success 'setting core.quotepath' '
+
+       git config --bool core.quotepath false
+
+'
+
+test_expect_success 'check fully quoted output from ls-files' '
+
+       git ls-files >current && diff -u expect.raw current
+
+'
+
+test_expect_success 'check fully quoted output from diff-files' '
+
+       git diff --name-only >current &&
+       diff -u expect.raw current
+
+'
+
+test_expect_success 'check fully quoted output from diff-index' '
+
+       git diff --name-only HEAD >current &&
+       diff -u expect.raw current
+
+'
+
+test_expect_success 'check fully quoted output from diff-tree' '
+
+       git diff --name-only HEAD^ HEAD >current &&
+       diff -u expect.raw current
+
+'
+
+test_done