Code

builtin-fetch.c (store_updated_refs): Honor update_local_ref() return value
[git.git] / config.c
index 062449459e1a4cfc2a605c065ed281669e0e7452..c2f2bbb000cd003002c1bd346e6be6c9d3ef5c2d 100644 (file)
--- a/config.c
+++ b/config.c
@@ -111,7 +111,7 @@ static inline int iskeychar(int c)
        return isalnum(c) || c == '-';
 }
 
-static int get_value(config_fn_t fn, char *name, unsigned int len)
+static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
 {
        int c;
        char *value;
@@ -139,7 +139,7 @@ static int get_value(config_fn_t fn, char *name, unsigned int len)
                if (!value)
                        return -1;
        }
-       return fn(name, value);
+       return fn(name, value, data);
 }
 
 static int get_extended_base_var(char *name, int baselen, int c)
@@ -197,7 +197,7 @@ static int get_base_var(char *name)
        }
 }
 
-static int git_parse_file(config_fn_t fn)
+static int git_parse_file(config_fn_t fn, void *data)
 {
        int comment = 0;
        int baselen = 0;
@@ -228,7 +228,7 @@ static int git_parse_file(config_fn_t fn)
                if (!isalpha(c))
                        break;
                var[baselen] = tolower(c);
-               if (get_value(fn, var, baselen+1) < 0)
+               if (get_value(fn, data, var, baselen+1) < 0)
                        break;
        }
        die("bad config file line %d in %s", config_linenr, config_file_name);
@@ -303,8 +303,9 @@ unsigned long git_config_ulong(const char *name, const char *value)
        return ret;
 }
 
-int git_config_bool(const char *name, const char *value)
+int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
 {
+       *is_bool = 1;
        if (!value)
                return 1;
        if (!*value)
@@ -313,7 +314,14 @@ int git_config_bool(const char *name, const char *value)
                return 1;
        if (!strcasecmp(value, "false") || !strcasecmp(value, "no"))
                return 0;
-       return git_config_int(name, value) != 0;
+       *is_bool = 0;
+       return git_config_int(name, value);
+}
+
+int git_config_bool(const char *name, const char *value)
+{
+       int discard;
+       return !!git_config_bool_or_int(name, value, &discard);
 }
 
 int git_config_string(const char **dest, const char *var, const char *value)
@@ -324,7 +332,7 @@ int git_config_string(const char **dest, const char *var, const char *value)
        return 0;
 }
 
-int git_default_config(const char *var, const char *value)
+int git_default_config(const char *var, const char *value, void *dummy)
 {
        /* This needs a better name */
        if (!strcmp(var, "core.filemode")) {
@@ -342,6 +350,11 @@ int git_default_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.ignorecase")) {
+               ignore_case = git_config_bool(var, value);
+               return 0;
+       }
+
        if (!strcmp(var, "core.bare")) {
                is_bare_repository_cfg = git_config_bool(var, value);
                return 0;
@@ -435,6 +448,8 @@ int git_default_config(const char *var, const char *value)
                if (!value)
                        return config_error_nonbool(var);
                strlcpy(git_default_name, value, sizeof(git_default_name));
+               if (git_default_email[0])
+                       user_ident_explicitly_given = 1;
                return 0;
        }
 
@@ -442,6 +457,8 @@ int git_default_config(const char *var, const char *value)
                if (!value)
                        return config_error_nonbool(var);
                strlcpy(git_default_email, value, sizeof(git_default_email));
+               if (git_default_name[0])
+                       user_ident_explicitly_given = 1;
                return 0;
        }
 
@@ -479,12 +496,27 @@ int git_default_config(const char *var, const char *value)
                git_branch_track = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "branch.autosetuprebase")) {
+               if (!value)
+                       return config_error_nonbool(var);
+               else if (!strcmp(value, "never"))
+                       autorebase = AUTOREBASE_NEVER;
+               else if (!strcmp(value, "local"))
+                       autorebase = AUTOREBASE_LOCAL;
+               else if (!strcmp(value, "remote"))
+                       autorebase = AUTOREBASE_REMOTE;
+               else if (!strcmp(value, "always"))
+                       autorebase = AUTOREBASE_ALWAYS;
+               else
+                       return error("Malformed value for %s", var);
+               return 0;
+       }
 
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
 
-int git_config_from_file(config_fn_t fn, const char *filename)
+int git_config_from_file(config_fn_t fn, const char *filename, void *data)
 {
        int ret;
        FILE *f = fopen(filename, "r");
@@ -495,7 +527,7 @@ int git_config_from_file(config_fn_t fn, const char *filename)
                config_file_name = filename;
                config_linenr = 1;
                config_file_eof = 0;
-               ret = git_parse_file(fn);
+               ret = git_parse_file(fn, data);
                fclose(f);
                config_file_name = NULL;
        }
@@ -533,7 +565,7 @@ int git_config_global(void)
        return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
 }
 
-int git_config(config_fn_t fn)
+int git_config(config_fn_t fn, void *data)
 {
        int ret = 0;
        char *repo_config = NULL;
@@ -546,7 +578,8 @@ int git_config(config_fn_t fn)
        filename = getenv(CONFIG_ENVIRONMENT);
        if (!filename) {
                if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
-                       ret += git_config_from_file(fn, git_etc_gitconfig());
+                       ret += git_config_from_file(fn, git_etc_gitconfig(),
+                               data);
                home = getenv("HOME");
                filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
                if (!filename)
@@ -556,11 +589,11 @@ int git_config(config_fn_t fn)
        if (git_config_global() && home) {
                char *user_config = xstrdup(mkpath("%s/.gitconfig", home));
                if (!access(user_config, R_OK))
-                       ret = git_config_from_file(fn, user_config);
+                       ret = git_config_from_file(fn, user_config, data);
                free(user_config);
        }
 
-       ret += git_config_from_file(fn, filename);
+       ret += git_config_from_file(fn, filename, data);
        free(repo_config);
        return ret;
 }
@@ -590,7 +623,7 @@ static int matches(const char* key, const char* value)
                  !regexec(store.value_regex, value, 0, NULL, 0)));
 }
 
-static int store_aux(const char* key, const char* value)
+static int store_aux(const char* key, const char* value, void *cb)
 {
        const char *ep;
        size_t section_len;
@@ -599,11 +632,9 @@ static int store_aux(const char* key, const char* value)
        case KEY_SEEN:
                if (matches(key, value)) {
                        if (store.seen == 1 && store.multi_replace == 0) {
-                               fprintf(stderr,
-                                       "Warning: %s has multiple values\n",
-                                       key);
+                               warning("%s has multiple values", key);
                        } else if (store.seen >= MAX_MATCHES) {
-                               fprintf(stderr, "Too many matches\n");
+                               error("too many matches for %s", key);
                                return 1;
                        }
 
@@ -653,9 +684,9 @@ static int store_aux(const char* key, const char* value)
        return 0;
 }
 
-static int write_error(void)
+static int write_error(const char *filename)
 {
-       fprintf(stderr, "Failed to write new configuration file\n");
+       error("failed to write new configuration file %s", filename);
 
        /* Same error code as "failed to rename". */
        return 4;
@@ -672,7 +703,7 @@ static int store_write_section(int fd, const char* key)
        if (dot) {
                strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
                for (i = dot - key + 1; i < store.baselen; i++) {
-                       if (key[i] == '"')
+                       if (key[i] == '"' || key[i] == '\\')
                                strbuf_addch(&sb, '\\');
                        strbuf_addch(&sb, key[i]);
                }
@@ -814,7 +845,7 @@ int git_config_set_multivar(const char* key, const char* value,
         */
 
        if (last_dot == NULL) {
-               fprintf(stderr, "key does not contain a section: %s\n", key);
+               error("key does not contain a section: %s", key);
                ret = 2;
                goto out_free;
        }
@@ -834,14 +865,14 @@ int git_config_set_multivar(const char* key, const char* value,
                /* Leave the extended basename untouched.. */
                if (!dot || i > store.baselen) {
                        if (!iskeychar(c) || (i == store.baselen+1 && !isalpha(c))) {
-                               fprintf(stderr, "invalid key: %s\n", key);
+                               error("invalid key: %s", key);
                                free(store.key);
                                ret = 1;
                                goto out_free;
                        }
                        c = tolower(c);
                } else if (c == '\n') {
-                       fprintf(stderr, "invalid key (newline): %s\n", key);
+                       error("invalid key (newline): %s", key);
                        free(store.key);
                        ret = 1;
                        goto out_free;
@@ -857,7 +888,7 @@ int git_config_set_multivar(const char* key, const char* value,
        lock = xcalloc(sizeof(struct lock_file), 1);
        fd = hold_lock_file_for_update(lock, config_filename, 0);
        if (fd < 0) {
-               fprintf(stderr, "could not lock config file\n");
+               error("could not lock config file %s", config_filename);
                free(store.key);
                ret = -1;
                goto out_free;
@@ -904,8 +935,7 @@ int git_config_set_multivar(const char* key, const char* value,
                        store.value_regex = (regex_t*)xmalloc(sizeof(regex_t));
                        if (regcomp(store.value_regex, value_regex,
                                        REG_EXTENDED)) {
-                               fprintf(stderr, "Invalid pattern: %s\n",
-                                       value_regex);
+                               error("invalid pattern: %s", value_regex);
                                free(store.value_regex);
                                ret = 6;
                                goto out_free;
@@ -922,8 +952,8 @@ int git_config_set_multivar(const char* key, const char* value,
                 * As a side effect, we make sure to transform only a valid
                 * existing config file.
                 */
-               if (git_config_from_file(store_aux, config_filename)) {
-                       fprintf(stderr, "invalid config file\n");
+               if (git_config_from_file(store_aux, config_filename, NULL)) {
+                       error("invalid config file %s", config_filename);
                        free(store.key);
                        if (store.value_regex != NULL) {
                                regfree(store.value_regex);
@@ -1002,7 +1032,7 @@ int git_config_set_multivar(const char* key, const char* value,
        }
 
        if (commit_lock_file(lock) < 0) {
-               fprintf(stderr, "Cannot commit config file!\n");
+               error("could not commit config file %s", config_filename);
                ret = 4;
                goto out_free;
        }
@@ -1023,7 +1053,7 @@ out_free:
        return ret;
 
 write_err_out:
-       ret = write_error();
+       ret = write_error(lock->filename);
        goto out_free;
 
 }
@@ -1073,7 +1103,7 @@ int git_config_rename_section(const char *old_name, const char *new_name)
        config_filename = xstrdup(config_filename);
        out_fd = hold_lock_file_for_update(lock, config_filename, 0);
        if (out_fd < 0) {
-               ret = error("Could not lock config file!");
+               ret = error("could not lock config file %s", config_filename);
                goto out;
        }
 
@@ -1097,7 +1127,7 @@ int git_config_rename_section(const char *old_name, const char *new_name)
                                }
                                store.baselen = strlen(new_name);
                                if (!store_write_section(out_fd, new_name)) {
-                                       ret = write_error();
+                                       ret = write_error(lock->filename);
                                        goto out;
                                }
                                continue;
@@ -1108,14 +1138,14 @@ int git_config_rename_section(const char *old_name, const char *new_name)
                        continue;
                length = strlen(buf);
                if (write_in_full(out_fd, buf, length) != length) {
-                       ret = write_error();
+                       ret = write_error(lock->filename);
                        goto out;
                }
        }
        fclose(config_file);
  unlock_and_out:
        if (commit_lock_file(lock) < 0)
-                       ret = error("Cannot commit config file!");
+               ret = error("could not commit config file %s", config_filename);
  out:
        free(config_filename);
        return ret;