static int use_key_regexp;
static int do_all;
static int do_not_match;
- static int seen;
static char delim = '=';
static char key_delim = ' ';
static char term = '\n';
return 0;
}
- static int show_config(const char *key_, const char *value_, void *cb)
+ struct strbuf_list {
+ struct strbuf *items;
+ int nr;
+ int alloc;
+ };
+
+ static int collect_config(const char *key_, const char *value_, void *cb)
{
+ struct strbuf_list *values = cb;
+ struct strbuf *buf;
char value[256];
const char *vptr = value;
int must_free_vptr = 0;
- int dup_error = 0;
int must_print_delim = 0;
if (!use_key_regexp && strcmp(key_, key))
(do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
return 0;
+ ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+ buf = &values->items[values->nr++];
+ strbuf_init(buf, 0);
+
if (show_keys) {
- printf("%s", key_);
+ strbuf_addstr(buf, key_);
must_print_delim = 1;
}
- if (seen && !do_all)
- dup_error = 1;
if (types == TYPE_INT)
sprintf(value, "%d", git_config_int(key_, value_?value_:""));
else if (types == TYPE_BOOL)
else
sprintf(value, "%d", v);
} else if (types == TYPE_PATH) {
- git_config_pathname(&vptr, key_, value_);
+ if (git_config_pathname(&vptr, key_, value_) < 0)
+ return -1;
must_free_vptr = 1;
} else if (value_) {
vptr = value_;
vptr = "";
must_print_delim = 0;
}
- seen++;
- if (dup_error) {
- error("More than one value for the key %s: %s",
- key_, vptr);
- }
- else {
- if (must_print_delim)
- printf("%c", key_delim);
- printf("%s%c", vptr, term);
- }
+
+ if (must_print_delim)
+ strbuf_addch(buf, key_delim);
+ strbuf_addstr(buf, vptr);
+ strbuf_addch(buf, term);
+
if (must_free_vptr)
/* If vptr must be freed, it's a pointer to a
* dynamically allocated buffer, it's safe to cast to
static int get_value(const char *key_, const char *regex_)
{
int ret = CONFIG_GENERIC_ERROR;
- char *global = NULL, *xdg = NULL, *repo_config = NULL;
- const char *system_wide = NULL, *local;
- struct config_include_data inc = CONFIG_INCLUDE_INIT;
- config_fn_t fn;
- void *data;
-
- local = given_config_file;
- if (!local) {
- local = repo_config = git_pathdup("config");
- if (git_config_system())
- system_wide = git_etc_gitconfig();
- home_config_paths(&global, &xdg, "config");
- }
+ struct strbuf_list values = {NULL};
+ int i;
if (use_key_regexp) {
char *tl;
key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
if (regcomp(key_regexp, key, REG_EXTENDED)) {
fprintf(stderr, "Invalid key pattern: %s\n", key_);
- free(key);
+ free(key_regexp);
+ key_regexp = NULL;
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
regexp = (regex_t*)xmalloc(sizeof(regex_t));
if (regcomp(regexp, regex_, REG_EXTENDED)) {
fprintf(stderr, "Invalid pattern: %s\n", regex_);
+ free(regexp);
+ regexp = NULL;
ret = CONFIG_INVALID_PATTERN;
goto free_strings;
}
}
- fn = show_config;
- data = NULL;
- if (respect_includes) {
- inc.fn = fn;
- inc.data = data;
- fn = git_config_include;
- data = &inc;
- }
+ git_config_with_options(collect_config, &values,
+ given_config_file, respect_includes);
+
+ ret = !values.nr;
- if (do_all && system_wide)
- git_config_from_file(fn, system_wide, data);
- if (do_all && xdg)
- git_config_from_file(fn, xdg, data);
- if (do_all && global)
- git_config_from_file(fn, global, data);
- if (do_all)
- git_config_from_file(fn, local, data);
- git_config_from_parameters(fn, data);
- if (!do_all && !seen)
- git_config_from_file(fn, local, data);
- if (!do_all && !seen && global)
- git_config_from_file(fn, global, data);
- if (!do_all && !seen && xdg)
- git_config_from_file(fn, xdg, data);
- if (!do_all && !seen && system_wide)
- git_config_from_file(fn, system_wide, data);
+ for (i = 0; i < values.nr; i++) {
+ struct strbuf *buf = values.items + i;
+ if (do_all || i == values.nr - 1)
+ fwrite(buf->buf, 1, buf->len, stdout);
+ strbuf_release(buf);
+ }
+ free(values.items);
+ free_strings:
free(key);
+ if (key_regexp) {
+ regfree(key_regexp);
+ free(key_regexp);
+ }
if (regexp) {
regfree(regexp);
free(regexp);
}
- if (do_all)
- ret = !seen;
- else
- ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
-
- free_strings:
- free(repo_config);
- free(global);
- free(xdg);
return ret;
}
#include "strbuf.h"
#include "quote.h"
-#define MAXNAME (256)
-
typedef struct config_file {
struct config_file *prev;
FILE *f;
int linenr;
int eof;
struct strbuf value;
- char var[MAXNAME];
+ struct strbuf var;
} config_file;
static config_file *cf;
return isalnum(c) || c == '-';
}
-static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
+static int get_value(config_fn_t fn, void *data, struct strbuf *name)
{
int c;
char *value;
break;
if (!iskeychar(c))
break;
- name[len++] = tolower(c);
- if (len >= MAXNAME)
- return -1;
+ strbuf_addch(name, tolower(c));
}
- name[len] = 0;
+
while (c == ' ' || c == '\t')
c = get_next_char();
if (!value)
return -1;
}
- return fn(name, value, data);
+ return fn(name->buf, value, data);
}
-static int get_extended_base_var(char *name, int baselen, int c)
+static int get_extended_base_var(struct strbuf *name, int c)
{
do {
if (c == '\n')
/* We require the format to be '[base "extension"]' */
if (c != '"')
return -1;
- name[baselen++] = '.';
+ strbuf_addch(name, '.');
for (;;) {
int c = get_next_char();
if (c == '\n')
goto error_incomplete_line;
}
- name[baselen++] = c;
- if (baselen > MAXNAME / 2)
- return -1;
+ strbuf_addch(name, c);
}
/* Final ']' */
if (get_next_char() != ']')
return -1;
- return baselen;
+ return 0;
error_incomplete_line:
cf->linenr--;
return -1;
}
-static int get_base_var(char *name)
+static int get_base_var(struct strbuf *name)
{
- int baselen = 0;
-
for (;;) {
int c = get_next_char();
if (cf->eof)
return -1;
if (c == ']')
- return baselen;
+ return 0;
if (isspace(c))
- return get_extended_base_var(name, baselen, c);
+ return get_extended_base_var(name, c);
if (!iskeychar(c) && c != '.')
return -1;
- if (baselen > MAXNAME / 2)
- return -1;
- name[baselen++] = tolower(c);
+ strbuf_addch(name, tolower(c));
}
}
{
int comment = 0;
int baselen = 0;
- char *var = cf->var;
+ struct strbuf *var = &cf->var;
/* U+FEFF Byte Order Mark in UTF8 */
static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
continue;
}
if (c == '[') {
- baselen = get_base_var(var);
- if (baselen <= 0)
+ /* Reset prior to determining a new stem */
+ strbuf_reset(var);
+ if (get_base_var(var) < 0 || var->len < 1)
break;
- var[baselen++] = '.';
- var[baselen] = 0;
+ strbuf_addch(var, '.');
+ baselen = var->len;
continue;
}
if (!isalpha(c))
break;
- var[baselen] = tolower(c);
- if (get_value(fn, data, var, baselen+1) < 0)
+ /*
+ * Truncate the var name back to the section header
+ * stem prior to grabbing the suffix part of the name
+ * and the value.
+ */
+ strbuf_setlen(var, baselen);
+ strbuf_addch(var, tolower(c));
+ if (get_value(fn, data, var) < 0)
break;
}
die("bad config file line %d in %s", cf->linenr, cf->name);
top.linenr = 1;
top.eof = 0;
strbuf_init(&top.value, 1024);
+ strbuf_init(&top.var, 1024);
cf = ⊤
ret = git_parse_file(fn, data);
/* pop config-file parsing state stack */
strbuf_release(&top.value);
+ strbuf_release(&top.var);
cf = top.prev;
fclose(f);
out_free_ret_1:
free(*store_key);
+ *store_key = NULL;
return -CONFIG_INVALID_KEY;
}
test_cmp expect .git/config
'
- test_expect_success 'replace with non-match' \
- 'git config core.penguin kingpin !blue'
+ test_expect_success 'replace with non-match' '
+ git config core.penguin kingpin !blue
+ '
- test_expect_success 'replace with non-match (actually matching)' \
- 'git config core.penguin "very blue" !kingpin'
+ test_expect_success 'replace with non-match (actually matching)' '
+ git config core.penguin "very blue" !kingpin
+ '
cat > expect << EOF
[core]
lines
EOF
- test_expect_success 'unset with cont. lines' \
- 'git config --unset beta.baz'
+ test_expect_success 'unset with cont. lines' '
+ git config --unset beta.baz
+ '
cat > expect <<\EOF
[alpha]
cp .git/config .git/config2
- test_expect_success 'multiple unset' \
- 'git config --unset-all beta.haha'
+ test_expect_success 'multiple unset' '
+ git config --unset-all beta.haha
+ '
cat > expect << EOF
[beta] ; silly comment # another comment
[nextSection] noNewline = ouch
EOF
- test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config'
+ test_expect_success 'multiple unset is correct' '
+ test_cmp expect .git/config
+ '
cp .git/config2 .git/config
rm .git/config2
- test_expect_success '--replace-all' \
- 'git config --replace-all beta.haha gamma'
+ test_expect_success '--replace-all' '
+ git config --replace-all beta.haha gamma
+ '
cat > expect << EOF
[beta] ; silly comment # another comment
[nextSection] noNewline = ouch
EOF
- test_expect_success 'all replaced' 'test_cmp expect .git/config'
+ test_expect_success 'all replaced' '
+ test_cmp expect .git/config
+ '
cat > expect << EOF
[beta] ; silly comment # another comment
test_cmp expect .git/config
'
- test_expect_success 'get value' 'test alpha = $(git config beta.haha)'
+ test_expect_success 'get value' '
+ echo alpha >expect &&
+ git config beta.haha >actual &&
+ test_cmp expect actual
+ '
cat > expect << EOF
[beta] ; silly comment # another comment
test_cmp expect .git/config
'
- test_expect_success 'non-match' \
- 'git config --get nextsection.nonewline !for'
+ test_expect_success 'non-match' '
+ git config --get nextsection.nonewline !for
+ '
- test_expect_success 'non-match value' \
- 'test wow = $(git config --get nextsection.nonewline !for)'
+ test_expect_success 'non-match value' '
+ echo wow >expect &&
+ git config --get nextsection.nonewline !for >actual &&
+ test_cmp expect actual
+ '
- test_expect_success 'ambiguous get' '
- test_must_fail git config --get nextsection.nonewline
+ test_expect_success 'multi-valued get returns final one' '
+ echo "wow2 for me" >expect &&
+ git config --get nextsection.nonewline >actual &&
+ test_cmp expect actual
'
- test_expect_success 'get multivar' \
- 'git config --get-all nextsection.nonewline'
+ test_expect_success 'multi-valued get-all returns all' '
+ cat >expect <<-\EOF &&
+ wow
+ wow2 for me
+ EOF
+ git config --get-all nextsection.nonewline >actual &&
+ test_cmp expect actual
+ '
cat > expect << EOF
[beta] ; silly comment # another comment
test_cmp expect .git/config
'
- test_expect_success 'ambiguous value' '
- test_must_fail git config nextsection.nonewline
- '
-
test_expect_success 'ambiguous unset' '
test_must_fail git config --unset nextsection.nonewline
'
test_expect_success 'correct key' 'git config 123456.a123 987'
- test_expect_success 'hierarchical section' \
- 'git config Version.1.2.3eX.Alpha beta'
+ test_expect_success 'hierarchical section' '
+ git config Version.1.2.3eX.Alpha beta
+ '
cat > expect << EOF
[beta] ; silly comment # another comment
Alpha = beta
EOF
- test_expect_success 'hierarchical section value' 'test_cmp expect .git/config'
+ test_expect_success 'hierarchical section value' '
+ test_cmp expect .git/config
+ '
cat > expect << EOF
beta.noindent=sillyValue
version.1.2.3eX.alpha=beta
EOF
- test_expect_success 'working --list' \
- 'git config --list > output && cmp output expect'
-
+ test_expect_success 'working --list' '
+ git config --list > output &&
+ test_cmp expect output
+ '
cat > expect << EOF
EOF
nextsection.nonewline wow2 for me
EOF
- test_expect_success '--get-regexp' \
- 'git config --get-regexp in > output && cmp output expect'
+ test_expect_success '--get-regexp' '
+ git config --get-regexp in >output &&
+ test_cmp expect output
+ '
cat > expect << EOF
wow2 for me
variable =
EOF
- test_expect_success 'get variable with no value' \
- 'git config --get novalue.variable ^$'
+ test_expect_success 'get variable with no value' '
+ git config --get novalue.variable ^$
+ '
- test_expect_success 'get variable with empty value' \
- 'git config --get emptyvalue.variable ^$'
+ test_expect_success 'get variable with empty value' '
+ git config --get emptyvalue.variable ^$
+ '
echo novalue.variable > expect
- test_expect_success 'get-regexp variable with no value' \
- 'git config --get-regexp novalue > output &&
- cmp output expect'
+ test_expect_success 'get-regexp variable with no value' '
+ git config --get-regexp novalue > output &&
+ test_cmp expect output
+ '
echo 'novalue.variable true' > expect
- test_expect_success 'get-regexp --bool variable with no value' \
- 'git config --bool --get-regexp novalue > output &&
- cmp output expect'
+ test_expect_success 'get-regexp --bool variable with no value' '
+ git config --bool --get-regexp novalue > output &&
+ test_cmp expect output
+ '
echo 'emptyvalue.variable ' > expect
- test_expect_success 'get-regexp variable with empty value' \
- 'git config --get-regexp emptyvalue > output &&
- cmp output expect'
+ test_expect_success 'get-regexp variable with empty value' '
+ git config --get-regexp emptyvalue > output &&
+ test_cmp expect output
+ '
echo true > expect
- test_expect_success 'get bool variable with no value' \
- 'git config --bool novalue.variable > output &&
- cmp output expect'
+ test_expect_success 'get bool variable with no value' '
+ git config --bool novalue.variable > output &&
+ test_cmp expect output
+ '
echo false > expect
- test_expect_success 'get bool variable with empty value' \
- 'git config --bool emptyvalue.variable > output &&
- cmp output expect'
+ test_expect_success 'get bool variable with empty value' '
+ git config --bool emptyvalue.variable > output &&
+ test_cmp expect output
+ '
test_expect_success 'no arguments, but no crash' '
test_must_fail git config >output 2>&1 &&
test_cmp expect .git/config
'
- test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \
- 'test_must_fail git config --file non-existing-config -l'
+ test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' '
+ test_must_fail git config --file non-existing-config -l
+ '
cat > other-config << EOF
[ein]
test_cmp expect output
'
- test_expect_success 'alternative GIT_CONFIG (--file)' \
- 'git config --file other-config -l > output && cmp output expect'
+ test_expect_success 'alternative GIT_CONFIG (--file)' '
+ git config --file other-config -l > output &&
+ test_cmp expect output
+ '
test_expect_success 'refer config from subdirectory' '
mkdir x &&
weird
EOF
- test_expect_success "rename section" \
- "git config --rename-section branch.eins branch.zwei"
+ test_expect_success 'rename section' '
+ git config --rename-section branch.eins branch.zwei
+ '
cat > expect << EOF
# Hallo
weird
EOF
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+ test_cmp expect .git/config
+ '
- test_expect_success "rename non-existing section" '
+ test_expect_success 'rename non-existing section' '
test_must_fail git config --rename-section \
branch."world domination" branch.drei
'
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+ test_cmp expect .git/config
+ '
- test_expect_success "rename another section" \
- 'git config --rename-section branch."1 234 blabl/a" branch.drei'
+ test_expect_success 'rename another section' '
+ git config --rename-section branch."1 234 blabl/a" branch.drei
+ '
cat > expect << EOF
# Hallo
weird
EOF
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+ test_cmp expect .git/config
+ '
cat >> .git/config << EOF
[branch "vier"] z = 1
EOF
- test_expect_success "rename a section with a var on the same line" \
- 'git config --rename-section branch.vier branch.zwei'
+ test_expect_success 'rename a section with a var on the same line' '
+ git config --rename-section branch.vier branch.zwei
+ '
cat > expect << EOF
# Hallo
z = 1
EOF
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+ test_cmp expect .git/config
+ '
test_expect_success 'renaming empty section name is rejected' '
test_must_fail git config --rename-section branch.zwei ""
[branch "zwei"] a = 1 [branch "vier"]
EOF
- test_expect_success "remove section" "git config --remove-section branch.zwei"
+ test_expect_success 'remove section' '
+ git config --remove-section branch.zwei
+ '
cat > expect << EOF
# Hallo
weird
EOF
- test_expect_success "section was removed properly" \
- "test_cmp expect .git/config"
+ test_expect_success 'section was removed properly' '
+ test_cmp expect .git/config
+ '
cat > expect << EOF
[gitcvs]
EOF
test_expect_success 'section ending' '
-
rm -f .git/config &&
git config gitcvs.enabled true &&
git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
'
test_expect_success numbers '
-
git config kilo.gram 1k &&
git config mega.ton 1m &&
- k=$(git config --int --get kilo.gram) &&
- test z1024 = "z$k" &&
- m=$(git config --int --get mega.ton) &&
- test z1048576 = "z$m"
+ echo 1024 >expect &&
+ echo 1048576 >>expect &&
+ git config --int --get kilo.gram >actual &&
+ git config --int --get mega.ton >>actual &&
+ test_cmp expect actual
'
- cat > expect <<EOF
- fatal: bad config value for 'aninvalid.unit' in .git/config
- EOF
-
test_expect_success 'invalid unit' '
-
git config aninvalid.unit "1auto" &&
- s=$(git config aninvalid.unit) &&
- test "z1auto" = "z$s" &&
- if git config --int --get aninvalid.unit 2>actual
- then
- echo config should have failed
- false
- fi &&
- cmp actual expect
+ echo 1auto >expect &&
+ git config aninvalid.unit >actual &&
+ test_cmp expect actual &&
+ cat > expect <<-\EOF
+ fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
+ EOF
+ test_must_fail git config --int --get aninvalid.unit 2>actual &&
+ test_cmp actual expect
'
cat > expect << EOF
git config --bool --get bool.true$i >>result
git config --bool --get bool.false$i >>result
done &&
- cmp expect result'
+ test_cmp expect result'
test_expect_success 'invalid bool (--get)' '
git config --bool bool.false2 "" &&
git config --bool bool.false3 nO &&
git config --bool bool.false4 FALSE &&
- cmp expect .git/config'
+ test_cmp expect .git/config'
cat > expect <<\EOF
[int]
git config --int int.val1 01 &&
git config --int int.val2 -1 &&
git config --int int.val3 5m &&
- cmp expect .git/config'
+ test_cmp expect .git/config
+ '
- cat >expect <<\EOF
- [bool]
- true1 = true
+ test_expect_success 'get --bool-or-int' '
+ cat >.git/config <<-\EOF &&
+ [bool]
+ true1
true2 = true
- false1 = false
- false2 = false
- [int]
+ false = false
+ [int]
int1 = 0
int2 = 1
int3 = -1
- EOF
-
- test_expect_success 'get --bool-or-int' '
- rm -f .git/config &&
- (
- echo "[bool]"
- echo true1
- echo true2 = true
- echo false = false
- echo "[int]"
- echo int1 = 0
- echo int2 = 1
- echo int3 = -1
- ) >>.git/config &&
- test $(git config --bool-or-int bool.true1) = true &&
- test $(git config --bool-or-int bool.true2) = true &&
- test $(git config --bool-or-int bool.false) = false &&
- test $(git config --bool-or-int int.int1) = 0 &&
- test $(git config --bool-or-int int.int2) = 1 &&
- test $(git config --bool-or-int int.int3) = -1
-
+ EOF
+ cat >expect <<-\EOF &&
+ true
+ true
+ false
+ 0
+ 1
+ -1
+ EOF
+ {
+ git config --bool-or-int bool.true1 &&
+ git config --bool-or-int bool.true2 &&
+ git config --bool-or-int bool.false &&
+ git config --bool-or-int int.int1 &&
+ git config --bool-or-int int.int2 &&
+ git config --bool-or-int int.int3
+ } >actual &&
+ test_cmp expect actual
'
cat >expect <<\EOF
test_cmp expect result
'
+test_expect_success 'get --path barfs on boolean variable' '
+ echo "[path]bool" >.git/config &&
+ test_must_fail git config --get --path path.bool
+'
+
cat > expect << EOF
[quote]
leading = " test"
test_expect_success 'value continued on next line' '
git config --list > result &&
- cmp result expect
+ test_cmp result expect
'
cat > .git/config <<\EOF
test_expect_success 'inner whitespace kept verbatim' '
git config section.val "foo bar" &&
- test "z$(git config section.val)" = "zfoo bar"
+ echo "foo bar" >expect &&
+ git config section.val >actual &&
+ test_cmp expect actual
'
test_expect_success SYMLINKS 'symlinked configuration' '
-
ln -s notyet myconfig &&
GIT_CONFIG=myconfig git config test.frotz nitfol &&
test -h myconfig &&
GIT_CONFIG=myconfig git config test.xyzzy rezrov &&
test -h myconfig &&
test -f notyet &&
- test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol &&
- test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov
-
+ cat >expect <<-\EOF &&
+ nitfol
+ rezrov
+ EOF
+ {
+ GIT_CONFIG=notyet git config test.frotz &&
+ GIT_CONFIG=notyet git config test.xyzzy
+ } >actual &&
+ test_cmp expect actual
'
test_expect_success 'nonexistent configuration' '
git commit -m 'initial commit' &&
git config branch.master.mergeoptions 'echo \"' &&
test_must_fail git merge master
- "
+ "
test_expect_success 'git -c "key=value" support' '
- test "z$(git -c core.name=value config core.name)" = zvalue &&
- test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
- test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
+ cat >expect <<-\EOF &&
+ value
+ value
+ true
+ EOF
+ {
+ git -c core.name=value config core.name &&
+ git -c foo.CamelCase=value config foo.camelcase &&
+ git -c foo.flag config --bool foo.flag
+ } >actual &&
+ test_cmp expect actual &&
test_must_fail git -c name=value config core.name
'