summaryrefslogtreecommitdiff
path: root/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'config.c')
-rw-r--r--config.c133
1 files changed, 81 insertions, 52 deletions
diff --git a/config.c b/config.c
index e1d66a145b..c227aa8517 100644
--- a/config.c
+++ b/config.c
@@ -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;
}
@@ -552,6 +557,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 +669,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"))
@@ -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;
- 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;
+ return do_config_from(&top, fn, data);
+}
- ret = do_config_from(&top, fn, data);
+static int git_config_from_stdin(config_fn_t fn, void *data)
+{
+ return do_config_from_file(fn, "<stdin>", NULL, stdin, 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);
}
}
@@ -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);
@@ -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;
/*