aboutsummaryrefslogtreecommitdiffstats
path: root/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'config.c')
-rw-r--r--config.c210
1 files changed, 166 insertions, 44 deletions
diff --git a/config.c b/config.c
index 9ff6ae1cb9..6421894614 100644
--- a/config.c
+++ b/config.c
@@ -5,6 +5,9 @@
* Copyright (C) Johannes Schindelin, 2005
*
*/
+
+#define USE_THE_REPOSITORY_VARIABLE
+
#include "git-compat-util.h"
#include "abspath.h"
#include "advice.h"
@@ -95,7 +98,6 @@ static long config_file_ftell(struct config_source *conf)
return ftell(conf->u.file);
}
-
static int config_buf_fgetc(struct config_source *conf)
{
if (conf->u.buf.pos < conf->u.buf.len)
@@ -126,7 +128,7 @@ struct config_include_data {
config_fn_t fn;
void *data;
const struct config_options *opts;
- struct git_config_source *config_source;
+ const struct git_config_source *config_source;
struct repository *repo;
/*
@@ -304,7 +306,8 @@ static int include_by_branch(const char *cond, size_t cond_len)
int ret;
struct strbuf pattern = STRBUF_INIT;
const char *refname = !the_repository->gitdir ?
- NULL : resolve_ref_unsafe("HEAD", 0, NULL, &flags);
+ NULL : refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
+ "HEAD", 0, NULL, &flags);
const char *shortname;
if (!refname || !(flags & REF_ISSYMREF) ||
@@ -818,7 +821,8 @@ static int get_next_char(struct config_source *cs)
static char *parse_value(struct config_source *cs)
{
- int quote = 0, comment = 0, space = 0;
+ int quote = 0, comment = 0;
+ size_t trim_len = 0;
strbuf_reset(&cs->value);
for (;;) {
@@ -828,13 +832,17 @@ static char *parse_value(struct config_source *cs)
cs->linenr--;
return NULL;
}
+ if (trim_len)
+ strbuf_setlen(&cs->value, trim_len);
return cs->value.buf;
}
if (comment)
continue;
if (isspace(c) && !quote) {
+ if (!trim_len)
+ trim_len = cs->value.len;
if (cs->value.len)
- space++;
+ strbuf_addch(&cs->value, c);
continue;
}
if (!quote) {
@@ -843,8 +851,8 @@ static char *parse_value(struct config_source *cs)
continue;
}
}
- for (; space; space--)
- strbuf_addch(&cs->value, ' ');
+ if (trim_len)
+ trim_len = 0;
if (c == '\\') {
c = get_next_char(cs);
switch (c) {
@@ -870,7 +878,7 @@ static char *parse_value(struct config_source *cs)
continue;
}
if (c == '"') {
- quote = 1-quote;
+ quote = 1 - quote;
continue;
}
strbuf_addch(&cs->value, c);
@@ -1239,6 +1247,15 @@ ssize_t git_config_ssize_t(const char *name, const char *value,
return ret;
}
+double git_config_double(const char *name, const char *value,
+ const struct key_value_info *kvi)
+{
+ double ret;
+ if (!git_parse_double(value, &ret))
+ die_bad_number(name, value, kvi);
+ return ret;
+}
+
static const struct fsync_component_name {
const char *name;
enum fsync_component component_bits;
@@ -1333,7 +1350,7 @@ int git_config_bool(const char *name, const char *value)
return v;
}
-int git_config_string(const char **dest, const char *var, const char *value)
+int git_config_string(char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
@@ -1341,7 +1358,7 @@ int git_config_string(const char **dest, const char *var, const char *value)
return 0;
}
-int git_config_pathname(const char **dest, const char *var, const char *value)
+int git_config_pathname(char **dest, const char *var, const char *value)
{
if (!value)
return config_error_nonbool(var);
@@ -1409,11 +1426,15 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.attributesfile"))
+ if (!strcmp(var, "core.attributesfile")) {
+ FREE_AND_NULL(git_attributes_file);
return git_config_pathname(&git_attributes_file, var, value);
+ }
- if (!strcmp(var, "core.hookspath"))
+ if (!strcmp(var, "core.hookspath")) {
+ FREE_AND_NULL(git_hooks_path);
return git_config_pathname(&git_hooks_path, var, value);
+ }
if (!strcmp(var, "core.bare")) {
is_bare_repository_cfg = git_config_bool(var, value);
@@ -1451,10 +1472,10 @@ static int git_default_core_config(const char *var, const char *value,
if (!strcasecmp(value, "auto"))
default_abbrev = -1;
else if (!git_parse_maybe_bool_text(value))
- default_abbrev = the_hash_algo->hexsz;
+ default_abbrev = GIT_MAX_HEXSZ;
else {
int abbrev = git_config_int(var, value, ctx->kvi);
- if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz)
+ if (abbrev < minimum_abbrev)
return error(_("abbrev length out of range: %d"), abbrev);
default_abbrev = abbrev;
}
@@ -1548,37 +1569,49 @@ static int git_default_core_config(const char *var, const char *value,
return 0;
}
- if (!strcmp(var, "core.checkroundtripencoding"))
+ if (!strcmp(var, "core.checkroundtripencoding")) {
+ FREE_AND_NULL(check_roundtrip_encoding);
return git_config_string(&check_roundtrip_encoding, var, value);
+ }
if (!strcmp(var, "core.notesref")) {
if (!value)
return config_error_nonbool(var);
+ free(notes_ref_name);
notes_ref_name = xstrdup(value);
return 0;
}
- if (!strcmp(var, "core.editor"))
+ if (!strcmp(var, "core.editor")) {
+ FREE_AND_NULL(editor_program);
return git_config_string(&editor_program, var, value);
+ }
- if (!strcmp(var, "core.commentchar")) {
+ if (!strcmp(var, "core.commentchar") ||
+ !strcmp(var, "core.commentstring")) {
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];
+ else if (value[0]) {
+ if (strchr(value, '\n'))
+ return error(_("%s cannot contain newline"), var);
+ comment_line_str = xstrdup(value);
auto_comment_line_char = 0;
} else
- return error(_("core.commentChar should only be one ASCII character"));
+ return error(_("%s must have at least one character"), var);
return 0;
}
- if (!strcmp(var, "core.askpass"))
+ if (!strcmp(var, "core.askpass")) {
+ FREE_AND_NULL(askpass_program);
return git_config_string(&askpass_program, var, value);
+ }
- if (!strcmp(var, "core.excludesfile"))
+ if (!strcmp(var, "core.excludesfile")) {
+ FREE_AND_NULL(excludes_file);
return git_config_pathname(&excludes_file, var, value);
+ }
if (!strcmp(var, "core.whitespace")) {
if (!value)
@@ -1679,11 +1712,15 @@ static int git_default_sparse_config(const char *var, const char *value)
static int git_default_i18n_config(const char *var, const char *value)
{
- if (!strcmp(var, "i18n.commitencoding"))
+ if (!strcmp(var, "i18n.commitencoding")) {
+ FREE_AND_NULL(git_commit_encoding);
return git_config_string(&git_commit_encoding, var, value);
+ }
- if (!strcmp(var, "i18n.logoutputencoding"))
+ if (!strcmp(var, "i18n.logoutputencoding")) {
+ FREE_AND_NULL(git_log_output_encoding);
return git_config_string(&git_log_output_encoding, var, value);
+ }
/* Add other config variables here and to Documentation/config.txt. */
return 0;
@@ -1756,10 +1793,15 @@ 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"))
+ if (!strcmp(var, "mailmap.file")) {
+ FREE_AND_NULL(git_mailmap_file);
return git_config_pathname(&git_mailmap_file, var, value);
- if (!strcmp(var, "mailmap.blob"))
+ }
+
+ if (!strcmp(var, "mailmap.blob")) {
+ FREE_AND_NULL(git_mailmap_blob);
return git_config_string(&git_mailmap_blob, var, value);
+ }
/* Add other config variables here and to Documentation/config.txt. */
return 0;
@@ -1767,8 +1809,10 @@ static int git_default_mailmap_config(const char *var, const char *value)
static int git_default_attr_config(const char *var, const char *value)
{
- if (!strcmp(var, "attr.tree"))
+ if (!strcmp(var, "attr.tree")) {
+ FREE_AND_NULL(git_attr_tree);
return git_config_string(&git_attr_tree, var, value);
+ }
/*
* Add other attribute related config variables here and to
@@ -1988,7 +2032,27 @@ char *git_system_config(void)
return system_config;
}
-void git_global_config(char **user_out, char **xdg_out)
+char *git_global_config(void)
+{
+ char *user_config, *xdg_config;
+
+ git_global_config_paths(&user_config, &xdg_config);
+ if (!user_config) {
+ free(xdg_config);
+ return NULL;
+ }
+
+ if (access_or_warn(user_config, R_OK, 0) && xdg_config &&
+ !access_or_warn(xdg_config, R_OK, 0)) {
+ free(user_config);
+ return xdg_config;
+ } else {
+ free(xdg_config);
+ return user_config;
+ }
+}
+
+void git_global_config_paths(char **user_out, char **xdg_out)
{
char *user_config = xstrdup_or_null(getenv("GIT_CONFIG_GLOBAL"));
char *xdg_config = NULL;
@@ -2041,7 +2105,7 @@ static int do_git_config_sequence(const struct config_options *opts,
data, CONFIG_SCOPE_SYSTEM,
NULL);
- git_global_config(&user_config, &xdg_config);
+ git_global_config_paths(&user_config, &xdg_config);
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
ret += git_config_from_file_with_options(fn, xdg_config, data,
@@ -2076,7 +2140,7 @@ static int do_git_config_sequence(const struct config_options *opts,
}
int config_with_options(config_fn_t fn, void *data,
- struct git_config_source *config_source,
+ const struct git_config_source *config_source,
struct repository *repo,
const struct config_options *opts)
{
@@ -2375,7 +2439,7 @@ int git_configset_get_string(struct config_set *set, const char *key, char **des
{
const char *value;
if (!git_configset_get_value(set, key, &value, NULL))
- return git_config_string((const char **)dest, key, value);
+ return git_config_string(dest, key, value);
else
return 1;
}
@@ -2453,7 +2517,7 @@ int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *d
return 1;
}
-int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
+int git_configset_get_pathname(struct config_set *set, const char *key, char **dest)
{
const char *value;
if (!git_configset_get_value(set, key, &value, NULL))
@@ -2598,7 +2662,7 @@ int repo_config_get_maybe_bool(struct repository *repo,
}
int repo_config_get_pathname(struct repository *repo,
- const char *key, const char **dest)
+ const char *key, char **dest)
{
int ret;
git_config_check_init(repo);
@@ -2697,7 +2761,7 @@ int git_config_get_maybe_bool(const char *key, int *dest)
return repo_config_get_maybe_bool(the_repository, key, dest);
}
-int git_config_get_pathname(const char *key, const char **dest)
+int git_config_get_pathname(const char *key, char **dest)
{
return repo_config_get_pathname(the_repository, key, dest);
}
@@ -2793,7 +2857,6 @@ void git_die_config_linenr(const char *key, const char *filename, int linenr)
key, filename, linenr);
}
-NORETURN __attribute__((format(printf, 2, 3)))
void git_die_config(const char *key, const char *err, ...)
{
const struct string_list *values;
@@ -2982,6 +3045,7 @@ static ssize_t write_section(int fd, const char *key,
}
static ssize_t write_pair(int fd, const char *key, const char *value,
+ const char *comment,
const struct config_store_data *store)
{
int i;
@@ -3022,7 +3086,11 @@ static ssize_t write_pair(int fd, const char *key, const char *value,
strbuf_addch(&sb, value[i]);
break;
}
- strbuf_addf(&sb, "%s\n", quote);
+
+ if (comment)
+ strbuf_addf(&sb, "%s%s\n", quote, comment);
+ else
+ strbuf_addf(&sb, "%s\n", quote);
ret = write_in_full(fd, sb.buf, sb.len);
strbuf_release(&sb);
@@ -3111,9 +3179,9 @@ static void maybe_remove_section(struct config_store_data *store,
}
int git_config_set_in_file_gently(const char *config_filename,
- const char *key, const char *value)
+ const char *key, const char *comment, const char *value)
{
- return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, 0);
+ return git_config_set_multivar_in_file_gently(config_filename, key, value, NULL, comment, 0);
}
void git_config_set_in_file(const char *config_filename,
@@ -3134,7 +3202,7 @@ int repo_config_set_worktree_gently(struct repository *r,
if (r->repository_format_worktree_config) {
char *file = repo_git_path(r, "config.worktree");
int ret = git_config_set_multivar_in_file_gently(
- file, key, value, NULL, 0);
+ file, key, value, NULL, NULL, 0);
free(file);
return ret;
}
@@ -3148,6 +3216,58 @@ void git_config_set(const char *key, const char *value)
trace2_cmd_set_config(key, value);
}
+char *git_config_prepare_comment_string(const char *comment)
+{
+ size_t leading_blanks;
+ char *prepared;
+
+ if (!comment)
+ return NULL;
+
+ if (strchr(comment, '\n'))
+ die(_("no multi-line comment allowed: '%s'"), comment);
+
+ /*
+ * If it begins with one or more leading whitespace characters
+ * followed by '#", the comment string is used as-is.
+ *
+ * If it begins with '#', a SP is inserted between the comment
+ * and the value the comment is about.
+ *
+ * Otherwise, the value is followed by a SP followed by '#'
+ * followed by SP and then the comment string comes.
+ */
+
+ leading_blanks = strspn(comment, " \t");
+ if (leading_blanks && comment[leading_blanks] == '#')
+ prepared = xstrdup(comment); /* use it as-is */
+ else if (comment[0] == '#')
+ prepared = xstrfmt(" %s", comment);
+ else
+ prepared = xstrfmt(" # %s", comment);
+
+ return prepared;
+}
+
+static void validate_comment_string(const char *comment)
+{
+ size_t leading_blanks;
+
+ if (!comment)
+ return;
+ /*
+ * The front-end must have massaged the comment string
+ * properly before calling us.
+ */
+ if (strchr(comment, '\n'))
+ BUG("multi-line comments are not permitted: '%s'", comment);
+
+ leading_blanks = strspn(comment, " \t");
+ if (!leading_blanks || comment[leading_blanks] != '#')
+ BUG("comment must begin with one or more SP followed by '#': '%s'",
+ comment);
+}
+
/*
* If value==NULL, unset in (remove from) config,
* if value_pattern!=NULL, disregard key/value pairs where value does not match.
@@ -3176,6 +3296,7 @@ void git_config_set(const char *key, const char *value)
int git_config_set_multivar_in_file_gently(const char *config_filename,
const char *key, const char *value,
const char *value_pattern,
+ const char *comment,
unsigned flags)
{
int fd = -1, in_fd = -1;
@@ -3186,6 +3307,8 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
size_t contents_sz;
struct config_store_data store = CONFIG_STORE_INIT;
+ validate_comment_string(comment);
+
/* parse-key returns negative; flip the sign to feed exit(3) */
ret = 0 - git_config_parse_key(key, &store.key, &store.baselen);
if (ret)
@@ -3226,7 +3349,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
free(store.key);
store.key = xstrdup(key);
if (write_section(fd, key, &store) < 0 ||
- write_pair(fd, key, value, &store) < 0)
+ write_pair(fd, key, value, comment, &store) < 0)
goto write_err_out;
} else {
struct stat st;
@@ -3380,7 +3503,7 @@ int git_config_set_multivar_in_file_gently(const char *config_filename,
if (write_section(fd, key, &store) < 0)
goto write_err_out;
}
- if (write_pair(fd, key, value, &store) < 0)
+ if (write_pair(fd, key, value, comment, &store) < 0)
goto write_err_out;
}
@@ -3418,7 +3541,6 @@ out_free:
write_err_out:
ret = write_error(get_lock_file_path(&lock));
goto out_free;
-
}
void git_config_set_multivar_in_file(const char *config_filename,
@@ -3426,7 +3548,7 @@ void git_config_set_multivar_in_file(const char *config_filename,
const char *value_pattern, unsigned flags)
{
if (!git_config_set_multivar_in_file_gently(config_filename, key, value,
- value_pattern, flags))
+ value_pattern, NULL, flags))
return;
if (value)
die(_("could not set '%s' to '%s'"), key, value);
@@ -3449,7 +3571,7 @@ int repo_config_set_multivar_gently(struct repository *r, const char *key,
int res = git_config_set_multivar_in_file_gently(file,
key, value,
value_pattern,
- flags);
+ NULL, flags);
free(file);
return res;
}