diff options
Diffstat (limited to 'subversion/libsvn_subr/config.c')
-rw-r--r-- | subversion/libsvn_subr/config.c | 357 |
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, §key, §keyLength, §val); + 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; } |