Code

Fix off-by-one in read_tree_recursive
[git.git] / config.c
index b2d5b4e4e35b467147ddb9374ef13d0523b4b58d..7a83c76f4b0480416b01213c0aca30b1e92556d2 100644 (file)
--- a/config.c
+++ b/config.c
@@ -16,6 +16,8 @@ static int config_linenr;
 static int config_file_eof;
 static int zlib_compression_seen;
 
+const char *config_exclusive_filename = NULL;
+
 static int get_next_char(void)
 {
        int c;
@@ -49,7 +51,7 @@ static char *parse_value(void)
 
        for (;;) {
                int c = get_next_char();
-               if (len >= sizeof(value))
+               if (len >= sizeof(value) - 1)
                        return NULL;
                if (c == '\n') {
                        if (quote)
@@ -203,8 +205,27 @@ static int git_parse_file(config_fn_t fn, void *data)
        int baselen = 0;
        static char var[MAXNAME];
 
+       /* U+FEFF Byte Order Mark in UTF8 */
+       static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
+       const unsigned char *bomptr = utf8_bom;
+
        for (;;) {
                int c = get_next_char();
+               if (bomptr && *bomptr) {
+                       /* We are at the file beginning; skip UTF8-encoded BOM
+                        * if present. Sane editors won't put this in on their
+                        * own, but e.g. Windows Notepad will do it happily. */
+                       if ((unsigned char) c == *bomptr) {
+                               bomptr++;
+                               continue;
+                       } else {
+                               /* Do not tolerate partial BOM. */
+                               if (bomptr != utf8_bom)
+                                       break;
+                               /* No BOM at file beginning. Cool. */
+                               bomptr = NULL;
+                       }
+               }
                if (c == '\n') {
                        if (config_file_eof)
                                return 0;
@@ -253,7 +274,7 @@ static int parse_unit_factor(const char *end, unsigned long *val)
        return 0;
 }
 
-int git_parse_long(const char *value, long *ret)
+static int git_parse_long(const char *value, long *ret)
 {
        if (value && *value) {
                char *end;
@@ -289,7 +310,7 @@ static void die_bad_config(const char *name)
 
 int git_config_int(const char *name, const char *value)
 {
-       long ret;
+       long ret = 0;
        if (!git_parse_long(value, &ret))
                die_bad_config(name);
        return ret;
@@ -339,6 +360,10 @@ static int git_default_core_config(const char *var, const char *value)
                trust_executable_bit = git_config_bool(var, value);
                return 0;
        }
+       if (!strcmp(var, "core.trustctime")) {
+               trust_ctime = git_config_bool(var, value);
+               return 0;
+       }
 
        if (!strcmp(var, "core.quotepath")) {
                quote_path_fully = git_config_bool(var, value);
@@ -465,6 +490,11 @@ static int git_default_core_config(const char *var, const char *value)
                return 0;
        }
 
+       if (!strcmp(var, "core.preloadindex")) {
+               core_preload_index = git_config_bool(var, value);
+               return 0;
+       }
+
        /* Add other config variables here and to Documentation/config.txt. */
        return 0;
 }
@@ -535,6 +565,15 @@ static int git_default_branch_config(const char *var, const char *value)
        return 0;
 }
 
+static int git_default_mailmap_config(const char *var, const char *value)
+{
+       if (!strcmp(var, "mailmap.file"))
+               return git_config_string(&git_mailmap_file, var, value);
+
+       /* Add other config variables here and to Documentation/config.txt. */
+       return 0;
+}
+
 int git_default_config(const char *var, const char *value, void *dummy)
 {
        if (!prefixcmp(var, "core."))
@@ -549,6 +588,9 @@ int git_default_config(const char *var, const char *value, void *dummy)
        if (!prefixcmp(var, "branch."))
                return git_default_branch_config(var, value);
 
+       if (!prefixcmp(var, "mailmap."))
+               return git_default_mailmap_config(var, value);
+
        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
                pager_use_color = git_config_bool(var,value);
                return 0;
@@ -579,19 +621,12 @@ int git_config_from_file(config_fn_t fn, const char *filename, void *data)
 const char *git_etc_gitconfig(void)
 {
        static const char *system_wide;
-       if (!system_wide) {
-               system_wide = ETC_GITCONFIG;
-               if (!is_absolute_path(system_wide)) {
-                       /* interpret path relative to exec-dir */
-                       struct strbuf d = STRBUF_INIT;
-                       strbuf_addf(&d, "%s/%s", git_exec_path(), system_wide);
-                       system_wide = strbuf_detach(&d, NULL);
-               }
-       }
+       if (!system_wide)
+               system_wide = system_path(ETC_GITCONFIG);
        return system_wide;
 }
 
-int git_env_bool(const char *k, int def)
+static int git_env_bool(const char *k, int def)
 {
        const char *v = getenv(k);
        return v ? git_config_bool(k, v) : def;
@@ -611,31 +646,25 @@ int git_config(config_fn_t fn, void *data)
 {
        int ret = 0;
        char *repo_config = NULL;
-       const char *home = NULL, *filename;
-
-       /* $GIT_CONFIG makes git read _only_ the given config file,
-        * $GIT_CONFIG_LOCAL will make it process it in addition to the
-        * global config file, the same way it would the per-repository
-        * config file otherwise. */
-       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(),
-                               data);
-               home = getenv("HOME");
-               filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
-               if (!filename)
-                       filename = repo_config = xstrdup(git_path("config"));
-       }
+       const char *home = NULL;
+
+       /* Setting $GIT_CONFIG makes git read _only_ the given config file. */
+       if (config_exclusive_filename)
+               return git_config_from_file(fn, config_exclusive_filename, data);
+       if (git_config_system() && !access(git_etc_gitconfig(), R_OK))
+               ret += git_config_from_file(fn, git_etc_gitconfig(),
+                                           data);
 
+       home = getenv("HOME");
        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, data);
+                       ret += git_config_from_file(fn, user_config, data);
                free(user_config);
        }
 
-       ret += git_config_from_file(fn, filename, data);
+       repo_config = git_pathdup("config");
+       ret += git_config_from_file(fn, repo_config, data);
        free(repo_config);
        return ret;
 }
@@ -738,9 +767,8 @@ static int store_write_section(int fd, const char* key)
 {
        const char *dot;
        int i, success;
-       struct strbuf sb;
+       struct strbuf sb = STRBUF_INIT;
 
-       strbuf_init(&sb, 0);
        dot = memchr(key, '.', store.baselen);
        if (dot) {
                strbuf_addf(&sb, "[%.*s \"", (int)(dot - key), key);
@@ -765,7 +793,7 @@ static int store_write_pair(int fd, const char* key, const char* value)
        int i, success;
        int length = strlen(key + store.baselen + 1);
        const char *quote = "";
-       struct strbuf sb;
+       struct strbuf sb = STRBUF_INIT;
 
        /*
         * Check to see if the value needs to be surrounded with a dq pair.
@@ -782,7 +810,6 @@ static int store_write_pair(int fd, const char* key, const char* value)
        if (i && value[i - 1] == ' ')
                quote = "\"";
 
-       strbuf_init(&sb, 0);
        strbuf_addf(&sb, "\t%.*s = %s",
                    length, key + store.baselen + 1, quote);
 
@@ -873,13 +900,10 @@ int git_config_set_multivar(const char* key, const char* value,
        struct lock_file *lock = NULL;
        const char* last_dot = strrchr(key, '.');
 
-       config_filename = getenv(CONFIG_ENVIRONMENT);
-       if (!config_filename) {
-               config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
-               if (!config_filename)
-                       config_filename  = git_path("config");
-       }
-       config_filename = xstrdup(config_filename);
+       if (config_exclusive_filename)
+               config_filename = xstrdup(config_exclusive_filename);
+       else
+               config_filename = git_pathdup("config");
 
        /*
         * Since "key" actually contains the section name and the real
@@ -1136,13 +1160,10 @@ int git_config_rename_section(const char *old_name, const char *new_name)
        int out_fd;
        char buf[1024];
 
-       config_filename = getenv(CONFIG_ENVIRONMENT);
-       if (!config_filename) {
-               config_filename = getenv(CONFIG_LOCAL_ENVIRONMENT);
-               if (!config_filename)
-                       config_filename  = git_path("config");
-       }
-       config_filename = xstrdup(config_filename);
+       if (config_exclusive_filename)
+               config_filename = xstrdup(config_exclusive_filename);
+       else
+               config_filename = git_pathdup("config");
        out_fd = hold_lock_file_for_update(lock, config_filename, 0);
        if (out_fd < 0) {
                ret = error("could not lock config file %s", config_filename);