Merge branch 'jn/cherry-pick-strategy-option'
[gitweb.git] / config.c
index 6963fbea43e6420f5f8dafc5b94fb5c27de6ffd2..625e0518767712583f917762634c2fc852c4d2eb 100644 (file)
--- a/config.c
+++ b/config.c
@@ -7,6 +7,8 @@
  */
 #include "cache.h"
 #include "exec_cmd.h"
+#include "strbuf.h"
+#include "quote.h"
 
 #define MAXNAME (256)
 
@@ -18,6 +20,92 @@ static int zlib_compression_seen;
 
 const char *config_exclusive_filename = NULL;
 
+struct config_item
+{
+       struct config_item *next;
+       char *name;
+       char *value;
+};
+static struct config_item *config_parameters;
+static struct config_item **config_parameters_tail = &config_parameters;
+
+static void lowercase(char *p)
+{
+       for (; *p; p++)
+               *p = tolower(*p);
+}
+
+void git_config_push_parameter(const char *text)
+{
+       struct strbuf env = STRBUF_INIT;
+       const char *old = getenv(CONFIG_DATA_ENVIRONMENT);
+       if (old) {
+               strbuf_addstr(&env, old);
+               strbuf_addch(&env, ' ');
+       }
+       sq_quote_buf(&env, text);
+       setenv(CONFIG_DATA_ENVIRONMENT, env.buf, 1);
+       strbuf_release(&env);
+}
+
+int git_config_parse_parameter(const char *text)
+{
+       struct config_item *ct;
+       struct strbuf tmp = STRBUF_INIT;
+       struct strbuf **pair;
+       strbuf_addstr(&tmp, text);
+       pair = strbuf_split(&tmp, '=');
+       if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=')
+               strbuf_setlen(pair[0], pair[0]->len - 1);
+       strbuf_trim(pair[0]);
+       if (!pair[0]->len) {
+               strbuf_list_free(pair);
+               return -1;
+       }
+       ct = xcalloc(1, sizeof(struct config_item));
+       ct->name = strbuf_detach(pair[0], NULL);
+       if (pair[1]) {
+               strbuf_trim(pair[1]);
+               ct->value = strbuf_detach(pair[1], NULL);
+       }
+       strbuf_list_free(pair);
+       lowercase(ct->name);
+       *config_parameters_tail = ct;
+       config_parameters_tail = &ct->next;
+       return 0;
+}
+
+int git_config_parse_environment(void) {
+       const char *env = getenv(CONFIG_DATA_ENVIRONMENT);
+       char *envw;
+       const char **argv = NULL;
+       int nr = 0, alloc = 0;
+       int i;
+
+       if (!env)
+               return 0;
+       /* sq_dequote will write over it */
+       envw = xstrdup(env);
+
+       if (sq_dequote_to_argv(envw, &argv, &nr, &alloc) < 0) {
+               free(envw);
+               return error("bogus format in " CONFIG_DATA_ENVIRONMENT);
+       }
+
+       for (i = 0; i < nr; i++) {
+               if (git_config_parse_parameter(argv[i]) < 0) {
+                       error("bogus config parameter: %s", argv[i]);
+                       free(argv);
+                       free(envw);
+                       return -1;
+               }
+       }
+
+       free(argv);
+       free(envw);
+       return 0;
+}
+
 static int get_next_char(void)
 {
        int c;
@@ -322,17 +410,40 @@ unsigned long git_config_ulong(const char *name, const char *value)
        return ret;
 }
 
-int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
+static int git_config_maybe_bool_text(const char *name, const char *value)
 {
-       *is_bool = 1;
        if (!value)
                return 1;
        if (!*value)
                return 0;
-       if (!strcasecmp(value, "true") || !strcasecmp(value, "yes") || !strcasecmp(value, "on"))
+       if (!strcasecmp(value, "true")
+           || !strcasecmp(value, "yes")
+           || !strcasecmp(value, "on"))
                return 1;
-       if (!strcasecmp(value, "false") || !strcasecmp(value, "no") || !strcasecmp(value, "off"))
+       if (!strcasecmp(value, "false")
+           || !strcasecmp(value, "no")
+           || !strcasecmp(value, "off"))
                return 0;
+       return -1;
+}
+
+int git_config_maybe_bool(const char *name, const char *value)
+{
+       long v = git_config_maybe_bool_text(name, value);
+       if (0 <= v)
+               return v;
+       if (git_parse_long(value, &v))
+               return !!v;
+       return -1;
+}
+
+int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
+{
+       int v = git_config_maybe_bool_text(name, value);
+       if (0 <= v) {
+               *is_bool = 1;
+               return v;
+       }
        *is_bool = 0;
        return git_config_int(name, value);
 }
@@ -388,6 +499,13 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.abbrevguard")) {
+               unique_abbrev_extra_length = git_config_int(var, value);
+               if (unique_abbrev_extra_length < 0)
+                       unique_abbrev_extra_length = 0;
+               return 0;
+       }
+
        if (!strcmp(var, "core.bare")) {
                is_bare_repository_cfg = git_config_bool(var, value);
                return 0;
@@ -461,7 +579,9 @@ static int git_default_core_config(const char *var, const char *value)
 
        if (!strcmp(var, "core.autocrlf")) {
                if (value && !strcasecmp(value, "input")) {
-                       auto_crlf = -1;
+                       if (eol == EOL_CRLF)
+                               return error("core.autocrlf=input conflicts with core.eol=crlf");
+                       auto_crlf = AUTO_CRLF_INPUT;
                        return 0;
                }
                auto_crlf = git_config_bool(var, value);
@@ -477,6 +597,20 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.eol")) {
+               if (value && !strcasecmp(value, "lf"))
+                       eol = EOL_LF;
+               else if (value && !strcasecmp(value, "crlf"))
+                       eol = EOL_CRLF;
+               else if (value && !strcasecmp(value, "native"))
+                       eol = EOL_NATIVE;
+               else
+                       eol = EOL_UNSET;
+               if (eol == EOL_CRLF && auto_crlf == AUTO_CRLF_INPUT)
+                       return error("core.autocrlf=input conflicts with core.eol=crlf");
+               return 0;
+       }
+
        if (!strcmp(var, "core.notesref")) {
                notes_ref_name = xstrdup(value);
                return 0;
@@ -488,6 +622,9 @@ static int git_default_core_config(const char *var, const char *value)
        if (!strcmp(var, "core.editor"))
                return git_config_string(&editor_program, var, value);
 
+       if (!strcmp(var, "core.askpass"))
+               return git_config_string(&askpass_program, var, value);
+
        if (!strcmp(var, "core.excludesfile"))
                return git_config_pathname(&excludes_file, var, value);
 
@@ -683,7 +820,7 @@ const char *git_etc_gitconfig(void)
        return system_wide;
 }
 
-static int git_env_bool(const char *k, int def)
+int git_env_bool(const char *k, int def)
 {
        const char *v = getenv(k);
        return v ? git_config_bool(k, v) : def;
@@ -699,10 +836,25 @@ int git_config_global(void)
        return !git_env_bool("GIT_CONFIG_NOGLOBAL", 0);
 }
 
-int git_config(config_fn_t fn, void *data)
+int git_config_from_parameters(config_fn_t fn, void *data)
+{
+       static int loaded_environment;
+       const struct config_item *ct;
+
+       if (!loaded_environment) {
+               if (git_config_parse_environment() < 0)
+                       return -1;
+               loaded_environment = 1;
+       }
+       for (ct = config_parameters; ct; ct = ct->next)
+               if (fn(ct->name, ct->value, data) < 0)
+                       return -1;
+       return 0;
+}
+
+int git_config_early(config_fn_t fn, void *data, const char *repo_config)
 {
        int ret = 0, found = 0;
-       char *repo_config = NULL;
        const char *home = NULL;
 
        /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
@@ -724,14 +876,27 @@ int git_config(config_fn_t fn, void *data)
                free(user_config);
        }
 
-       repo_config = git_pathdup("config");
-       if (!access(repo_config, R_OK)) {
+       if (repo_config && !access(repo_config, R_OK)) {
                ret += git_config_from_file(fn, repo_config, data);
                found += 1;
        }
-       free(repo_config);
-       if (found == 0)
-               return -1;
+
+       ret += git_config_from_parameters(fn, data);
+       if (config_parameters)
+               found += 1;
+
+       return ret == 0 ? found : ret;
+}
+
+int git_config(config_fn_t fn, void *data)
+{
+       char *repo_config = NULL;
+       int ret;
+
+       repo_config = git_pathdup("config");
+       ret = git_config_early(fn, data, repo_config);
+       if (repo_config)
+               free(repo_config);
        return ret;
 }