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) 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 svn_pool_destroy(tmp_pool); 498 } 499 } 500 else 501 { 502 opt->expanded = TRUE; 503 } 504 } 505 506 if (opt->x_value) 507 *valuep = opt->x_value; 508 else 509 *valuep = opt->value; 510} 511 512 513/* Start of variable-replacement placeholder */ 514#define FMT_START "%(" 515#define FMT_START_LEN (sizeof(FMT_START) - 1) 516 517/* End of variable-replacement placeholder */ 518#define FMT_END ")s" 519#define FMT_END_LEN (sizeof(FMT_END) - 1) 520 521 522/* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP. 523 If no variable replacements are done, set *OPT_X_VALUEP to 524 NULL. Allocate from X_POOL. */ 525static void 526expand_option_value(svn_config_t *cfg, cfg_section_t *section, 527 const char *opt_value, const char **opt_x_valuep, 528 apr_pool_t *x_pool) 529{ 530 svn_stringbuf_t *buf = NULL; 531 const char *parse_from = opt_value; 532 const char *copy_from = parse_from; 533 const char *name_start, *name_end; 534 535 while (parse_from != NULL 536 && *parse_from != '\0' 537 && (name_start = strstr(parse_from, FMT_START)) != NULL) 538 { 539 name_start += FMT_START_LEN; 540 if (*name_start == '\0') 541 /* FMT_START at end of opt_value. */ 542 break; 543 544 name_end = strstr(name_start, FMT_END); 545 if (name_end != NULL) 546 { 547 cfg_option_t *x_opt; 548 apr_size_t len = name_end - name_start; 549 char *name = apr_pstrmemdup(x_pool, name_start, len); 550 551 x_opt = find_option(cfg, section->name, name, NULL); 552 553 if (x_opt != NULL) 554 { 555 const char *cstring; 556 557 /* Pass back the sub-pool originally provided by 558 make_string_from_option() as an indication of when it 559 should terminate. */ 560 make_string_from_option(&cstring, cfg, section, x_opt, x_pool); 561 562 /* Append the plain text preceding the expansion. */ 563 len = name_start - FMT_START_LEN - copy_from; 564 if (buf == NULL) 565 { 566 buf = svn_stringbuf_ncreate(copy_from, len, x_pool); 567 cfg->x_values = TRUE; 568 } 569 else 570 svn_stringbuf_appendbytes(buf, copy_from, len); 571 572 /* Append the expansion and adjust parse pointers. */ 573 svn_stringbuf_appendcstr(buf, cstring); 574 parse_from = name_end + FMT_END_LEN; 575 copy_from = parse_from; 576 } 577 else 578 /* Though ConfigParser considers the failure to resolve 579 the requested expansion an exception condition, we 580 consider it to be plain text, and look for the start of 581 the next one. */ 582 parse_from = name_end + FMT_END_LEN; 583 } 584 else 585 /* Though ConfigParser treats unterminated format specifiers 586 as an exception condition, we consider them to be plain 587 text. The fact that there are no more format specifier 588 endings means we're done parsing. */ 589 parse_from = NULL; 590 } 591 592 if (buf != NULL) 593 { 594 /* Copy the remainder of the plain text. */ 595 svn_stringbuf_appendcstr(buf, copy_from); 596 *opt_x_valuep = buf->data; 597 } 598 else 599 *opt_x_valuep = NULL; 600} 601 602static cfg_section_t * 603svn_config_addsection(svn_config_t *cfg, 604 const char *section) 605{ 606 cfg_section_t *s; 607 const char *hash_key; 608 609 s = apr_palloc(cfg->pool, sizeof(cfg_section_t)); 610 s->name = apr_pstrdup(cfg->pool, section); 611 if(cfg->section_names_case_sensitive) 612 hash_key = s->name; 613 else 614 hash_key = make_hash_key(apr_pstrdup(cfg->pool, section)); 615 s->options = apr_hash_make(cfg->pool); 616 svn_hash_sets(cfg->sections, hash_key, s); 617 618 return s; 619} 620 621static void 622svn_config_create_option(cfg_option_t **opt, 623 const char *option, 624 const char *value, 625 svn_boolean_t option_names_case_sensitive, 626 apr_pool_t *pool) 627{ 628 cfg_option_t *o; 629 630 o = apr_palloc(pool, sizeof(cfg_option_t)); 631 o->name = apr_pstrdup(pool, option); 632 if(option_names_case_sensitive) 633 o->hash_key = o->name; 634 else 635 o->hash_key = make_hash_key(apr_pstrdup(pool, option)); 636 637 o->value = apr_pstrdup(pool, value); 638 o->x_value = NULL; 639 o->expanded = FALSE; 640 641 *opt = o; 642} 643 644 645void 646svn_config_get(svn_config_t *cfg, const char **valuep, 647 const char *section, const char *option, 648 const char *default_value) 649{ 650 *valuep = default_value; 651 if (cfg) 652 { 653 cfg_section_t *sec; 654 cfg_option_t *opt = find_option(cfg, section, option, &sec); 655 if (opt != NULL) 656 { 657 make_string_from_option(valuep, cfg, sec, opt, NULL); 658 } 659 else 660 /* before attempting to expand an option, check for the placeholder. 661 * If none is there, there is no point in calling expand_option_value. 662 */ 663 if (default_value && strchr(default_value, '%')) 664 { 665 apr_pool_t *tmp_pool = svn_pool_create(cfg->x_pool); 666 const char *x_default; 667 expand_option_value(cfg, sec, default_value, &x_default, tmp_pool); 668 if (x_default) 669 { 670 svn_stringbuf_set(cfg->tmp_value, x_default); 671 *valuep = cfg->tmp_value->data; 672 } 673 svn_pool_destroy(tmp_pool); 674 } 675 } 676} 677 678 679 680void 681svn_config_set(svn_config_t *cfg, 682 const char *section, const char *option, 683 const char *value) 684{ 685 cfg_section_t *sec; 686 cfg_option_t *opt; 687 688 remove_expansions(cfg); 689 690 opt = find_option(cfg, section, option, &sec); 691 if (opt != NULL) 692 { 693 /* Replace the option's value. */ 694 opt->value = apr_pstrdup(cfg->pool, value); 695 opt->expanded = FALSE; 696 return; 697 } 698 699 /* Create a new option */ 700 svn_config_create_option(&opt, option, value, 701 cfg->option_names_case_sensitive, 702 cfg->pool); 703 704 if (sec == NULL) 705 { 706 /* Even the section doesn't exist. Create it. */ 707 sec = svn_config_addsection(cfg, section); 708 } 709 710 svn_hash_sets(sec->options, opt->hash_key, opt); 711} 712 713 714 715/* Set *BOOLP to true or false depending (case-insensitively) on INPUT. 716 If INPUT is null, set *BOOLP to DEFAULT_VALUE. 717 718 INPUT is a string indicating truth or falsehood in any of the usual 719 ways: "true"/"yes"/"on"/etc, "false"/"no"/"off"/etc. 720 721 If INPUT is neither NULL nor a recognized string, return an error 722 with code SVN_ERR_BAD_CONFIG_VALUE; use SECTION and OPTION in 723 constructing the error string. */ 724static svn_error_t * 725get_bool(svn_boolean_t *boolp, const char *input, svn_boolean_t default_value, 726 const char *section, const char *option) 727{ 728 svn_tristate_t value = svn_tristate__from_word(input); 729 730 if (value == svn_tristate_true) 731 *boolp = TRUE; 732 else if (value == svn_tristate_false) 733 *boolp = FALSE; 734 else if (input == NULL) /* no value provided */ 735 *boolp = default_value; 736 737 else if (section) /* unrecognized value */ 738 return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 739 _("Config error: invalid boolean " 740 "value '%s' for '[%s] %s'"), 741 input, section, option); 742 else 743 return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL, 744 _("Config error: invalid boolean " 745 "value '%s' for '%s'"), 746 input, option); 747 748 return SVN_NO_ERROR; 749} 750 751 752svn_error_t * 753svn_config_get_bool(svn_config_t *cfg, svn_boolean_t *valuep, 754 const char *section, const char *option, 755 svn_boolean_t default_value) 756{ 757 const char *tmp_value; 758 svn_config_get(cfg, &tmp_value, section, option, NULL); 759 return get_bool(valuep, tmp_value, default_value, section, option); 760} 761 762 763 764void 765svn_config_set_bool(svn_config_t *cfg, 766 const char *section, const char *option, 767 svn_boolean_t value) 768{ 769 svn_config_set(cfg, section, option, 770 (value ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE)); 771} 772 773svn_error_t * 774svn_config_get_int64(svn_config_t *cfg, 775 apr_int64_t *valuep, 776 const char *section, 777 const char *option, 778 apr_int64_t default_value) 779{ 780 const char *tmp_value; 781 svn_config_get(cfg, &tmp_value, section, option, NULL); 782 if (tmp_value) 783 return svn_cstring_strtoi64(valuep, tmp_value, 784 APR_INT64_MIN, APR_INT64_MAX, 10); 785 786 *valuep = default_value; 787 return SVN_NO_ERROR; 788} 789 790void 791svn_config_set_int64(svn_config_t *cfg, 792 const char *section, 793 const char *option, 794 apr_int64_t value) 795{ 796 svn_config_set(cfg, section, option, 797 apr_psprintf(cfg->pool, "%" APR_INT64_T_FMT, value)); 798} 799 800svn_error_t * 801svn_config_get_yes_no_ask(svn_config_t *cfg, const char **valuep, 802 const char *section, const char *option, 803 const char* default_value) 804{ 805 const char *tmp_value; 806 807 svn_config_get(cfg, &tmp_value, section, option, NULL); 808 809 if (! tmp_value) 810 tmp_value = default_value; 811 812 if (tmp_value && (0 == svn_cstring_casecmp(tmp_value, SVN_CONFIG_ASK))) 813 { 814 *valuep = SVN_CONFIG_ASK; 815 } 816 else 817 { 818 svn_boolean_t bool_val; 819 /* We already incorporated default_value into tmp_value if 820 necessary, so the FALSE below will be ignored unless the 821 caller is doing something it shouldn't be doing. */ 822 SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option)); 823 *valuep = bool_val ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE; 824 } 825 826 return SVN_NO_ERROR; 827} 828 829svn_error_t * 830svn_config_get_tristate(svn_config_t *cfg, svn_tristate_t *valuep, 831 const char *section, const char *option, 832 const char *unknown_value, 833 svn_tristate_t default_value) 834{ 835 const char *tmp_value; 836 837 svn_config_get(cfg, &tmp_value, section, option, NULL); 838 839 if (! tmp_value) 840 { 841 *valuep = default_value; 842 } 843 else if (0 == svn_cstring_casecmp(tmp_value, unknown_value)) 844 { 845 *valuep = svn_tristate_unknown; 846 } 847 else 848 { 849 svn_boolean_t bool_val; 850 /* We already incorporated default_value into tmp_value if 851 necessary, so the FALSE below will be ignored unless the 852 caller is doing something it shouldn't be doing. */ 853 SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option)); 854 *valuep = bool_val ? svn_tristate_true : svn_tristate_false; 855 } 856 857 return SVN_NO_ERROR; 858} 859 860int 861svn_config_enumerate_sections(svn_config_t *cfg, 862 svn_config_section_enumerator_t callback, 863 void *baton) 864{ 865 apr_hash_index_t *sec_ndx; 866 int count = 0; 867 apr_pool_t *subpool = svn_pool_create(cfg->x_pool); 868 869 for (sec_ndx = apr_hash_first(subpool, cfg->sections); 870 sec_ndx != NULL; 871 sec_ndx = apr_hash_next(sec_ndx)) 872 { 873 void *sec_ptr; 874 cfg_section_t *sec; 875 876 apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); 877 sec = sec_ptr; 878 ++count; 879 if (!callback(sec->name, baton)) 880 break; 881 } 882 883 svn_pool_destroy(subpool); 884 return count; 885} 886 887 888int 889svn_config_enumerate_sections2(svn_config_t *cfg, 890 svn_config_section_enumerator2_t callback, 891 void *baton, apr_pool_t *pool) 892{ 893 apr_hash_index_t *sec_ndx; 894 apr_pool_t *iteration_pool; 895 int count = 0; 896 897 iteration_pool = svn_pool_create(pool); 898 for (sec_ndx = apr_hash_first(pool, cfg->sections); 899 sec_ndx != NULL; 900 sec_ndx = apr_hash_next(sec_ndx)) 901 { 902 void *sec_ptr; 903 cfg_section_t *sec; 904 905 apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); 906 sec = sec_ptr; 907 ++count; 908 svn_pool_clear(iteration_pool); 909 if (!callback(sec->name, baton, iteration_pool)) 910 break; 911 } 912 svn_pool_destroy(iteration_pool); 913 914 return count; 915} 916 917 918 919int 920svn_config_enumerate(svn_config_t *cfg, const char *section, 921 svn_config_enumerator_t callback, void *baton) 922{ 923 cfg_section_t *sec; 924 apr_hash_index_t *opt_ndx; 925 int count; 926 apr_pool_t *subpool; 927 928 find_option(cfg, section, NULL, &sec); 929 if (sec == NULL) 930 return 0; 931 932 subpool = svn_pool_create(cfg->x_pool); 933 count = 0; 934 for (opt_ndx = apr_hash_first(subpool, sec->options); 935 opt_ndx != NULL; 936 opt_ndx = apr_hash_next(opt_ndx)) 937 { 938 void *opt_ptr; 939 cfg_option_t *opt; 940 const char *temp_value; 941 942 apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr); 943 opt = opt_ptr; 944 945 ++count; 946 make_string_from_option(&temp_value, cfg, sec, opt, NULL); 947 if (!callback(opt->name, temp_value, baton)) 948 break; 949 } 950 951 svn_pool_destroy(subpool); 952 return count; 953} 954 955 956int 957svn_config_enumerate2(svn_config_t *cfg, const char *section, 958 svn_config_enumerator2_t callback, void *baton, 959 apr_pool_t *pool) 960{ 961 cfg_section_t *sec; 962 apr_hash_index_t *opt_ndx; 963 apr_pool_t *iteration_pool; 964 int count; 965 966 find_option(cfg, section, NULL, &sec); 967 if (sec == NULL) 968 return 0; 969 970 iteration_pool = svn_pool_create(pool); 971 count = 0; 972 for (opt_ndx = apr_hash_first(pool, sec->options); 973 opt_ndx != NULL; 974 opt_ndx = apr_hash_next(opt_ndx)) 975 { 976 void *opt_ptr; 977 cfg_option_t *opt; 978 const char *temp_value; 979 980 apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr); 981 opt = opt_ptr; 982 983 ++count; 984 make_string_from_option(&temp_value, cfg, sec, opt, NULL); 985 svn_pool_clear(iteration_pool); 986 if (!callback(opt->name, temp_value, baton, iteration_pool)) 987 break; 988 } 989 svn_pool_destroy(iteration_pool); 990 991 return count; 992} 993 994 995 996/* Baton for search_groups() */ 997struct search_groups_baton 998{ 999 const char *key; /* Provided by caller of svn_config_find_group */ 1000 const char *match; /* Filled in by search_groups */ 1001 apr_pool_t *pool; 1002}; 1003 1004 1005/* This is an `svn_config_enumerator_t' function, and BATON is a 1006 * `struct search_groups_baton *'. 1007 */ 1008static svn_boolean_t search_groups(const char *name, 1009 const char *value, 1010 void *baton, 1011 apr_pool_t *pool) 1012{ 1013 struct search_groups_baton *b = baton; 1014 apr_array_header_t *list; 1015 1016 list = svn_cstring_split(value, ",", TRUE, pool); 1017 if (svn_cstring_match_glob_list(b->key, list)) 1018 { 1019 /* Fill in the match and return false, to stop enumerating. */ 1020 b->match = apr_pstrdup(b->pool, name); 1021 return FALSE; 1022 } 1023 else 1024 return TRUE; 1025} 1026 1027 1028const char *svn_config_find_group(svn_config_t *cfg, const char *key, 1029 const char *master_section, 1030 apr_pool_t *pool) 1031{ 1032 struct search_groups_baton gb; 1033 1034 gb.key = key; 1035 gb.match = NULL; 1036 gb.pool = pool; 1037 (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool); 1038 return gb.match; 1039} 1040 1041 1042const char* 1043svn_config_get_server_setting(svn_config_t *cfg, 1044 const char* server_group, 1045 const char* option_name, 1046 const char* default_value) 1047{ 1048 const char *retval; 1049 svn_config_get(cfg, &retval, SVN_CONFIG_SECTION_GLOBAL, 1050 option_name, default_value); 1051 if (server_group) 1052 { 1053 svn_config_get(cfg, &retval, server_group, option_name, retval); 1054 } 1055 return retval; 1056} 1057 1058 1059svn_error_t * 1060svn_config_dup(svn_config_t **cfgp, 1061 svn_config_t *src, 1062 apr_pool_t *pool) 1063{ 1064 apr_hash_index_t *sectidx; 1065 apr_hash_index_t *optidx; 1066 1067 *cfgp = 0; 1068 SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool)); 1069 1070 (*cfgp)->x_values = src->x_values; 1071 (*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive; 1072 (*cfgp)->option_names_case_sensitive = src->option_names_case_sensitive; 1073 1074 for (sectidx = apr_hash_first(pool, src->sections); 1075 sectidx != NULL; 1076 sectidx = apr_hash_next(sectidx)) 1077 { 1078 const void *sectkey; 1079 void *sectval; 1080 apr_ssize_t sectkeyLength; 1081 cfg_section_t * srcsect; 1082 cfg_section_t * destsec; 1083 1084 apr_hash_this(sectidx, §key, §keyLength, §val); 1085 srcsect = sectval; 1086 1087 destsec = svn_config_addsection(*cfgp, srcsect->name); 1088 1089 for (optidx = apr_hash_first(pool, srcsect->options); 1090 optidx != NULL; 1091 optidx = apr_hash_next(optidx)) 1092 { 1093 const void *optkey; 1094 void *optval; 1095 apr_ssize_t optkeyLength; 1096 cfg_option_t *srcopt; 1097 cfg_option_t *destopt; 1098 1099 apr_hash_this(optidx, &optkey, &optkeyLength, &optval); 1100 srcopt = optval; 1101 1102 svn_config_create_option(&destopt, srcopt->name, srcopt->value, 1103 (*cfgp)->option_names_case_sensitive, 1104 pool); 1105 1106 destopt->value = apr_pstrdup(pool, srcopt->value); 1107 destopt->x_value = apr_pstrdup(pool, srcopt->x_value); 1108 destopt->expanded = srcopt->expanded; 1109 apr_hash_set(destsec->options, 1110 apr_pstrdup(pool, (const char*)optkey), 1111 optkeyLength, destopt); 1112 } 1113 } 1114 1115 return SVN_NO_ERROR; 1116} 1117 1118svn_error_t * 1119svn_config_copy_config(apr_hash_t **cfg_hash, 1120 apr_hash_t *src_hash, 1121 apr_pool_t *pool) 1122{ 1123 apr_hash_index_t *cidx; 1124 1125 *cfg_hash = apr_hash_make(pool); 1126 for (cidx = apr_hash_first(pool, src_hash); 1127 cidx != NULL; 1128 cidx = apr_hash_next(cidx)) 1129 { 1130 const void *ckey; 1131 void *cval; 1132 apr_ssize_t ckeyLength; 1133 svn_config_t * srcconfig; 1134 svn_config_t * destconfig; 1135 1136 apr_hash_this(cidx, &ckey, &ckeyLength, &cval); 1137 srcconfig = cval; 1138 1139 SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool)); 1140 1141 apr_hash_set(*cfg_hash, 1142 apr_pstrdup(pool, (const char*)ckey), 1143 ckeyLength, destconfig); 1144 } 1145 1146 return SVN_NO_ERROR; 1147} 1148 1149svn_error_t* 1150svn_config_get_server_setting_int(svn_config_t *cfg, 1151 const char *server_group, 1152 const char *option_name, 1153 apr_int64_t default_value, 1154 apr_int64_t *result_value, 1155 apr_pool_t *pool) 1156{ 1157 const char* tmp_value; 1158 char *end_pos; 1159 1160 tmp_value = svn_config_get_server_setting(cfg, server_group, 1161 option_name, NULL); 1162 if (tmp_value == NULL) 1163 *result_value = default_value; 1164 else 1165 { 1166 /* read tmp_value as an int now */ 1167 *result_value = apr_strtoi64(tmp_value, &end_pos, 0); 1168 1169 if (*end_pos != 0) 1170 { 1171 return svn_error_createf 1172 (SVN_ERR_BAD_CONFIG_VALUE, NULL, 1173 _("Config error: invalid integer value '%s'"), 1174 tmp_value); 1175 } 1176 } 1177 1178 return SVN_NO_ERROR; 1179} 1180 1181svn_error_t * 1182svn_config_get_server_setting_bool(svn_config_t *cfg, 1183 svn_boolean_t *valuep, 1184 const char *server_group, 1185 const char *option_name, 1186 svn_boolean_t default_value) 1187{ 1188 const char* tmp_value; 1189 tmp_value = svn_config_get_server_setting(cfg, server_group, 1190 option_name, NULL); 1191 return get_bool(valuep, tmp_value, default_value, 1192 server_group, option_name); 1193} 1194 1195 1196svn_boolean_t 1197svn_config_has_section(svn_config_t *cfg, const char *section) 1198{ 1199 cfg_section_t *sec; 1200 1201 /* Canonicalize the hash key */ 1202 svn_stringbuf_set(cfg->tmp_key, section); 1203 if (! cfg->section_names_case_sensitive) 1204 make_hash_key(cfg->tmp_key->data); 1205 1206 sec = svn_hash_gets(cfg->sections, cfg->tmp_key->data); 1207 return sec != NULL; 1208} 1209