*
* The "source" variable will be non-NULL only when we are actually
* parsing a real config source (file, blob, cmdline, etc).
- *
- * The "config_kvi" variable will be non-NULL only when we are feeding
- * cached config from a configset into a callback.
- *
- * They cannot be non-NULL at the same time. If they are both NULL, then
- * we aren't parsing anything (and depending on the function looking at
- * the variables, it's either a bug for it to be called in the first
- * place, or it's a function which can be reused for non-config
- * purposes, and should fall back to some sane behavior).
*/
struct config_source *source;
- struct key_value_info *config_kvi;
- /*
- * The "scope" of the current config source being parsed (repo, global,
- * etc). Like "source", this is only set when parsing a config source.
- * It's not part of "source" because it transcends a single file (i.e.,
- * a file included from .git/config is still in "repo" scope).
- *
- * When iterating through a configset, the equivalent value is
- * "config_kvi.scope" (see above).
- */
- enum config_scope parsing_scope;
};
/*
* Where possible, prefer to accept "struct config_reader" as an arg than to use
static inline void config_reader_push_source(struct config_reader *reader,
struct config_source *top)
{
- if (reader->config_kvi)
- BUG("source should not be set while iterating a config set");
top->prev = reader->source;
reader->source = top;
}
return ret;
}
-static inline void config_reader_set_kvi(struct config_reader *reader,
- struct key_value_info *kvi)
-{
- if (kvi && (reader->source || reader->parsing_scope))
- BUG("kvi should not be set while parsing a config source");
- reader->config_kvi = kvi;
-}
-
-static inline void config_reader_set_scope(struct config_reader *reader,
- enum config_scope scope)
-{
- if (scope && reader->config_kvi)
- BUG("scope should only be set when iterating through a config source");
- reader->parsing_scope = scope;
-}
-
static int pack_compression_seen;
static int zlib_compression_seen;
void *data;
const struct config_options *opts;
struct git_config_source *config_source;
+ struct repository *repo;
struct config_reader *config_reader;
/*
};
#define CONFIG_INCLUDE_INIT { 0 }
-static int git_config_include(const char *var, const char *value, void *data);
+static int git_config_include(const char *var, const char *value,
+ const struct config_context *ctx, void *data);
#define MAX_INCLUDE_DEPTH 10
static const char include_depth_advice[] = N_(
"from\n"
" %s\n"
"This might be due to circular includes.");
-static int handle_path_include(struct config_source *cs, const char *path,
+static int handle_path_include(struct config_source *cs,
+ const struct key_value_info *kvi,
+ const char *path,
struct config_include_data *inc)
{
int ret = 0;
!cs ? "<unknown>" :
cs->name ? cs->name :
"the command line");
- ret = git_config_from_file(git_config_include, path, inc);
+ ret = git_config_from_file_with_options(git_config_include, path, inc,
+ kvi->scope, NULL);
inc->depth--;
}
cleanup:
return ret;
}
-static int add_remote_url(const char *var, const char *value, void *data)
+static int add_remote_url(const char *var, const char *value,
+ const struct config_context *ctx UNUSED, void *data)
{
struct string_list *remote_urls = data;
const char *remote_name;
{
struct config_options opts;
- enum config_scope store_scope = inc->config_reader->parsing_scope;
-
opts = *inc->opts;
opts.unconditional_remote_url = 1;
- config_reader_set_scope(inc->config_reader, 0);
-
inc->remote_urls = xmalloc(sizeof(*inc->remote_urls));
string_list_init_dup(inc->remote_urls);
- config_with_options(add_remote_url, inc->remote_urls, inc->config_source, &opts);
-
- config_reader_set_scope(inc->config_reader, store_scope);
+ config_with_options(add_remote_url, inc->remote_urls,
+ inc->config_source, inc->repo, &opts);
}
static int forbid_remote_url(const char *var, const char *value UNUSED,
+ const struct config_context *ctx UNUSED,
void *data UNUSED)
{
const char *remote_name;
return 0;
}
-static int git_config_include(const char *var, const char *value, void *data)
+static int git_config_include(const char *var, const char *value,
+ const struct config_context *ctx,
+ void *data)
{
struct config_include_data *inc = data;
struct config_source *cs = inc->config_reader->source;
* Pass along all values, including "include" directives; this makes it
* possible to query information on the includes themselves.
*/
- ret = inc->fn(var, value, inc->data);
+ ret = inc->fn(var, value, ctx, inc->data);
if (ret < 0)
return ret;
if (!strcmp(var, "include.path"))
- ret = handle_path_include(cs, value, inc);
+ ret = handle_path_include(cs, ctx->kvi, value, inc);
if (!parse_config_key(var, "includeif", &cond, &cond_len, &key) &&
cond && include_condition_is_true(cs, inc, cond, cond_len) &&
if (inc->opts->unconditional_remote_url)
inc->fn = forbid_remote_url;
- ret = handle_path_include(cs, value, inc);
+ ret = handle_path_include(cs, ctx->kvi, value, inc);
inc->fn = old_fn;
}
}
static int config_parse_pair(const char *key, const char *value,
- config_fn_t fn, void *data)
+ struct key_value_info *kvi,
+ config_fn_t fn, void *data)
{
char *canonical_name;
int ret;
+ struct config_context ctx = {
+ .kvi = kvi,
+ };
if (!strlen(key))
return error(_("empty config key"));
if (git_config_parse_key(key, &canonical_name, NULL))
return -1;
- ret = (fn(canonical_name, value, data) < 0) ? -1 : 0;
+ ret = (fn(canonical_name, value, &ctx, data) < 0) ? -1 : 0;
free(canonical_name);
return ret;
}
+
+/* for values read from `git_config_from_parameters()` */
+void kvi_from_param(struct key_value_info *out)
+{
+ out->filename = NULL;
+ out->linenr = -1;
+ out->origin_type = CONFIG_ORIGIN_CMDLINE;
+ out->scope = CONFIG_SCOPE_COMMAND;
+}
+
int git_config_parse_parameter(const char *text,
config_fn_t fn, void *data)
{
const char *value;
struct strbuf **pair;
int ret;
+ struct key_value_info kvi = KVI_INIT;
+
+ kvi_from_param(&kvi);
pair = strbuf_split_str(text, '=', 2);
if (!pair[0])
return error(_("bogus config parameter: %s"), text);
}
- ret = config_parse_pair(pair[0]->buf, value, fn, data);
+ ret = config_parse_pair(pair[0]->buf, value, &kvi, fn, data);
strbuf_list_free(pair);
return ret;
}
-static int parse_config_env_list(char *env, config_fn_t fn, void *data)
+static int parse_config_env_list(char *env, struct key_value_info *kvi,
+ config_fn_t fn, void *data)
{
char *cur = env;
while (cur && *cur) {
CONFIG_DATA_ENVIRONMENT);
}
- if (config_parse_pair(key, value, fn, data) < 0)
+ if (config_parse_pair(key, value, kvi, fn, data) < 0)
return -1;
}
else {
int ret = 0;
char *envw = NULL;
struct config_source source = CONFIG_SOURCE_INIT;
+ struct key_value_info kvi = KVI_INIT;
source.origin_type = CONFIG_ORIGIN_CMDLINE;
config_reader_push_source(&the_reader, &source);
+ kvi_from_param(&kvi);
+
env = getenv(CONFIG_COUNT_ENVIRONMENT);
if (env) {
unsigned long count;
}
strbuf_reset(&envvar);
- if (config_parse_pair(key, value, fn, data) < 0) {
+ if (config_parse_pair(key, value, &kvi, fn, data) < 0) {
ret = -1;
goto out;
}
if (env) {
/* sq_dequote will write over it */
envw = xstrdup(env);
- if (parse_config_env_list(envw, fn, data) < 0) {
+ if (parse_config_env_list(envw, &kvi, fn, data) < 0) {
ret = -1;
goto out;
}
}
}
-static int get_value(struct config_source *cs, config_fn_t fn, void *data,
- struct strbuf *name)
+static int get_value(struct config_source *cs, struct key_value_info *kvi,
+ config_fn_t fn, void *data, struct strbuf *name)
{
int c;
char *value;
int ret;
+ struct config_context ctx = {
+ .kvi = kvi,
+ };
/* Get the full name */
for (;;) {
* accurate line number in error messages.
*/
cs->linenr--;
- ret = fn(name->buf, value, data);
+ kvi->linenr = cs->linenr;
+ ret = fn(name->buf, value, &ctx, data);
if (ret >= 0)
cs->linenr++;
return ret;
return 0;
}
+static void kvi_from_source(struct config_source *cs,
+ enum config_scope scope,
+ struct key_value_info *out)
+{
+ out->filename = strintern(cs->name);
+ out->origin_type = cs->origin_type;
+ out->linenr = cs->linenr;
+ out->scope = scope;
+}
+
static int git_parse_source(struct config_source *cs, config_fn_t fn,
- void *data, const struct config_options *opts)
+ struct key_value_info *kvi, void *data,
+ const struct config_options *opts)
{
int comment = 0;
size_t baselen = 0;
*/
strbuf_setlen(var, baselen);
strbuf_addch(var, tolower(c));
- if (get_value(cs, fn, data, var) < 0)
+ if (get_value(cs, kvi, fn, data, var) < 0)
break;
}
return 1;
}
-static int reader_config_name(struct config_reader *reader, const char **out);
-static int reader_origin_type(struct config_reader *reader,
- enum config_origin_type *type);
NORETURN
-static void die_bad_number(struct config_reader *reader, const char *name,
- const char *value)
+static void die_bad_number(const char *name, const char *value,
+ const struct key_value_info *kvi)
{
const char *error_type = (errno == ERANGE) ?
N_("out of range") : N_("invalid unit");
const char *bad_numeric = N_("bad numeric config value '%s' for '%s': %s");
- const char *config_name = NULL;
- enum config_origin_type config_origin = CONFIG_ORIGIN_UNKNOWN;
+
+ if (!kvi)
+ BUG("kvi should not be NULL");
if (!value)
value = "";
- /* Ignoring the return value is okay since we handle missing values. */
- reader_config_name(reader, &config_name);
- reader_origin_type(reader, &config_origin);
-
- if (!config_name)
+ if (!kvi->filename)
die(_(bad_numeric), value, name, _(error_type));
- switch (config_origin) {
+ switch (kvi->origin_type) {
case CONFIG_ORIGIN_BLOB:
die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
- value, name, config_name, _(error_type));
+ value, name, kvi->filename, _(error_type));
case CONFIG_ORIGIN_FILE:
die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
- value, name, config_name, _(error_type));
+ value, name, kvi->filename, _(error_type));
case CONFIG_ORIGIN_STDIN:
die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
value, name, _(error_type));
case CONFIG_ORIGIN_SUBMODULE_BLOB:
die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
- value, name, config_name, _(error_type));
+ value, name, kvi->filename, _(error_type));
case CONFIG_ORIGIN_CMDLINE:
die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
- value, name, config_name, _(error_type));
+ value, name, kvi->filename, _(error_type));
default:
die(_("bad numeric config value '%s' for '%s' in %s: %s"),
- value, name, config_name, _(error_type));
+ value, name, kvi->filename, _(error_type));
}
}
-int git_config_int(const char *name, const char *value)
+int git_config_int(const char *name, const char *value,
+ const struct key_value_info *kvi)
{
int ret;
if (!git_parse_int(value, &ret))
- die_bad_number(&the_reader, name, value);
+ die_bad_number(name, value, kvi);
return ret;
}
-int64_t git_config_int64(const char *name, const char *value)
+int64_t git_config_int64(const char *name, const char *value,
+ const struct key_value_info *kvi)
{
int64_t ret;
if (!git_parse_int64(value, &ret))
- die_bad_number(&the_reader, name, value);
+ die_bad_number(name, value, kvi);
return ret;
}
-unsigned long git_config_ulong(const char *name, const char *value)
+unsigned long git_config_ulong(const char *name, const char *value,
+ const struct key_value_info *kvi)
{
unsigned long ret;
if (!git_parse_ulong(value, &ret))
- die_bad_number(&the_reader, name, value);
+ die_bad_number(name, value, kvi);
return ret;
}
-ssize_t git_config_ssize_t(const char *name, const char *value)
+ssize_t git_config_ssize_t(const char *name, const char *value,
+ const struct key_value_info *kvi)
{
ssize_t ret;
if (!git_parse_ssize_t(value, &ret))
- die_bad_number(&the_reader, name, value);
+ die_bad_number(name, value, kvi);
return ret;
}
return -1;
}
-int git_config_bool_or_int(const char *name, const char *value, int *is_bool)
+int git_config_bool_or_int(const char *name, const char *value,
+ const struct key_value_info *kvi, int *is_bool)
{
int v = git_parse_maybe_bool_text(value);
if (0 <= v) {
return v;
}
*is_bool = 0;
- return git_config_int(name, value);
+ return git_config_int(name, value, kvi);
}
int git_config_bool(const char *name, const char *value)
return 0;
}
-static int git_default_core_config(const char *var, const char *value, void *cb)
+static int git_default_core_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
/* This needs a better name */
if (!strcmp(var, "core.filemode")) {
else if (!git_parse_maybe_bool_text(value))
default_abbrev = the_hash_algo->hexsz;
else {
- int abbrev = git_config_int(var, value);
+ int abbrev = git_config_int(var, value, ctx->kvi);
if (abbrev < minimum_abbrev || abbrev > the_hash_algo->hexsz)
return error(_("abbrev length out of range: %d"), abbrev);
default_abbrev = abbrev;
return set_disambiguate_hint_config(var, value);
if (!strcmp(var, "core.loosecompression")) {
- int level = git_config_int(var, value);
+ int level = git_config_int(var, value, ctx->kvi);
if (level == -1)
level = Z_DEFAULT_COMPRESSION;
else if (level < 0 || level > Z_BEST_COMPRESSION)
}
if (!strcmp(var, "core.compression")) {
- int level = git_config_int(var, value);
+ int level = git_config_int(var, value, ctx->kvi);
if (level == -1)
level = Z_DEFAULT_COMPRESSION;
else if (level < 0 || level > Z_BEST_COMPRESSION)
if (!strcmp(var, "core.packedgitwindowsize")) {
int pgsz_x2 = getpagesize() * 2;
- packed_git_window_size = git_config_ulong(var, value);
+ packed_git_window_size = git_config_ulong(var, value, ctx->kvi);
/* This value must be multiple of (pagesize * 2) */
packed_git_window_size /= pgsz_x2;
}
if (!strcmp(var, "core.bigfilethreshold")) {
- big_file_threshold = git_config_ulong(var, value);
+ big_file_threshold = git_config_ulong(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "core.packedgitlimit")) {
- packed_git_limit = git_config_ulong(var, value);
+ packed_git_limit = git_config_ulong(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "core.deltabasecachelimit")) {
- delta_base_cache_limit = git_config_ulong(var, value);
+ delta_base_cache_limit = git_config_ulong(var, value, ctx->kvi);
return 0;
}
return 0;
}
- if (!strcmp(var, "core.usereplacerefs")) {
- read_replace_refs = git_config_bool(var, value);
- return 0;
- }
-
/* Add other config variables here and to Documentation/config.txt. */
- return platform_core_config(var, value, cb);
+ return platform_core_config(var, value, ctx, cb);
}
static int git_default_sparse_config(const char *var, const char *value)
return 0;
}
-int git_default_config(const char *var, const char *value, void *cb)
+int git_default_config(const char *var, const char *value,
+ const struct config_context *ctx, void *cb)
{
if (starts_with(var, "core."))
- return git_default_core_config(var, value, cb);
+ return git_default_core_config(var, value, ctx, cb);
if (starts_with(var, "user.") ||
starts_with(var, "author.") ||
starts_with(var, "committer."))
- return git_ident_config(var, value, cb);
+ return git_ident_config(var, value, ctx, cb);
if (starts_with(var, "i18n."))
return git_default_i18n_config(var, value);
}
if (!strcmp(var, "pack.packsizelimit")) {
- pack_size_limit_cfg = git_config_ulong(var, value);
+ pack_size_limit_cfg = git_config_ulong(var, value, ctx->kvi);
return 0;
}
if (!strcmp(var, "pack.compression")) {
- int level = git_config_int(var, value);
+ int level = git_config_int(var, value, ctx->kvi);
if (level == -1)
level = Z_DEFAULT_COMPRESSION;
else if (level < 0 || level > Z_BEST_COMPRESSION)
* this function.
*/
static int do_config_from(struct config_reader *reader,
- struct config_source *top, config_fn_t fn, void *data,
+ struct config_source *top, config_fn_t fn,
+ void *data, enum config_scope scope,
const struct config_options *opts)
{
+ struct key_value_info kvi = KVI_INIT;
int ret;
/* push config-file parsing state stack */
strbuf_init(&top->value, 1024);
strbuf_init(&top->var, 1024);
config_reader_push_source(reader, top);
+ kvi_from_source(top, scope, &kvi);
- ret = git_parse_source(top, fn, data, opts);
+ ret = git_parse_source(top, fn, &kvi, data, opts);
/* pop config-file parsing state stack */
strbuf_release(&top->value);
config_fn_t fn,
const enum config_origin_type origin_type,
const char *name, const char *path, FILE *f,
- void *data, const struct config_options *opts)
+ void *data, enum config_scope scope,
+ const struct config_options *opts)
{
struct config_source top = CONFIG_SOURCE_INIT;
int ret;
top.do_ftell = config_file_ftell;
flockfile(f);
- ret = do_config_from(reader, &top, fn, data, opts);
+ ret = do_config_from(reader, &top, fn, data, scope, opts);
funlockfile(f);
return ret;
}
-static int git_config_from_stdin(config_fn_t fn, void *data)
+static int git_config_from_stdin(config_fn_t fn, void *data,
+ enum config_scope scope)
{
return do_config_from_file(&the_reader, fn, CONFIG_ORIGIN_STDIN, "",
- NULL, stdin, data, NULL);
+ NULL, stdin, data, scope, NULL);
}
int git_config_from_file_with_options(config_fn_t fn, const char *filename,
- void *data,
+ void *data, enum config_scope scope,
const struct config_options *opts)
{
int ret = -1;
f = fopen_or_warn(filename, "r");
if (f) {
ret = do_config_from_file(&the_reader, fn, CONFIG_ORIGIN_FILE,
- filename, filename, f, data, opts);
+ filename, filename, f, data, scope,
+ opts);
fclose(f);
}
return ret;
int git_config_from_file(config_fn_t fn, const char *filename, void *data)
{
- return git_config_from_file_with_options(fn, filename, data, NULL);
+ return git_config_from_file_with_options(fn, filename, data,
+ CONFIG_SCOPE_UNKNOWN, NULL);
}
int git_config_from_mem(config_fn_t fn,
const enum config_origin_type origin_type,
const char *name, const char *buf, size_t len,
- void *data, const struct config_options *opts)
+ void *data, enum config_scope scope,
+ const struct config_options *opts)
{
struct config_source top = CONFIG_SOURCE_INIT;
top.do_ungetc = config_buf_ungetc;
top.do_ftell = config_buf_ftell;
- return do_config_from(&the_reader, &top, fn, data, opts);
+ return do_config_from(&the_reader, &top, fn, data, scope, opts);
}
int git_config_from_blob_oid(config_fn_t fn,
const char *name,
struct repository *repo,
const struct object_id *oid,
- void *data)
+ void *data,
+ enum config_scope scope)
{
enum object_type type;
char *buf;
}
ret = git_config_from_mem(fn, CONFIG_ORIGIN_BLOB, name, buf, size,
- data, NULL);
+ data, scope, NULL);
free(buf);
return ret;
static int git_config_from_blob_ref(config_fn_t fn,
struct repository *repo,
const char *name,
- void *data)
+ void *data,
+ enum config_scope scope)
{
struct object_id oid;
if (repo_get_oid(repo, name, &oid) < 0)
return error(_("unable to resolve config blob '%s'"), name);
- return git_config_from_blob_oid(fn, name, repo, &oid, data);
+ return git_config_from_blob_oid(fn, name, repo, &oid, data, scope);
}
char *git_system_config(void)
static int do_git_config_sequence(struct config_reader *reader,
const struct config_options *opts,
+ const struct repository *repo,
config_fn_t fn, void *data)
{
int ret = 0;
char *xdg_config = NULL;
char *user_config = NULL;
char *repo_config;
- enum config_scope prev_parsing_scope = reader->parsing_scope;
+ char *worktree_config;
+
+ /*
+ * Ensure that either:
+ * - the git_dir and commondir are both set, or
+ * - the git_dir and commondir are both NULL
+ */
+ if (!opts->git_dir != !opts->commondir)
+ BUG("only one of commondir and git_dir is non-NULL");
- if (opts->commondir)
+ if (opts->commondir) {
repo_config = mkpathdup("%s/config", opts->commondir);
- else if (opts->git_dir)
- BUG("git_dir without commondir");
- else
+ worktree_config = mkpathdup("%s/config.worktree", opts->git_dir);
+ } else {
repo_config = NULL;
+ worktree_config = NULL;
+ }
- config_reader_set_scope(reader, CONFIG_SCOPE_SYSTEM);
if (git_config_system() && system_config &&
!access_or_die(system_config, R_OK,
opts->system_gently ? ACCESS_EACCES_OK : 0))
- ret += git_config_from_file(fn, system_config, data);
+ ret += git_config_from_file_with_options(fn, system_config,
+ data, CONFIG_SCOPE_SYSTEM,
+ NULL);
- config_reader_set_scope(reader, CONFIG_SCOPE_GLOBAL);
git_global_config(&user_config, &xdg_config);
if (xdg_config && !access_or_die(xdg_config, R_OK, ACCESS_EACCES_OK))
- ret += git_config_from_file(fn, xdg_config, data);
+ ret += git_config_from_file_with_options(fn, xdg_config, data,
+ CONFIG_SCOPE_GLOBAL, NULL);
if (user_config && !access_or_die(user_config, R_OK, ACCESS_EACCES_OK))
- ret += git_config_from_file(fn, user_config, data);
+ ret += git_config_from_file_with_options(fn, user_config, data,
+ CONFIG_SCOPE_GLOBAL, NULL);
- config_reader_set_scope(reader, CONFIG_SCOPE_LOCAL);
if (!opts->ignore_repo && repo_config &&
!access_or_die(repo_config, R_OK, 0))
- ret += git_config_from_file(fn, repo_config, data);
+ ret += git_config_from_file_with_options(fn, repo_config, data,
+ CONFIG_SCOPE_LOCAL, NULL);
- config_reader_set_scope(reader, CONFIG_SCOPE_WORKTREE);
- if (!opts->ignore_worktree && repository_format_worktree_config) {
- char *path = git_pathdup("config.worktree");
- if (!access_or_die(path, R_OK, 0))
- ret += git_config_from_file(fn, path, data);
- free(path);
+ if (!opts->ignore_worktree && worktree_config &&
+ repo && repo->repository_format_worktree_config &&
+ !access_or_die(worktree_config, R_OK, 0)) {
+ ret += git_config_from_file_with_options(fn, worktree_config, data,
+ CONFIG_SCOPE_WORKTREE,
+ NULL);
}
- config_reader_set_scope(reader, CONFIG_SCOPE_COMMAND);
if (!opts->ignore_cmdline && git_config_from_parameters(fn, data) < 0)
die(_("unable to parse command-line config"));
- config_reader_set_scope(reader, prev_parsing_scope);
free(system_config);
free(xdg_config);
free(user_config);
free(repo_config);
+ free(worktree_config);
return ret;
}
int config_with_options(config_fn_t fn, void *data,
struct git_config_source *config_source,
+ struct repository *repo,
const struct config_options *opts)
{
struct config_include_data inc = CONFIG_INCLUDE_INIT;
- enum config_scope prev_scope = the_reader.parsing_scope;
int ret;
if (opts->respect_includes) {
inc.fn = fn;
inc.data = data;
inc.opts = opts;
+ inc.repo = repo;
inc.config_source = config_source;
inc.config_reader = &the_reader;
fn = git_config_include;
data = &inc;
}
- if (config_source)
- config_reader_set_scope(&the_reader, config_source->scope);
-
/*
* If we have a specific filename, use it. Otherwise, follow the
* regular lookup sequence.
*/
if (config_source && config_source->use_stdin) {
- ret = git_config_from_stdin(fn, data);
+ ret = git_config_from_stdin(fn, data, config_source->scope);
} else if (config_source && config_source->file) {
- ret = git_config_from_file(fn, config_source->file, data);
+ ret = git_config_from_file_with_options(fn, config_source->file,
+ data, config_source->scope,
+ NULL);
} else if (config_source && config_source->blob) {
- struct repository *repo = config_source->repo ?
- config_source->repo : the_repository;
ret = git_config_from_blob_ref(fn, repo, config_source->blob,
- data);
+ data, config_source->scope);
} else {
- ret = do_git_config_sequence(&the_reader, opts, fn, data);
+ ret = do_git_config_sequence(&the_reader, opts, repo, fn, data);
}
if (inc.remote_urls) {
string_list_clear(inc.remote_urls, 0);
FREE_AND_NULL(inc.remote_urls);
}
- config_reader_set_scope(&the_reader, prev_scope);
return ret;
}
struct string_list *values;
struct config_set_element *entry;
struct configset_list *list = &set->list;
+ struct config_context ctx = CONFIG_CONTEXT_INIT;
for (i = 0; i < list->nr; i++) {
entry = list->items[i].e;
value_index = list->items[i].value_index;
values = &entry->value_list;
- config_reader_set_kvi(reader, values->items[value_index].util);
-
- if (fn(entry->key, values->items[value_index].string, data) < 0)
+ ctx.kvi = values->items[value_index].util;
+ if (fn(entry->key, values->items[value_index].string, &ctx, data) < 0)
git_die_config_linenr(entry->key,
- reader->config_kvi->filename,
- reader->config_kvi->linenr);
-
- config_reader_set_kvi(reader, NULL);
+ ctx.kvi->filename,
+ ctx.kvi->linenr);
}
}
opts.git_dir = gitdir.buf;
}
- config_with_options(cb, data, NULL, &opts);
+ config_with_options(cb, data, NULL, NULL, &opts);
strbuf_release(&commondir);
strbuf_release(&gitdir);
opts.ignore_cmdline = 1;
opts.system_gently = 1;
- config_with_options(cb, data, NULL, &opts);
+ config_with_options(cb, data, NULL, NULL, &opts);
}
RESULT_MUST_BE_USED
return 0;
}
-static int configset_add_value(struct config_reader *reader,
+static int configset_add_value(const struct key_value_info *kvi_p,
+ struct config_reader *reader,
struct config_set *set, const char *key,
const char *value)
{
if (!reader->source)
BUG("configset_add_value has no source");
if (reader->source->name) {
- kv_info->filename = strintern(reader->source->name);
- kv_info->linenr = reader->source->linenr;
- kv_info->origin_type = reader->source->origin_type;
+ kvi_from_source(reader->source, kvi_p->scope, kv_info);
} else {
- /* for values read from `git_config_from_parameters()` */
- kv_info->filename = NULL;
- kv_info->linenr = -1;
- kv_info->origin_type = CONFIG_ORIGIN_CMDLINE;
+ kvi_from_param(kv_info);
}
- kv_info->scope = reader->parsing_scope;
si->util = kv_info;
return 0;
};
#define CONFIGSET_ADD_INIT { 0 }
-static int config_set_callback(const char *key, const char *value, void *cb)
+static int config_set_callback(const char *key, const char *value,
+ const struct config_context *ctx,
+ void *cb)
{
struct configset_add_data *data = cb;
- configset_add_value(data->config_reader, data->config_set, key, value);
+ configset_add_value(ctx->kvi, data->config_reader, data->config_set,
+ key, value);
return 0;
}
return git_config_from_file(config_set_callback, filename, &data);
}
-int git_configset_get_value(struct config_set *set, const char *key, const char **value)
+int git_configset_get_value(struct config_set *set, const char *key,
+ const char **value, struct key_value_info *kvi)
{
const struct string_list *values = NULL;
int ret;
-
+ struct string_list_item item;
/*
* Follows "last one wins" semantic, i.e., if there are multiple matches for the
* queried key in the files of the configset, the value returned will be the last
return ret;
assert(values->nr > 0);
- *value = values->items[values->nr - 1].string;
+ item = values->items[values->nr - 1];
+ *value = item.string;
+ if (kvi)
+ *kvi = *((struct key_value_info *)item.util);
return 0;
}
int git_configset_get_string(struct config_set *set, const char *key, char **dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value))
+ if (!git_configset_get_value(set, key, &value, NULL))
return git_config_string((const char **)dest, key, value);
else
return 1;
const char **dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value)) {
+ if (!git_configset_get_value(set, key, &value, NULL)) {
if (!value)
return config_error_nonbool(key);
*dest = value;
int git_configset_get_int(struct config_set *set, const char *key, int *dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value)) {
- *dest = git_config_int(key, value);
+ struct key_value_info kvi;
+
+ if (!git_configset_get_value(set, key, &value, &kvi)) {
+ *dest = git_config_int(key, value, &kvi);
return 0;
} else
return 1;
int git_configset_get_ulong(struct config_set *set, const char *key, unsigned long *dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value)) {
- *dest = git_config_ulong(key, value);
+ struct key_value_info kvi;
+
+ if (!git_configset_get_value(set, key, &value, &kvi)) {
+ *dest = git_config_ulong(key, value, &kvi);
return 0;
} else
return 1;
int git_configset_get_bool(struct config_set *set, const char *key, int *dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value)) {
+ if (!git_configset_get_value(set, key, &value, NULL)) {
*dest = git_config_bool(key, value);
return 0;
} else
int *is_bool, int *dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value)) {
- *dest = git_config_bool_or_int(key, value, is_bool);
+ struct key_value_info kvi;
+
+ if (!git_configset_get_value(set, key, &value, &kvi)) {
+ *dest = git_config_bool_or_int(key, value, &kvi, is_bool);
return 0;
} else
return 1;
int git_configset_get_maybe_bool(struct config_set *set, const char *key, int *dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value)) {
+ if (!git_configset_get_value(set, key, &value, NULL)) {
*dest = git_parse_maybe_bool(value);
if (*dest == -1)
return -1;
int git_configset_get_pathname(struct config_set *set, const char *key, const char **dest)
{
const char *value;
- if (!git_configset_get_value(set, key, &value))
+ if (!git_configset_get_value(set, key, &value, NULL))
return git_config_pathname(dest, key, value);
else
return 1;
data.config_set = repo->config;
data.config_reader = &the_reader;
- if (config_with_options(config_set_callback, &data, NULL, &opts) < 0)
+ if (config_with_options(config_set_callback, &data, NULL, repo, &opts) < 0)
/*
* config_with_options() normally returns only
* zero, as most errors are fatal, and
const char *key, const char **value)
{
git_config_check_init(repo);
- return git_configset_get_value(repo->config, key, value);
+ return git_configset_get_value(repo->config, key, value, NULL);
}
int repo_config_get_value_multi(struct repository *repo, const char *key,
git_configset_init(&protected_config);
data.config_set = &protected_config;
data.config_reader = &the_reader;
- config_with_options(config_set_callback, &data, NULL, &opts);
+ config_with_options(config_set_callback, &data, NULL, NULL, &opts);
}
void git_protected_config(config_fn_t fn, void *data)
return 0;
}
-static int store_aux(const char *key, const char *value, void *cb)
+static int store_aux(const char *key, const char *value,
+ const struct config_context *ctx UNUSED, void *cb)
{
struct config_store_data *store = cb;
const char *key, const char *value)
{
/* Only use worktree-specific config if it is already enabled. */
- if (repository_format_worktree_config) {
+ 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);
*/
if (git_config_from_file_with_options(store_aux,
config_filename,
- &store, &opts)) {
+ &store, CONFIG_SCOPE_UNKNOWN,
+ &opts)) {
error(_("invalid config file %s"), config_filename);
ret = CONFIG_INVALID_FILE;
goto out_free;
output[0] = '\t';
}
} else {
+ strbuf_release(©str);
copystr = store_create_section(new_name, &store);
}
}
free(filename_buf);
config_store_data_clear(&store);
strbuf_release(&buf);
+ strbuf_release(©str);
return ret;
}
return 0;
}
-static int reader_origin_type(struct config_reader *reader,
- enum config_origin_type *type)
+const char *config_origin_type_name(enum config_origin_type type)
{
- if (the_reader.config_kvi)
- *type = reader->config_kvi->origin_type;
- else if(the_reader.source)
- *type = reader->source->origin_type;
- else
- return 1;
- return 0;
-}
-
-const char *current_config_origin_type(void)
-{
- enum config_origin_type type = CONFIG_ORIGIN_UNKNOWN;
-
- if (reader_origin_type(&the_reader, &type))
- BUG("current_config_origin_type called outside config callback");
-
switch (type) {
case CONFIG_ORIGIN_BLOB:
return "blob";
}
}
-static int reader_config_name(struct config_reader *reader, const char **out)
-{
- if (the_reader.config_kvi)
- *out = reader->config_kvi->filename;
- else if (the_reader.source)
- *out = reader->source->name;
- else
- return 1;
- return 0;
-}
-
-const char *current_config_name(void)
-{
- const char *name;
- if (reader_config_name(&the_reader, &name))
- BUG("current_config_name called outside config callback");
- return name ? name : "";
-}
-
-enum config_scope current_config_scope(void)
-{
- if (the_reader.config_kvi)
- return the_reader.config_kvi->scope;
- else
- return the_reader.parsing_scope;
-}
-
-int current_config_line(void)
-{
- if (the_reader.config_kvi)
- return the_reader.config_kvi->linenr;
- else
- return the_reader.source->linenr;
-}
-
int lookup_config(const char **mapping, int nr_mapping, const char *var)
{
int i;