From: Junio C Hamano Date: Mon, 26 Mar 2012 19:10:05 +0000 (-0700) Subject: Merge branch 'ms/maint-config-error-at-eol-linecount' into maint X-Git-Tag: v1.7.9.5~3 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/ed6ce4382b5cb34e98ca3db2f19de82a037da322?ds=inline;hp=-c Merge branch 'ms/maint-config-error-at-eol-linecount' into maint * ms/maint-config-error-at-eol-linecount: config: report errors at the EOL with correct line number --- ed6ce4382b5cb34e98ca3db2f19de82a037da322 diff --combined config.c index 40f9c6d103,fc27913c3b..818ba6df00 --- a/config.c +++ b/config.c @@@ -135,8 -135,10 +135,10 @@@ static char *parse_value(void for (;;) { int c = get_next_char(); if (c == '\n') { - if (quote) + if (quote) { + cf->linenr--; return NULL; + } return cf->value.buf; } if (comment) @@@ -226,7 -228,7 +228,7 @@@ static int get_extended_base_var(char * { do { if (c == '\n') - return -1; + goto error_incomplete_line; c = get_next_char(); } while (isspace(c)); @@@ -238,13 -240,13 +240,13 @@@ for (;;) { int c = get_next_char(); if (c == '\n') - return -1; + goto error_incomplete_line; if (c == '"') break; if (c == '\\') { c = get_next_char(); if (c == '\n') - return -1; + goto error_incomplete_line; } name[baselen++] = c; if (baselen > MAXNAME / 2) @@@ -255,6 -257,9 +257,9 @@@ if (get_next_char() != ']') return -1; return baselen; + error_incomplete_line: + cf->linenr--; + return -1; } static int get_base_var(char *name) @@@ -333,7 -338,7 +338,7 @@@ static int git_parse_file(config_fn_t f die("bad config file line %d in %s", cf->linenr, cf->name); } -static int parse_unit_factor(const char *end, unsigned long *val) +static int parse_unit_factor(const char *end, uintmax_t *val) { if (!*end) return 1; @@@ -356,23 -361,11 +361,23 @@@ static int git_parse_long(const char *v { if (value && *value) { char *end; - long val = strtol(value, &end, 0); - unsigned long factor = 1; + intmax_t val; + uintmax_t uval; + uintmax_t factor = 1; + + errno = 0; + val = strtoimax(value, &end, 0); + if (errno == ERANGE) + return 0; if (!parse_unit_factor(end, &factor)) return 0; - *ret = val * factor; + uval = abs(val); + uval *= factor; + if ((uval > maximum_signed_value_of_type(long)) || + (abs(val) > uval)) + return 0; + val *= factor; + *ret = val; return 1; } return 0; @@@ -382,19 -375,9 +387,19 @@@ int git_parse_ulong(const char *value, { if (value && *value) { char *end; - unsigned long val = strtoul(value, &end, 0); + uintmax_t val; + uintmax_t oldval; + + errno = 0; + val = strtoumax(value, &end, 0); + if (errno == ERANGE) + return 0; + oldval = val; if (!parse_unit_factor(end, &val)) return 0; + if ((val > maximum_unsigned_value_of_type(long)) || + (oldval > val)) + return 0; *ret = val; return 1; } @@@ -575,7 -558,7 +580,7 @@@ static int git_default_core_config(cons if (!strcmp(var, "core.packedgitwindowsize")) { int pgsz_x2 = getpagesize() * 2; - packed_git_window_size = git_config_int(var, value); + packed_git_window_size = git_config_ulong(var, value); /* This value must be multiple of (pagesize * 2) */ packed_git_window_size /= pgsz_x2; @@@ -586,17 -569,18 +591,17 @@@ } if (!strcmp(var, "core.bigfilethreshold")) { - long n = git_config_int(var, value); - big_file_threshold = 0 < n ? n : 0; + big_file_threshold = git_config_ulong(var, value); return 0; } if (!strcmp(var, "core.packedgitlimit")) { - packed_git_limit = git_config_int(var, value); + packed_git_limit = git_config_ulong(var, value); return 0; } if (!strcmp(var, "core.deltabasecachelimit")) { - delta_base_cache_limit = git_config_int(var, value); + delta_base_cache_limit = git_config_ulong(var, value); return 0; } @@@ -818,10 -802,6 +823,10 @@@ int git_default_config(const char *var return 0; } + if (!strcmp(var, "pack.packsizelimit")) { + pack_size_limit_cfg = git_config_ulong(var, value); + return 0; + } /* Add other config variables here and to Documentation/config.txt. */ return 0; } @@@ -890,12 -870,12 +895,12 @@@ int git_config_early(config_fn_t fn, vo home = getenv("HOME"); if (home) { - char *user_config = xstrdup(mkpath("%s/.gitconfig", home)); + char buf[PATH_MAX]; + char *user_config = mksnpath(buf, sizeof(buf), "%s/.gitconfig", home); if (!access(user_config, R_OK)) { ret += git_config_from_file(fn, user_config, data); found += 1; } - free(user_config); } if (repo_config && !access(repo_config, R_OK)) { @@@ -1123,12 -1103,6 +1128,12 @@@ contline return offset; } +int git_config_set_in_file(const char *config_filename, + const char *key, const char *value) +{ + return git_config_set_multivar_in_file(config_filename, key, value, NULL, 0); +} + int git_config_set(const char *key, const char *value) { return git_config_set_multivar(key, value, NULL, 0); @@@ -1226,14 -1200,19 +1231,14 @@@ out_free_ret_1 * - the config file is removed and the lock file rename()d to it. * */ -int git_config_set_multivar(const char *key, const char *value, - const char *value_regex, int multi_replace) +int git_config_set_multivar_in_file(const char *config_filename, + const char *key, const char *value, + const char *value_regex, int multi_replace) { int fd = -1, in_fd; int ret; - char *config_filename; struct lock_file *lock = NULL; - if (config_exclusive_filename) - config_filename = xstrdup(config_exclusive_filename); - else - config_filename = git_pathdup("config"); - /* parse-key returns negative; flip the sign to feed exit(3) */ ret = 0 - git_config_parse_key(key, &store.key, &store.baselen); if (ret) @@@ -1410,6 -1389,7 +1415,6 @@@ out_free: if (lock) rollback_lock_file(lock); - free(config_filename); return ret; write_err_out: @@@ -1418,24 -1398,6 +1423,24 @@@ } +int git_config_set_multivar(const char *key, const char *value, + const char *value_regex, int multi_replace) +{ + const char *config_filename; + char *buf = NULL; + int ret; + + if (config_exclusive_filename) + config_filename = config_exclusive_filename; + else + config_filename = buf = git_pathdup("config"); + + ret = git_config_set_multivar_in_file(config_filename, key, value, + value_regex, multi_replace); + free(buf); + return ret; +} + static int section_name_match (const char *buf, const char *name) { int i = 0, j = 0, dot = 0; diff --combined t/t1300-repo-config.sh index 0690e0edf4,23c8711d71..728a965669 --- a/t/t1300-repo-config.sh +++ b/t/t1300-repo-config.sh @@@ -7,28 -7,28 +7,28 @@@ test_description='Test git config in di . ./test-lib.sh -test -f .git/config && rm .git/config - -git config core.penguin "little blue" +test_expect_success 'clear default config' ' + rm -f .git/config +' cat > expect << EOF [core] penguin = little blue EOF - -test_expect_success 'initial' 'cmp .git/config expect' - -git config Core.Movie BadPhysics +test_expect_success 'initial' ' + git config core.penguin "little blue" && + test_cmp expect .git/config +' cat > expect << EOF [core] penguin = little blue Movie = BadPhysics EOF - -test_expect_success 'mixed case' 'cmp .git/config expect' - -git config Cores.WhatEver Second +test_expect_success 'mixed case' ' + git config Core.Movie BadPhysics && + test_cmp expect .git/config +' cat > expect << EOF [core] @@@ -37,10 -37,10 +37,10 @@@ [Cores] WhatEver = Second EOF - -test_expect_success 'similar section' 'cmp .git/config expect' - -git config CORE.UPPERCASE true +test_expect_success 'similar section' ' + git config Cores.WhatEver Second && + test_cmp expect .git/config +' cat > expect << EOF [core] @@@ -50,10 -50,8 +50,10 @@@ [Cores] WhatEver = Second EOF - -test_expect_success 'similar section' 'cmp .git/config expect' +test_expect_success 'uppercase section' ' + git config CORE.UPPERCASE true && + test_cmp expect .git/config +' test_expect_success 'replace with non-match' \ 'git config core.penguin kingpin !blue' @@@ -71,34 -69,7 +71,34 @@@ cat > expect << EO WhatEver = Second EOF -test_expect_success 'non-match result' 'cmp .git/config expect' +test_expect_success 'non-match result' 'test_cmp expect .git/config' + +test_expect_success 'find mixed-case key by canonical name' ' + echo Second >expect && + git config cores.whatever >actual && + test_cmp expect actual +' + +test_expect_success 'find mixed-case key by non-canonical name' ' + echo Second >expect && + git config CoReS.WhAtEvEr >actual && + test_cmp expect actual +' + +test_expect_success 'subsections are not canonicalized by git-config' ' + cat >>.git/config <<-\EOF && + [section.SubSection] + key = one + [section "SubSection"] + key = two + EOF + echo one >expect && + git config section.subsection.key >actual && + test_cmp expect actual && + echo two >expect && + git config section.SubSection.key >actual && + test_cmp expect actual +' cat > .git/config <<\EOF [alpha] @@@ -117,7 -88,7 +117,7 @@@ bar = fo [beta] EOF -test_expect_success 'unset with cont. lines is correct' 'cmp .git/config expect' +test_expect_success 'unset with cont. lines is correct' 'test_cmp expect .git/config' cat > .git/config << EOF [beta] ; silly comment # another comment @@@ -145,7 -116,7 +145,7 @@@ noIndent= sillyValue ; 'nother silly co [nextSection] noNewline = ouch EOF -test_expect_success 'multiple unset is correct' 'cmp .git/config expect' +test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config' cp .git/config2 .git/config @@@ -169,7 -140,9 +169,7 @@@ noIndent= sillyValue ; 'nother silly co [nextSection] noNewline = ouch EOF -test_expect_success 'all replaced' 'cmp .git/config expect' - -git config beta.haha alpha +test_expect_success 'all replaced' 'test_cmp expect .git/config' cat > expect << EOF [beta] ; silly comment # another comment @@@ -180,10 -153,10 +180,10 @@@ noIndent= sillyValue ; 'nother silly co haha = alpha [nextSection] noNewline = ouch EOF - -test_expect_success 'really mean test' 'cmp .git/config expect' - -git config nextsection.nonewline wow +test_expect_success 'really mean test' ' + git config beta.haha alpha && + test_cmp expect .git/config +' cat > expect << EOF [beta] ; silly comment # another comment @@@ -195,12 -168,11 +195,12 @@@ noIndent= sillyValue ; 'nother silly co [nextSection] nonewline = wow EOF - -test_expect_success 'really really mean test' 'cmp .git/config expect' +test_expect_success 'really really mean test' ' + git config nextsection.nonewline wow && + test_cmp expect .git/config +' test_expect_success 'get value' 'test alpha = $(git config beta.haha)' -git config --unset beta.haha cat > expect << EOF [beta] ; silly comment # another comment @@@ -211,10 -183,10 +211,10 @@@ noIndent= sillyValue ; 'nother silly co [nextSection] nonewline = wow EOF - -test_expect_success 'unset' 'cmp .git/config expect' - -git config nextsection.NoNewLine "wow2 for me" "for me$" +test_expect_success 'unset' ' + git config --unset beta.haha && + test_cmp expect .git/config +' cat > expect << EOF [beta] ; silly comment # another comment @@@ -226,10 -198,8 +226,10 @@@ noIndent= sillyValue ; 'nother silly co nonewline = wow NoNewLine = wow2 for me EOF - -test_expect_success 'multivar' 'cmp .git/config expect' +test_expect_success 'multivar' ' + git config nextsection.NoNewLine "wow2 for me" "for me$" && + test_cmp expect .git/config +' test_expect_success 'non-match' \ 'git config --get nextsection.nonewline !for' @@@ -244,6 -214,8 +244,6 @@@ test_expect_success 'ambiguous get' test_expect_success 'get multivar' \ 'git config --get-all nextsection.nonewline' -git config nextsection.nonewline "wow3" "wow$" - cat > expect << EOF [beta] ; silly comment # another comment noIndent= sillyValue ; 'nother silly comment @@@ -254,10 -226,8 +254,10 @@@ nonewline = wow3 NoNewLine = wow2 for me EOF - -test_expect_success 'multivar replace' 'cmp .git/config expect' +test_expect_success 'multivar replace' ' + git config nextsection.nonewline "wow3" "wow$" && + test_cmp expect .git/config +' test_expect_success 'ambiguous value' ' test_must_fail git config nextsection.nonewline @@@ -271,6 -241,8 +271,6 @@@ test_expect_success 'invalid unset' test_must_fail git config --unset somesection.nonewline ' -git config --unset nextsection.nonewline "wow3$" - cat > expect << EOF [beta] ; silly comment # another comment noIndent= sillyValue ; 'nother silly comment @@@ -281,10 -253,7 +281,10 @@@ NoNewLine = wow2 for me EOF -test_expect_success 'multivar unset' 'cmp .git/config expect' +test_expect_success 'multivar unset' ' + git config --unset nextsection.nonewline "wow3$" && + test_cmp expect .git/config +' test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla' @@@ -307,7 -276,7 +307,7 @@@ noIndent= sillyValue ; 'nother silly co Alpha = beta EOF -test_expect_success 'hierarchical section value' 'cmp .git/config expect' +test_expect_success 'hierarchical section value' 'test_cmp expect .git/config' cat > expect << EOF beta.noindent=sillyValue @@@ -335,16 -304,15 +335,16 @@@ EO test_expect_success '--get-regexp' \ 'git config --get-regexp in > output && cmp output expect' -git config --add nextsection.nonewline "wow4 for you" - cat > expect << EOF wow2 for me wow4 for you EOF -test_expect_success '--add' \ - 'git config --get-all nextsection.nonewline > output && cmp output expect' +test_expect_success '--add' ' + git config --add nextsection.nonewline "wow4 for you" && + git config --get-all nextsection.nonewline > output && + test_cmp expect output +' cat > .git/config << EOF [novalue] @@@ -399,6 -367,8 +399,6 @@@ cat > .git/config << EO c = d EOF -git config a.x y - cat > expect << EOF [a.b] c = d @@@ -406,10 -376,10 +406,10 @@@ x = y EOF -test_expect_success 'new section is partial match of another' 'cmp .git/config expect' - -git config b.x y -git config a.b c +test_expect_success 'new section is partial match of another' ' + git config a.x y && + test_cmp expect .git/config +' cat > expect << EOF [a.b] @@@ -421,11 -391,7 +421,11 @@@ x = y EOF -test_expect_success 'new variable inserts into proper section' 'cmp .git/config expect' +test_expect_success 'new variable inserts into proper section' ' + git config b.x y && + git config a.b c && + 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' @@@ -439,10 -405,9 +439,10 @@@ cat > expect << EO ein.bahn=strasse EOF -GIT_CONFIG=other-config git config -l > output - -test_expect_success 'alternative GIT_CONFIG' 'cmp output expect' +test_expect_success 'alternative GIT_CONFIG' ' + GIT_CONFIG=other-config git config -l >output && + test_cmp expect output +' test_expect_success 'alternative GIT_CONFIG (--file)' \ 'git config --file other-config -l > output && cmp output expect' @@@ -458,6 -423,8 +458,6 @@@ test_expect_success 'refer config from ' -GIT_CONFIG=other-config git config anwohner.park ausweis - cat > expect << EOF [ein] bahn = strasse @@@ -465,10 -432,7 +465,10 @@@ park = ausweis EOF -test_expect_success '--set in alternative GIT_CONFIG' 'cmp other-config expect' +test_expect_success '--set in alternative GIT_CONFIG' ' + GIT_CONFIG=other-config git config anwohner.park ausweis && + test_cmp expect other-config +' cat > .git/config << EOF # Hallo @@@ -558,6 -522,8 +558,6 @@@ EO test_expect_success "section was removed properly" \ "test_cmp expect .git/config" -rm .git/config - cat > expect << EOF [gitcvs] enabled = true @@@ -568,11 -534,10 +568,11 @@@ EO test_expect_success 'section ending' ' + rm -f .git/config && git config gitcvs.enabled true && git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite && git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite && - cmp .git/config expect + test_cmp expect .git/config ' @@@ -641,6 -606,8 +641,6 @@@ test_expect_success 'invalid bool (set) test_must_fail git config --bool bool.nobool foobar' -rm .git/config - cat > expect <<\EOF [bool] true1 = true @@@ -655,7 -622,6 +655,7 @@@ EO test_expect_success 'set --bool' ' + rm -f .git/config && git config --bool bool.true1 01 && git config --bool bool.true2 -1 && git config --bool bool.true3 YeS && @@@ -666,6 -632,8 +666,6 @@@ git config --bool bool.false4 FALSE && cmp expect .git/config' -rm .git/config - cat > expect <<\EOF [int] val1 = 1 @@@ -675,12 -643,13 +675,12 @@@ EO test_expect_success 'set --int' ' + rm -f .git/config && git config --int int.val1 01 && git config --int int.val2 -1 && git config --int int.val3 5m && cmp expect .git/config' -rm .git/config - cat >expect <<\EOF [bool] true1 = true @@@ -694,7 -663,6 +694,7 @@@ EOF test_expect_success 'get --bool-or-int' ' + rm -f .git/config && ( echo "[bool]" echo true1 @@@ -714,6 -682,7 +714,6 @@@ ' -rm .git/config cat >expect <<\EOF [bool] true1 = true @@@ -727,7 -696,6 +727,7 @@@ EOF test_expect_success 'set --bool-or-int' ' + rm -f .git/config && git config --bool-or-int bool.true1 true && git config --bool-or-int bool.false1 false && git config --bool-or-int bool.true2 yes && @@@ -738,6 -706,8 +738,6 @@@ test_cmp expect .git/config ' -rm .git/config - cat >expect <<\EOF [path] home = ~/ @@@ -746,7 -716,6 +746,7 @@@ EOF test_expect_success NOT_MINGW 'set --path' ' + rm -f .git/config && git config --path path.home "~/" && git config --path path.normal "/dev/null" && git config --path path.trailingtilde "foo~" && @@@ -787,6 -756,13 +787,6 @@@ test_expect_success NOT_MINGW 'get --pa test_cmp expect result ' -rm .git/config - -git config quote.leading " test" -git config quote.ending "test " -git config quote.semicolon "test;test" -git config quote.hash "test#test" - cat > expect << EOF [quote] leading = " test" @@@ -794,14 -770,8 +794,14 @@@ semicolon = "test;test" hash = "test#test" EOF - -test_expect_success 'quoting' 'cmp .git/config expect' +test_expect_success 'quoting' ' + rm -f .git/config && + git config quote.leading " test" && + git config quote.ending "test " && + git config quote.semicolon "test;test" && + git config quote.hash "test#test" && + test_cmp expect .git/config +' test_expect_success 'key with newline' ' test_must_fail git config "key.with @@@ -826,10 -796,9 +826,10 @@@ section.noncont=not continue section.quotecont=cont;inued EOF -git config --list > result - -test_expect_success 'value continued on next line' 'cmp result expect' +test_expect_success 'value continued on next line' ' + git config --list > result && + cmp result expect +' cat > .git/config <<\EOF [section "sub=section"] @@@ -850,17 -819,16 +850,17 @@@ barQsection.sub=section.val Qsection.sub=section.val4 Qsection.sub=section.val5Q EOF +test_expect_success '--null --list' ' + git config --null --list | nul_to_q >result && + echo >>result && + test_cmp expect result +' -git config --null --list | perl -pe 'y/\000/Q/' > result -echo >>result - -test_expect_success '--null --list' 'cmp result expect' - -git config --null --get-regexp 'val[0-9]' | perl -pe 'y/\000/Q/' > result -echo >>result - -test_expect_success '--null --get-regexp' 'cmp result expect' +test_expect_success '--null --get-regexp' ' + git config --null --get-regexp "val[0-9]" | nul_to_q >result && + echo >>result && + test_cmp expect result +' test_expect_success 'inner whitespace kept verbatim' ' git config section.val "foo bar" && @@@ -960,4 -928,35 +960,35 @@@ test_expect_success 'git -c complains a test_must_fail git -c "" rev-parse ' + # malformed configuration files + test_expect_success 'barf on syntax error' ' + cat >.git/config <<-\EOF && + # broken section line + [section] + key garbage + EOF + test_must_fail git config --get section.key >actual 2>error && + grep " line 3 " error + ' + + test_expect_success 'barf on incomplete section header' ' + cat >.git/config <<-\EOF && + # broken section line + [section + key = value + EOF + test_must_fail git config --get section.key >actual 2>error && + grep " line 2 " error + ' + + test_expect_success 'barf on incomplete string' ' + cat >.git/config <<-\EOF && + # broken section line + [section] + key = "value string + EOF + test_must_fail git config --get section.key >actual 2>error && + grep " line 3 " error + ' + test_done