summaryrefslogtreecommitdiff
path: root/subversion/libsvn_subr/config.c
diff options
context:
space:
mode:
Diffstat (limited to 'subversion/libsvn_subr/config.c')
-rw-r--r--subversion/libsvn_subr/config.c357
1 files changed, 294 insertions, 63 deletions
diff --git a/subversion/libsvn_subr/config.c b/subversion/libsvn_subr/config.c
index 152c1ff..cf97f0d 100644
--- a/subversion/libsvn_subr/config.c
+++ b/subversion/libsvn_subr/config.c
@@ -29,11 +29,13 @@
#include <apr_general.h>
#include <apr_lib.h>
+#include "svn_hash.h"
#include "svn_error.h"
#include "svn_pools.h"
#include "config_impl.h"
#include "svn_private_config.h"
+#include "private/svn_dep_compat.h"
@@ -45,9 +47,6 @@ struct cfg_section_t
/* The section name. */
const char *name;
- /* The section name, converted into a hash key. */
- const char *hash_key;
-
/* Table of cfg_option_t's. */
apr_hash_t *options;
};
@@ -78,9 +77,10 @@ struct cfg_option_t
svn_error_t *
-svn_config_create(svn_config_t **cfgp,
- svn_boolean_t section_names_case_sensitive,
- apr_pool_t *result_pool)
+svn_config_create2(svn_config_t **cfgp,
+ svn_boolean_t section_names_case_sensitive,
+ svn_boolean_t option_names_case_sensitive,
+ apr_pool_t *result_pool)
{
svn_config_t *cfg = apr_palloc(result_pool, sizeof(*cfg));
@@ -88,24 +88,29 @@ svn_config_create(svn_config_t **cfgp,
cfg->pool = result_pool;
cfg->x_pool = svn_pool_create(result_pool);
cfg->x_values = FALSE;
- cfg->tmp_key = svn_stringbuf_create("", result_pool);
- cfg->tmp_value = svn_stringbuf_create("", result_pool);
+ cfg->tmp_key = svn_stringbuf_create_empty(result_pool);
+ cfg->tmp_value = svn_stringbuf_create_empty(result_pool);
cfg->section_names_case_sensitive = section_names_case_sensitive;
+ cfg->option_names_case_sensitive = option_names_case_sensitive;
*cfgp = cfg;
return SVN_NO_ERROR;
}
svn_error_t *
-svn_config_read2(svn_config_t **cfgp, const char *file,
+svn_config_read3(svn_config_t **cfgp, const char *file,
svn_boolean_t must_exist,
svn_boolean_t section_names_case_sensitive,
- apr_pool_t *pool)
+ svn_boolean_t option_names_case_sensitive,
+ apr_pool_t *result_pool)
{
svn_config_t *cfg;
svn_error_t *err;
- SVN_ERR(svn_config_create(&cfg, section_names_case_sensitive, pool));
+ SVN_ERR(svn_config_create2(&cfg,
+ section_names_case_sensitive,
+ option_names_case_sensitive,
+ result_pool));
/* Yes, this is platform-specific code in Subversion, but there's no
practical way to migrate it into APR, as it's simultaneously
@@ -115,10 +120,10 @@ svn_config_read2(svn_config_t **cfgp, const char *file,
#ifdef WIN32
if (0 == strncmp(file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN))
err = svn_config__parse_registry(cfg, file + SVN_REGISTRY_PREFIX_LEN,
- must_exist, pool);
+ must_exist, result_pool);
else
#endif /* WIN32 */
- err = svn_config__parse_file(cfg, file, must_exist, pool);
+ err = svn_config__parse_file(cfg, file, must_exist, result_pool);
if (err != SVN_NO_ERROR)
return err;
@@ -128,7 +133,31 @@ svn_config_read2(svn_config_t **cfgp, const char *file,
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_config_parse(svn_config_t **cfgp, svn_stream_t *stream,
+ svn_boolean_t section_names_case_sensitive,
+ svn_boolean_t option_names_case_sensitive,
+ apr_pool_t *result_pool)
+{
+ svn_config_t *cfg;
+ svn_error_t *err;
+ apr_pool_t *scratch_pool = svn_pool_create(result_pool);
+ err = svn_config_create2(&cfg,
+ section_names_case_sensitive,
+ option_names_case_sensitive,
+ result_pool);
+
+ if (err == SVN_NO_ERROR)
+ err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
+
+ if (err == SVN_NO_ERROR)
+ *cfgp = cfg;
+
+ svn_pool_destroy(scratch_pool);
+
+ return err;
+}
/* Read various configuration sources into *CFGP, in this order, with
* later reads overriding the results of earlier ones:
@@ -170,7 +199,8 @@ read_all(svn_config_t **cfgp,
SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE));
else
{
- SVN_ERR(svn_config_read2(cfgp, sys_file_path, FALSE, FALSE, pool));
+ SVN_ERR(svn_config_read3(cfgp, sys_file_path,
+ FALSE, FALSE, FALSE, pool));
red_config = TRUE;
}
}
@@ -197,13 +227,14 @@ read_all(svn_config_t **cfgp,
SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE));
else
{
- SVN_ERR(svn_config_read2(cfgp, usr_file_path, FALSE, FALSE, pool));
+ SVN_ERR(svn_config_read3(cfgp, usr_file_path,
+ FALSE, FALSE, FALSE, pool));
red_config = TRUE;
}
}
if (! red_config)
- *cfgp = NULL;
+ SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
return SVN_NO_ERROR;
}
@@ -333,7 +364,10 @@ svn_config_merge(svn_config_t *cfg, const char *file,
### We could use a tmp subpool for this, since merge_cfg is going
to be tossed afterwards. Premature optimization, though? */
svn_config_t *merge_cfg;
- SVN_ERR(svn_config_read2(&merge_cfg, file, must_exist, FALSE, cfg->pool));
+ SVN_ERR(svn_config_read3(&merge_cfg, file, must_exist,
+ cfg->section_names_case_sensitive,
+ cfg->option_names_case_sensitive,
+ cfg->pool));
/* Now copy the new options into the original table. */
for_each_option(merge_cfg, cfg, merge_cfg->pool, merge_callback);
@@ -408,7 +442,8 @@ find_option(svn_config_t *cfg, const char *section, const char *option,
/* Canonicalize the option key */
svn_stringbuf_set(cfg->tmp_key, option);
- make_hash_key(cfg->tmp_key->data);
+ if (! cfg->option_names_case_sensitive)
+ make_hash_key(cfg->tmp_key->data);
opt = apr_hash_get(sec->options, cfg->tmp_key->data,
cfg->tmp_key->len);
@@ -442,19 +477,30 @@ make_string_from_option(const char **valuep, svn_config_t *cfg,
/* Expand the option value if necessary. */
if (!opt->expanded)
{
- apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
+ /* before attempting to expand an option, check for the placeholder.
+ * If none is there, there is no point in calling expand_option_value.
+ */
+ if (opt->value && strchr(opt->value, '%'))
+ {
+ apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
- expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
- opt->expanded = TRUE;
+ expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
+ opt->expanded = TRUE;
- if (!x_pool)
+ if (x_pool != cfg->x_pool)
+ {
+ /* Grab the fully expanded value from tmp_pool before its
+ disappearing act. */
+ if (opt->x_value)
+ opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
+ strlen(opt->x_value));
+ if (!x_pool)
+ svn_pool_destroy(tmp_pool);
+ }
+ }
+ else
{
- /* Grab the fully expanded value from tmp_pool before its
- disappearing act. */
- if (opt->x_value)
- opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
- strlen(opt->x_value));
- svn_pool_destroy(tmp_pool);
+ opt->expanded = TRUE;
}
}
@@ -554,6 +600,47 @@ expand_option_value(svn_config_t *cfg, cfg_section_t *section,
*opt_x_valuep = NULL;
}
+static cfg_section_t *
+svn_config_addsection(svn_config_t *cfg,
+ const char *section)
+{
+ cfg_section_t *s;
+ const char *hash_key;
+
+ s = apr_palloc(cfg->pool, sizeof(cfg_section_t));
+ s->name = apr_pstrdup(cfg->pool, section);
+ if(cfg->section_names_case_sensitive)
+ hash_key = s->name;
+ else
+ hash_key = make_hash_key(apr_pstrdup(cfg->pool, section));
+ s->options = apr_hash_make(cfg->pool);
+ svn_hash_sets(cfg->sections, hash_key, s);
+
+ return s;
+}
+
+static void
+svn_config_create_option(cfg_option_t **opt,
+ const char *option,
+ const char *value,
+ svn_boolean_t option_names_case_sensitive,
+ apr_pool_t *pool)
+{
+ cfg_option_t *o;
+
+ o = apr_palloc(pool, sizeof(cfg_option_t));
+ o->name = apr_pstrdup(pool, option);
+ if(option_names_case_sensitive)
+ o->hash_key = o->name;
+ else
+ o->hash_key = make_hash_key(apr_pstrdup(pool, option));
+
+ o->value = apr_pstrdup(pool, value);
+ o->x_value = NULL;
+ o->expanded = FALSE;
+
+ *opt = o;
+}
void
@@ -561,6 +648,7 @@ svn_config_get(svn_config_t *cfg, const char **valuep,
const char *section, const char *option,
const char *default_value)
{
+ *valuep = default_value;
if (cfg)
{
cfg_section_t *sec;
@@ -570,23 +658,21 @@ svn_config_get(svn_config_t *cfg, const char **valuep,
make_string_from_option(valuep, cfg, sec, opt, NULL);
}
else
- {
- apr_pool_t *tmp_pool = svn_pool_create(cfg->x_pool);
- const char *x_default;
- expand_option_value(cfg, sec, default_value, &x_default, tmp_pool);
- if (x_default)
- {
- svn_stringbuf_set(cfg->tmp_value, x_default);
- *valuep = cfg->tmp_value->data;
- }
- else
- *valuep = default_value;
- svn_pool_destroy(tmp_pool);
- }
- }
- else
- {
- *valuep = default_value;
+ /* before attempting to expand an option, check for the placeholder.
+ * If none is there, there is no point in calling expand_option_value.
+ */
+ if (default_value && strchr(default_value, '%'))
+ {
+ apr_pool_t *tmp_pool = svn_pool_create(cfg->x_pool);
+ const char *x_default;
+ expand_option_value(cfg, sec, default_value, &x_default, tmp_pool);
+ if (x_default)
+ {
+ svn_stringbuf_set(cfg->tmp_value, x_default);
+ *valuep = cfg->tmp_value->data;
+ }
+ svn_pool_destroy(tmp_pool);
+ }
}
}
@@ -612,28 +698,17 @@ svn_config_set(svn_config_t *cfg,
}
/* Create a new option */
- opt = apr_palloc(cfg->pool, sizeof(*opt));
- opt->name = apr_pstrdup(cfg->pool, option);
- opt->hash_key = make_hash_key(apr_pstrdup(cfg->pool, option));
-
- opt->value = apr_pstrdup(cfg->pool, value);
- opt->x_value = NULL;
- opt->expanded = FALSE;
+ svn_config_create_option(&opt, option, value,
+ cfg->option_names_case_sensitive,
+ cfg->pool);
if (sec == NULL)
{
/* Even the section doesn't exist. Create it. */
- sec = apr_palloc(cfg->pool, sizeof(*sec));
- sec->name = apr_pstrdup(cfg->pool, section);
- if(cfg->section_names_case_sensitive)
- sec->hash_key = sec->name;
- else
- sec->hash_key = make_hash_key(apr_pstrdup(cfg->pool, section));
- sec->options = apr_hash_make(cfg->pool);
- apr_hash_set(cfg->sections, sec->hash_key, APR_HASH_KEY_STRING, sec);
+ sec = svn_config_addsection(cfg, section);
}
- apr_hash_set(sec->options, opt->hash_key, APR_HASH_KEY_STRING, opt);
+ svn_hash_sets(sec->options, opt->hash_key, opt);
}
@@ -697,6 +772,33 @@ svn_config_set_bool(svn_config_t *cfg,
}
svn_error_t *
+svn_config_get_int64(svn_config_t *cfg,
+ apr_int64_t *valuep,
+ const char *section,
+ const char *option,
+ apr_int64_t default_value)
+{
+ const char *tmp_value;
+ svn_config_get(cfg, &tmp_value, section, option, NULL);
+ if (tmp_value)
+ return svn_cstring_strtoi64(valuep, tmp_value,
+ APR_INT64_MIN, APR_INT64_MAX, 10);
+
+ *valuep = default_value;
+ return SVN_NO_ERROR;
+}
+
+void
+svn_config_set_int64(svn_config_t *cfg,
+ const char *section,
+ const char *option,
+ apr_int64_t value)
+{
+ svn_config_set(cfg, section, option,
+ apr_psprintf(cfg->pool, "%" APR_INT64_T_FMT, value));
+}
+
+svn_error_t *
svn_config_get_yes_no_ask(svn_config_t *cfg, const char **valuep,
const char *section, const char *option,
const char* default_value)
@@ -725,6 +827,36 @@ svn_config_get_yes_no_ask(svn_config_t *cfg, const char **valuep,
return SVN_NO_ERROR;
}
+svn_error_t *
+svn_config_get_tristate(svn_config_t *cfg, svn_tristate_t *valuep,
+ const char *section, const char *option,
+ const char *unknown_value,
+ svn_tristate_t default_value)
+{
+ const char *tmp_value;
+
+ svn_config_get(cfg, &tmp_value, section, option, NULL);
+
+ if (! tmp_value)
+ {
+ *valuep = default_value;
+ }
+ else if (0 == svn_cstring_casecmp(tmp_value, unknown_value))
+ {
+ *valuep = svn_tristate_unknown;
+ }
+ else
+ {
+ svn_boolean_t bool_val;
+ /* We already incorporated default_value into tmp_value if
+ necessary, so the FALSE below will be ignored unless the
+ caller is doing something it shouldn't be doing. */
+ SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option));
+ *valuep = bool_val ? svn_tristate_true : svn_tristate_false;
+ }
+
+ return SVN_NO_ERROR;
+}
int
svn_config_enumerate_sections(svn_config_t *cfg,
@@ -903,7 +1035,7 @@ const char *svn_config_find_group(svn_config_t *cfg, const char *key,
gb.key = key;
gb.match = NULL;
gb.pool = pool;
- svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool);
+ (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool);
return gb.match;
}
@@ -924,6 +1056,97 @@ svn_config_get_server_setting(svn_config_t *cfg,
return retval;
}
+
+svn_error_t *
+svn_config_dup(svn_config_t **cfgp,
+ svn_config_t *src,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *sectidx;
+ apr_hash_index_t *optidx;
+
+ *cfgp = 0;
+ SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
+
+ (*cfgp)->x_values = src->x_values;
+ (*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive;
+ (*cfgp)->option_names_case_sensitive = src->option_names_case_sensitive;
+
+ for (sectidx = apr_hash_first(pool, src->sections);
+ sectidx != NULL;
+ sectidx = apr_hash_next(sectidx))
+ {
+ const void *sectkey;
+ void *sectval;
+ apr_ssize_t sectkeyLength;
+ cfg_section_t * srcsect;
+ cfg_section_t * destsec;
+
+ apr_hash_this(sectidx, &sectkey, &sectkeyLength, &sectval);
+ srcsect = sectval;
+
+ destsec = svn_config_addsection(*cfgp, srcsect->name);
+
+ for (optidx = apr_hash_first(pool, srcsect->options);
+ optidx != NULL;
+ optidx = apr_hash_next(optidx))
+ {
+ const void *optkey;
+ void *optval;
+ apr_ssize_t optkeyLength;
+ cfg_option_t *srcopt;
+ cfg_option_t *destopt;
+
+ apr_hash_this(optidx, &optkey, &optkeyLength, &optval);
+ srcopt = optval;
+
+ svn_config_create_option(&destopt, srcopt->name, srcopt->value,
+ (*cfgp)->option_names_case_sensitive,
+ pool);
+
+ destopt->value = apr_pstrdup(pool, srcopt->value);
+ destopt->x_value = apr_pstrdup(pool, srcopt->x_value);
+ destopt->expanded = srcopt->expanded;
+ apr_hash_set(destsec->options,
+ apr_pstrdup(pool, (const char*)optkey),
+ optkeyLength, destopt);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_config_copy_config(apr_hash_t **cfg_hash,
+ apr_hash_t *src_hash,
+ apr_pool_t *pool)
+{
+ apr_hash_index_t *cidx;
+
+ *cfg_hash = apr_hash_make(pool);
+ for (cidx = apr_hash_first(pool, src_hash);
+ cidx != NULL;
+ cidx = apr_hash_next(cidx))
+ {
+ const void *ckey;
+ void *cval;
+ apr_ssize_t ckeyLength;
+ svn_config_t * srcconfig;
+ svn_config_t * destconfig;
+
+ apr_hash_this(cidx, &ckey, &ckeyLength, &cval);
+ srcconfig = cval;
+
+ SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool));
+
+ apr_hash_set(*cfg_hash,
+ apr_pstrdup(pool, (const char*)ckey),
+ ckeyLength, destconfig);
+ }
+
+ return SVN_NO_ERROR;
+}
+
svn_error_t*
svn_config_get_server_setting_int(svn_config_t *cfg,
const char *server_group,
@@ -974,5 +1197,13 @@ svn_config_get_server_setting_bool(svn_config_t *cfg,
svn_boolean_t
svn_config_has_section(svn_config_t *cfg, const char *section)
{
- return apr_hash_get(cfg->sections, section, APR_HASH_KEY_STRING) != NULL;
+ cfg_section_t *sec;
+
+ /* Canonicalize the hash key */
+ svn_stringbuf_set(cfg->tmp_key, section);
+ if (! cfg->section_names_case_sensitive)
+ make_hash_key(cfg->tmp_key->data);
+
+ sec = svn_hash_gets(cfg->sections, cfg->tmp_key->data);
+ return sec != NULL;
}