config.c revision 289166
1/* 2 * config.c : reading configuration information 3 * 4 * ==================================================================== 5 * Licensed to the Apache Software Foundation (ASF) under one 6 * or more contributor license agreements. See the NOTICE file 7 * distributed with this work for additional information 8 * regarding copyright ownership. The ASF licenses this file 9 * to you under the Apache License, Version 2.0 (the 10 * "License"); you may not use this file except in compliance 11 * with the License. You may obtain a copy of the License at 12 * 13 * http://www.apache.org/licenses/LICENSE-2.0 14 * 15 * Unless required by applicable law or agreed to in writing, 16 * software distributed under the License is distributed on an 17 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 18 * KIND, either express or implied. See the License for the 19 * specific language governing permissions and limitations 20 * under the License. 21 * ==================================================================== 22 */ 23 24 25 26#define APR_WANT_STRFUNC 27#define APR_WANT_MEMFUNC 28#include <apr_want.h> 29 30#include <apr_general.h> 31#include <apr_lib.h> 32#include "svn_hash.h" 33#include "svn_error.h" 34#include "svn_pools.h" 35#include "config_impl.h" 36 37#include "svn_private_config.h" 38#include "private/svn_dep_compat.h" 39 40 41 42 43/* Section table entries. */ 44typedef struct cfg_section_t cfg_section_t; 45struct cfg_section_t 46{ 47 /* The section name. */ 48 const char *name; 49 50 /* Table of cfg_option_t's. */ 51 apr_hash_t *options; 52}; 53 54 55/* Option table entries. */ 56typedef struct cfg_option_t cfg_option_t; 57struct cfg_option_t 58{ 59 /* The option name. */ 60 const char *name; 61 62 /* The option name, converted into a hash key. */ 63 const char *hash_key; 64 65 /* The unexpanded option value. */ 66 const char *value; 67 68 /* The expanded option value. */ 69 const char *x_value; 70 71 /* Expansion flag. If this is TRUE, this value has already been expanded. 72 In this case, if x_value is NULL, no expansions were necessary, 73 and value should be used directly. */ 74 svn_boolean_t expanded; 75}; 76 77 78 79svn_error_t * 80svn_config_create2(svn_config_t **cfgp, 81 svn_boolean_t section_names_case_sensitive, 82 svn_boolean_t option_names_case_sensitive, 83 apr_pool_t *result_pool) 84{ 85 svn_config_t *cfg = apr_palloc(result_pool, sizeof(*cfg)); 86 87 cfg->sections = apr_hash_make(result_pool); 88 cfg->pool = result_pool; 89 cfg->x_pool = svn_pool_create(result_pool); 90 cfg->x_values = FALSE; 91 cfg->tmp_key = svn_stringbuf_create_empty(result_pool); 92 cfg->tmp_value = svn_stringbuf_create_empty(result_pool); 93 cfg->section_names_case_sensitive = section_names_case_sensitive; 94 cfg->option_names_case_sensitive = option_names_case_sensitive; 95 96 *cfgp = cfg; 97 return SVN_NO_ERROR; 98} 99 100svn_error_t * 101svn_config_read3(svn_config_t **cfgp, const char *file, 102 svn_boolean_t must_exist, 103 svn_boolean_t section_names_case_sensitive, 104 svn_boolean_t option_names_case_sensitive, 105 apr_pool_t *result_pool) 106{ 107 svn_config_t *cfg; 108 svn_error_t *err; 109 110 SVN_ERR(svn_config_create2(&cfg, 111 section_names_case_sensitive, 112 option_names_case_sensitive, 113 result_pool)); 114 115 /* Yes, this is platform-specific code in Subversion, but there's no 116 practical way to migrate it into APR, as it's simultaneously 117 Subversion-specific and Windows-specific. Even if we eventually 118 want to have APR offer a generic config-reading interface, it 119 makes sense to test it here first and migrate it later. */ 120#ifdef WIN32 121 if (0 == strncmp(file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN)) 122 err = svn_config__parse_registry(cfg, file + SVN_REGISTRY_PREFIX_LEN, 123 must_exist, result_pool); 124 else 125#endif /* WIN32 */ 126 err = svn_config__parse_file(cfg, file, must_exist, result_pool); 127 128 if (err != SVN_NO_ERROR) 129 return err; 130 else 131 *cfgp = cfg; 132 133 return SVN_NO_ERROR; 134} 135 136svn_error_t * 137svn_config_parse(svn_config_t **cfgp, svn_stream_t *stream, 138 svn_boolean_t section_names_case_sensitive, 139 svn_boolean_t option_names_case_sensitive, 140 apr_pool_t *result_pool) 141{ 142 svn_config_t *cfg; 143 svn_error_t *err; 144 apr_pool_t *scratch_pool = svn_pool_create(result_pool); 145 146 err = svn_config_create2(&cfg, 147 section_names_case_sensitive, 148 option_names_case_sensitive, 149 result_pool); 150 151 if (err == SVN_NO_ERROR) 152 err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool); 153 154 if (err == SVN_NO_ERROR) 155 *cfgp = cfg; 156 157 svn_pool_destroy(scratch_pool); 158 159 return err; 160} 161 162/* Read various configuration sources into *CFGP, in this order, with 163 * later reads overriding the results of earlier ones: 164 * 165 * 1. SYS_REGISTRY_PATH (only on Win32, but ignored if NULL) 166 * 167 * 2. SYS_FILE_PATH (everywhere, but ignored if NULL) 168 * 169 * 3. USR_REGISTRY_PATH (only on Win32, but ignored if NULL) 170 * 171 * 4. USR_FILE_PATH (everywhere, but ignored if NULL) 172 * 173 * Allocate *CFGP in POOL. Even if no configurations are read, 174 * allocate an empty *CFGP. 175 */ 176static svn_error_t * 177read_all(svn_config_t **cfgp, 178 const char *sys_registry_path, 179 const char *usr_registry_path, 180 const char *sys_file_path, 181 const char *usr_file_path, 182 apr_pool_t *pool) 183{ 184 svn_boolean_t red_config = FALSE; /* "red" is the past tense of "read" */ 185 186 /*** Read system-wide configurations first... ***/ 187 188#ifdef WIN32 189 if (sys_registry_path) 190 { 191 SVN_ERR(svn_config_read2(cfgp, sys_registry_path, FALSE, FALSE, pool)); 192 red_config = TRUE; 193 } 194#endif /* WIN32 */ 195 196 if (sys_file_path) 197 { 198 if (red_config) 199 SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE)); 200 else 201 { 202 SVN_ERR(svn_config_read3(cfgp, sys_file_path, 203 FALSE, FALSE, FALSE, pool)); 204 red_config = TRUE; 205 } 206 } 207 208 /*** ...followed by per-user configurations. ***/ 209 210#ifdef WIN32 211 if (usr_registry_path) 212 { 213 if (red_config) 214 SVN_ERR(svn_config_merge(*cfgp, usr_registry_path, FALSE)); 215 else 216 { 217 SVN_ERR(svn_config_read2(cfgp, usr_registry_path, 218 FALSE, FALSE, pool)); 219 red_config = TRUE; 220 } 221 } 222#endif /* WIN32 */ 223 224 if (usr_file_path) 225 { 226 if (red_config) 227 SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE)); 228 else 229 { 230 SVN_ERR(svn_config_read3(cfgp, usr_file_path, 231 FALSE, FALSE, FALSE, pool)); 232 red_config = TRUE; 233 } 234 } 235 236 if (! red_config) 237 SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool)); 238 239 return SVN_NO_ERROR; 240} 241 242 243/* CONFIG_DIR provides an override for the default behavior of reading 244 the default set of overlay files described by read_all()'s doc 245 string. */ 246static svn_error_t * 247get_category_config(svn_config_t **cfg, 248 const char *config_dir, 249 const char *category, 250 apr_pool_t *pool) 251{ 252 const char *usr_reg_path = NULL, *sys_reg_path = NULL; 253 const char *usr_cfg_path, *sys_cfg_path; 254 svn_error_t *err = NULL; 255 256 *cfg = NULL; 257 258 if (! config_dir) 259 { 260#ifdef WIN32 261 sys_reg_path = apr_pstrcat(pool, SVN_REGISTRY_SYS_CONFIG_PATH, 262 category, NULL); 263 usr_reg_path = apr_pstrcat(pool, SVN_REGISTRY_USR_CONFIG_PATH, 264 category, NULL); 265#endif /* WIN32 */ 266 267 err = svn_config__sys_config_path(&sys_cfg_path, category, pool); 268 if ((err) && (err->apr_err == SVN_ERR_BAD_FILENAME)) 269 { 270 sys_cfg_path = NULL; 271 svn_error_clear(err); 272 } 273 else if (err) 274 return err; 275 } 276 else 277 sys_cfg_path = NULL; 278 279 SVN_ERR(svn_config_get_user_config_path(&usr_cfg_path, config_dir, category, 280 pool)); 281 return read_all(cfg, sys_reg_path, usr_reg_path, 282 sys_cfg_path, usr_cfg_path, pool); 283} 284 285 286svn_error_t * 287svn_config_get_config(apr_hash_t **cfg_hash, 288 const char *config_dir, 289 apr_pool_t *pool) 290{ 291 svn_config_t *cfg; 292 *cfg_hash = apr_hash_make(pool); 293 294#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_SERVERS) - 1) 295 SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_SERVERS, 296 pool)); 297 if (cfg) 298 apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, CATLEN, cfg); 299#undef CATLEN 300 301#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_CONFIG) - 1) 302 SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_CONFIG, 303 pool)); 304 if (cfg) 305 apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, CATLEN, cfg); 306#undef CATLEN 307 308 return SVN_NO_ERROR; 309} 310 311 312 313/* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION) 314 pair. Stop if CALLBACK returns TRUE. Allocate from POOL. */ 315static void 316for_each_option(svn_config_t *cfg, void *baton, apr_pool_t *pool, 317 svn_boolean_t callback(void *same_baton, 318 cfg_section_t *section, 319 cfg_option_t *option)) 320{ 321 apr_hash_index_t *sec_ndx; 322 for (sec_ndx = apr_hash_first(pool, cfg->sections); 323 sec_ndx != NULL; 324 sec_ndx = apr_hash_next(sec_ndx)) 325 { 326 void *sec_ptr; 327 cfg_section_t *sec; 328 apr_hash_index_t *opt_ndx; 329 330 apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); 331 sec = sec_ptr; 332 333 for (opt_ndx = apr_hash_first(pool, sec->options); 334 opt_ndx != NULL; 335 opt_ndx = apr_hash_next(opt_ndx)) 336 { 337 void *opt_ptr; 338 cfg_option_t *opt; 339 340 apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr); 341 opt = opt_ptr; 342 343 if (callback(baton, sec, opt)) 344 return; 345 } 346 } 347} 348 349 350 351static svn_boolean_t 352merge_callback(void *baton, cfg_section_t *section, cfg_option_t *option) 353{ 354 svn_config_set(baton, section->name, option->name, option->value); 355 return FALSE; 356} 357 358svn_error_t * 359svn_config_merge(svn_config_t *cfg, const char *file, 360 svn_boolean_t must_exist) 361{ 362 /* The original config hash shouldn't change if there's an error 363 while reading the confguration, so read into a temporary table. 364 ### We could use a tmp subpool for this, since merge_cfg is going 365 to be tossed afterwards. Premature optimization, though? */ 366 svn_config_t *merge_cfg; 367 SVN_ERR(svn_config_read3(&merge_cfg, file, must_exist, 368 cfg->section_names_case_sensitive, 369 cfg->option_names_case_sensitive, 370 cfg->pool)); 371 372 /* Now copy the new options into the original table. */ 373 for_each_option(merge_cfg, cfg, merge_cfg->pool, merge_callback); 374 return SVN_NO_ERROR; 375} 376 377 378 379/* Remove variable expansions from CFG. Walk through the options tree, 380 killing all expanded values, then clear the expanded value pool. */ 381static svn_boolean_t 382rmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option) 383{ 384 /* Only clear the `expanded' flag if the value actually contains 385 variable expansions. */ 386 if (option->expanded && option->x_value != NULL) 387 { 388 option->x_value = NULL; 389 option->expanded = FALSE; 390 } 391 392 return FALSE; 393} 394 395static void 396remove_expansions(svn_config_t *cfg) 397{ 398 if (!cfg->x_values) 399 return; 400 401 for_each_option(cfg, NULL, cfg->x_pool, rmex_callback); 402 svn_pool_clear(cfg->x_pool); 403 cfg->x_values = FALSE; 404} 405 406 407 408/* Canonicalize a string for hashing. Modifies KEY in place. */ 409static APR_INLINE char * 410make_hash_key(char *key) 411{ 412 register char *p; 413 for (p = key; *p != 0; ++p) 414 *p = (char)apr_tolower(*p); 415 return key; 416} 417 418 419/* Return a pointer to an option in CFG, or NULL if it doesn't exist. 420 if SECTIONP is non-null, return a pointer to the option's section. 421 OPTION may be NULL. */ 422static cfg_option_t * 423find_option(svn_config_t *cfg, const char *section, const char *option, 424 cfg_section_t **sectionp) 425{ 426 void *sec_ptr; 427 428 /* Canonicalize the hash key */ 429 svn_stringbuf_set(cfg->tmp_key, section); 430 if (! cfg->section_names_case_sensitive) 431 make_hash_key(cfg->tmp_key->data); 432 433 sec_ptr = apr_hash_get(cfg->sections, cfg->tmp_key->data, 434 cfg->tmp_key->len); 435 if (sectionp != NULL) 436 *sectionp = sec_ptr; 437 438 if (sec_ptr != NULL && option != NULL) 439 { 440 cfg_section_t *sec = sec_ptr; 441 cfg_option_t *opt; 442 443 /* Canonicalize the option key */ 444 svn_stringbuf_set(cfg->tmp_key, option); 445 if (! cfg->option_names_case_sensitive) 446 make_hash_key(cfg->tmp_key->data); 447 448 opt = apr_hash_get(sec->options, cfg->tmp_key->data, 449 cfg->tmp_key->len); 450 /* NOTE: ConfigParser's sections are case sensitive. */ 451 if (opt == NULL 452 && apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0) 453 /* Options which aren't found in the requested section are 454 also sought after in the default section. */ 455 opt = find_option(cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec); 456 return opt; 457 } 458 459 return NULL; 460} 461 462 463/* Has a bi-directional dependency with make_string_from_option(). */ 464static void 465expand_option_value(svn_config_t *cfg, cfg_section_t *section, 466 const char *opt_value, const char **opt_x_valuep, 467 apr_pool_t *x_pool); 468 469 470/* Set *VALUEP according to the OPT's value. A value for X_POOL must 471 only ever be passed into this function by expand_option_value(). */ 472static void 473make_string_from_option(const char **valuep, svn_config_t *cfg, 474 cfg_section_t *section, cfg_option_t *opt, 475 apr_pool_t* x_pool) 476{ 477 /* Expand the option value if necessary. */ 478 if (!opt->expanded) 479 { 480 /* before attempting to expand an option, check for the placeholder. 481 * If none is there, there is no point in calling expand_option_value. 482 */ 483 if (opt->value && strchr(opt->value, '%')) 484 { 485 apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool)); 486 487 expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool); 488 opt->expanded = TRUE; 489 490 if (x_pool != cfg->x_pool) 491 { 492 /* Grab the fully expanded value from tmp_pool before its 493 disappearing act. */ 494 if (opt->x_value) 495 opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value, 496 strlen(opt->x_value)); 497 if (!x_pool) 498 svn_pool_destroy(tmp_pool); 499 } 500 } 501 else 502 { 503 opt->expanded = TRUE; 504 } 505 } 506 507 if (opt->x_value) 508 *valuep = opt->x_value; 509 else 510 *valuep = opt->value; 511} 512 513 514/* Start of variable-replacement placeholder */ 515#define FMT_START "%(" 516#define FMT_START_LEN (sizeof(FMT_START) - 1) 517 518/* End of variable-replacement placeholder */ 519#define FMT_END ")s" 520#define FMT_END_LEN (sizeof(FMT_END) - 1) 521 522 523/* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP. 524 If no variable replacements are done, set *OPT_X_VALUEP to 525 NULL. Allocate from X_POOL. */ 526static void 527expand_option_value(svn_config_t *cfg, cfg_section_t *section, 528 const char *opt_value, const char **opt_x_valuep, 529 apr_pool_t *x_pool) 530{ 531 svn_stringbuf_t *buf = NULL; 532 const char *parse_from = opt_value; 533 const char *copy_from = parse_from; 534 const char *name_start, *name_end; 535 536 while (parse_from != NULL 537 && *parse_from != '\0' 538 && (name_start = strstr(parse_from, FMT_START)) != NULL) 539 { 540 name_start += FMT_START_LEN; 541 if (*name_start == '\0') 542 /* FMT_START at end of opt_value. */ 543 break; 544 545 name_end = strstr(name_start, FMT_END); 546 if (name_end != NULL) 547 { 548 cfg_option_t *x_opt; 549 apr_size_t len = name_end - name_start; 550 char *name = apr_pstrmemdup(x_pool, name_start, len); 551 552 x_opt = find_option(cfg, section->name, name, NULL); 553 554 if (x_opt != NULL) 555 { 556 const char *cstring; 557 558 /* Pass back the sub-pool originally provided by 559 make_string_from_option() as an indication of when it 560 should terminate. */ 561 make_string_from_option(&cstring, cfg, section, x_opt, x_pool); 562 563 /* Append the plain text preceding the expansion. */ 564 len = name_start - FMT_START_LEN - copy_from; 565 if (buf == NULL) 566 { 567 buf = svn_stringbuf_ncreate(copy_from, len, x_pool); 568 cfg->x_values = TRUE; 569 } 570 else 571 svn_stringbuf_appendbytes(buf, copy_from, len); 572 573 /* Append the expansion and adjust parse pointers. */ 574 svn_stringbuf_appendcstr(buf, cstring); 575 parse_from = name_end + FMT_END_LEN; 576 copy_from = parse_from; 577 } 578 else 579 /* Though ConfigParser considers the failure to resolve 580 the requested expansion an exception condition, we 581 consider it to be plain text, and look for the start of 582 the next one. */ 583 parse_from = name_end + FMT_END_LEN; 584 } 585 else 586 /* Though ConfigParser treats unterminated format specifiers 587 as an exception condition, we consider them to be plain 588 text. The fact that there are no more format specifier 589 endings means we're done parsing. */ 590 parse_from = NULL; 591 } 592 593 if (buf != NULL) 594 { 595 /* Copy the remainder of the plain text. */ 596 svn_stringbuf_appendcstr(buf, copy_from); 597 *opt_x_valuep = buf->data; 598 } 599 else 600 *opt_x_valuep = NULL; 601} 602 603static cfg_section_t * 604svn_config_addsection(svn_config_t *cfg, 605 const char *section) 606{ 607 cfg_section_t *s; 608 const char *hash_key; 609 610 s = apr_palloc(cfg->pool, sizeof(cfg_section_t)); 611 s->name = apr_pstrdup(cfg->pool, section); 612 if(cfg->section_names_case_sensitive) 613 hash_key = s->name; 614 else 615 hash_key = make_hash_key(apr_pstrdup(cfg->pool, section)); 616 s->options = apr_hash_make(cfg->pool); 617 svn_hash_sets(cfg->sections, hash_key, s); 618 619 return s; 620} 621 622static void 623svn_config_create_option(cfg_option_t **opt, 624 const char *option, 625 const char *value, 626 svn_boolean_t option_names_case_sensitive, 627 apr_pool_t *pool) 628{ 629 cfg_option_t *o; 630 631 o = apr_palloc(pool, sizeof(cfg_option_t)); 632 o->name = apr_pstrdup(pool, option); 633 if(option_names_case_sensitive) 634 o->hash_key = o->name; 635 else 636 o->hash_key = make_hash_key(apr_pstrdup(pool, option)); 637 638 o->value = apr_pstrdup(pool, value); 639 o->x_value = NULL; 640 o->expanded = FALSE; 641 642 *opt = o; 643} 644 645 646void 647svn_config_get(svn_config_t *cfg, const char **valuep, 648 const char *section, const char *option, 649 const char *default_value) 650{ 651 *valuep = default_value; 652 if (cfg) 653 { 654 cfg_section_t *sec; 655 cfg_option_t *opt = find_option(cfg, section, option, &sec); 656 if (opt != NULL) 657 { 658 make_string_from_option(valuep, cfg, sec, opt, NULL); 659 } 660 else 661 /* before attempting to expand an option, check for the placeholder. 662 * If none is there, there is no point in calling expand_option_value. 663 */ 664 if (default_value && strchr(default_value, '%')) 665 { 666 apr_pool_t *tmp_pool = svn_pool_create(cfg->x_pool); 667 const char *x_default; 668 expand_option_value(cfg, sec, default_value, &x_default, tmp_pool); 669 if (x_default) 670 { 671 svn_stringbuf_set(cfg->tmp_value, x_default); 672 *valuep = cfg->tmp_value->data; 673 } 674 svn_pool_destroy(tmp_pool); 675 } 676 } 677} 678 679 680 681void 682svn_config_set(svn_config_t *cfg, 683 const char *section, const char *option, 684 const char *value) 685{ 686 cfg_section_t *sec; 687 cfg_option_t *opt; 688 689 remove_expansions(cfg); 690 691 opt = find_option(cfg, section, option, &sec); 692 if (opt != NULL) 693 { 694 /* Replace the option's value. */ 695 opt->value = apr_pstrdup(cfg->pool, value); 696 opt->expanded = FALSE; 697 return; 698 } 699 700 /* Create a new option */ 701 svn_config_create_option(&opt, option, value, 702 cfg->option_names_case_sensitive, 703 cfg->pool); 704 705 if (sec == NULL) 706 { 707 /* Even the section doesn't exist. Create it. */ 708 sec = svn_config_addsection(cfg, section); 709 } 710 711 svn_hash_sets(sec->options, opt->hash_key, opt); 712} 713 714 715 716/* Set *BOOLP to true or false depending (case-insensitively) on INPUT. 717 If INPUT is null, set *BOOLP to DEFAULT_VALUE. 718 719 INPUT is a string indicating truth or falsehood in any of the usual 720 ways: "true"/"yes"/"on"/etc, "false"/"no"/"off"/etc. 721 722 If INPUT is neither NULL nor a recognized string, return an error 723 with code SVN_ERR_BAD_CONFIG_VALUE; use SECTION and OPTION in 724 constructing the error string. */ 725static svn_error_t * 726get_bool(svn_boolean_t *boolp, const char *input, svn_boolean_t default_value, 727 const char *section, const char *option) 728{ 729 svn_tristate_t value = svn_tristate__from_word(input); 730 731 if (value == svn_tristate_true) 732 *boolp = TRUE; 733 else if (value == svn_tristate_false) 734 *boolp = FALSE; 735 else if (input == NULL) /* no value provided */ 736 *boolp = default_value; 737 738 else if (section) /* unrecognized value */ 739 return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 740 _("Config error: invalid boolean " 741 "value '%s' for '[%s] %s'"), 742 input, section, option); 743 else 744 return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 745 _("Config error: invalid boolean " 746 "value '%s' for '%s'"), 747 input, option); 748 749 return SVN_NO_ERROR; 750} 751 752 753svn_error_t * 754svn_config_get_bool(svn_config_t *cfg, svn_boolean_t *valuep, 755 const char *section, const char *option, 756 svn_boolean_t default_value) 757{ 758 const char *tmp_value; 759 svn_config_get(cfg, &tmp_value, section, option, NULL); 760 return get_bool(valuep, tmp_value, default_value, section, option); 761} 762 763 764 765void 766svn_config_set_bool(svn_config_t *cfg, 767 const char *section, const char *option, 768 svn_boolean_t value) 769{ 770 svn_config_set(cfg, section, option, 771 (value ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE)); 772} 773 774svn_error_t * 775svn_config_get_int64(svn_config_t *cfg, 776 apr_int64_t *valuep, 777 const char *section, 778 const char *option, 779 apr_int64_t default_value) 780{ 781 const char *tmp_value; 782 svn_config_get(cfg, &tmp_value, section, option, NULL); 783 if (tmp_value) 784 return svn_cstring_strtoi64(valuep, tmp_value, 785 APR_INT64_MIN, APR_INT64_MAX, 10); 786 787 *valuep = default_value; 788 return SVN_NO_ERROR; 789} 790 791void 792svn_config_set_int64(svn_config_t *cfg, 793 const char *section, 794 const char *option, 795 apr_int64_t value) 796{ 797 svn_config_set(cfg, section, option, 798 apr_psprintf(cfg->pool, "%" APR_INT64_T_FMT, value)); 799} 800 801svn_error_t * 802svn_config_get_yes_no_ask(svn_config_t *cfg, const char **valuep, 803 const char *section, const char *option, 804 const char* default_value) 805{ 806 const char *tmp_value; 807 808 svn_config_get(cfg, &tmp_value, section, option, NULL); 809 810 if (! tmp_value) 811 tmp_value = default_value; 812 813 if (tmp_value && (0 == svn_cstring_casecmp(tmp_value, SVN_CONFIG_ASK))) 814 { 815 *valuep = SVN_CONFIG_ASK; 816 } 817 else 818 { 819 svn_boolean_t bool_val; 820 /* We already incorporated default_value into tmp_value if 821 necessary, so the FALSE below will be ignored unless the 822 caller is doing something it shouldn't be doing. */ 823 SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option)); 824 *valuep = bool_val ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE; 825 } 826 827 return SVN_NO_ERROR; 828} 829 830svn_error_t * 831svn_config_get_tristate(svn_config_t *cfg, svn_tristate_t *valuep, 832 const char *section, const char *option, 833 const char *unknown_value, 834 svn_tristate_t default_value) 835{ 836 const char *tmp_value; 837 838 svn_config_get(cfg, &tmp_value, section, option, NULL); 839 840 if (! tmp_value) 841 { 842 *valuep = default_value; 843 } 844 else if (0 == svn_cstring_casecmp(tmp_value, unknown_value)) 845 { 846 *valuep = svn_tristate_unknown; 847 } 848 else 849 { 850 svn_boolean_t bool_val; 851 /* We already incorporated default_value into tmp_value if 852 necessary, so the FALSE below will be ignored unless the 853 caller is doing something it shouldn't be doing. */ 854 SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option)); 855 *valuep = bool_val ? svn_tristate_true : svn_tristate_false; 856 } 857 858 return SVN_NO_ERROR; 859} 860 861int 862svn_config_enumerate_sections(svn_config_t *cfg, 863 svn_config_section_enumerator_t callback, 864 void *baton) 865{ 866 apr_hash_index_t *sec_ndx; 867 int count = 0; 868 apr_pool_t *subpool = svn_pool_create(cfg->x_pool); 869 870 for (sec_ndx = apr_hash_first(subpool, cfg->sections); 871 sec_ndx != NULL; 872 sec_ndx = apr_hash_next(sec_ndx)) 873 { 874 void *sec_ptr; 875 cfg_section_t *sec; 876 877 apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); 878 sec = sec_ptr; 879 ++count; 880 if (!callback(sec->name, baton)) 881 break; 882 } 883 884 svn_pool_destroy(subpool); 885 return count; 886} 887 888 889int 890svn_config_enumerate_sections2(svn_config_t *cfg, 891 svn_config_section_enumerator2_t callback, 892 void *baton, apr_pool_t *pool) 893{ 894 apr_hash_index_t *sec_ndx; 895 apr_pool_t *iteration_pool; 896 int count = 0; 897 898 iteration_pool = svn_pool_create(pool); 899 for (sec_ndx = apr_hash_first(pool, cfg->sections); 900 sec_ndx != NULL; 901 sec_ndx = apr_hash_next(sec_ndx)) 902 { 903 void *sec_ptr; 904 cfg_section_t *sec; 905 906 apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); 907 sec = sec_ptr; 908 ++count; 909 svn_pool_clear(iteration_pool); 910 if (!callback(sec->name, baton, iteration_pool)) 911 break; 912 } 913 svn_pool_destroy(iteration_pool); 914 915 return count; 916} 917 918 919 920int 921svn_config_enumerate(svn_config_t *cfg, const char *section, 922 svn_config_enumerator_t callback, void *baton) 923{ 924 cfg_section_t *sec; 925 apr_hash_index_t *opt_ndx; 926 int count; 927 apr_pool_t *subpool; 928 929 find_option(cfg, section, NULL, &sec); 930 if (sec == NULL) 931 return 0; 932 933 subpool = svn_pool_create(cfg->x_pool); 934 count = 0; 935 for (opt_ndx = apr_hash_first(subpool, sec->options); 936 opt_ndx != NULL; 937 opt_ndx = apr_hash_next(opt_ndx)) 938 { 939 void *opt_ptr; 940 cfg_option_t *opt; 941 const char *temp_value; 942 943 apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr); 944 opt = opt_ptr; 945 946 ++count; 947 make_string_from_option(&temp_value, cfg, sec, opt, NULL); 948 if (!callback(opt->name, temp_value, baton)) 949 break; 950 } 951 952 svn_pool_destroy(subpool); 953 return count; 954} 955 956 957int 958svn_config_enumerate2(svn_config_t *cfg, const char *section, 959 svn_config_enumerator2_t callback, void *baton, 960 apr_pool_t *pool) 961{ 962 cfg_section_t *sec; 963 apr_hash_index_t *opt_ndx; 964 apr_pool_t *iteration_pool; 965 int count; 966 967 find_option(cfg, section, NULL, &sec); 968 if (sec == NULL) 969 return 0; 970 971 iteration_pool = svn_pool_create(pool); 972 count = 0; 973 for (opt_ndx = apr_hash_first(pool, sec->options); 974 opt_ndx != NULL; 975 opt_ndx = apr_hash_next(opt_ndx)) 976 { 977 void *opt_ptr; 978 cfg_option_t *opt; 979 const char *temp_value; 980 981 apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr); 982 opt = opt_ptr; 983 984 ++count; 985 make_string_from_option(&temp_value, cfg, sec, opt, NULL); 986 svn_pool_clear(iteration_pool); 987 if (!callback(opt->name, temp_value, baton, iteration_pool)) 988 break; 989 } 990 svn_pool_destroy(iteration_pool); 991 992 return count; 993} 994 995 996 997/* Baton for search_groups() */ 998struct search_groups_baton 999{ 1000 const char *key; /* Provided by caller of svn_config_find_group */ 1001 const char *match; /* Filled in by search_groups */ 1002 apr_pool_t *pool; 1003}; 1004 1005 1006/* This is an `svn_config_enumerator_t' function, and BATON is a 1007 * `struct search_groups_baton *'. 1008 */ 1009static svn_boolean_t search_groups(const char *name, 1010 const char *value, 1011 void *baton, 1012 apr_pool_t *pool) 1013{ 1014 struct search_groups_baton *b = baton; 1015 apr_array_header_t *list; 1016 1017 list = svn_cstring_split(value, ",", TRUE, pool); 1018 if (svn_cstring_match_glob_list(b->key, list)) 1019 { 1020 /* Fill in the match and return false, to stop enumerating. */ 1021 b->match = apr_pstrdup(b->pool, name); 1022 return FALSE; 1023 } 1024 else 1025 return TRUE; 1026} 1027 1028 1029const char *svn_config_find_group(svn_config_t *cfg, const char *key, 1030 const char *master_section, 1031 apr_pool_t *pool) 1032{ 1033 struct search_groups_baton gb; 1034 1035 gb.key = key; 1036 gb.match = NULL; 1037 gb.pool = pool; 1038 (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool); 1039 return gb.match; 1040} 1041 1042 1043const char* 1044svn_config_get_server_setting(svn_config_t *cfg, 1045 const char* server_group, 1046 const char* option_name, 1047 const char* default_value) 1048{ 1049 const char *retval; 1050 svn_config_get(cfg, &retval, SVN_CONFIG_SECTION_GLOBAL, 1051 option_name, default_value); 1052 if (server_group) 1053 { 1054 svn_config_get(cfg, &retval, server_group, option_name, retval); 1055 } 1056 return retval; 1057} 1058 1059 1060svn_error_t * 1061svn_config_dup(svn_config_t **cfgp, 1062 svn_config_t *src, 1063 apr_pool_t *pool) 1064{ 1065 apr_hash_index_t *sectidx; 1066 apr_hash_index_t *optidx; 1067 1068 *cfgp = 0; 1069 SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool)); 1070 1071 (*cfgp)->x_values = src->x_values; 1072 (*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive; 1073 (*cfgp)->option_names_case_sensitive = src->option_names_case_sensitive; 1074 1075 for (sectidx = apr_hash_first(pool, src->sections); 1076 sectidx != NULL; 1077 sectidx = apr_hash_next(sectidx)) 1078 { 1079 const void *sectkey; 1080 void *sectval; 1081 apr_ssize_t sectkeyLength; 1082 cfg_section_t * srcsect; 1083 cfg_section_t * destsec; 1084 1085 apr_hash_this(sectidx, §key, §keyLength, §val); 1086 srcsect = sectval; 1087 1088 destsec = svn_config_addsection(*cfgp, srcsect->name); 1089 1090 for (optidx = apr_hash_first(pool, srcsect->options); 1091 optidx != NULL; 1092 optidx = apr_hash_next(optidx)) 1093 { 1094 const void *optkey; 1095 void *optval; 1096 apr_ssize_t optkeyLength; 1097 cfg_option_t *srcopt; 1098 cfg_option_t *destopt; 1099 1100 apr_hash_this(optidx, &optkey, &optkeyLength, &optval); 1101 srcopt = optval; 1102 1103 svn_config_create_option(&destopt, srcopt->name, srcopt->value, 1104 (*cfgp)->option_names_case_sensitive, 1105 pool); 1106 1107 destopt->value = apr_pstrdup(pool, srcopt->value); 1108 destopt->x_value = apr_pstrdup(pool, srcopt->x_value); 1109 destopt->expanded = srcopt->expanded; 1110 apr_hash_set(destsec->options, 1111 apr_pstrdup(pool, (const char*)optkey), 1112 optkeyLength, destopt); 1113 } 1114 } 1115 1116 return SVN_NO_ERROR; 1117} 1118 1119svn_error_t * 1120svn_config_copy_config(apr_hash_t **cfg_hash, 1121 apr_hash_t *src_hash, 1122 apr_pool_t *pool) 1123{ 1124 apr_hash_index_t *cidx; 1125 1126 *cfg_hash = apr_hash_make(pool); 1127 for (cidx = apr_hash_first(pool, src_hash); 1128 cidx != NULL; 1129 cidx = apr_hash_next(cidx)) 1130 { 1131 const void *ckey; 1132 void *cval; 1133 apr_ssize_t ckeyLength; 1134 svn_config_t * srcconfig; 1135 svn_config_t * destconfig; 1136 1137 apr_hash_this(cidx, &ckey, &ckeyLength, &cval); 1138 srcconfig = cval; 1139 1140 SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool)); 1141 1142 apr_hash_set(*cfg_hash, 1143 apr_pstrdup(pool, (const char*)ckey), 1144 ckeyLength, destconfig); 1145 } 1146 1147 return SVN_NO_ERROR; 1148} 1149 1150svn_error_t* 1151svn_config_get_server_setting_int(svn_config_t *cfg, 1152 const char *server_group, 1153 const char *option_name, 1154 apr_int64_t default_value, 1155 apr_int64_t *result_value, 1156 apr_pool_t *pool) 1157{ 1158 const char* tmp_value; 1159 char *end_pos; 1160 1161 tmp_value = svn_config_get_server_setting(cfg, server_group, 1162 option_name, NULL); 1163 if (tmp_value == NULL) 1164 *result_value = default_value; 1165 else 1166 { 1167 /* read tmp_value as an int now */ 1168 *result_value = apr_strtoi64(tmp_value, &end_pos, 0); 1169 1170 if (*end_pos != 0) 1171 { 1172 return svn_error_createf 1173 (SVN_ERR_BAD_CONFIG_VALUE, NULL, 1174 _("Config error: invalid integer value '%s'"), 1175 tmp_value); 1176 } 1177 } 1178 1179 return SVN_NO_ERROR; 1180} 1181 1182svn_error_t * 1183svn_config_get_server_setting_bool(svn_config_t *cfg, 1184 svn_boolean_t *valuep, 1185 const char *server_group, 1186 const char *option_name, 1187 svn_boolean_t default_value) 1188{ 1189 const char* tmp_value; 1190 tmp_value = svn_config_get_server_setting(cfg, server_group, 1191 option_name, NULL); 1192 return get_bool(valuep, tmp_value, default_value, 1193 server_group, option_name); 1194} 1195 1196 1197svn_boolean_t 1198svn_config_has_section(svn_config_t *cfg, const char *section) 1199{ 1200 cfg_section_t *sec; 1201 1202 /* Canonicalize the hash key */ 1203 svn_stringbuf_set(cfg->tmp_key, section); 1204 if (! cfg->section_names_case_sensitive) 1205 make_hash_key(cfg->tmp_key->data); 1206 1207 sec = svn_hash_gets(cfg->sections, cfg->tmp_key->data); 1208 return sec != NULL; 1209} 1210