]> CyberLeo.Net >> Repos - FreeBSD/stable/10.git/blob - contrib/subversion/subversion/libsvn_subr/config.c
MFC r275385 (by bapt):
[FreeBSD/stable/10.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 #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 \f
44
45
46 /* Section table entries. */
47 typedef struct cfg_section_t cfg_section_t;
48 struct 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. */
59 typedef struct cfg_option_t cfg_option_t;
60 struct 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 \f
82 svn_error_t *
83 svn_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
104 svn_error_t *
105 svn_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
140 svn_error_t *
141 svn_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  */
180 static svn_error_t *
181 read_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. */
251 static svn_error_t *
252 get_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
291 svn_error_t *
292 svn_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
310 svn_error_t *
311 svn_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 \f
328 /* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION)
329    pair.  Stop if CALLBACK returns TRUE.  Allocate from POOL. */
330 static void
331 for_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 \f
366 static svn_boolean_t
367 merge_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
373 svn_error_t *
374 svn_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 \f
394 /* Remove variable expansions from CFG.  Walk through the options tree,
395    killing all expanded values, then clear the expanded value pool. */
396 static svn_boolean_t
397 rmex_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
410 static void
411 remove_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 \f
423 /* Canonicalize a string for hashing.  Modifies KEY in place. */
424 static APR_INLINE char *
425 make_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. */
435 static void *
436 get_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. */
457 static cfg_option_t *
458 find_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(). */
485 static void
486 expand_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(). */
493 static void
494 make_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. */
553 static void
554 expand_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
630 static cfg_section_t *
631 svn_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
649 static void
650 svn_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
672 svn_boolean_t
673 svn_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 \f
700 void
701 svn_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 \f
735 void
736 svn_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 \f
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. */
790 static svn_error_t *
791 get_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
818 svn_error_t *
819 svn_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 \f
830 void
831 svn_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
839 svn_error_t *
840 svn_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
856 void
857 svn_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
866 svn_error_t *
867 svn_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
895 svn_error_t *
896 svn_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 \f
926 int
927 svn_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
954 int
955 svn_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 \f
985 int
986 svn_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
1022 int
1023 svn_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 \f
1062 /* Baton for search_groups() */
1063 struct 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  */
1074 static 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
1094 const 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 \f
1108 const char*
1109 svn_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
1125 svn_error_t *
1126 svn_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, &sectkey, &sectkeyLength, &sectval);
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
1184 svn_error_t *
1185 svn_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
1215 svn_error_t*
1216 svn_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
1247 svn_error_t *
1248 svn_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
1262 svn_boolean_t
1263 svn_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 }