1251881Speter/* 2251881Speter * config.c : reading configuration information 3251881Speter * 4251881Speter * ==================================================================== 5251881Speter * Licensed to the Apache Software Foundation (ASF) under one 6251881Speter * or more contributor license agreements. See the NOTICE file 7251881Speter * distributed with this work for additional information 8251881Speter * regarding copyright ownership. The ASF licenses this file 9251881Speter * to you under the Apache License, Version 2.0 (the 10251881Speter * "License"); you may not use this file except in compliance 11251881Speter * with the License. You may obtain a copy of the License at 12251881Speter * 13251881Speter * http://www.apache.org/licenses/LICENSE-2.0 14251881Speter * 15251881Speter * Unless required by applicable law or agreed to in writing, 16251881Speter * software distributed under the License is distributed on an 17251881Speter * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18251881Speter * KIND, either express or implied. See the License for the 19251881Speter * specific language governing permissions and limitations 20251881Speter * under the License. 21251881Speter * ==================================================================== 22251881Speter */ 23251881Speter 24251881Speter 25251881Speter 26289180Speter#include <assert.h> 27289180Speter 28251881Speter#define APR_WANT_STRFUNC 29251881Speter#define APR_WANT_MEMFUNC 30251881Speter#include <apr_want.h> 31251881Speter 32251881Speter#include <apr_general.h> 33251881Speter#include <apr_lib.h> 34251881Speter#include "svn_hash.h" 35251881Speter#include "svn_error.h" 36362181Sdim#include "svn_string.h" 37251881Speter#include "svn_pools.h" 38251881Speter#include "config_impl.h" 39251881Speter 40251881Speter#include "private/svn_dep_compat.h" 41289180Speter#include "private/svn_subr_private.h" 42362181Sdim#include "private/svn_config_private.h" 43251881Speter 44362181Sdim#include "svn_private_config.h" 45362181Sdim 46251881Speter 47251881Speter 48251881Speter 49251881Speter/* Section table entries. */ 50251881Spetertypedef struct cfg_section_t cfg_section_t; 51251881Speterstruct cfg_section_t 52251881Speter{ 53251881Speter /* The section name. */ 54251881Speter const char *name; 55251881Speter 56251881Speter /* Table of cfg_option_t's. */ 57251881Speter apr_hash_t *options; 58251881Speter}; 59251881Speter 60251881Speter 61362181Sdim/* States that a config option value can assume. */ 62362181Sdimtypedef enum option_state_t 63362181Sdim{ 64362181Sdim /* Value still needs to be expanded. 65362181Sdim This is the initial state for *all* values. */ 66362181Sdim option_state_needs_expanding, 67362181Sdim 68362181Sdim /* Value is currently being expanded. 69362181Sdim This transitional state allows for detecting cyclic dependencies. */ 70362181Sdim option_state_expanding, 71362181Sdim 72362181Sdim /* Expanded value is available. 73362181Sdim Values that never needed expanding directly go into that state 74362181Sdim skipping option_state_expanding. */ 75362181Sdim option_state_expanded, 76362181Sdim 77362181Sdim /* The value expansion is cyclic which results in "undefined" behavior. 78362181Sdim This is to return a defined value ("") in that case. */ 79362181Sdim option_state_cyclic 80362181Sdim} option_state_t; 81362181Sdim 82251881Speter/* Option table entries. */ 83251881Spetertypedef struct cfg_option_t cfg_option_t; 84251881Speterstruct cfg_option_t 85251881Speter{ 86251881Speter /* The option name. */ 87251881Speter const char *name; 88251881Speter 89251881Speter /* The option name, converted into a hash key. */ 90251881Speter const char *hash_key; 91251881Speter 92251881Speter /* The unexpanded option value. */ 93251881Speter const char *value; 94251881Speter 95251881Speter /* The expanded option value. */ 96251881Speter const char *x_value; 97251881Speter 98362181Sdim /* Expansion state. If this is option_state_expanded, VALUE has already 99362181Sdim been expanded. In this case, if x_value is NULL, no expansions were 100362181Sdim necessary, and value should be used directly. */ 101362181Sdim option_state_t state; 102251881Speter}; 103251881Speter 104251881Speter 105251881Speter 106251881Spetersvn_error_t * 107251881Spetersvn_config_create2(svn_config_t **cfgp, 108251881Speter svn_boolean_t section_names_case_sensitive, 109251881Speter svn_boolean_t option_names_case_sensitive, 110251881Speter apr_pool_t *result_pool) 111251881Speter{ 112251881Speter svn_config_t *cfg = apr_palloc(result_pool, sizeof(*cfg)); 113251881Speter 114362181Sdim cfg->sections = svn_hash__make(result_pool); 115251881Speter cfg->pool = result_pool; 116251881Speter cfg->x_pool = svn_pool_create(result_pool); 117251881Speter cfg->x_values = FALSE; 118251881Speter cfg->tmp_key = svn_stringbuf_create_empty(result_pool); 119251881Speter cfg->tmp_value = svn_stringbuf_create_empty(result_pool); 120251881Speter cfg->section_names_case_sensitive = section_names_case_sensitive; 121251881Speter cfg->option_names_case_sensitive = option_names_case_sensitive; 122289180Speter cfg->read_only = FALSE; 123251881Speter 124251881Speter *cfgp = cfg; 125251881Speter return SVN_NO_ERROR; 126251881Speter} 127251881Speter 128251881Spetersvn_error_t * 129251881Spetersvn_config_read3(svn_config_t **cfgp, const char *file, 130251881Speter svn_boolean_t must_exist, 131251881Speter svn_boolean_t section_names_case_sensitive, 132251881Speter svn_boolean_t option_names_case_sensitive, 133251881Speter apr_pool_t *result_pool) 134251881Speter{ 135251881Speter svn_config_t *cfg; 136251881Speter svn_error_t *err; 137251881Speter 138251881Speter SVN_ERR(svn_config_create2(&cfg, 139251881Speter section_names_case_sensitive, 140251881Speter option_names_case_sensitive, 141251881Speter result_pool)); 142251881Speter 143251881Speter /* Yes, this is platform-specific code in Subversion, but there's no 144251881Speter practical way to migrate it into APR, as it's simultaneously 145251881Speter Subversion-specific and Windows-specific. Even if we eventually 146251881Speter want to have APR offer a generic config-reading interface, it 147251881Speter makes sense to test it here first and migrate it later. */ 148251881Speter#ifdef WIN32 149251881Speter if (0 == strncmp(file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN)) 150251881Speter err = svn_config__parse_registry(cfg, file + SVN_REGISTRY_PREFIX_LEN, 151251881Speter must_exist, result_pool); 152251881Speter else 153251881Speter#endif /* WIN32 */ 154251881Speter err = svn_config__parse_file(cfg, file, must_exist, result_pool); 155251881Speter 156251881Speter if (err != SVN_NO_ERROR) 157251881Speter return err; 158251881Speter else 159251881Speter *cfgp = cfg; 160251881Speter 161251881Speter return SVN_NO_ERROR; 162251881Speter} 163251881Speter 164251881Spetersvn_error_t * 165362181Sdimsvn_config__default_add_value_fn(void *baton, 166362181Sdim svn_stringbuf_t *section, 167362181Sdim svn_stringbuf_t *option, 168362181Sdim svn_stringbuf_t *value) 169362181Sdim{ 170362181Sdim /* FIXME: We may as well propagate the known string sizes here. */ 171362181Sdim svn_config_set((svn_config_t *)baton, section->data, 172362181Sdim option->data, value->data); 173362181Sdim return SVN_NO_ERROR; 174362181Sdim} 175362181Sdim 176362181Sdimsvn_error_t * 177251881Spetersvn_config_parse(svn_config_t **cfgp, svn_stream_t *stream, 178251881Speter svn_boolean_t section_names_case_sensitive, 179251881Speter svn_boolean_t option_names_case_sensitive, 180251881Speter apr_pool_t *result_pool) 181251881Speter{ 182251881Speter svn_config_t *cfg; 183251881Speter svn_error_t *err; 184251881Speter apr_pool_t *scratch_pool = svn_pool_create(result_pool); 185251881Speter 186251881Speter err = svn_config_create2(&cfg, 187251881Speter section_names_case_sensitive, 188251881Speter option_names_case_sensitive, 189251881Speter result_pool); 190251881Speter 191251881Speter if (err == SVN_NO_ERROR) 192362181Sdim err = svn_config__parse_stream(stream, 193362181Sdim svn_config__constructor_create( 194362181Sdim NULL, NULL, 195362181Sdim svn_config__default_add_value_fn, 196362181Sdim scratch_pool), 197362181Sdim cfg, scratch_pool); 198251881Speter 199251881Speter if (err == SVN_NO_ERROR) 200251881Speter *cfgp = cfg; 201251881Speter 202251881Speter svn_pool_destroy(scratch_pool); 203251881Speter 204251881Speter return err; 205251881Speter} 206251881Speter 207251881Speter/* Read various configuration sources into *CFGP, in this order, with 208251881Speter * later reads overriding the results of earlier ones: 209251881Speter * 210251881Speter * 1. SYS_REGISTRY_PATH (only on Win32, but ignored if NULL) 211251881Speter * 212251881Speter * 2. SYS_FILE_PATH (everywhere, but ignored if NULL) 213251881Speter * 214251881Speter * 3. USR_REGISTRY_PATH (only on Win32, but ignored if NULL) 215251881Speter * 216251881Speter * 4. USR_FILE_PATH (everywhere, but ignored if NULL) 217251881Speter * 218251881Speter * Allocate *CFGP in POOL. Even if no configurations are read, 219251881Speter * allocate an empty *CFGP. 220251881Speter */ 221251881Speterstatic svn_error_t * 222251881Speterread_all(svn_config_t **cfgp, 223251881Speter const char *sys_registry_path, 224251881Speter const char *usr_registry_path, 225251881Speter const char *sys_file_path, 226251881Speter const char *usr_file_path, 227251881Speter apr_pool_t *pool) 228251881Speter{ 229251881Speter svn_boolean_t red_config = FALSE; /* "red" is the past tense of "read" */ 230251881Speter 231251881Speter /*** Read system-wide configurations first... ***/ 232251881Speter 233251881Speter#ifdef WIN32 234251881Speter if (sys_registry_path) 235251881Speter { 236289180Speter SVN_ERR(svn_config_read3(cfgp, sys_registry_path, FALSE, FALSE, FALSE, 237289180Speter pool)); 238251881Speter red_config = TRUE; 239251881Speter } 240251881Speter#endif /* WIN32 */ 241251881Speter 242251881Speter if (sys_file_path) 243251881Speter { 244251881Speter if (red_config) 245251881Speter SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE)); 246251881Speter else 247251881Speter { 248251881Speter SVN_ERR(svn_config_read3(cfgp, sys_file_path, 249251881Speter FALSE, FALSE, FALSE, pool)); 250251881Speter red_config = TRUE; 251251881Speter } 252251881Speter } 253251881Speter 254251881Speter /*** ...followed by per-user configurations. ***/ 255251881Speter 256251881Speter#ifdef WIN32 257251881Speter if (usr_registry_path) 258251881Speter { 259251881Speter if (red_config) 260251881Speter SVN_ERR(svn_config_merge(*cfgp, usr_registry_path, FALSE)); 261251881Speter else 262251881Speter { 263289180Speter SVN_ERR(svn_config_read3(cfgp, usr_registry_path, 264289180Speter FALSE, FALSE, FALSE, pool)); 265251881Speter red_config = TRUE; 266251881Speter } 267251881Speter } 268251881Speter#endif /* WIN32 */ 269251881Speter 270251881Speter if (usr_file_path) 271251881Speter { 272251881Speter if (red_config) 273251881Speter SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE)); 274251881Speter else 275251881Speter { 276251881Speter SVN_ERR(svn_config_read3(cfgp, usr_file_path, 277251881Speter FALSE, FALSE, FALSE, pool)); 278251881Speter red_config = TRUE; 279251881Speter } 280251881Speter } 281251881Speter 282251881Speter if (! red_config) 283251881Speter SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool)); 284251881Speter 285251881Speter return SVN_NO_ERROR; 286251881Speter} 287251881Speter 288251881Speter 289251881Speter/* CONFIG_DIR provides an override for the default behavior of reading 290251881Speter the default set of overlay files described by read_all()'s doc 291289180Speter string. Returns non-NULL *CFG or an error. */ 292251881Speterstatic svn_error_t * 293251881Speterget_category_config(svn_config_t **cfg, 294251881Speter const char *config_dir, 295251881Speter const char *category, 296251881Speter apr_pool_t *pool) 297251881Speter{ 298251881Speter const char *usr_reg_path = NULL, *sys_reg_path = NULL; 299251881Speter const char *usr_cfg_path, *sys_cfg_path; 300251881Speter svn_error_t *err = NULL; 301251881Speter 302251881Speter *cfg = NULL; 303251881Speter 304251881Speter if (! config_dir) 305251881Speter { 306251881Speter#ifdef WIN32 307251881Speter sys_reg_path = apr_pstrcat(pool, SVN_REGISTRY_SYS_CONFIG_PATH, 308289180Speter category, SVN_VA_NULL); 309251881Speter usr_reg_path = apr_pstrcat(pool, SVN_REGISTRY_USR_CONFIG_PATH, 310289180Speter category, SVN_VA_NULL); 311251881Speter#endif /* WIN32 */ 312251881Speter 313251881Speter err = svn_config__sys_config_path(&sys_cfg_path, category, pool); 314251881Speter if ((err) && (err->apr_err == SVN_ERR_BAD_FILENAME)) 315251881Speter { 316251881Speter sys_cfg_path = NULL; 317251881Speter svn_error_clear(err); 318251881Speter } 319251881Speter else if (err) 320251881Speter return err; 321251881Speter } 322251881Speter else 323251881Speter sys_cfg_path = NULL; 324251881Speter 325251881Speter SVN_ERR(svn_config_get_user_config_path(&usr_cfg_path, config_dir, category, 326251881Speter pool)); 327251881Speter return read_all(cfg, sys_reg_path, usr_reg_path, 328251881Speter sys_cfg_path, usr_cfg_path, pool); 329251881Speter} 330251881Speter 331251881Speter 332251881Spetersvn_error_t * 333251881Spetersvn_config_get_config(apr_hash_t **cfg_hash, 334251881Speter const char *config_dir, 335251881Speter apr_pool_t *pool) 336251881Speter{ 337251881Speter svn_config_t *cfg; 338362181Sdim *cfg_hash = svn_hash__make(pool); 339251881Speter 340251881Speter SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_SERVERS, 341251881Speter pool)); 342289180Speter svn_hash_sets(*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, cfg); 343251881Speter 344251881Speter SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_CONFIG, 345251881Speter pool)); 346289180Speter svn_hash_sets(*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, cfg); 347251881Speter 348251881Speter return SVN_NO_ERROR; 349251881Speter} 350251881Speter 351289180Spetersvn_error_t * 352289180Spetersvn_config__get_default_config(apr_hash_t **cfg_hash, 353289180Speter apr_pool_t *pool) 354289180Speter{ 355289180Speter svn_config_t *empty_cfg; 356362181Sdim *cfg_hash = svn_hash__make(pool); 357251881Speter 358289180Speter SVN_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool)); 359289180Speter svn_hash_sets(*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, empty_cfg); 360289180Speter 361289180Speter SVN_ERR(svn_config_create2(&empty_cfg, FALSE, FALSE, pool)); 362289180Speter svn_hash_sets(*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, empty_cfg); 363289180Speter 364289180Speter return SVN_NO_ERROR; 365289180Speter} 366289180Speter 367289180Speter 368251881Speter 369251881Speter/* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION) 370251881Speter pair. Stop if CALLBACK returns TRUE. Allocate from POOL. */ 371251881Speterstatic void 372251881Speterfor_each_option(svn_config_t *cfg, void *baton, apr_pool_t *pool, 373251881Speter svn_boolean_t callback(void *same_baton, 374251881Speter cfg_section_t *section, 375251881Speter cfg_option_t *option)) 376251881Speter{ 377251881Speter apr_hash_index_t *sec_ndx; 378251881Speter for (sec_ndx = apr_hash_first(pool, cfg->sections); 379251881Speter sec_ndx != NULL; 380251881Speter sec_ndx = apr_hash_next(sec_ndx)) 381251881Speter { 382362181Sdim cfg_section_t *sec = apr_hash_this_val(sec_ndx); 383251881Speter apr_hash_index_t *opt_ndx; 384251881Speter 385251881Speter for (opt_ndx = apr_hash_first(pool, sec->options); 386251881Speter opt_ndx != NULL; 387251881Speter opt_ndx = apr_hash_next(opt_ndx)) 388251881Speter { 389362181Sdim cfg_option_t *opt = apr_hash_this_val(opt_ndx); 390251881Speter 391251881Speter if (callback(baton, sec, opt)) 392251881Speter return; 393251881Speter } 394251881Speter } 395251881Speter} 396251881Speter 397251881Speter 398251881Speter 399251881Speterstatic svn_boolean_t 400251881Spetermerge_callback(void *baton, cfg_section_t *section, cfg_option_t *option) 401251881Speter{ 402251881Speter svn_config_set(baton, section->name, option->name, option->value); 403251881Speter return FALSE; 404251881Speter} 405251881Speter 406251881Spetersvn_error_t * 407251881Spetersvn_config_merge(svn_config_t *cfg, const char *file, 408251881Speter svn_boolean_t must_exist) 409251881Speter{ 410251881Speter /* The original config hash shouldn't change if there's an error 411251881Speter while reading the confguration, so read into a temporary table. 412251881Speter ### We could use a tmp subpool for this, since merge_cfg is going 413251881Speter to be tossed afterwards. Premature optimization, though? */ 414251881Speter svn_config_t *merge_cfg; 415251881Speter SVN_ERR(svn_config_read3(&merge_cfg, file, must_exist, 416251881Speter cfg->section_names_case_sensitive, 417251881Speter cfg->option_names_case_sensitive, 418251881Speter cfg->pool)); 419251881Speter 420251881Speter /* Now copy the new options into the original table. */ 421251881Speter for_each_option(merge_cfg, cfg, merge_cfg->pool, merge_callback); 422251881Speter return SVN_NO_ERROR; 423251881Speter} 424251881Speter 425251881Speter 426251881Speter 427251881Speter/* Remove variable expansions from CFG. Walk through the options tree, 428251881Speter killing all expanded values, then clear the expanded value pool. */ 429251881Speterstatic svn_boolean_t 430251881Speterrmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option) 431251881Speter{ 432362181Sdim /* Only reset the expansion state if the value actually contains 433251881Speter variable expansions. */ 434362181Sdim if ( (option->state == option_state_expanded && option->x_value != NULL) 435362181Sdim || option->state == option_state_cyclic) 436251881Speter { 437251881Speter option->x_value = NULL; 438362181Sdim option->state = option_state_needs_expanding; 439251881Speter } 440251881Speter 441251881Speter return FALSE; 442251881Speter} 443251881Speter 444251881Speterstatic void 445251881Speterremove_expansions(svn_config_t *cfg) 446251881Speter{ 447251881Speter if (!cfg->x_values) 448251881Speter return; 449251881Speter 450251881Speter for_each_option(cfg, NULL, cfg->x_pool, rmex_callback); 451251881Speter svn_pool_clear(cfg->x_pool); 452251881Speter cfg->x_values = FALSE; 453251881Speter} 454251881Speter 455251881Speter 456251881Speter 457251881Speter/* Canonicalize a string for hashing. Modifies KEY in place. */ 458251881Speterstatic APR_INLINE char * 459251881Spetermake_hash_key(char *key) 460251881Speter{ 461251881Speter register char *p; 462251881Speter for (p = key; *p != 0; ++p) 463251881Speter *p = (char)apr_tolower(*p); 464251881Speter return key; 465251881Speter} 466251881Speter 467289180Speter/* Return the value for KEY in HASH. If CASE_SENSITIVE is FALSE, 468289180Speter BUFFER will be used to construct the normalized hash key. */ 469289180Speterstatic void * 470289180Speterget_hash_value(apr_hash_t *hash, 471289180Speter svn_stringbuf_t *buffer, 472289180Speter const char *key, 473289180Speter svn_boolean_t case_sensitive) 474289180Speter{ 475289180Speter apr_size_t i; 476289180Speter apr_size_t len = strlen(key); 477251881Speter 478289180Speter if (case_sensitive) 479289180Speter return apr_hash_get(hash, key, len); 480289180Speter 481289180Speter svn_stringbuf_ensure(buffer, len); 482289180Speter for (i = 0; i < len; ++i) 483289180Speter buffer->data[i] = (char)apr_tolower(key[i]); 484289180Speter 485289180Speter return apr_hash_get(hash, buffer->data, len); 486289180Speter} 487289180Speter 488251881Speter/* Return a pointer to an option in CFG, or NULL if it doesn't exist. 489251881Speter if SECTIONP is non-null, return a pointer to the option's section. 490251881Speter OPTION may be NULL. */ 491251881Speterstatic cfg_option_t * 492251881Speterfind_option(svn_config_t *cfg, const char *section, const char *option, 493251881Speter cfg_section_t **sectionp) 494251881Speter{ 495289180Speter void *sec_ptr = get_hash_value(cfg->sections, cfg->tmp_key, section, 496289180Speter cfg->section_names_case_sensitive); 497251881Speter if (sectionp != NULL) 498251881Speter *sectionp = sec_ptr; 499251881Speter 500251881Speter if (sec_ptr != NULL && option != NULL) 501251881Speter { 502251881Speter cfg_section_t *sec = sec_ptr; 503289180Speter cfg_option_t *opt = get_hash_value(sec->options, cfg->tmp_key, option, 504289180Speter cfg->option_names_case_sensitive); 505251881Speter /* NOTE: ConfigParser's sections are case sensitive. */ 506251881Speter if (opt == NULL 507251881Speter && apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0) 508251881Speter /* Options which aren't found in the requested section are 509251881Speter also sought after in the default section. */ 510251881Speter opt = find_option(cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec); 511251881Speter return opt; 512251881Speter } 513251881Speter 514251881Speter return NULL; 515251881Speter} 516251881Speter 517251881Speter 518251881Speter/* Has a bi-directional dependency with make_string_from_option(). */ 519362181Sdimstatic svn_boolean_t 520251881Speterexpand_option_value(svn_config_t *cfg, cfg_section_t *section, 521251881Speter const char *opt_value, const char **opt_x_valuep, 522251881Speter apr_pool_t *x_pool); 523251881Speter 524251881Speter 525251881Speter/* Set *VALUEP according to the OPT's value. A value for X_POOL must 526251881Speter only ever be passed into this function by expand_option_value(). */ 527251881Speterstatic void 528251881Spetermake_string_from_option(const char **valuep, svn_config_t *cfg, 529251881Speter cfg_section_t *section, cfg_option_t *opt, 530251881Speter apr_pool_t* x_pool) 531251881Speter{ 532251881Speter /* Expand the option value if necessary. */ 533362181Sdim if ( opt->state == option_state_expanding 534362181Sdim || opt->state == option_state_cyclic) 535251881Speter { 536362181Sdim /* Recursion is not supported. Since we can't produce an error 537362181Sdim * nor should we abort the process, the next best thing is to 538362181Sdim * report the recursive part as an empty string. */ 539362181Sdim *valuep = ""; 540362181Sdim 541362181Sdim /* Go into "value undefined" state. */ 542362181Sdim opt->state = option_state_cyclic; 543362181Sdim 544362181Sdim return; 545362181Sdim } 546362181Sdim else if (opt->state == option_state_needs_expanding) 547362181Sdim { 548251881Speter /* before attempting to expand an option, check for the placeholder. 549251881Speter * If none is there, there is no point in calling expand_option_value. 550251881Speter */ 551251881Speter if (opt->value && strchr(opt->value, '%')) 552251881Speter { 553289180Speter apr_pool_t *tmp_pool; 554251881Speter 555289180Speter /* setting read-only mode should have expanded all values 556289180Speter * automatically. */ 557289180Speter assert(!cfg->read_only); 558289180Speter 559289180Speter tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool)); 560289180Speter 561362181Sdim /* Expand the value. During that process, have the option marked 562362181Sdim * as "expanding" to detect cycles. */ 563362181Sdim opt->state = option_state_expanding; 564362181Sdim if (expand_option_value(cfg, section, opt->value, &opt->x_value, 565362181Sdim tmp_pool)) 566362181Sdim opt->state = option_state_expanded; 567362181Sdim else 568362181Sdim opt->state = option_state_cyclic; 569251881Speter 570362181Sdim /* Ensure the expanded value is allocated in a permanent pool. */ 571286506Speter if (x_pool != cfg->x_pool) 572251881Speter { 573251881Speter /* Grab the fully expanded value from tmp_pool before its 574251881Speter disappearing act. */ 575251881Speter if (opt->x_value) 576251881Speter opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value, 577251881Speter strlen(opt->x_value)); 578286506Speter if (!x_pool) 579286506Speter svn_pool_destroy(tmp_pool); 580251881Speter } 581251881Speter } 582251881Speter else 583251881Speter { 584362181Sdim opt->state = option_state_expanded; 585251881Speter } 586251881Speter } 587251881Speter 588251881Speter if (opt->x_value) 589251881Speter *valuep = opt->x_value; 590251881Speter else 591251881Speter *valuep = opt->value; 592251881Speter} 593251881Speter 594251881Speter 595251881Speter/* Start of variable-replacement placeholder */ 596251881Speter#define FMT_START "%(" 597251881Speter#define FMT_START_LEN (sizeof(FMT_START) - 1) 598251881Speter 599251881Speter/* End of variable-replacement placeholder */ 600251881Speter#define FMT_END ")s" 601251881Speter#define FMT_END_LEN (sizeof(FMT_END) - 1) 602251881Speter 603251881Speter 604251881Speter/* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP. 605251881Speter If no variable replacements are done, set *OPT_X_VALUEP to 606362181Sdim NULL. Return TRUE if the expanded value is defined and FALSE 607362181Sdim for recursive definitions. Allocate from X_POOL. */ 608362181Sdimstatic svn_boolean_t 609251881Speterexpand_option_value(svn_config_t *cfg, cfg_section_t *section, 610251881Speter const char *opt_value, const char **opt_x_valuep, 611251881Speter apr_pool_t *x_pool) 612251881Speter{ 613251881Speter svn_stringbuf_t *buf = NULL; 614251881Speter const char *parse_from = opt_value; 615251881Speter const char *copy_from = parse_from; 616251881Speter const char *name_start, *name_end; 617251881Speter 618251881Speter while (parse_from != NULL 619251881Speter && *parse_from != '\0' 620251881Speter && (name_start = strstr(parse_from, FMT_START)) != NULL) 621251881Speter { 622251881Speter name_start += FMT_START_LEN; 623251881Speter if (*name_start == '\0') 624251881Speter /* FMT_START at end of opt_value. */ 625251881Speter break; 626251881Speter 627251881Speter name_end = strstr(name_start, FMT_END); 628251881Speter if (name_end != NULL) 629251881Speter { 630251881Speter cfg_option_t *x_opt; 631251881Speter apr_size_t len = name_end - name_start; 632251881Speter char *name = apr_pstrmemdup(x_pool, name_start, len); 633251881Speter 634251881Speter x_opt = find_option(cfg, section->name, name, NULL); 635251881Speter 636251881Speter if (x_opt != NULL) 637251881Speter { 638251881Speter const char *cstring; 639251881Speter 640251881Speter /* Pass back the sub-pool originally provided by 641251881Speter make_string_from_option() as an indication of when it 642251881Speter should terminate. */ 643251881Speter make_string_from_option(&cstring, cfg, section, x_opt, x_pool); 644251881Speter 645362181Sdim /* Values depending on cyclic values must also be marked as 646362181Sdim * "undefined" because they might themselves form cycles with 647362181Sdim * the one cycle we just detected. Due to the early abort of 648362181Sdim * the recursion, we won't follow and thus detect dependent 649362181Sdim * cycles anymore. 650362181Sdim */ 651362181Sdim if (x_opt->state == option_state_cyclic) 652362181Sdim { 653362181Sdim *opt_x_valuep = ""; 654362181Sdim return FALSE; 655362181Sdim } 656362181Sdim 657251881Speter /* Append the plain text preceding the expansion. */ 658251881Speter len = name_start - FMT_START_LEN - copy_from; 659251881Speter if (buf == NULL) 660251881Speter { 661251881Speter buf = svn_stringbuf_ncreate(copy_from, len, x_pool); 662251881Speter cfg->x_values = TRUE; 663251881Speter } 664251881Speter else 665251881Speter svn_stringbuf_appendbytes(buf, copy_from, len); 666251881Speter 667251881Speter /* Append the expansion and adjust parse pointers. */ 668251881Speter svn_stringbuf_appendcstr(buf, cstring); 669251881Speter parse_from = name_end + FMT_END_LEN; 670251881Speter copy_from = parse_from; 671251881Speter } 672251881Speter else 673251881Speter /* Though ConfigParser considers the failure to resolve 674251881Speter the requested expansion an exception condition, we 675251881Speter consider it to be plain text, and look for the start of 676251881Speter the next one. */ 677251881Speter parse_from = name_end + FMT_END_LEN; 678251881Speter } 679251881Speter else 680251881Speter /* Though ConfigParser treats unterminated format specifiers 681251881Speter as an exception condition, we consider them to be plain 682251881Speter text. The fact that there are no more format specifier 683251881Speter endings means we're done parsing. */ 684251881Speter parse_from = NULL; 685251881Speter } 686251881Speter 687251881Speter if (buf != NULL) 688251881Speter { 689251881Speter /* Copy the remainder of the plain text. */ 690251881Speter svn_stringbuf_appendcstr(buf, copy_from); 691251881Speter *opt_x_valuep = buf->data; 692251881Speter } 693251881Speter else 694251881Speter *opt_x_valuep = NULL; 695362181Sdim 696362181Sdim /* Expansion has a well-defined answer. */ 697362181Sdim return TRUE; 698251881Speter} 699251881Speter 700251881Speterstatic cfg_section_t * 701251881Spetersvn_config_addsection(svn_config_t *cfg, 702251881Speter const char *section) 703251881Speter{ 704251881Speter cfg_section_t *s; 705251881Speter const char *hash_key; 706251881Speter 707251881Speter s = apr_palloc(cfg->pool, sizeof(cfg_section_t)); 708251881Speter s->name = apr_pstrdup(cfg->pool, section); 709251881Speter if(cfg->section_names_case_sensitive) 710251881Speter hash_key = s->name; 711251881Speter else 712251881Speter hash_key = make_hash_key(apr_pstrdup(cfg->pool, section)); 713362181Sdim s->options = svn_hash__make(cfg->pool); 714362181Sdim 715251881Speter svn_hash_sets(cfg->sections, hash_key, s); 716251881Speter 717251881Speter return s; 718251881Speter} 719251881Speter 720251881Speterstatic void 721251881Spetersvn_config_create_option(cfg_option_t **opt, 722251881Speter const char *option, 723251881Speter const char *value, 724251881Speter svn_boolean_t option_names_case_sensitive, 725251881Speter apr_pool_t *pool) 726251881Speter{ 727251881Speter cfg_option_t *o; 728251881Speter 729251881Speter o = apr_palloc(pool, sizeof(cfg_option_t)); 730251881Speter o->name = apr_pstrdup(pool, option); 731251881Speter if(option_names_case_sensitive) 732251881Speter o->hash_key = o->name; 733251881Speter else 734251881Speter o->hash_key = make_hash_key(apr_pstrdup(pool, option)); 735251881Speter 736251881Speter o->value = apr_pstrdup(pool, value); 737251881Speter o->x_value = NULL; 738362181Sdim o->state = option_state_needs_expanding; 739251881Speter 740251881Speter *opt = o; 741251881Speter} 742251881Speter 743289180Spetersvn_boolean_t 744289180Spetersvn_config__is_expanded(svn_config_t *cfg, 745289180Speter const char *section, 746289180Speter const char *option) 747289180Speter{ 748289180Speter cfg_option_t *opt; 749289180Speter 750289180Speter if (cfg == NULL) 751289180Speter return FALSE; 752289180Speter 753289180Speter /* does the option even exist? */ 754289180Speter opt = find_option(cfg, section, option, NULL); 755289180Speter if (opt == NULL) 756289180Speter return FALSE; 757289180Speter 758289180Speter /* already expanded? */ 759362181Sdim if ( opt->state == option_state_expanded 760362181Sdim || opt->state == option_state_cyclic) 761289180Speter return TRUE; 762289180Speter 763289180Speter /* needs expansion? */ 764289180Speter if (opt->value && strchr(opt->value, '%')) 765289180Speter return FALSE; 766289180Speter 767289180Speter /* no expansion necessary */ 768289180Speter return TRUE; 769289180Speter} 770289180Speter 771251881Speter 772251881Spetervoid 773251881Spetersvn_config_get(svn_config_t *cfg, const char **valuep, 774251881Speter const char *section, const char *option, 775251881Speter const char *default_value) 776251881Speter{ 777251881Speter *valuep = default_value; 778251881Speter if (cfg) 779251881Speter { 780251881Speter cfg_section_t *sec; 781251881Speter cfg_option_t *opt = find_option(cfg, section, option, &sec); 782251881Speter if (opt != NULL) 783251881Speter { 784251881Speter make_string_from_option(valuep, cfg, sec, opt, NULL); 785251881Speter } 786251881Speter else 787251881Speter /* before attempting to expand an option, check for the placeholder. 788289180Speter * If there is none, there is no point in calling expand_option_value. 789251881Speter */ 790251881Speter if (default_value && strchr(default_value, '%')) 791251881Speter { 792289180Speter apr_pool_t *tmp_pool = svn_pool_create(cfg->pool); 793251881Speter const char *x_default; 794362181Sdim if (!expand_option_value(cfg, sec, default_value, &x_default, 795362181Sdim tmp_pool)) 796251881Speter { 797362181Sdim /* Recursive definitions are not supported. 798362181Sdim Normalize the answer in that case. */ 799362181Sdim *valuep = ""; 800362181Sdim } 801362181Sdim else if (x_default) 802362181Sdim { 803251881Speter svn_stringbuf_set(cfg->tmp_value, x_default); 804251881Speter *valuep = cfg->tmp_value->data; 805251881Speter } 806251881Speter svn_pool_destroy(tmp_pool); 807251881Speter } 808251881Speter } 809251881Speter} 810251881Speter 811251881Speter 812251881Speter 813251881Spetervoid 814251881Spetersvn_config_set(svn_config_t *cfg, 815251881Speter const char *section, const char *option, 816251881Speter const char *value) 817251881Speter{ 818251881Speter cfg_section_t *sec; 819251881Speter cfg_option_t *opt; 820251881Speter 821289180Speter /* Ignore write attempts to r/o configurations. 822289180Speter * 823289180Speter * Since we should never try to modify r/o data, trigger an assertion 824289180Speter * in debug mode. 825289180Speter */ 826289180Speter#ifdef SVN_DEBUG 827289180Speter SVN_ERR_ASSERT_NO_RETURN(!cfg->read_only); 828289180Speter#endif 829289180Speter if (cfg->read_only) 830289180Speter return; 831289180Speter 832251881Speter remove_expansions(cfg); 833251881Speter 834251881Speter opt = find_option(cfg, section, option, &sec); 835251881Speter if (opt != NULL) 836251881Speter { 837251881Speter /* Replace the option's value. */ 838251881Speter opt->value = apr_pstrdup(cfg->pool, value); 839362181Sdim opt->state = option_state_needs_expanding; 840251881Speter return; 841251881Speter } 842251881Speter 843251881Speter /* Create a new option */ 844251881Speter svn_config_create_option(&opt, option, value, 845251881Speter cfg->option_names_case_sensitive, 846251881Speter cfg->pool); 847251881Speter 848251881Speter if (sec == NULL) 849251881Speter { 850251881Speter /* Even the section doesn't exist. Create it. */ 851251881Speter sec = svn_config_addsection(cfg, section); 852251881Speter } 853251881Speter 854251881Speter svn_hash_sets(sec->options, opt->hash_key, opt); 855251881Speter} 856251881Speter 857251881Speter 858251881Speter 859251881Speter/* Set *BOOLP to true or false depending (case-insensitively) on INPUT. 860251881Speter If INPUT is null, set *BOOLP to DEFAULT_VALUE. 861251881Speter 862251881Speter INPUT is a string indicating truth or falsehood in any of the usual 863251881Speter ways: "true"/"yes"/"on"/etc, "false"/"no"/"off"/etc. 864251881Speter 865251881Speter If INPUT is neither NULL nor a recognized string, return an error 866251881Speter with code SVN_ERR_BAD_CONFIG_VALUE; use SECTION and OPTION in 867251881Speter constructing the error string. */ 868251881Speterstatic svn_error_t * 869251881Speterget_bool(svn_boolean_t *boolp, const char *input, svn_boolean_t default_value, 870251881Speter const char *section, const char *option) 871251881Speter{ 872251881Speter svn_tristate_t value = svn_tristate__from_word(input); 873251881Speter 874251881Speter if (value == svn_tristate_true) 875251881Speter *boolp = TRUE; 876251881Speter else if (value == svn_tristate_false) 877251881Speter *boolp = FALSE; 878251881Speter else if (input == NULL) /* no value provided */ 879251881Speter *boolp = default_value; 880251881Speter 881251881Speter else if (section) /* unrecognized value */ 882251881Speter return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 883251881Speter _("Config error: invalid boolean " 884251881Speter "value '%s' for '[%s] %s'"), 885251881Speter input, section, option); 886251881Speter else 887251881Speter return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 888251881Speter _("Config error: invalid boolean " 889251881Speter "value '%s' for '%s'"), 890251881Speter input, option); 891251881Speter 892251881Speter return SVN_NO_ERROR; 893251881Speter} 894251881Speter 895251881Speter 896251881Spetersvn_error_t * 897251881Spetersvn_config_get_bool(svn_config_t *cfg, svn_boolean_t *valuep, 898251881Speter const char *section, const char *option, 899251881Speter svn_boolean_t default_value) 900251881Speter{ 901251881Speter const char *tmp_value; 902251881Speter svn_config_get(cfg, &tmp_value, section, option, NULL); 903251881Speter return get_bool(valuep, tmp_value, default_value, section, option); 904251881Speter} 905251881Speter 906251881Speter 907251881Speter 908251881Spetervoid 909251881Spetersvn_config_set_bool(svn_config_t *cfg, 910251881Speter const char *section, const char *option, 911251881Speter svn_boolean_t value) 912251881Speter{ 913251881Speter svn_config_set(cfg, section, option, 914251881Speter (value ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE)); 915251881Speter} 916251881Speter 917251881Spetersvn_error_t * 918251881Spetersvn_config_get_int64(svn_config_t *cfg, 919251881Speter apr_int64_t *valuep, 920251881Speter const char *section, 921251881Speter const char *option, 922251881Speter apr_int64_t default_value) 923251881Speter{ 924251881Speter const char *tmp_value; 925251881Speter svn_config_get(cfg, &tmp_value, section, option, NULL); 926251881Speter if (tmp_value) 927251881Speter return svn_cstring_strtoi64(valuep, tmp_value, 928251881Speter APR_INT64_MIN, APR_INT64_MAX, 10); 929251881Speter 930251881Speter *valuep = default_value; 931251881Speter return SVN_NO_ERROR; 932251881Speter} 933251881Speter 934251881Spetervoid 935251881Spetersvn_config_set_int64(svn_config_t *cfg, 936251881Speter const char *section, 937251881Speter const char *option, 938251881Speter apr_int64_t value) 939251881Speter{ 940251881Speter svn_config_set(cfg, section, option, 941251881Speter apr_psprintf(cfg->pool, "%" APR_INT64_T_FMT, value)); 942251881Speter} 943251881Speter 944251881Spetersvn_error_t * 945251881Spetersvn_config_get_yes_no_ask(svn_config_t *cfg, const char **valuep, 946251881Speter const char *section, const char *option, 947251881Speter const char* default_value) 948251881Speter{ 949251881Speter const char *tmp_value; 950251881Speter 951251881Speter svn_config_get(cfg, &tmp_value, section, option, NULL); 952251881Speter 953251881Speter if (! tmp_value) 954251881Speter tmp_value = default_value; 955251881Speter 956251881Speter if (tmp_value && (0 == svn_cstring_casecmp(tmp_value, SVN_CONFIG_ASK))) 957251881Speter { 958251881Speter *valuep = SVN_CONFIG_ASK; 959251881Speter } 960251881Speter else 961251881Speter { 962251881Speter svn_boolean_t bool_val; 963251881Speter /* We already incorporated default_value into tmp_value if 964251881Speter necessary, so the FALSE below will be ignored unless the 965251881Speter caller is doing something it shouldn't be doing. */ 966251881Speter SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option)); 967251881Speter *valuep = bool_val ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE; 968251881Speter } 969251881Speter 970251881Speter return SVN_NO_ERROR; 971251881Speter} 972251881Speter 973251881Spetersvn_error_t * 974251881Spetersvn_config_get_tristate(svn_config_t *cfg, svn_tristate_t *valuep, 975251881Speter const char *section, const char *option, 976251881Speter const char *unknown_value, 977251881Speter svn_tristate_t default_value) 978251881Speter{ 979251881Speter const char *tmp_value; 980251881Speter 981251881Speter svn_config_get(cfg, &tmp_value, section, option, NULL); 982251881Speter 983251881Speter if (! tmp_value) 984251881Speter { 985251881Speter *valuep = default_value; 986251881Speter } 987251881Speter else if (0 == svn_cstring_casecmp(tmp_value, unknown_value)) 988251881Speter { 989251881Speter *valuep = svn_tristate_unknown; 990251881Speter } 991251881Speter else 992251881Speter { 993251881Speter svn_boolean_t bool_val; 994251881Speter /* We already incorporated default_value into tmp_value if 995251881Speter necessary, so the FALSE below will be ignored unless the 996251881Speter caller is doing something it shouldn't be doing. */ 997251881Speter SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option)); 998251881Speter *valuep = bool_val ? svn_tristate_true : svn_tristate_false; 999251881Speter } 1000251881Speter 1001251881Speter return SVN_NO_ERROR; 1002251881Speter} 1003251881Speter 1004251881Speterint 1005251881Spetersvn_config_enumerate_sections(svn_config_t *cfg, 1006251881Speter svn_config_section_enumerator_t callback, 1007251881Speter void *baton) 1008251881Speter{ 1009251881Speter apr_hash_index_t *sec_ndx; 1010251881Speter int count = 0; 1011251881Speter apr_pool_t *subpool = svn_pool_create(cfg->x_pool); 1012251881Speter 1013251881Speter for (sec_ndx = apr_hash_first(subpool, cfg->sections); 1014251881Speter sec_ndx != NULL; 1015251881Speter sec_ndx = apr_hash_next(sec_ndx)) 1016251881Speter { 1017251881Speter void *sec_ptr; 1018251881Speter cfg_section_t *sec; 1019251881Speter 1020251881Speter apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); 1021251881Speter sec = sec_ptr; 1022251881Speter ++count; 1023251881Speter if (!callback(sec->name, baton)) 1024251881Speter break; 1025251881Speter } 1026251881Speter 1027251881Speter svn_pool_destroy(subpool); 1028251881Speter return count; 1029251881Speter} 1030251881Speter 1031251881Speter 1032251881Speterint 1033251881Spetersvn_config_enumerate_sections2(svn_config_t *cfg, 1034251881Speter svn_config_section_enumerator2_t callback, 1035251881Speter void *baton, apr_pool_t *pool) 1036251881Speter{ 1037251881Speter apr_hash_index_t *sec_ndx; 1038251881Speter apr_pool_t *iteration_pool; 1039251881Speter int count = 0; 1040251881Speter 1041251881Speter iteration_pool = svn_pool_create(pool); 1042251881Speter for (sec_ndx = apr_hash_first(pool, cfg->sections); 1043251881Speter sec_ndx != NULL; 1044251881Speter sec_ndx = apr_hash_next(sec_ndx)) 1045251881Speter { 1046362181Sdim cfg_section_t *sec = apr_hash_this_val(sec_ndx); 1047251881Speter 1048251881Speter ++count; 1049251881Speter svn_pool_clear(iteration_pool); 1050251881Speter if (!callback(sec->name, baton, iteration_pool)) 1051251881Speter break; 1052251881Speter } 1053251881Speter svn_pool_destroy(iteration_pool); 1054251881Speter 1055251881Speter return count; 1056251881Speter} 1057251881Speter 1058251881Speter 1059251881Speter 1060251881Speterint 1061251881Spetersvn_config_enumerate(svn_config_t *cfg, const char *section, 1062251881Speter svn_config_enumerator_t callback, void *baton) 1063251881Speter{ 1064251881Speter cfg_section_t *sec; 1065251881Speter apr_hash_index_t *opt_ndx; 1066251881Speter int count; 1067251881Speter apr_pool_t *subpool; 1068251881Speter 1069251881Speter find_option(cfg, section, NULL, &sec); 1070251881Speter if (sec == NULL) 1071251881Speter return 0; 1072251881Speter 1073289180Speter subpool = svn_pool_create(cfg->pool); 1074251881Speter count = 0; 1075251881Speter for (opt_ndx = apr_hash_first(subpool, sec->options); 1076251881Speter opt_ndx != NULL; 1077251881Speter opt_ndx = apr_hash_next(opt_ndx)) 1078251881Speter { 1079362181Sdim cfg_option_t *opt = apr_hash_this_val(opt_ndx); 1080251881Speter const char *temp_value; 1081251881Speter 1082251881Speter ++count; 1083251881Speter make_string_from_option(&temp_value, cfg, sec, opt, NULL); 1084251881Speter if (!callback(opt->name, temp_value, baton)) 1085251881Speter break; 1086251881Speter } 1087251881Speter 1088251881Speter svn_pool_destroy(subpool); 1089251881Speter return count; 1090251881Speter} 1091251881Speter 1092251881Speter 1093251881Speterint 1094251881Spetersvn_config_enumerate2(svn_config_t *cfg, const char *section, 1095251881Speter svn_config_enumerator2_t callback, void *baton, 1096251881Speter apr_pool_t *pool) 1097251881Speter{ 1098251881Speter cfg_section_t *sec; 1099251881Speter apr_hash_index_t *opt_ndx; 1100251881Speter apr_pool_t *iteration_pool; 1101251881Speter int count; 1102251881Speter 1103251881Speter find_option(cfg, section, NULL, &sec); 1104251881Speter if (sec == NULL) 1105251881Speter return 0; 1106251881Speter 1107251881Speter iteration_pool = svn_pool_create(pool); 1108251881Speter count = 0; 1109251881Speter for (opt_ndx = apr_hash_first(pool, sec->options); 1110251881Speter opt_ndx != NULL; 1111251881Speter opt_ndx = apr_hash_next(opt_ndx)) 1112251881Speter { 1113362181Sdim cfg_option_t *opt = apr_hash_this_val(opt_ndx); 1114251881Speter const char *temp_value; 1115251881Speter 1116251881Speter ++count; 1117251881Speter make_string_from_option(&temp_value, cfg, sec, opt, NULL); 1118251881Speter svn_pool_clear(iteration_pool); 1119251881Speter if (!callback(opt->name, temp_value, baton, iteration_pool)) 1120251881Speter break; 1121251881Speter } 1122251881Speter svn_pool_destroy(iteration_pool); 1123251881Speter 1124251881Speter return count; 1125251881Speter} 1126251881Speter 1127251881Speter 1128251881Speter 1129251881Speter/* Baton for search_groups() */ 1130251881Speterstruct search_groups_baton 1131251881Speter{ 1132251881Speter const char *key; /* Provided by caller of svn_config_find_group */ 1133251881Speter const char *match; /* Filled in by search_groups */ 1134251881Speter apr_pool_t *pool; 1135251881Speter}; 1136251881Speter 1137251881Speter 1138251881Speter/* This is an `svn_config_enumerator_t' function, and BATON is a 1139251881Speter * `struct search_groups_baton *'. 1140251881Speter */ 1141251881Speterstatic svn_boolean_t search_groups(const char *name, 1142251881Speter const char *value, 1143251881Speter void *baton, 1144251881Speter apr_pool_t *pool) 1145251881Speter{ 1146251881Speter struct search_groups_baton *b = baton; 1147251881Speter apr_array_header_t *list; 1148251881Speter 1149251881Speter list = svn_cstring_split(value, ",", TRUE, pool); 1150251881Speter if (svn_cstring_match_glob_list(b->key, list)) 1151251881Speter { 1152251881Speter /* Fill in the match and return false, to stop enumerating. */ 1153251881Speter b->match = apr_pstrdup(b->pool, name); 1154251881Speter return FALSE; 1155251881Speter } 1156251881Speter else 1157251881Speter return TRUE; 1158251881Speter} 1159251881Speter 1160251881Speter 1161251881Speterconst char *svn_config_find_group(svn_config_t *cfg, const char *key, 1162251881Speter const char *master_section, 1163251881Speter apr_pool_t *pool) 1164251881Speter{ 1165251881Speter struct search_groups_baton gb; 1166251881Speter 1167251881Speter gb.key = key; 1168251881Speter gb.match = NULL; 1169251881Speter gb.pool = pool; 1170251881Speter (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool); 1171251881Speter return gb.match; 1172251881Speter} 1173251881Speter 1174251881Speter 1175251881Speterconst char* 1176251881Spetersvn_config_get_server_setting(svn_config_t *cfg, 1177251881Speter const char* server_group, 1178251881Speter const char* option_name, 1179251881Speter const char* default_value) 1180251881Speter{ 1181251881Speter const char *retval; 1182251881Speter svn_config_get(cfg, &retval, SVN_CONFIG_SECTION_GLOBAL, 1183251881Speter option_name, default_value); 1184251881Speter if (server_group) 1185251881Speter { 1186251881Speter svn_config_get(cfg, &retval, server_group, option_name, retval); 1187251881Speter } 1188251881Speter return retval; 1189251881Speter} 1190251881Speter 1191251881Speter 1192251881Spetersvn_error_t * 1193251881Spetersvn_config_dup(svn_config_t **cfgp, 1194289180Speter const svn_config_t *src, 1195251881Speter apr_pool_t *pool) 1196251881Speter{ 1197251881Speter apr_hash_index_t *sectidx; 1198251881Speter apr_hash_index_t *optidx; 1199251881Speter 1200251881Speter *cfgp = 0; 1201251881Speter SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool)); 1202251881Speter 1203251881Speter (*cfgp)->x_values = src->x_values; 1204251881Speter (*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive; 1205251881Speter (*cfgp)->option_names_case_sensitive = src->option_names_case_sensitive; 1206251881Speter 1207251881Speter for (sectidx = apr_hash_first(pool, src->sections); 1208251881Speter sectidx != NULL; 1209251881Speter sectidx = apr_hash_next(sectidx)) 1210251881Speter { 1211251881Speter const void *sectkey; 1212251881Speter void *sectval; 1213251881Speter apr_ssize_t sectkeyLength; 1214251881Speter cfg_section_t * srcsect; 1215251881Speter cfg_section_t * destsec; 1216251881Speter 1217251881Speter apr_hash_this(sectidx, §key, §keyLength, §val); 1218251881Speter srcsect = sectval; 1219251881Speter 1220251881Speter destsec = svn_config_addsection(*cfgp, srcsect->name); 1221251881Speter 1222251881Speter for (optidx = apr_hash_first(pool, srcsect->options); 1223251881Speter optidx != NULL; 1224251881Speter optidx = apr_hash_next(optidx)) 1225251881Speter { 1226251881Speter const void *optkey; 1227251881Speter void *optval; 1228251881Speter apr_ssize_t optkeyLength; 1229251881Speter cfg_option_t *srcopt; 1230251881Speter cfg_option_t *destopt; 1231251881Speter 1232251881Speter apr_hash_this(optidx, &optkey, &optkeyLength, &optval); 1233251881Speter srcopt = optval; 1234251881Speter 1235251881Speter svn_config_create_option(&destopt, srcopt->name, srcopt->value, 1236251881Speter (*cfgp)->option_names_case_sensitive, 1237251881Speter pool); 1238251881Speter 1239251881Speter destopt->value = apr_pstrdup(pool, srcopt->value); 1240251881Speter destopt->x_value = apr_pstrdup(pool, srcopt->x_value); 1241362181Sdim destopt->state = srcopt->state; 1242251881Speter apr_hash_set(destsec->options, 1243251881Speter apr_pstrdup(pool, (const char*)optkey), 1244251881Speter optkeyLength, destopt); 1245251881Speter } 1246251881Speter } 1247251881Speter 1248251881Speter return SVN_NO_ERROR; 1249251881Speter} 1250251881Speter 1251251881Spetersvn_error_t * 1252251881Spetersvn_config_copy_config(apr_hash_t **cfg_hash, 1253251881Speter apr_hash_t *src_hash, 1254251881Speter apr_pool_t *pool) 1255251881Speter{ 1256251881Speter apr_hash_index_t *cidx; 1257251881Speter 1258362181Sdim *cfg_hash = svn_hash__make(pool); 1259251881Speter for (cidx = apr_hash_first(pool, src_hash); 1260251881Speter cidx != NULL; 1261251881Speter cidx = apr_hash_next(cidx)) 1262251881Speter { 1263251881Speter const void *ckey; 1264251881Speter void *cval; 1265251881Speter apr_ssize_t ckeyLength; 1266251881Speter svn_config_t * srcconfig; 1267251881Speter svn_config_t * destconfig; 1268251881Speter 1269251881Speter apr_hash_this(cidx, &ckey, &ckeyLength, &cval); 1270251881Speter srcconfig = cval; 1271251881Speter 1272251881Speter SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool)); 1273251881Speter 1274251881Speter apr_hash_set(*cfg_hash, 1275251881Speter apr_pstrdup(pool, (const char*)ckey), 1276251881Speter ckeyLength, destconfig); 1277251881Speter } 1278251881Speter 1279251881Speter return SVN_NO_ERROR; 1280251881Speter} 1281251881Speter 1282251881Spetersvn_error_t* 1283251881Spetersvn_config_get_server_setting_int(svn_config_t *cfg, 1284251881Speter const char *server_group, 1285251881Speter const char *option_name, 1286251881Speter apr_int64_t default_value, 1287251881Speter apr_int64_t *result_value, 1288251881Speter apr_pool_t *pool) 1289251881Speter{ 1290251881Speter const char* tmp_value; 1291251881Speter char *end_pos; 1292251881Speter 1293251881Speter tmp_value = svn_config_get_server_setting(cfg, server_group, 1294251881Speter option_name, NULL); 1295251881Speter if (tmp_value == NULL) 1296251881Speter *result_value = default_value; 1297251881Speter else 1298251881Speter { 1299251881Speter /* read tmp_value as an int now */ 1300251881Speter *result_value = apr_strtoi64(tmp_value, &end_pos, 0); 1301251881Speter 1302251881Speter if (*end_pos != 0) 1303251881Speter { 1304251881Speter return svn_error_createf 1305251881Speter (SVN_ERR_BAD_CONFIG_VALUE, NULL, 1306251881Speter _("Config error: invalid integer value '%s'"), 1307251881Speter tmp_value); 1308251881Speter } 1309251881Speter } 1310251881Speter 1311251881Speter return SVN_NO_ERROR; 1312251881Speter} 1313251881Speter 1314251881Spetersvn_error_t * 1315251881Spetersvn_config_get_server_setting_bool(svn_config_t *cfg, 1316251881Speter svn_boolean_t *valuep, 1317251881Speter const char *server_group, 1318251881Speter const char *option_name, 1319251881Speter svn_boolean_t default_value) 1320251881Speter{ 1321251881Speter const char* tmp_value; 1322251881Speter tmp_value = svn_config_get_server_setting(cfg, server_group, 1323251881Speter option_name, NULL); 1324251881Speter return get_bool(valuep, tmp_value, default_value, 1325251881Speter server_group, option_name); 1326251881Speter} 1327251881Speter 1328251881Speter 1329251881Spetersvn_boolean_t 1330251881Spetersvn_config_has_section(svn_config_t *cfg, const char *section) 1331251881Speter{ 1332289180Speter return NULL != get_hash_value(cfg->sections, cfg->tmp_key, section, 1333289180Speter cfg->section_names_case_sensitive); 1334251881Speter} 1335362181Sdim 1336362181Sdimsvn_error_t * 1337362181Sdimsvn_config__write(svn_stream_t *stream, 1338362181Sdim const struct svn_config_t *cfg, 1339362181Sdim apr_pool_t *scratch_pool) 1340362181Sdim{ 1341362181Sdim apr_hash_index_t *section_i; 1342362181Sdim apr_hash_index_t *options_i; 1343362181Sdim apr_pool_t *section_pool = svn_pool_create(scratch_pool); 1344362181Sdim apr_pool_t *options_pool = svn_pool_create(scratch_pool); 1345362181Sdim 1346362181Sdim for (section_i = apr_hash_first(scratch_pool, cfg->sections); 1347362181Sdim section_i != NULL; 1348362181Sdim section_i = apr_hash_next(section_i)) 1349362181Sdim { 1350362181Sdim cfg_section_t *section = apr_hash_this_val(section_i); 1351362181Sdim svn_pool_clear(section_pool); 1352362181Sdim SVN_ERR(svn_stream_printf(stream, section_pool, "\n[%s]\n", 1353362181Sdim section->name)); 1354362181Sdim 1355362181Sdim for (options_i = apr_hash_first(section_pool, section->options); 1356362181Sdim options_i != NULL; 1357362181Sdim options_i = apr_hash_next(options_i)) 1358362181Sdim { 1359362181Sdim cfg_option_t *option = apr_hash_this_val(options_i); 1360362181Sdim svn_pool_clear(options_pool); 1361362181Sdim SVN_ERR(svn_stream_printf(stream, options_pool, "%s=%s\n", 1362362181Sdim option->name, option->value)); 1363362181Sdim } 1364362181Sdim } 1365362181Sdim 1366362181Sdim svn_pool_destroy(section_pool); 1367362181Sdim svn_pool_destroy(options_pool); 1368362181Sdim 1369362181Sdim return SVN_NO_ERROR; 1370362181Sdim} 1371362181Sdim 1372