Code

Merge branch 'ms/maint-config-error-at-eol-linecount' into maint
authorJunio C Hamano <gitster@pobox.com>
Mon, 26 Mar 2012 19:10:05 +0000 (12:10 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 26 Mar 2012 19:10:05 +0000 (12:10 -0700)
* ms/maint-config-error-at-eol-linecount:
  config: report errors at the EOL with correct line number

1  2 
config.c
t/t1300-repo-config.sh

diff --combined config.c
index 40f9c6d10317ed47f7786e5c328df3ab6f167e7c,fc27913c3bb3646a6fd6592356be6a979e9cc7d2..818ba6df00e342f55fb7151b05299848240e61bd
+++ 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));
  
        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)
        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;
        }
  
        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)
  out_free:
        if (lock)
                rollback_lock_file(lock);
 -      free(config_filename);
        return ret;
  
  write_err_out:
  
  }
  
 +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 0690e0edf4e758200d4febb1c7837b5c7059add6,23c8711d714eefa34f2bfc14b92818953aeafa49..728a965669e7a69014b950b8abbc672702caca27
@@@ -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]
  [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]
  [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
        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
        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
        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]
        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
        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 &&
        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
  EOF
  
  test_expect_success 'get --bool-or-int' '
 +      rm -f .git/config &&
        (
                echo "[bool]"
                echo true1
  
  '
  
 -rm .git/config
  cat >expect <<\EOF
  [bool]
        true1 = true
  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 &&
        test_cmp expect .git/config
  '
  
 -rm .git/config
 -
  cat >expect <<\EOF
  [path]
        home = ~/
  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"
        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