} buf;
} u;
const char *name;
+ const char *path;
int die_on_error;
int linenr;
int eof;
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;
}
if (ret < 0)
return ret;
- type = skip_prefix(var, "include.");
- if (!type)
+ if (!skip_prefix(var, "include.", &type))
return ret;
if (!strcmp(type, "path"))
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;
int git_config_parse_parameter(const char *text,
config_fn_t fn, void *data)
{
+ const char *value;
struct strbuf **pair;
+
pair = strbuf_split_str(text, '=', 2);
if (!pair[0])
return error("bogus config parameter: %s", text);
- if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=')
+
+ if (pair[0]->len && pair[0]->buf[pair[0]->len - 1] == '=') {
strbuf_setlen(pair[0], pair[0]->len - 1);
+ value = pair[1] ? pair[1]->buf : "";
+ } else {
+ value = NULL;
+ }
+
strbuf_trim(pair[0]);
if (!pair[0]->len) {
strbuf_list_free(pair);
return error("bogus config parameter: %s", text);
}
- lowercase(pair[0]->buf);
- if (fn(pair[0]->buf, pair[1] ? pair[1]->buf : NULL, data) < 0) {
+ strbuf_tolower(pair[0]);
+ if (fn(pair[0]->buf, value, data) < 0) {
strbuf_list_free(pair);
return -1;
}
return 1;
}
+NORETURN
static void die_bad_number(const char *name, const char *value)
{
const char *reason = errno == ERANGE ?
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"))
return git_config_string(&editor_program, var, value);
if (!strcmp(var, "core.commentchar")) {
- const char *comment;
- int ret = git_config_string(&comment, var, value);
- if (!ret)
- comment_line_char = comment[0];
- return ret;
+ if (!value)
+ return config_error_nonbool(var);
+ else if (!strcasecmp(value, "auto"))
+ auto_comment_line_char = 1;
+ else if (value[0] && !value[1]) {
+ comment_line_char = value[0];
+ auto_comment_line_char = 0;
+ } else
+ return error("core.commentChar should only be one character");
+ return 0;
}
if (!strcmp(var, "core.askpass"))
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);
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;
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;
}
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;
* 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);
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);
}
/*
static int matches(const char *key, const char *value)
{
- return !strcmp(key, store.key) &&
- (store.value_regex == NULL ||
- (store.do_not_match ^
- !regexec(store.value_regex, value, 0, NULL, 0)));
+ if (strcmp(key, store.key))
+ return 0; /* not ours */
+ if (!store.value_regex)
+ return 1; /* always matches */
+ if (store.value_regex == CONFIG_REGEX_NONE)
+ return 0; /* never matches */
+
+ return store.do_not_match ^
+ (value && !regexec(store.value_regex, value, 0, NULL, 0));
}
static int store_aux(const char *key, const char *value, void *cb)
/*
* If value==NULL, unset in (remove from) config,
* if value_regex!=NULL, disregard key/value pairs where value does not match.
+ * if value_regex==CONFIG_REGEX_NONE, do not match any existing values
+ * (only add a new one)
* if multi_replace==0, nothing, or only one matching key/value is replaced,
* else all matching key/values (regardless how many) are removed,
* before the new pair is written.
* 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));
if (value_regex == NULL)
store.value_regex = NULL;
+ else if (value_regex == CONFIG_REGEX_NONE)
+ store.value_regex = CONFIG_REGEX_NONE;
else {
if (value_regex[0] == '!') {
store.do_not_match = 1;
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) {
+ if (store.value_regex != NULL &&
+ store.value_regex != CONFIG_REGEX_NONE) {
regfree(store.value_regex);
free(store.value_regex);
}
}
free(store.key);
- if (store.value_regex != NULL) {
+ if (store.value_regex != NULL &&
+ store.value_regex != CONFIG_REGEX_NONE) {
regfree(store.value_regex);
free(store.value_regex);
}
MAP_PRIVATE, in_fd, 0);
close(in_fd);
+ if (chmod(lock->filename, st.st_mode & 07777) < 0) {
+ error("chmod on %s failed: %s",
+ lock->filename, strerror(errno));
+ ret = CONFIG_NO_WRITE;
+ goto out_free;
+ }
+
if (store.seen == 0)
store.seen = 1;
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);
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);
goto unlock_and_out;
}
+ fstat(fileno(config_file), &st);
+
+ if (chmod(lock->filename, st.st_mode & 07777) < 0) {
+ ret = error("chmod on %s failed: %s",
+ lock->filename, strerror(errno));
+ goto out;
+ }
+
while (fgets(buf, sizeof(buf), config_file)) {
int i;
int length;