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