]> CyberLeo.Net >> Repos - FreeBSD/releng/10.2.git/blob - contrib/subversion/subversion/libsvn_subr/config.c
- Copy stable/10@285827 to releng/10.2 in preparation for 10.2-RC1
[FreeBSD/releng/10.2.git] / contrib / subversion / subversion / libsvn_subr / config.c
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 \f
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 \f
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 \f
79 svn_error_t *
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 *
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 *
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 *
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 *
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 *
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 \f
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
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 \f
351 static svn_boolean_t
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 *
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 \f
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
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
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 \f
408 /* Canonicalize a string for hashing.  Modifies KEY in place. */
409 static APR_INLINE char *
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 *
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
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
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 *
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
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 \f
645 void
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 \f
680 void
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 \f
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 *
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 *
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 \f
764 void
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 *
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
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 *
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 *
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 \f
860 int
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
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 \f
919 int
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
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 \f
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  */
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
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 \f
1042 const char*
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 *
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, &sectkey, &sectkeyLength, &sectval);
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 *
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*
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 *
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
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 }