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. */
44 typedef struct cfg_section_t cfg_section_t;
45 struct 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. */
56 typedef struct cfg_option_t cfg_option_t;
57 struct 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
79 svn_error_t *
svn_config_create2(svn_config_t ** cfgp,svn_boolean_t section_names_case_sensitive,svn_boolean_t option_names_case_sensitive,apr_pool_t * result_pool)80 svn_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
100 svn_error_t *
svn_config_read3(svn_config_t ** cfgp,const char * file,svn_boolean_t must_exist,svn_boolean_t section_names_case_sensitive,svn_boolean_t option_names_case_sensitive,apr_pool_t * result_pool)101 svn_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
136 svn_error_t *
svn_config_parse(svn_config_t ** cfgp,svn_stream_t * stream,svn_boolean_t section_names_case_sensitive,svn_boolean_t option_names_case_sensitive,apr_pool_t * result_pool)137 svn_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 */
176 static svn_error_t *
read_all(svn_config_t ** cfgp,const char * sys_registry_path,const char * usr_registry_path,const char * sys_file_path,const char * usr_file_path,apr_pool_t * pool)177 read_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. */
246 static svn_error_t *
get_category_config(svn_config_t ** cfg,const char * config_dir,const char * category,apr_pool_t * pool)247 get_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
286 svn_error_t *
svn_config_get_config(apr_hash_t ** cfg_hash,const char * config_dir,apr_pool_t * pool)287 svn_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. */
315 static void
for_each_option(svn_config_t * cfg,void * baton,apr_pool_t * pool,svn_boolean_t callback (void * same_baton,cfg_section_t * section,cfg_option_t * option))316 for_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
351 static svn_boolean_t
merge_callback(void * baton,cfg_section_t * section,cfg_option_t * option)352 merge_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
358 svn_error_t *
svn_config_merge(svn_config_t * cfg,const char * file,svn_boolean_t must_exist)359 svn_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. */
381 static svn_boolean_t
rmex_callback(void * baton,cfg_section_t * section,cfg_option_t * option)382 rmex_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
395 static void
remove_expansions(svn_config_t * cfg)396 remove_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. */
409 static APR_INLINE char *
make_hash_key(char * key)410 make_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. */
422 static cfg_option_t *
find_option(svn_config_t * cfg,const char * section,const char * option,cfg_section_t ** sectionp)423 find_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(). */
464 static void
465 expand_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(). */
472 static void
make_string_from_option(const char ** valuep,svn_config_t * cfg,cfg_section_t * section,cfg_option_t * opt,apr_pool_t * x_pool)473 make_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. */
525 static void
expand_option_value(svn_config_t * cfg,cfg_section_t * section,const char * opt_value,const char ** opt_x_valuep,apr_pool_t * x_pool)526 expand_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
602 static cfg_section_t *
svn_config_addsection(svn_config_t * cfg,const char * section)603 svn_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
621 static void
svn_config_create_option(cfg_option_t ** opt,const char * option,const char * value,svn_boolean_t option_names_case_sensitive,apr_pool_t * pool)622 svn_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
645 void
svn_config_get(svn_config_t * cfg,const char ** valuep,const char * section,const char * option,const char * default_value)646 svn_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
680 void
svn_config_set(svn_config_t * cfg,const char * section,const char * option,const char * value)681 svn_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. */
724 static svn_error_t *
get_bool(svn_boolean_t * boolp,const char * input,svn_boolean_t default_value,const char * section,const char * option)725 get_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
752 svn_error_t *
svn_config_get_bool(svn_config_t * cfg,svn_boolean_t * valuep,const char * section,const char * option,svn_boolean_t default_value)753 svn_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
764 void
svn_config_set_bool(svn_config_t * cfg,const char * section,const char * option,svn_boolean_t value)765 svn_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
773 svn_error_t *
svn_config_get_int64(svn_config_t * cfg,apr_int64_t * valuep,const char * section,const char * option,apr_int64_t default_value)774 svn_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
790 void
svn_config_set_int64(svn_config_t * cfg,const char * section,const char * option,apr_int64_t value)791 svn_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
800 svn_error_t *
svn_config_get_yes_no_ask(svn_config_t * cfg,const char ** valuep,const char * section,const char * option,const char * default_value)801 svn_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
829 svn_error_t *
svn_config_get_tristate(svn_config_t * cfg,svn_tristate_t * valuep,const char * section,const char * option,const char * unknown_value,svn_tristate_t default_value)830 svn_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
860 int
svn_config_enumerate_sections(svn_config_t * cfg,svn_config_section_enumerator_t callback,void * baton)861 svn_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
888 int
svn_config_enumerate_sections2(svn_config_t * cfg,svn_config_section_enumerator2_t callback,void * baton,apr_pool_t * pool)889 svn_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
919 int
svn_config_enumerate(svn_config_t * cfg,const char * section,svn_config_enumerator_t callback,void * baton)920 svn_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
956 int
svn_config_enumerate2(svn_config_t * cfg,const char * section,svn_config_enumerator2_t callback,void * baton,apr_pool_t * pool)957 svn_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() */
997 struct 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 */
search_groups(const char * name,const char * value,void * baton,apr_pool_t * pool)1008 static 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
svn_config_find_group(svn_config_t * cfg,const char * key,const char * master_section,apr_pool_t * pool)1028 const 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
1042 const char*
svn_config_get_server_setting(svn_config_t * cfg,const char * server_group,const char * option_name,const char * default_value)1043 svn_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
1059 svn_error_t *
svn_config_dup(svn_config_t ** cfgp,svn_config_t * src,apr_pool_t * pool)1060 svn_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
1118 svn_error_t *
svn_config_copy_config(apr_hash_t ** cfg_hash,apr_hash_t * src_hash,apr_pool_t * pool)1119 svn_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
1149 svn_error_t*
svn_config_get_server_setting_int(svn_config_t * cfg,const char * server_group,const char * option_name,apr_int64_t default_value,apr_int64_t * result_value,apr_pool_t * pool)1150 svn_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
1181 svn_error_t *
svn_config_get_server_setting_bool(svn_config_t * cfg,svn_boolean_t * valuep,const char * server_group,const char * option_name,svn_boolean_t default_value)1182 svn_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
1196 svn_boolean_t
svn_config_has_section(svn_config_t * cfg,const char * section)1197 svn_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