summaryrefslogtreecommitdiffstats
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.c1208
1 files changed, 1208 insertions, 0 deletions
diff --git a/subversion/libsvn_subr/config.c b/subversion/libsvn_subr/config.c
new file mode 100644
index 0000000..94aecd3
--- /dev/null
+++ b/subversion/libsvn_subr/config.c
@@ -0,0 +1,1208 @@
+/*
+ * config.c : reading configuration information
+ *
+ * ====================================================================
+ * Licensed to the Apache Software Foundation (ASF) under one
+ * or more contributor license agreements. See the NOTICE file
+ * distributed with this work for additional information
+ * regarding copyright ownership. The ASF licenses this file
+ * to you under the Apache License, Version 2.0 (the
+ * "License"); you may not use this file except in compliance
+ * with the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+ * KIND, either express or implied. See the License for the
+ * specific language governing permissions and limitations
+ * under the License.
+ * ====================================================================
+ */
+
+
+
+#define APR_WANT_STRFUNC
+#define APR_WANT_MEMFUNC
+#include <apr_want.h>
+
+#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"
+
+
+
+
+/* Section table entries. */
+typedef struct cfg_section_t cfg_section_t;
+struct cfg_section_t
+{
+ /* The section name. */
+ const char *name;
+
+ /* Table of cfg_option_t's. */
+ apr_hash_t *options;
+};
+
+
+/* Option table entries. */
+typedef struct cfg_option_t cfg_option_t;
+struct cfg_option_t
+{
+ /* The option name. */
+ const char *name;
+
+ /* The option name, converted into a hash key. */
+ const char *hash_key;
+
+ /* The unexpanded option value. */
+ const char *value;
+
+ /* The expanded option value. */
+ const char *x_value;
+
+ /* Expansion flag. If this is TRUE, this value has already been expanded.
+ In this case, if x_value is NULL, no expansions were necessary,
+ and value should be used directly. */
+ svn_boolean_t expanded;
+};
+
+
+
+svn_error_t *
+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));
+
+ cfg->sections = apr_hash_make(result_pool);
+ cfg->pool = result_pool;
+ cfg->x_pool = svn_pool_create(result_pool);
+ cfg->x_values = FALSE;
+ 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_read3(svn_config_t **cfgp, const char *file,
+ svn_boolean_t must_exist,
+ 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;
+
+ 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
+ Subversion-specific and Windows-specific. Even if we eventually
+ want to have APR offer a generic config-reading interface, it
+ makes sense to test it here first and migrate it later. */
+#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, result_pool);
+ else
+#endif /* WIN32 */
+ err = svn_config__parse_file(cfg, file, must_exist, result_pool);
+
+ if (err != SVN_NO_ERROR)
+ return err;
+ else
+ *cfgp = cfg;
+
+ 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:
+ *
+ * 1. SYS_REGISTRY_PATH (only on Win32, but ignored if NULL)
+ *
+ * 2. SYS_FILE_PATH (everywhere, but ignored if NULL)
+ *
+ * 3. USR_REGISTRY_PATH (only on Win32, but ignored if NULL)
+ *
+ * 4. USR_FILE_PATH (everywhere, but ignored if NULL)
+ *
+ * Allocate *CFGP in POOL. Even if no configurations are read,
+ * allocate an empty *CFGP.
+ */
+static svn_error_t *
+read_all(svn_config_t **cfgp,
+ const char *sys_registry_path,
+ const char *usr_registry_path,
+ const char *sys_file_path,
+ const char *usr_file_path,
+ apr_pool_t *pool)
+{
+ svn_boolean_t red_config = FALSE; /* "red" is the past tense of "read" */
+
+ /*** Read system-wide configurations first... ***/
+
+#ifdef WIN32
+ if (sys_registry_path)
+ {
+ SVN_ERR(svn_config_read2(cfgp, sys_registry_path, FALSE, FALSE, pool));
+ red_config = TRUE;
+ }
+#endif /* WIN32 */
+
+ if (sys_file_path)
+ {
+ if (red_config)
+ SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE));
+ else
+ {
+ SVN_ERR(svn_config_read3(cfgp, sys_file_path,
+ FALSE, FALSE, FALSE, pool));
+ red_config = TRUE;
+ }
+ }
+
+ /*** ...followed by per-user configurations. ***/
+
+#ifdef WIN32
+ if (usr_registry_path)
+ {
+ if (red_config)
+ SVN_ERR(svn_config_merge(*cfgp, usr_registry_path, FALSE));
+ else
+ {
+ SVN_ERR(svn_config_read2(cfgp, usr_registry_path,
+ FALSE, FALSE, pool));
+ red_config = TRUE;
+ }
+ }
+#endif /* WIN32 */
+
+ if (usr_file_path)
+ {
+ if (red_config)
+ SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE));
+ else
+ {
+ SVN_ERR(svn_config_read3(cfgp, usr_file_path,
+ FALSE, FALSE, FALSE, pool));
+ red_config = TRUE;
+ }
+ }
+
+ if (! red_config)
+ SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
+
+ return SVN_NO_ERROR;
+}
+
+
+/* CONFIG_DIR provides an override for the default behavior of reading
+ the default set of overlay files described by read_all()'s doc
+ string. */
+static svn_error_t *
+get_category_config(svn_config_t **cfg,
+ const char *config_dir,
+ const char *category,
+ apr_pool_t *pool)
+{
+ const char *usr_reg_path = NULL, *sys_reg_path = NULL;
+ const char *usr_cfg_path, *sys_cfg_path;
+ svn_error_t *err = NULL;
+
+ *cfg = NULL;
+
+ if (! config_dir)
+ {
+#ifdef WIN32
+ sys_reg_path = apr_pstrcat(pool, SVN_REGISTRY_SYS_CONFIG_PATH,
+ category, NULL);
+ usr_reg_path = apr_pstrcat(pool, SVN_REGISTRY_USR_CONFIG_PATH,
+ category, NULL);
+#endif /* WIN32 */
+
+ err = svn_config__sys_config_path(&sys_cfg_path, category, pool);
+ if ((err) && (err->apr_err == SVN_ERR_BAD_FILENAME))
+ {
+ sys_cfg_path = NULL;
+ svn_error_clear(err);
+ }
+ else if (err)
+ return err;
+ }
+ else
+ sys_cfg_path = NULL;
+
+ SVN_ERR(svn_config_get_user_config_path(&usr_cfg_path, config_dir, category,
+ pool));
+ return read_all(cfg, sys_reg_path, usr_reg_path,
+ sys_cfg_path, usr_cfg_path, pool);
+}
+
+
+svn_error_t *
+svn_config_get_config(apr_hash_t **cfg_hash,
+ const char *config_dir,
+ apr_pool_t *pool)
+{
+ svn_config_t *cfg;
+ *cfg_hash = apr_hash_make(pool);
+
+#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_SERVERS) - 1)
+ SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_SERVERS,
+ pool));
+ if (cfg)
+ apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, CATLEN, cfg);
+#undef CATLEN
+
+#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_CONFIG) - 1)
+ SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_CONFIG,
+ pool));
+ if (cfg)
+ apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, CATLEN, cfg);
+#undef CATLEN
+
+ return SVN_NO_ERROR;
+}
+
+
+
+/* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION)
+ pair. Stop if CALLBACK returns TRUE. Allocate from POOL. */
+static void
+for_each_option(svn_config_t *cfg, void *baton, apr_pool_t *pool,
+ svn_boolean_t callback(void *same_baton,
+ cfg_section_t *section,
+ cfg_option_t *option))
+{
+ apr_hash_index_t *sec_ndx;
+ for (sec_ndx = apr_hash_first(pool, cfg->sections);
+ sec_ndx != NULL;
+ sec_ndx = apr_hash_next(sec_ndx))
+ {
+ void *sec_ptr;
+ cfg_section_t *sec;
+ apr_hash_index_t *opt_ndx;
+
+ apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
+ sec = sec_ptr;
+
+ for (opt_ndx = apr_hash_first(pool, sec->options);
+ opt_ndx != NULL;
+ opt_ndx = apr_hash_next(opt_ndx))
+ {
+ void *opt_ptr;
+ cfg_option_t *opt;
+
+ apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
+ opt = opt_ptr;
+
+ if (callback(baton, sec, opt))
+ return;
+ }
+ }
+}
+
+
+
+static svn_boolean_t
+merge_callback(void *baton, cfg_section_t *section, cfg_option_t *option)
+{
+ svn_config_set(baton, section->name, option->name, option->value);
+ return FALSE;
+}
+
+svn_error_t *
+svn_config_merge(svn_config_t *cfg, const char *file,
+ svn_boolean_t must_exist)
+{
+ /* The original config hash shouldn't change if there's an error
+ while reading the confguration, so read into a temporary table.
+ ### 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_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);
+ return SVN_NO_ERROR;
+}
+
+
+
+/* Remove variable expansions from CFG. Walk through the options tree,
+ killing all expanded values, then clear the expanded value pool. */
+static svn_boolean_t
+rmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option)
+{
+ /* Only clear the `expanded' flag if the value actually contains
+ variable expansions. */
+ if (option->expanded && option->x_value != NULL)
+ {
+ option->x_value = NULL;
+ option->expanded = FALSE;
+ }
+
+ return FALSE;
+}
+
+static void
+remove_expansions(svn_config_t *cfg)
+{
+ if (!cfg->x_values)
+ return;
+
+ for_each_option(cfg, NULL, cfg->x_pool, rmex_callback);
+ svn_pool_clear(cfg->x_pool);
+ cfg->x_values = FALSE;
+}
+
+
+
+/* Canonicalize a string for hashing. Modifies KEY in place. */
+static APR_INLINE char *
+make_hash_key(char *key)
+{
+ register char *p;
+ for (p = key; *p != 0; ++p)
+ *p = (char)apr_tolower(*p);
+ return key;
+}
+
+
+/* Return a pointer to an option in CFG, or NULL if it doesn't exist.
+ if SECTIONP is non-null, return a pointer to the option's section.
+ OPTION may be NULL. */
+static cfg_option_t *
+find_option(svn_config_t *cfg, const char *section, const char *option,
+ cfg_section_t **sectionp)
+{
+ void *sec_ptr;
+
+ /* 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_ptr = apr_hash_get(cfg->sections, cfg->tmp_key->data,
+ cfg->tmp_key->len);
+ if (sectionp != NULL)
+ *sectionp = sec_ptr;
+
+ if (sec_ptr != NULL && option != NULL)
+ {
+ cfg_section_t *sec = sec_ptr;
+ cfg_option_t *opt;
+
+ /* Canonicalize the option key */
+ svn_stringbuf_set(cfg->tmp_key, option);
+ 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);
+ /* NOTE: ConfigParser's sections are case sensitive. */
+ if (opt == NULL
+ && apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0)
+ /* Options which aren't found in the requested section are
+ also sought after in the default section. */
+ opt = find_option(cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec);
+ return opt;
+ }
+
+ return NULL;
+}
+
+
+/* Has a bi-directional dependency with make_string_from_option(). */
+static void
+expand_option_value(svn_config_t *cfg, cfg_section_t *section,
+ const char *opt_value, const char **opt_x_valuep,
+ apr_pool_t *x_pool);
+
+
+/* Set *VALUEP according to the OPT's value. A value for X_POOL must
+ only ever be passed into this function by expand_option_value(). */
+static void
+make_string_from_option(const char **valuep, svn_config_t *cfg,
+ cfg_section_t *section, cfg_option_t *opt,
+ apr_pool_t* x_pool)
+{
+ /* Expand the option value if necessary. */
+ if (!opt->expanded)
+ {
+ /* 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;
+
+ if (!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));
+ svn_pool_destroy(tmp_pool);
+ }
+ }
+ else
+ {
+ opt->expanded = TRUE;
+ }
+ }
+
+ if (opt->x_value)
+ *valuep = opt->x_value;
+ else
+ *valuep = opt->value;
+}
+
+
+/* Start of variable-replacement placeholder */
+#define FMT_START "%("
+#define FMT_START_LEN (sizeof(FMT_START) - 1)
+
+/* End of variable-replacement placeholder */
+#define FMT_END ")s"
+#define FMT_END_LEN (sizeof(FMT_END) - 1)
+
+
+/* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP.
+ If no variable replacements are done, set *OPT_X_VALUEP to
+ NULL. Allocate from X_POOL. */
+static void
+expand_option_value(svn_config_t *cfg, cfg_section_t *section,
+ const char *opt_value, const char **opt_x_valuep,
+ apr_pool_t *x_pool)
+{
+ svn_stringbuf_t *buf = NULL;
+ const char *parse_from = opt_value;
+ const char *copy_from = parse_from;
+ const char *name_start, *name_end;
+
+ while (parse_from != NULL
+ && *parse_from != '\0'
+ && (name_start = strstr(parse_from, FMT_START)) != NULL)
+ {
+ name_start += FMT_START_LEN;
+ if (*name_start == '\0')
+ /* FMT_START at end of opt_value. */
+ break;
+
+ name_end = strstr(name_start, FMT_END);
+ if (name_end != NULL)
+ {
+ cfg_option_t *x_opt;
+ apr_size_t len = name_end - name_start;
+ char *name = apr_pstrmemdup(x_pool, name_start, len);
+
+ x_opt = find_option(cfg, section->name, name, NULL);
+
+ if (x_opt != NULL)
+ {
+ const char *cstring;
+
+ /* Pass back the sub-pool originally provided by
+ make_string_from_option() as an indication of when it
+ should terminate. */
+ make_string_from_option(&cstring, cfg, section, x_opt, x_pool);
+
+ /* Append the plain text preceding the expansion. */
+ len = name_start - FMT_START_LEN - copy_from;
+ if (buf == NULL)
+ {
+ buf = svn_stringbuf_ncreate(copy_from, len, x_pool);
+ cfg->x_values = TRUE;
+ }
+ else
+ svn_stringbuf_appendbytes(buf, copy_from, len);
+
+ /* Append the expansion and adjust parse pointers. */
+ svn_stringbuf_appendcstr(buf, cstring);
+ parse_from = name_end + FMT_END_LEN;
+ copy_from = parse_from;
+ }
+ else
+ /* Though ConfigParser considers the failure to resolve
+ the requested expansion an exception condition, we
+ consider it to be plain text, and look for the start of
+ the next one. */
+ parse_from = name_end + FMT_END_LEN;
+ }
+ else
+ /* Though ConfigParser treats unterminated format specifiers
+ as an exception condition, we consider them to be plain
+ text. The fact that there are no more format specifier
+ endings means we're done parsing. */
+ parse_from = NULL;
+ }
+
+ if (buf != NULL)
+ {
+ /* Copy the remainder of the plain text. */
+ svn_stringbuf_appendcstr(buf, copy_from);
+ *opt_x_valuep = buf->data;
+ }
+ else
+ *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
+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;
+ cfg_option_t *opt = find_option(cfg, section, option, &sec);
+ if (opt != NULL)
+ {
+ make_string_from_option(valuep, cfg, sec, opt, NULL);
+ }
+ else
+ /* 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);
+ }
+ }
+}
+
+
+
+void
+svn_config_set(svn_config_t *cfg,
+ const char *section, const char *option,
+ const char *value)
+{
+ cfg_section_t *sec;
+ cfg_option_t *opt;
+
+ remove_expansions(cfg);
+
+ opt = find_option(cfg, section, option, &sec);
+ if (opt != NULL)
+ {
+ /* Replace the option's value. */
+ opt->value = apr_pstrdup(cfg->pool, value);
+ opt->expanded = FALSE;
+ return;
+ }
+
+ /* Create a new option */
+ 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 = svn_config_addsection(cfg, section);
+ }
+
+ svn_hash_sets(sec->options, opt->hash_key, opt);
+}
+
+
+
+/* Set *BOOLP to true or false depending (case-insensitively) on INPUT.
+ If INPUT is null, set *BOOLP to DEFAULT_VALUE.
+
+ INPUT is a string indicating truth or falsehood in any of the usual
+ ways: "true"/"yes"/"on"/etc, "false"/"no"/"off"/etc.
+
+ If INPUT is neither NULL nor a recognized string, return an error
+ with code SVN_ERR_BAD_CONFIG_VALUE; use SECTION and OPTION in
+ constructing the error string. */
+static svn_error_t *
+get_bool(svn_boolean_t *boolp, const char *input, svn_boolean_t default_value,
+ const char *section, const char *option)
+{
+ svn_tristate_t value = svn_tristate__from_word(input);
+
+ if (value == svn_tristate_true)
+ *boolp = TRUE;
+ else if (value == svn_tristate_false)
+ *boolp = FALSE;
+ else if (input == NULL) /* no value provided */
+ *boolp = default_value;
+
+ else if (section) /* unrecognized value */
+ return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+ _("Config error: invalid boolean "
+ "value '%s' for '[%s] %s'"),
+ input, section, option);
+ else
+ return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
+ _("Config error: invalid boolean "
+ "value '%s' for '%s'"),
+ input, option);
+
+ return SVN_NO_ERROR;
+}
+
+
+svn_error_t *
+svn_config_get_bool(svn_config_t *cfg, svn_boolean_t *valuep,
+ const char *section, const char *option,
+ svn_boolean_t default_value)
+{
+ const char *tmp_value;
+ svn_config_get(cfg, &tmp_value, section, option, NULL);
+ return get_bool(valuep, tmp_value, default_value, section, option);
+}
+
+
+
+void
+svn_config_set_bool(svn_config_t *cfg,
+ const char *section, const char *option,
+ svn_boolean_t value)
+{
+ svn_config_set(cfg, section, option,
+ (value ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE));
+}
+
+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)
+{
+ const char *tmp_value;
+
+ svn_config_get(cfg, &tmp_value, section, option, NULL);
+
+ if (! tmp_value)
+ tmp_value = default_value;
+
+ if (tmp_value && (0 == svn_cstring_casecmp(tmp_value, SVN_CONFIG_ASK)))
+ {
+ *valuep = SVN_CONFIG_ASK;
+ }
+ 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_CONFIG_TRUE : SVN_CONFIG_FALSE;
+ }
+
+ 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,
+ svn_config_section_enumerator_t callback,
+ void *baton)
+{
+ apr_hash_index_t *sec_ndx;
+ int count = 0;
+ apr_pool_t *subpool = svn_pool_create(cfg->x_pool);
+
+ for (sec_ndx = apr_hash_first(subpool, cfg->sections);
+ sec_ndx != NULL;
+ sec_ndx = apr_hash_next(sec_ndx))
+ {
+ void *sec_ptr;
+ cfg_section_t *sec;
+
+ apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
+ sec = sec_ptr;
+ ++count;
+ if (!callback(sec->name, baton))
+ break;
+ }
+
+ svn_pool_destroy(subpool);
+ return count;
+}
+
+
+int
+svn_config_enumerate_sections2(svn_config_t *cfg,
+ svn_config_section_enumerator2_t callback,
+ void *baton, apr_pool_t *pool)
+{
+ apr_hash_index_t *sec_ndx;
+ apr_pool_t *iteration_pool;
+ int count = 0;
+
+ iteration_pool = svn_pool_create(pool);
+ for (sec_ndx = apr_hash_first(pool, cfg->sections);
+ sec_ndx != NULL;
+ sec_ndx = apr_hash_next(sec_ndx))
+ {
+ void *sec_ptr;
+ cfg_section_t *sec;
+
+ apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
+ sec = sec_ptr;
+ ++count;
+ svn_pool_clear(iteration_pool);
+ if (!callback(sec->name, baton, iteration_pool))
+ break;
+ }
+ svn_pool_destroy(iteration_pool);
+
+ return count;
+}
+
+
+
+int
+svn_config_enumerate(svn_config_t *cfg, const char *section,
+ svn_config_enumerator_t callback, void *baton)
+{
+ cfg_section_t *sec;
+ apr_hash_index_t *opt_ndx;
+ int count;
+ apr_pool_t *subpool;
+
+ find_option(cfg, section, NULL, &sec);
+ if (sec == NULL)
+ return 0;
+
+ subpool = svn_pool_create(cfg->x_pool);
+ count = 0;
+ for (opt_ndx = apr_hash_first(subpool, sec->options);
+ opt_ndx != NULL;
+ opt_ndx = apr_hash_next(opt_ndx))
+ {
+ void *opt_ptr;
+ cfg_option_t *opt;
+ const char *temp_value;
+
+ apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
+ opt = opt_ptr;
+
+ ++count;
+ make_string_from_option(&temp_value, cfg, sec, opt, NULL);
+ if (!callback(opt->name, temp_value, baton))
+ break;
+ }
+
+ svn_pool_destroy(subpool);
+ return count;
+}
+
+
+int
+svn_config_enumerate2(svn_config_t *cfg, const char *section,
+ svn_config_enumerator2_t callback, void *baton,
+ apr_pool_t *pool)
+{
+ cfg_section_t *sec;
+ apr_hash_index_t *opt_ndx;
+ apr_pool_t *iteration_pool;
+ int count;
+
+ find_option(cfg, section, NULL, &sec);
+ if (sec == NULL)
+ return 0;
+
+ iteration_pool = svn_pool_create(pool);
+ count = 0;
+ for (opt_ndx = apr_hash_first(pool, sec->options);
+ opt_ndx != NULL;
+ opt_ndx = apr_hash_next(opt_ndx))
+ {
+ void *opt_ptr;
+ cfg_option_t *opt;
+ const char *temp_value;
+
+ apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
+ opt = opt_ptr;
+
+ ++count;
+ make_string_from_option(&temp_value, cfg, sec, opt, NULL);
+ svn_pool_clear(iteration_pool);
+ if (!callback(opt->name, temp_value, baton, iteration_pool))
+ break;
+ }
+ svn_pool_destroy(iteration_pool);
+
+ return count;
+}
+
+
+
+/* Baton for search_groups() */
+struct search_groups_baton
+{
+ const char *key; /* Provided by caller of svn_config_find_group */
+ const char *match; /* Filled in by search_groups */
+ apr_pool_t *pool;
+};
+
+
+/* This is an `svn_config_enumerator_t' function, and BATON is a
+ * `struct search_groups_baton *'.
+ */
+static svn_boolean_t search_groups(const char *name,
+ const char *value,
+ void *baton,
+ apr_pool_t *pool)
+{
+ struct search_groups_baton *b = baton;
+ apr_array_header_t *list;
+
+ list = svn_cstring_split(value, ",", TRUE, pool);
+ if (svn_cstring_match_glob_list(b->key, list))
+ {
+ /* Fill in the match and return false, to stop enumerating. */
+ b->match = apr_pstrdup(b->pool, name);
+ return FALSE;
+ }
+ else
+ return TRUE;
+}
+
+
+const char *svn_config_find_group(svn_config_t *cfg, const char *key,
+ const char *master_section,
+ apr_pool_t *pool)
+{
+ struct search_groups_baton gb;
+
+ gb.key = key;
+ gb.match = NULL;
+ gb.pool = pool;
+ (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool);
+ return gb.match;
+}
+
+
+const char*
+svn_config_get_server_setting(svn_config_t *cfg,
+ const char* server_group,
+ const char* option_name,
+ const char* default_value)
+{
+ const char *retval;
+ svn_config_get(cfg, &retval, SVN_CONFIG_SECTION_GLOBAL,
+ option_name, default_value);
+ if (server_group)
+ {
+ svn_config_get(cfg, &retval, server_group, option_name, retval);
+ }
+ 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,
+ const char *option_name,
+ apr_int64_t default_value,
+ apr_int64_t *result_value,
+ apr_pool_t *pool)
+{
+ const char* tmp_value;
+ char *end_pos;
+
+ tmp_value = svn_config_get_server_setting(cfg, server_group,
+ option_name, NULL);
+ if (tmp_value == NULL)
+ *result_value = default_value;
+ else
+ {
+ /* read tmp_value as an int now */
+ *result_value = apr_strtoi64(tmp_value, &end_pos, 0);
+
+ if (*end_pos != 0)
+ {
+ return svn_error_createf
+ (SVN_ERR_BAD_CONFIG_VALUE, NULL,
+ _("Config error: invalid integer value '%s'"),
+ tmp_value);
+ }
+ }
+
+ return SVN_NO_ERROR;
+}
+
+svn_error_t *
+svn_config_get_server_setting_bool(svn_config_t *cfg,
+ svn_boolean_t *valuep,
+ const char *server_group,
+ const char *option_name,
+ svn_boolean_t default_value)
+{
+ const char* tmp_value;
+ tmp_value = svn_config_get_server_setting(cfg, server_group,
+ option_name, NULL);
+ return get_bool(valuep, tmp_value, default_value,
+ server_group, option_name);
+}
+
+
+svn_boolean_t
+svn_config_has_section(svn_config_t *cfg, const char *section)
+{
+ 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;
+}
OpenPOWER on IntegriCloud