[PATCH] Fix git_config_set() for mean cases
From: Johannes Schindelin <hidden>
Date: 2016-06-15 22:42:12
Subsystem:
the rest · Maintainer:
Linus Torvalds
There were problems when the keys´ case didn´t match, and also when the section was in the same line as the key. This patch also adds a test case, so you see that it works now. Signed-off-by: Johannes Schindelin <redacted> --- I shoulda started by writing those tests. This patch is on top of my earlier patch, which worked only in the nice cases. It now needs git-config-set, though. config.c | 42 ++++++++++++++---- t/t1300-config-set.sh | 112 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 144 insertions(+), 10 deletions(-) create mode 100644 t/t1300-config-set.sh applies-to: ae3c1e28a1df80086033825ac68fdf4c6c835eee e326b690c85a648ffcbbc63e69333a7100a07892
diff --git a/config.c b/config.c
index 3b883b2..9315351 100644
--- a/config.c
+++ b/config.c@@ -255,7 +255,7 @@ int git_config(config_fn_t fn) static struct { int baselen; - const char* key; + char* key; const char* value; off_t offset; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state;
@@ -270,10 +270,10 @@ static int store_aux(const char* key, co break; case SECTION_SEEN: if (strncmp(key, store.key, store.baselen+1)) { - store.offset = ftell(config_file); store.state = SECTION_END_SEEN; break; - } + } else + store.offset = ftell(config_file); case SECTION_END_SEEN: case START: if (!strcmp(key, store.key)) {
@@ -326,18 +326,21 @@ int git_config_set(const char* key, cons return 2; } + store.key = strdup(key); for (i = 0; key[i]; i++) if (i != store.baselen && !isalpha(key[i])) { fprintf(stderr, "invalid key: %s\n", key); + free(store.key); return 1; - } + } else + store.key[i] = tolower(key[i]); - store.key = key; store.value = value; fd = open(lock_file, O_WRONLY | O_CREAT | O_EXCL, 0666); if (fd < 0) { fprintf(stderr, "could not lock config file\n"); + free(store.key); return -1; }
@@ -349,6 +352,9 @@ int git_config_set(const char* key, cons "#\n" "\n"; + free(store.key); + store.key = (char*)key; + write(fd, contents, sizeof(contents)-1); store_write_section(fd); store_write_pair(fd);
@@ -362,25 +368,41 @@ int git_config_set(const char* key, cons if (git_config(store_aux)) { fprintf(stderr, "invalid config file\n"); + free(store.key); return 3; } + free(store.key); + store.key = (char*)key; + in_fd = open(config_file, O_RDONLY, 0666); contents = mmap(NULL, st.st_size, PROT_READ, MAP_PRIVATE, in_fd, 0); close(in_fd); if (store.offset == 0) - offset = st.st_size; - else { + store.offset = offset = st.st_size; + else if (store.state != KEY_SEEN) { + offset = store.offset; + } else { + int equal_offset = st.st_size, + bracket_offset = st.st_size; for (offset = store.offset-2; offset > 0 - && contents[offset] != '\n'; offset--); - offset++; + && contents[offset] != '\n'; offset--) + switch (contents[offset]) { + case '=': equal_offset = offset; break; + case ']': bracket_offset = offset; break; + } + if (bracket_offset < equal_offset) { + contents[bracket_offset+1] = '\n'; + offset = bracket_offset+2; + } else + offset++; } write(fd, contents, offset); if (store.state == START) store_write_section(fd); store_write_pair(fd); - if (store.offset > offset) + if (store.offset < st.st_size) write(fd, contents + store.offset, st.st_size - store.offset);
diff --git a/t/t1300-config-set.sh b/t/t1300-config-set.sh
new file mode 100644
index 0000000..48d4ff1
--- /dev/null
+++ b/t/t1300-config-set.sh@@ -0,0 +1,112 @@ +#!/bin/sh +# +# Copyright (c) 2005 Johannes Schindelin +# + +test_description='Test git-config-set in different settings' + +. ./test-lib.sh + +test -f .git/config && rm .git/config + +git-config-set core.penguin "little blue" + +cat > expect.1 << EOF +# +# This is the config file +# + +[core] + penguin = little blue +EOF + +test_expect_success 'initial' 'cmp .git/config expect.1' + +git-config-set Core.Movie BadPhysics + +cat > expect.2 << EOF +# +# This is the config file +# + +[core] + penguin = little blue + Movie = BadPhysics +EOF + +test_expect_success 'mixed case' 'cmp .git/config expect.2' + +git-config-set Cores.WhatEver Second + +cat > expect.3 << EOF +# +# This is the config file +# + +[core] + penguin = little blue + Movie = BadPhysics +[Cores] + WhatEver = Second +EOF + +test_expect_success 'similar section' 'cmp .git/config expect.3' + +git-config-set CORE.UPPERCASE true + +cat > expect.4 << EOF +# +# This is the config file +# + +[core] + penguin = little blue + Movie = BadPhysics + UPPERCASE = true +[Cores] + WhatEver = Second +EOF + +test_expect_success 'similar section' 'cmp .git/config expect.4' + +cat > .git/config << EOF +[beta] ; silly comment # another comment +noIndent= sillyValue ; ´nother silly comment + +# empty line + ; comment + haha ="beta" # last silly comment +[nextSection] noNewline = ouch +EOF + +git-config-set beta.haha alpha + +cat > expect.5 << EOF +[beta] ; silly comment # another comment +noIndent= sillyValue ; ´nother silly comment + +# empty line + ; comment + haha = alpha +[nextSection] noNewline = ouch +EOF + +test_expect_success 'really mean test' 'cmp .git/config expect.5' + +git-config-set nextsection.nonewline wow + +cat > expect.6 << EOF +[beta] ; silly comment # another comment +noIndent= sillyValue ; ´nother silly comment + +# empty line + ; comment + haha = alpha +[nextSection] + nonewline = wow +EOF + +test_expect_success 'really really mean test' 'cmp .git/config expect.6' + +test_done +
--- 0.99.9.GIT