diff options
Diffstat (limited to 'config.c')
-rw-r--r-- | config.c | 161 |
1 files changed, 95 insertions, 66 deletions
@@ -21,6 +21,7 @@ struct config_source { } buf; } u; const char *name; + const char *path; int die_on_error; int linenr; int eof; @@ -84,8 +85,12 @@ static int handle_path_include(const char *path, struct config_include_data *inc { int ret = 0; struct strbuf buf = STRBUF_INIT; - char *expanded = expand_user_path(path); + char *expanded; + if (!path) + return config_error_nonbool("include.path"); + + expanded = expand_user_path(path); if (!expanded) return error("Could not expand include path '%s'", path); path = expanded; @@ -97,12 +102,12 @@ static int handle_path_include(const char *path, struct config_include_data *inc if (!is_absolute_path(path)) { char *slash; - if (!cf || !cf->name) + if (!cf || !cf->path) return error("relative config includes must come from files"); - slash = find_last_dir_sep(cf->name); + slash = find_last_dir_sep(cf->path); if (slash) - strbuf_add(&buf, cf->name, slash - cf->name + 1); + strbuf_add(&buf, cf->path, slash - cf->path + 1); strbuf_addstr(&buf, path); path = buf.buf; } @@ -133,8 +138,7 @@ int git_config_include(const char *var, const char *value, void *data) if (ret < 0) return ret; - type = skip_prefix(var, "include."); - if (!type) + if (!skip_prefix(var, "include.", &type)) return ret; if (!strcmp(type, "path")) @@ -142,12 +146,6 @@ int git_config_include(const char *var, const char *value, void *data) return ret; } -static void lowercase(char *p) -{ - for (; *p; p++) - *p = tolower(*p); -} - void git_config_push_parameter(const char *text) { struct strbuf env = STRBUF_INIT; @@ -175,7 +173,7 @@ int git_config_parse_parameter(const char *text, strbuf_list_free(pair); return error("bogus config parameter: %s", text); } - lowercase(pair[0]->buf); + strbuf_tolower(pair[0]); if (fn(pair[0]->buf, pair[1] ? pair[1]->buf : NULL, data) < 0) { strbuf_list_free(pair); return -1; @@ -552,6 +550,7 @@ int git_parse_ulong(const char *value, unsigned long *ret) return 1; } +NORETURN static void die_bad_number(const char *name, const char *value) { const char *reason = errno == ERANGE ? @@ -663,20 +662,7 @@ static int git_default_core_config(const char *var, const char *value) trust_ctime = git_config_bool(var, value); return 0; } - if (!strcmp(var, "core.statinfo") || - !strcmp(var, "core.checkstat")) { - /* - * NEEDSWORK: statinfo was a typo in v1.8.2 that has - * never been advertised. we will remove it at Git - * 2.0 boundary. - */ - if (!strcmp(var, "core.statinfo")) { - static int warned; - if (!warned++) { - warning("'core.statinfo' will be removed in Git 2.0; " - "use 'core.checkstat' instead."); - } - } + if (!strcmp(var, "core.checkstat")) { if (!strcasecmp(value, "default")) check_stat = 1; else if (!strcasecmp(value, "minimal")) @@ -833,9 +819,16 @@ static int git_default_core_config(const char *var, const char *value) if (!strcmp(var, "core.commentchar")) { const char *comment; int ret = git_config_string(&comment, var, value); - if (!ret) + if (ret) + return ret; + else if (!strcasecmp(comment, "auto")) + auto_comment_line_char = 1; + else if (comment[0] && !comment[1]) { comment_line_char = comment[0]; - return ret; + auto_comment_line_char = 0; + } else + return error("core.commentChar should only be one character"); + return 0; } if (!strcmp(var, "core.askpass")) @@ -959,7 +952,7 @@ static int git_default_push_config(const char *var, const char *value) 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); + return git_config_pathname(&git_mailmap_file, var, value); if (!strcmp(var, "mailmap.blob")) return git_config_string(&git_mailmap_blob, var, value); @@ -969,25 +962,25 @@ static int git_default_mailmap_config(const char *var, const char *value) int git_default_config(const char *var, const char *value, void *dummy) { - if (!prefixcmp(var, "core.")) + if (starts_with(var, "core.")) return git_default_core_config(var, value); - if (!prefixcmp(var, "user.")) + if (starts_with(var, "user.")) return git_ident_config(var, value, dummy); - if (!prefixcmp(var, "i18n.")) + if (starts_with(var, "i18n.")) return git_default_i18n_config(var, value); - if (!prefixcmp(var, "branch.")) + if (starts_with(var, "branch.")) return git_default_branch_config(var, value); - if (!prefixcmp(var, "push.")) + if (starts_with(var, "push.")) return git_default_push_config(var, value); - if (!prefixcmp(var, "mailmap.")) + if (starts_with(var, "mailmap.")) return git_default_mailmap_config(var, value); - if (!prefixcmp(var, "advice.")) + if (starts_with(var, "advice.")) return git_default_advice_config(var, value); if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) { @@ -1030,24 +1023,35 @@ static int do_config_from(struct config_source *top, config_fn_t fn, void *data) return ret; } -int git_config_from_file(config_fn_t fn, const char *filename, void *data) +static int do_config_from_file(config_fn_t fn, + const char *name, const char *path, FILE *f, void *data) { - int ret; - FILE *f = fopen(filename, "r"); + struct config_source top; - ret = -1; - if (f) { - struct config_source top; + top.u.file = f; + top.name = name; + top.path = path; + top.die_on_error = 1; + top.do_fgetc = config_file_fgetc; + top.do_ungetc = config_file_ungetc; + top.do_ftell = config_file_ftell; + + return do_config_from(&top, fn, data); +} - top.u.file = f; - top.name = filename; - top.die_on_error = 1; - top.do_fgetc = config_file_fgetc; - top.do_ungetc = config_file_ungetc; - top.do_ftell = config_file_ftell; +static int git_config_from_stdin(config_fn_t fn, void *data) +{ + return do_config_from_file(fn, "<stdin>", NULL, stdin, data); +} - ret = do_config_from(&top, fn, data); +int git_config_from_file(config_fn_t fn, const char *filename, void *data) +{ + int ret = -1; + FILE *f; + f = fopen(filename, "r"); + if (f) { + ret = do_config_from_file(fn, filename, filename, f, data); fclose(f); } return ret; @@ -1062,6 +1066,7 @@ int git_config_from_buf(config_fn_t fn, const char *name, const char *buf, top.u.buf.len = len; top.u.buf.pos = 0; top.name = name; + top.path = NULL; top.die_on_error = 0; top.do_fgetc = config_buf_fgetc; top.do_ungetc = config_buf_ungetc; @@ -1170,8 +1175,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config) } int git_config_with_options(config_fn_t fn, void *data, - const char *filename, - const char *blob_ref, + struct git_config_source *config_source, int respect_includes) { char *repo_config = NULL; @@ -1189,10 +1193,12 @@ int git_config_with_options(config_fn_t fn, void *data, * If we have a specific filename, use it. Otherwise, follow the * regular lookup sequence. */ - if (filename) - return git_config_from_file(fn, filename, data); - else if (blob_ref) - return git_config_from_blob_ref(fn, blob_ref, data); + if (config_source && config_source->use_stdin) + return git_config_from_stdin(fn, data); + else if (config_source && config_source->file) + return git_config_from_file(fn, config_source->file, data); + else if (config_source && config_source->blob) + return git_config_from_blob_ref(fn, config_source->blob, data); repo_config = git_pathdup("config"); ret = git_config_early(fn, data, repo_config); @@ -1203,22 +1209,21 @@ int git_config_with_options(config_fn_t fn, void *data, int git_config(config_fn_t fn, void *data) { - return git_config_with_options(fn, data, NULL, NULL, 1); + return git_config_with_options(fn, data, NULL, 1); } /* * Find all the stuff for git_config_set() below. */ -#define MAX_MATCHES 512 - static struct { int baselen; char *key; int do_not_match; regex_t *value_regex; int multi_replace; - size_t offset[MAX_MATCHES]; + size_t *offset; + unsigned int offset_alloc; enum { START, SECTION_SEEN, SECTION_END_SEEN, KEY_SEEN } state; int seen; } store; @@ -1241,11 +1246,11 @@ static int store_aux(const char *key, const char *value, void *cb) if (matches(key, value)) { if (store.seen == 1 && store.multi_replace == 0) { warning("%s has multiple values", key); - } else if (store.seen >= MAX_MATCHES) { - error("too many matches for %s", key); - return 1; } + ALLOC_GROW(store.offset, store.seen + 1, + store.offset_alloc); + store.offset[store.seen] = cf->do_ftell(cf); store.seen++; } @@ -1273,11 +1278,15 @@ static int store_aux(const char *key, const char *value, void *cb) * Do not increment matches: this is no match, but we * just made sure we are in the desired section. */ + ALLOC_GROW(store.offset, store.seen + 1, + store.offset_alloc); store.offset[store.seen] = cf->do_ftell(cf); /* fallthru */ case SECTION_END_SEEN: case START: if (matches(key, value)) { + ALLOC_GROW(store.offset, store.seen + 1, + store.offset_alloc); store.offset[store.seen] = cf->do_ftell(cf); store.state = KEY_SEEN; store.seen++; @@ -1285,6 +1294,9 @@ static int store_aux(const char *key, const char *value, void *cb) if (strrchr(key, '.') - key == store.baselen && !strncmp(key, store.key, store.baselen)) { store.state = SECTION_SEEN; + ALLOC_GROW(store.offset, + store.seen + 1, + store.offset_alloc); store.offset[store.seen] = cf->do_ftell(cf); } } @@ -1526,7 +1538,7 @@ int git_config_set_multivar_in_file(const char *config_filename, * The lock serves a purpose in addition to locking: the new * contents of .git/config will be written into it. */ - lock = xcalloc(sizeof(struct lock_file), 1); + lock = xcalloc(1, sizeof(struct lock_file)); fd = hold_lock_file_for_update(lock, config_filename, 0); if (fd < 0) { error("could not lock config file %s: %s", config_filename, strerror(errno)); @@ -1583,6 +1595,7 @@ int git_config_set_multivar_in_file(const char *config_filename, } } + ALLOC_GROW(store.offset, 1, store.offset_alloc); store.offset[0] = 0; store.state = START; store.seen = 0; @@ -1623,6 +1636,13 @@ int git_config_set_multivar_in_file(const char *config_filename, MAP_PRIVATE, in_fd, 0); close(in_fd); + if (fchmod(fd, st.st_mode & 07777) < 0) { + error("fchmod on %s failed: %s", + lock->filename, strerror(errno)); + ret = CONFIG_NO_WRITE; + goto out_free; + } + if (store.seen == 0) store.seen = 1; @@ -1771,6 +1791,7 @@ int git_config_rename_section_in_file(const char *config_filename, int out_fd; char buf[1024]; FILE *config_file; + struct stat st; if (new_name && !section_name_is_ok(new_name)) { ret = error("invalid section name: %s", new_name); @@ -1780,7 +1801,7 @@ int git_config_rename_section_in_file(const char *config_filename, if (!config_filename) config_filename = filename_buf = git_pathdup("config"); - lock = xcalloc(sizeof(struct lock_file), 1); + lock = xcalloc(1, sizeof(struct lock_file)); 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); @@ -1792,6 +1813,14 @@ int git_config_rename_section_in_file(const char *config_filename, goto unlock_and_out; } + fstat(fileno(config_file), &st); + + if (fchmod(out_fd, st.st_mode & 07777) < 0) { + ret = error("fchmod on %s failed: %s", + lock->filename, strerror(errno)); + goto out; + } + while (fgets(buf, sizeof(buf), config_file)) { int i; int length; @@ -1872,7 +1901,7 @@ int parse_config_key(const char *var, const char *dot; /* Does it start with "section." ? */ - if (prefixcmp(var, section) || var[section_len] != '.') + if (!starts_with(var, section) || var[section_len] != '.') return -1; /* |