summaryrefslogtreecommitdiff
path: root/config.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-09-11 10:33:25 -0700
committerJunio C Hamano <gitster@pobox.com>2014-09-11 10:33:25 -0700
commit7f346e9d73e75871d525664f36b7a5166b4feaf3 (patch)
tree23ed0c98c3e379888f2d16e8d8dfd31468637ec0 /config.c
parent0c72b98f31bf6eabd75be565a08ffcf0d8e74b1f (diff)
parent8a7b034d6d451491dbcfaebc3d4ed4f08c756822 (diff)
downloadgit-7f346e9d73e75871d525664f36b7a5166b4feaf3.tar.gz
Merge branch 'ta/config-set-1'
Use the new caching config-set API in git_config() calls. * ta/config-set-1: add tests for `git_config_get_string_const()` add a test for semantic errors in config files rewrite git_config() to use the config-set API config: add `git_die_config()` to the config-set API change `git_config()` return value to void add line number and file name info to `config_set` config.c: fix accuracy of line number in errors config.c: mark error and warnings strings for translation
Diffstat (limited to 'config.c')
-rw-r--r--config.c152
1 files changed, 128 insertions, 24 deletions
diff --git a/config.c b/config.c
index 01e0bdbafd..83c913ad09 100644
--- a/config.c
+++ b/config.c
@@ -35,12 +35,6 @@ struct config_source {
long (*do_ftell)(struct config_source *c);
};
-struct config_set_element {
- struct hashmap_entry ent;
- char *key;
- struct string_list value_list;
-};
-
static struct config_source *cf;
static int zlib_compression_seen;
@@ -252,6 +246,7 @@ static int get_next_char(void)
cf->linenr++;
if (c == EOF) {
cf->eof = 1;
+ cf->linenr++;
c = '\n';
}
return c;
@@ -327,6 +322,7 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
{
int c;
char *value;
+ int ret;
/* Get the full name */
for (;;) {
@@ -349,7 +345,15 @@ static int get_value(config_fn_t fn, void *data, struct strbuf *name)
if (!value)
return -1;
}
- return fn(name->buf, value, data);
+ /*
+ * We already consumed the \n, but we need linenr to point to
+ * the line we just parsed during the call to fn to get
+ * accurate line number in error messages.
+ */
+ cf->linenr--;
+ ret = fn(name->buf, value, data);
+ cf->linenr++;
+ return ret;
}
static int get_extended_base_var(struct strbuf *name, int c)
@@ -465,9 +469,9 @@ static int git_parse_source(config_fn_t fn, void *data)
break;
}
if (cf->die_on_error)
- die("bad config file line %d in %s", cf->linenr, cf->name);
+ die(_("bad config file line %d in %s"), cf->linenr, cf->name);
else
- return error("bad config file line %d in %s", cf->linenr, cf->name);
+ return error(_("bad config file line %d in %s"), cf->linenr, cf->name);
}
static int parse_unit_factor(const char *end, uintmax_t *val)
@@ -583,9 +587,9 @@ static void die_bad_number(const char *name, const char *value)
value = "";
if (cf && cf->name)
- die("bad numeric config value '%s' for '%s' in %s: %s",
+ die(_("bad numeric config value '%s' for '%s' in %s: %s"),
value, name, cf->name, reason);
- die("bad numeric config value '%s' for '%s': %s", value, name, reason);
+ die(_("bad numeric config value '%s' for '%s': %s"), value, name, reason);
}
int git_config_int(const char *name, const char *value)
@@ -670,7 +674,7 @@ int git_config_pathname(const char **dest, const char *var, const char *value)
return config_error_nonbool(var);
*dest = expand_user_path(value);
if (!*dest)
- die("Failed to expand user dir in: '%s'", value);
+ die(_("failed to expand user dir in: '%s'"), value);
return 0;
}
@@ -748,7 +752,7 @@ static int git_default_core_config(const char *var, const char *value)
if (level == -1)
level = Z_DEFAULT_COMPRESSION;
else if (level < 0 || level > Z_BEST_COMPRESSION)
- die("bad zlib compression level %d", level);
+ die(_("bad zlib compression level %d"), level);
zlib_compression_level = level;
zlib_compression_seen = 1;
return 0;
@@ -759,7 +763,7 @@ static int git_default_core_config(const char *var, const char *value)
if (level == -1)
level = Z_DEFAULT_COMPRESSION;
else if (level < 0 || level > Z_BEST_COMPRESSION)
- die("bad zlib compression level %d", level);
+ die(_("bad zlib compression level %d"), level);
core_compression_level = level;
core_compression_seen = 1;
if (!zlib_compression_seen)
@@ -881,7 +885,7 @@ static int git_default_core_config(const char *var, const char *value)
else if (!strcmp(value, "link"))
object_creation_mode = OBJECT_CREATION_USES_HARDLINKS;
else
- die("Invalid mode for object creation: %s", value);
+ die(_("invalid mode for object creation: %s"), value);
return 0;
}
@@ -1181,7 +1185,7 @@ int git_config_early(config_fn_t fn, void *data, const char *repo_config)
switch (git_config_from_parameters(fn, data)) {
case -1: /* error */
- die("unable to parse command-line config");
+ die(_("unable to parse command-line config"));
break;
case 0: /* found nothing */
break;
@@ -1228,9 +1232,48 @@ int git_config_with_options(config_fn_t fn, void *data,
return ret;
}
-int git_config(config_fn_t fn, void *data)
+static void git_config_raw(config_fn_t fn, void *data)
+{
+ if (git_config_with_options(fn, data, NULL, 1) < 0)
+ /*
+ * git_config_with_options() normally returns only
+ * positive values, as most errors are fatal, and
+ * non-fatal potential errors are guarded by "if"
+ * statements that are entered only when no error is
+ * possible.
+ *
+ * If we ever encounter a non-fatal error, it means
+ * something went really wrong and we should stop
+ * immediately.
+ */
+ die(_("unknown error occured while reading the configuration files"));
+}
+
+static void configset_iter(struct config_set *cs, config_fn_t fn, void *data)
{
- return git_config_with_options(fn, data, NULL, 1);
+ int i, value_index;
+ struct string_list *values;
+ struct config_set_element *entry;
+ struct configset_list *list = &cs->list;
+ struct key_value_info *kv_info;
+
+ for (i = 0; i < list->nr; i++) {
+ entry = list->items[i].e;
+ value_index = list->items[i].value_index;
+ values = &entry->value_list;
+ if (fn(entry->key, values->items[value_index].string, data) < 0) {
+ kv_info = values->items[value_index].util;
+ git_die_config_linenr(entry->key, kv_info->filename, kv_info->linenr);
+ }
+ }
+}
+
+static void git_config_check_init(void);
+
+void git_config(config_fn_t fn, void *data)
+{
+ git_config_check_init();
+ configset_iter(&the_config_set, fn, data);
}
static struct config_set_element *configset_find_element(struct config_set *cs, const char *key)
@@ -1258,6 +1301,10 @@ static struct config_set_element *configset_find_element(struct config_set *cs,
static int configset_add_value(struct config_set *cs, const char *key, const char *value)
{
struct config_set_element *e;
+ struct string_list_item *si;
+ struct configset_list_item *l_item;
+ struct key_value_info *kv_info = xmalloc(sizeof(*kv_info));
+
e = configset_find_element(cs, key);
/*
* Since the keys are being fed by git_config*() callback mechanism, they
@@ -1270,7 +1317,22 @@ static int configset_add_value(struct config_set *cs, const char *key, const cha
string_list_init(&e->value_list, 1);
hashmap_add(&cs->config_hash, e);
}
- string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+ si = string_list_append_nodup(&e->value_list, value ? xstrdup(value) : NULL);
+
+ ALLOC_GROW(cs->list.items, cs->list.nr + 1, cs->list.alloc);
+ l_item = &cs->list.items[cs->list.nr++];
+ l_item->e = e;
+ l_item->value_index = e->value_list.nr - 1;
+
+ if (cf) {
+ kv_info->filename = strintern(cf->name);
+ kv_info->linenr = cf->linenr;
+ } else {
+ /* for values read from `git_config_from_parameters()` */
+ kv_info->filename = NULL;
+ kv_info->linenr = -1;
+ }
+ si->util = kv_info;
return 0;
}
@@ -1285,6 +1347,9 @@ void git_configset_init(struct config_set *cs)
{
hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp, 0);
cs->hash_initialized = 1;
+ cs->list.nr = 0;
+ cs->list.alloc = 0;
+ cs->list.items = NULL;
}
void git_configset_clear(struct config_set *cs)
@@ -1297,10 +1362,14 @@ void git_configset_clear(struct config_set *cs)
hashmap_iter_init(&cs->config_hash, &iter);
while ((entry = hashmap_iter_next(&iter))) {
free(entry->key);
- string_list_clear(&entry->value_list, 0);
+ string_list_clear(&entry->value_list, 1);
}
hashmap_free(&cs->config_hash, 1);
cs->hash_initialized = 0;
+ free(cs->list.items);
+ cs->list.nr = 0;
+ cs->list.alloc = 0;
+ cs->list.items = NULL;
}
static int config_set_callback(const char *key, const char *value, void *cb)
@@ -1419,7 +1488,7 @@ static void git_config_check_init(void)
if (the_config_set.hash_initialized)
return;
git_configset_init(&the_config_set);
- git_config(config_set_callback, &the_config_set);
+ git_config_raw(config_set_callback, &the_config_set);
}
void git_config_clear(void)
@@ -1443,8 +1512,12 @@ const struct string_list *git_config_get_value_multi(const char *key)
int git_config_get_string_const(const char *key, const char **dest)
{
+ int ret;
git_config_check_init();
- return git_configset_get_string_const(&the_config_set, key, dest);
+ ret = git_configset_get_string_const(&the_config_set, key, dest);
+ if (ret < 0)
+ git_die_config(key, NULL);
+ return ret;
}
int git_config_get_string(const char *key, char **dest)
@@ -1485,8 +1558,39 @@ int git_config_get_maybe_bool(const char *key, int *dest)
int git_config_get_pathname(const char *key, const char **dest)
{
+ int ret;
git_config_check_init();
- return git_configset_get_pathname(&the_config_set, key, dest);
+ ret = git_configset_get_pathname(&the_config_set, key, dest);
+ if (ret < 0)
+ git_die_config(key, NULL);
+ return ret;
+}
+
+NORETURN
+void git_die_config_linenr(const char *key, const char *filename, int linenr)
+{
+ if (!filename)
+ die(_("unable to parse '%s' from command-line config"), key);
+ else
+ die(_("bad config variable '%s' in file '%s' at line %d"),
+ key, filename, linenr);
+}
+
+NORETURN __attribute__((format(printf, 2, 3)))
+void git_die_config(const char *key, const char *err, ...)
+{
+ const struct string_list *values;
+ struct key_value_info *kv_info;
+
+ if (err) {
+ va_list params;
+ va_start(params, err);
+ vreportf("error: ", err, params);
+ va_end(params);
+ }
+ values = git_config_get_value_multi(key);
+ kv_info = values->items[values->nr - 1].util;
+ git_die_config_linenr(key, kv_info->filename, kv_info->linenr);
}
/*
@@ -1522,7 +1626,7 @@ static int store_aux(const char *key, const char *value, void *cb)
case KEY_SEEN:
if (matches(key, value)) {
if (store.seen == 1 && store.multi_replace == 0) {
- warning("%s has multiple values", key);
+ warning(_("%s has multiple values"), key);
}
ALLOC_GROW(store.offset, store.seen + 1,