1251881Speter/*
2251881Speter * config.c :  reading configuration information
3251881Speter *
4251881Speter * ====================================================================
5251881Speter *    Licensed to the Apache Software Foundation (ASF) under one
6251881Speter *    or more contributor license agreements.  See the NOTICE file
7251881Speter *    distributed with this work for additional information
8251881Speter *    regarding copyright ownership.  The ASF licenses this file
9251881Speter *    to you under the Apache License, Version 2.0 (the
10251881Speter *    "License"); you may not use this file except in compliance
11251881Speter *    with the License.  You may obtain a copy of the License at
12251881Speter *
13251881Speter *      http://www.apache.org/licenses/LICENSE-2.0
14251881Speter *
15251881Speter *    Unless required by applicable law or agreed to in writing,
16251881Speter *    software distributed under the License is distributed on an
17251881Speter *    "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
18251881Speter *    KIND, either express or implied.  See the License for the
19251881Speter *    specific language governing permissions and limitations
20251881Speter *    under the License.
21251881Speter * ====================================================================
22251881Speter */
23251881Speter
24251881Speter
25251881Speter
26251881Speter#define APR_WANT_STRFUNC
27251881Speter#define APR_WANT_MEMFUNC
28251881Speter#include <apr_want.h>
29251881Speter
30251881Speter#include <apr_general.h>
31251881Speter#include <apr_lib.h>
32251881Speter#include "svn_hash.h"
33251881Speter#include "svn_error.h"
34251881Speter#include "svn_pools.h"
35251881Speter#include "config_impl.h"
36251881Speter
37251881Speter#include "svn_private_config.h"
38251881Speter#include "private/svn_dep_compat.h"
39251881Speter
40251881Speter
41251881Speter
42251881Speter
43251881Speter/* Section table entries. */
44251881Spetertypedef struct cfg_section_t cfg_section_t;
45251881Speterstruct cfg_section_t
46251881Speter{
47251881Speter  /* The section name. */
48251881Speter  const char *name;
49251881Speter
50251881Speter  /* Table of cfg_option_t's. */
51251881Speter  apr_hash_t *options;
52251881Speter};
53251881Speter
54251881Speter
55251881Speter/* Option table entries. */
56251881Spetertypedef struct cfg_option_t cfg_option_t;
57251881Speterstruct cfg_option_t
58251881Speter{
59251881Speter  /* The option name. */
60251881Speter  const char *name;
61251881Speter
62251881Speter  /* The option name, converted into a hash key. */
63251881Speter  const char *hash_key;
64251881Speter
65251881Speter  /* The unexpanded option value. */
66251881Speter  const char *value;
67251881Speter
68251881Speter  /* The expanded option value. */
69251881Speter  const char *x_value;
70251881Speter
71251881Speter  /* Expansion flag. If this is TRUE, this value has already been expanded.
72251881Speter     In this case, if x_value is NULL, no expansions were necessary,
73251881Speter     and value should be used directly. */
74251881Speter  svn_boolean_t expanded;
75251881Speter};
76251881Speter
77251881Speter
78251881Speter
79251881Spetersvn_error_t *
80251881Spetersvn_config_create2(svn_config_t **cfgp,
81251881Speter                   svn_boolean_t section_names_case_sensitive,
82251881Speter                   svn_boolean_t option_names_case_sensitive,
83251881Speter                   apr_pool_t *result_pool)
84251881Speter{
85251881Speter  svn_config_t *cfg = apr_palloc(result_pool, sizeof(*cfg));
86251881Speter
87251881Speter  cfg->sections = apr_hash_make(result_pool);
88251881Speter  cfg->pool = result_pool;
89251881Speter  cfg->x_pool = svn_pool_create(result_pool);
90251881Speter  cfg->x_values = FALSE;
91251881Speter  cfg->tmp_key = svn_stringbuf_create_empty(result_pool);
92251881Speter  cfg->tmp_value = svn_stringbuf_create_empty(result_pool);
93251881Speter  cfg->section_names_case_sensitive = section_names_case_sensitive;
94251881Speter  cfg->option_names_case_sensitive = option_names_case_sensitive;
95251881Speter
96251881Speter  *cfgp = cfg;
97251881Speter  return SVN_NO_ERROR;
98251881Speter}
99251881Speter
100251881Spetersvn_error_t *
101251881Spetersvn_config_read3(svn_config_t **cfgp, const char *file,
102251881Speter                 svn_boolean_t must_exist,
103251881Speter                 svn_boolean_t section_names_case_sensitive,
104251881Speter                 svn_boolean_t option_names_case_sensitive,
105251881Speter                 apr_pool_t *result_pool)
106251881Speter{
107251881Speter  svn_config_t *cfg;
108251881Speter  svn_error_t *err;
109251881Speter
110251881Speter  SVN_ERR(svn_config_create2(&cfg,
111251881Speter                             section_names_case_sensitive,
112251881Speter                             option_names_case_sensitive,
113251881Speter                             result_pool));
114251881Speter
115251881Speter  /* Yes, this is platform-specific code in Subversion, but there's no
116251881Speter     practical way to migrate it into APR, as it's simultaneously
117251881Speter     Subversion-specific and Windows-specific.  Even if we eventually
118251881Speter     want to have APR offer a generic config-reading interface, it
119251881Speter     makes sense to test it here first and migrate it later. */
120251881Speter#ifdef WIN32
121251881Speter  if (0 == strncmp(file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN))
122251881Speter    err = svn_config__parse_registry(cfg, file + SVN_REGISTRY_PREFIX_LEN,
123251881Speter                                     must_exist, result_pool);
124251881Speter  else
125251881Speter#endif /* WIN32 */
126251881Speter    err = svn_config__parse_file(cfg, file, must_exist, result_pool);
127251881Speter
128251881Speter  if (err != SVN_NO_ERROR)
129251881Speter    return err;
130251881Speter  else
131251881Speter    *cfgp = cfg;
132251881Speter
133251881Speter  return SVN_NO_ERROR;
134251881Speter}
135251881Speter
136251881Spetersvn_error_t *
137251881Spetersvn_config_parse(svn_config_t **cfgp, svn_stream_t *stream,
138251881Speter                 svn_boolean_t section_names_case_sensitive,
139251881Speter                 svn_boolean_t option_names_case_sensitive,
140251881Speter                 apr_pool_t *result_pool)
141251881Speter{
142251881Speter  svn_config_t *cfg;
143251881Speter  svn_error_t *err;
144251881Speter  apr_pool_t *scratch_pool = svn_pool_create(result_pool);
145251881Speter
146251881Speter  err = svn_config_create2(&cfg,
147251881Speter                           section_names_case_sensitive,
148251881Speter                           option_names_case_sensitive,
149251881Speter                           result_pool);
150251881Speter
151251881Speter  if (err == SVN_NO_ERROR)
152251881Speter    err = svn_config__parse_stream(cfg, stream, result_pool, scratch_pool);
153251881Speter
154251881Speter  if (err == SVN_NO_ERROR)
155251881Speter    *cfgp = cfg;
156251881Speter
157251881Speter  svn_pool_destroy(scratch_pool);
158251881Speter
159251881Speter  return err;
160251881Speter}
161251881Speter
162251881Speter/* Read various configuration sources into *CFGP, in this order, with
163251881Speter * later reads overriding the results of earlier ones:
164251881Speter *
165251881Speter *    1. SYS_REGISTRY_PATH   (only on Win32, but ignored if NULL)
166251881Speter *
167251881Speter *    2. SYS_FILE_PATH       (everywhere, but ignored if NULL)
168251881Speter *
169251881Speter *    3. USR_REGISTRY_PATH   (only on Win32, but ignored if NULL)
170251881Speter *
171251881Speter *    4. USR_FILE_PATH       (everywhere, but ignored if NULL)
172251881Speter *
173251881Speter * Allocate *CFGP in POOL.  Even if no configurations are read,
174251881Speter * allocate an empty *CFGP.
175251881Speter */
176251881Speterstatic svn_error_t *
177251881Speterread_all(svn_config_t **cfgp,
178251881Speter         const char *sys_registry_path,
179251881Speter         const char *usr_registry_path,
180251881Speter         const char *sys_file_path,
181251881Speter         const char *usr_file_path,
182251881Speter         apr_pool_t *pool)
183251881Speter{
184251881Speter  svn_boolean_t red_config = FALSE;  /* "red" is the past tense of "read" */
185251881Speter
186251881Speter  /*** Read system-wide configurations first... ***/
187251881Speter
188251881Speter#ifdef WIN32
189251881Speter  if (sys_registry_path)
190251881Speter    {
191251881Speter      SVN_ERR(svn_config_read2(cfgp, sys_registry_path, FALSE, FALSE, pool));
192251881Speter      red_config = TRUE;
193251881Speter    }
194251881Speter#endif /* WIN32 */
195251881Speter
196251881Speter  if (sys_file_path)
197251881Speter    {
198251881Speter      if (red_config)
199251881Speter        SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE));
200251881Speter      else
201251881Speter        {
202251881Speter          SVN_ERR(svn_config_read3(cfgp, sys_file_path,
203251881Speter                                   FALSE, FALSE, FALSE, pool));
204251881Speter          red_config = TRUE;
205251881Speter        }
206251881Speter    }
207251881Speter
208251881Speter  /*** ...followed by per-user configurations. ***/
209251881Speter
210251881Speter#ifdef WIN32
211251881Speter  if (usr_registry_path)
212251881Speter    {
213251881Speter      if (red_config)
214251881Speter        SVN_ERR(svn_config_merge(*cfgp, usr_registry_path, FALSE));
215251881Speter      else
216251881Speter        {
217251881Speter          SVN_ERR(svn_config_read2(cfgp, usr_registry_path,
218251881Speter                                   FALSE, FALSE, pool));
219251881Speter          red_config = TRUE;
220251881Speter        }
221251881Speter    }
222251881Speter#endif /* WIN32 */
223251881Speter
224251881Speter  if (usr_file_path)
225251881Speter    {
226251881Speter      if (red_config)
227251881Speter        SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE));
228251881Speter      else
229251881Speter        {
230251881Speter          SVN_ERR(svn_config_read3(cfgp, usr_file_path,
231251881Speter                                   FALSE, FALSE, FALSE, pool));
232251881Speter          red_config = TRUE;
233251881Speter        }
234251881Speter    }
235251881Speter
236251881Speter  if (! red_config)
237251881Speter    SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
238251881Speter
239251881Speter  return SVN_NO_ERROR;
240251881Speter}
241251881Speter
242251881Speter
243251881Speter/* CONFIG_DIR provides an override for the default behavior of reading
244251881Speter   the default set of overlay files described by read_all()'s doc
245251881Speter   string. */
246251881Speterstatic svn_error_t *
247251881Speterget_category_config(svn_config_t **cfg,
248251881Speter                    const char *config_dir,
249251881Speter                    const char *category,
250251881Speter                    apr_pool_t *pool)
251251881Speter{
252251881Speter  const char *usr_reg_path = NULL, *sys_reg_path = NULL;
253251881Speter  const char *usr_cfg_path, *sys_cfg_path;
254251881Speter  svn_error_t *err = NULL;
255251881Speter
256251881Speter  *cfg = NULL;
257251881Speter
258251881Speter  if (! config_dir)
259251881Speter    {
260251881Speter#ifdef WIN32
261251881Speter      sys_reg_path = apr_pstrcat(pool, SVN_REGISTRY_SYS_CONFIG_PATH,
262251881Speter                                 category, NULL);
263251881Speter      usr_reg_path = apr_pstrcat(pool, SVN_REGISTRY_USR_CONFIG_PATH,
264251881Speter                                 category, NULL);
265251881Speter#endif /* WIN32 */
266251881Speter
267251881Speter      err = svn_config__sys_config_path(&sys_cfg_path, category, pool);
268251881Speter      if ((err) && (err->apr_err == SVN_ERR_BAD_FILENAME))
269251881Speter        {
270251881Speter          sys_cfg_path = NULL;
271251881Speter          svn_error_clear(err);
272251881Speter        }
273251881Speter      else if (err)
274251881Speter        return err;
275251881Speter    }
276251881Speter  else
277251881Speter    sys_cfg_path = NULL;
278251881Speter
279251881Speter  SVN_ERR(svn_config_get_user_config_path(&usr_cfg_path, config_dir, category,
280251881Speter                                          pool));
281251881Speter  return read_all(cfg, sys_reg_path, usr_reg_path,
282251881Speter                  sys_cfg_path, usr_cfg_path, pool);
283251881Speter}
284251881Speter
285251881Speter
286251881Spetersvn_error_t *
287251881Spetersvn_config_get_config(apr_hash_t **cfg_hash,
288251881Speter                      const char *config_dir,
289251881Speter                      apr_pool_t *pool)
290251881Speter{
291251881Speter  svn_config_t *cfg;
292251881Speter  *cfg_hash = apr_hash_make(pool);
293251881Speter
294251881Speter#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_SERVERS) - 1)
295251881Speter  SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_SERVERS,
296251881Speter                              pool));
297251881Speter  if (cfg)
298251881Speter    apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, CATLEN, cfg);
299251881Speter#undef CATLEN
300251881Speter
301251881Speter#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_CONFIG) - 1)
302251881Speter  SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_CONFIG,
303251881Speter                              pool));
304251881Speter  if (cfg)
305251881Speter    apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, CATLEN, cfg);
306251881Speter#undef CATLEN
307251881Speter
308251881Speter  return SVN_NO_ERROR;
309251881Speter}
310251881Speter
311251881Speter
312251881Speter
313251881Speter/* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION)
314251881Speter   pair.  Stop if CALLBACK returns TRUE.  Allocate from POOL. */
315251881Speterstatic void
316251881Speterfor_each_option(svn_config_t *cfg, void *baton, apr_pool_t *pool,
317251881Speter                svn_boolean_t callback(void *same_baton,
318251881Speter                                       cfg_section_t *section,
319251881Speter                                       cfg_option_t *option))
320251881Speter{
321251881Speter  apr_hash_index_t *sec_ndx;
322251881Speter  for (sec_ndx = apr_hash_first(pool, cfg->sections);
323251881Speter       sec_ndx != NULL;
324251881Speter       sec_ndx = apr_hash_next(sec_ndx))
325251881Speter    {
326251881Speter      void *sec_ptr;
327251881Speter      cfg_section_t *sec;
328251881Speter      apr_hash_index_t *opt_ndx;
329251881Speter
330251881Speter      apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
331251881Speter      sec = sec_ptr;
332251881Speter
333251881Speter      for (opt_ndx = apr_hash_first(pool, sec->options);
334251881Speter           opt_ndx != NULL;
335251881Speter           opt_ndx = apr_hash_next(opt_ndx))
336251881Speter        {
337251881Speter          void *opt_ptr;
338251881Speter          cfg_option_t *opt;
339251881Speter
340251881Speter          apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
341251881Speter          opt = opt_ptr;
342251881Speter
343251881Speter          if (callback(baton, sec, opt))
344251881Speter            return;
345251881Speter        }
346251881Speter    }
347251881Speter}
348251881Speter
349251881Speter
350251881Speter
351251881Speterstatic svn_boolean_t
352251881Spetermerge_callback(void *baton, cfg_section_t *section, cfg_option_t *option)
353251881Speter{
354251881Speter  svn_config_set(baton, section->name, option->name, option->value);
355251881Speter  return FALSE;
356251881Speter}
357251881Speter
358251881Spetersvn_error_t *
359251881Spetersvn_config_merge(svn_config_t *cfg, const char *file,
360251881Speter                 svn_boolean_t must_exist)
361251881Speter{
362251881Speter  /* The original config hash shouldn't change if there's an error
363251881Speter     while reading the confguration, so read into a temporary table.
364251881Speter     ### We could use a tmp subpool for this, since merge_cfg is going
365251881Speter     to be tossed afterwards.  Premature optimization, though? */
366251881Speter  svn_config_t *merge_cfg;
367251881Speter  SVN_ERR(svn_config_read3(&merge_cfg, file, must_exist,
368251881Speter                           cfg->section_names_case_sensitive,
369251881Speter                           cfg->option_names_case_sensitive,
370251881Speter                           cfg->pool));
371251881Speter
372251881Speter  /* Now copy the new options into the original table. */
373251881Speter  for_each_option(merge_cfg, cfg, merge_cfg->pool, merge_callback);
374251881Speter  return SVN_NO_ERROR;
375251881Speter}
376251881Speter
377251881Speter
378251881Speter
379251881Speter/* Remove variable expansions from CFG.  Walk through the options tree,
380251881Speter   killing all expanded values, then clear the expanded value pool. */
381251881Speterstatic svn_boolean_t
382251881Speterrmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option)
383251881Speter{
384251881Speter  /* Only clear the `expanded' flag if the value actually contains
385251881Speter     variable expansions. */
386251881Speter  if (option->expanded && option->x_value != NULL)
387251881Speter    {
388251881Speter      option->x_value = NULL;
389251881Speter      option->expanded = FALSE;
390251881Speter    }
391251881Speter
392251881Speter  return FALSE;
393251881Speter}
394251881Speter
395251881Speterstatic void
396251881Speterremove_expansions(svn_config_t *cfg)
397251881Speter{
398251881Speter  if (!cfg->x_values)
399251881Speter    return;
400251881Speter
401251881Speter  for_each_option(cfg, NULL, cfg->x_pool, rmex_callback);
402251881Speter  svn_pool_clear(cfg->x_pool);
403251881Speter  cfg->x_values = FALSE;
404251881Speter}
405251881Speter
406251881Speter
407251881Speter
408251881Speter/* Canonicalize a string for hashing.  Modifies KEY in place. */
409251881Speterstatic APR_INLINE char *
410251881Spetermake_hash_key(char *key)
411251881Speter{
412251881Speter  register char *p;
413251881Speter  for (p = key; *p != 0; ++p)
414251881Speter    *p = (char)apr_tolower(*p);
415251881Speter  return key;
416251881Speter}
417251881Speter
418251881Speter
419251881Speter/* Return a pointer to an option in CFG, or NULL if it doesn't exist.
420251881Speter   if SECTIONP is non-null, return a pointer to the option's section.
421251881Speter   OPTION may be NULL. */
422251881Speterstatic cfg_option_t *
423251881Speterfind_option(svn_config_t *cfg, const char *section, const char *option,
424251881Speter            cfg_section_t **sectionp)
425251881Speter{
426251881Speter  void *sec_ptr;
427251881Speter
428251881Speter  /* Canonicalize the hash key */
429251881Speter  svn_stringbuf_set(cfg->tmp_key, section);
430251881Speter  if (! cfg->section_names_case_sensitive)
431251881Speter    make_hash_key(cfg->tmp_key->data);
432251881Speter
433251881Speter  sec_ptr = apr_hash_get(cfg->sections, cfg->tmp_key->data,
434251881Speter                         cfg->tmp_key->len);
435251881Speter  if (sectionp != NULL)
436251881Speter    *sectionp = sec_ptr;
437251881Speter
438251881Speter  if (sec_ptr != NULL && option != NULL)
439251881Speter    {
440251881Speter      cfg_section_t *sec = sec_ptr;
441251881Speter      cfg_option_t *opt;
442251881Speter
443251881Speter      /* Canonicalize the option key */
444251881Speter      svn_stringbuf_set(cfg->tmp_key, option);
445251881Speter      if (! cfg->option_names_case_sensitive)
446251881Speter        make_hash_key(cfg->tmp_key->data);
447251881Speter
448251881Speter      opt = apr_hash_get(sec->options, cfg->tmp_key->data,
449251881Speter                         cfg->tmp_key->len);
450251881Speter      /* NOTE: ConfigParser's sections are case sensitive. */
451251881Speter      if (opt == NULL
452251881Speter          && apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0)
453251881Speter        /* Options which aren't found in the requested section are
454251881Speter           also sought after in the default section. */
455251881Speter        opt = find_option(cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec);
456251881Speter      return opt;
457251881Speter    }
458251881Speter
459251881Speter  return NULL;
460251881Speter}
461251881Speter
462251881Speter
463251881Speter/* Has a bi-directional dependency with make_string_from_option(). */
464251881Speterstatic void
465251881Speterexpand_option_value(svn_config_t *cfg, cfg_section_t *section,
466251881Speter                    const char *opt_value, const char **opt_x_valuep,
467251881Speter                    apr_pool_t *x_pool);
468251881Speter
469251881Speter
470251881Speter/* Set *VALUEP according to the OPT's value.  A value for X_POOL must
471251881Speter   only ever be passed into this function by expand_option_value(). */
472251881Speterstatic void
473251881Spetermake_string_from_option(const char **valuep, svn_config_t *cfg,
474251881Speter                        cfg_section_t *section, cfg_option_t *opt,
475251881Speter                        apr_pool_t* x_pool)
476251881Speter{
477251881Speter  /* Expand the option value if necessary. */
478251881Speter  if (!opt->expanded)
479251881Speter    {
480251881Speter      /* before attempting to expand an option, check for the placeholder.
481251881Speter       * If none is there, there is no point in calling expand_option_value.
482251881Speter       */
483251881Speter      if (opt->value && strchr(opt->value, '%'))
484251881Speter        {
485251881Speter          apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool));
486251881Speter
487251881Speter          expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool);
488251881Speter          opt->expanded = TRUE;
489251881Speter
490251881Speter          if (!x_pool)
491251881Speter            {
492251881Speter              /* Grab the fully expanded value from tmp_pool before its
493251881Speter                 disappearing act. */
494251881Speter              if (opt->x_value)
495251881Speter                opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value,
496251881Speter                                              strlen(opt->x_value));
497251881Speter              svn_pool_destroy(tmp_pool);
498251881Speter            }
499251881Speter        }
500251881Speter      else
501251881Speter        {
502251881Speter          opt->expanded = TRUE;
503251881Speter        }
504251881Speter    }
505251881Speter
506251881Speter  if (opt->x_value)
507251881Speter    *valuep = opt->x_value;
508251881Speter  else
509251881Speter    *valuep = opt->value;
510251881Speter}
511251881Speter
512251881Speter
513251881Speter/* Start of variable-replacement placeholder */
514251881Speter#define FMT_START     "%("
515251881Speter#define FMT_START_LEN (sizeof(FMT_START) - 1)
516251881Speter
517251881Speter/* End of variable-replacement placeholder */
518251881Speter#define FMT_END       ")s"
519251881Speter#define FMT_END_LEN   (sizeof(FMT_END) - 1)
520251881Speter
521251881Speter
522251881Speter/* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP.
523251881Speter   If no variable replacements are done, set *OPT_X_VALUEP to
524251881Speter   NULL. Allocate from X_POOL. */
525251881Speterstatic void
526251881Speterexpand_option_value(svn_config_t *cfg, cfg_section_t *section,
527251881Speter                    const char *opt_value, const char **opt_x_valuep,
528251881Speter                    apr_pool_t *x_pool)
529251881Speter{
530251881Speter  svn_stringbuf_t *buf = NULL;
531251881Speter  const char *parse_from = opt_value;
532251881Speter  const char *copy_from = parse_from;
533251881Speter  const char *name_start, *name_end;
534251881Speter
535251881Speter  while (parse_from != NULL
536251881Speter         && *parse_from != '\0'
537251881Speter         && (name_start = strstr(parse_from, FMT_START)) != NULL)
538251881Speter    {
539251881Speter      name_start += FMT_START_LEN;
540251881Speter      if (*name_start == '\0')
541251881Speter        /* FMT_START at end of opt_value. */
542251881Speter        break;
543251881Speter
544251881Speter      name_end = strstr(name_start, FMT_END);
545251881Speter      if (name_end != NULL)
546251881Speter        {
547251881Speter          cfg_option_t *x_opt;
548251881Speter          apr_size_t len = name_end - name_start;
549251881Speter          char *name = apr_pstrmemdup(x_pool, name_start, len);
550251881Speter
551251881Speter          x_opt = find_option(cfg, section->name, name, NULL);
552251881Speter
553251881Speter          if (x_opt != NULL)
554251881Speter            {
555251881Speter              const char *cstring;
556251881Speter
557251881Speter              /* Pass back the sub-pool originally provided by
558251881Speter                 make_string_from_option() as an indication of when it
559251881Speter                 should terminate. */
560251881Speter              make_string_from_option(&cstring, cfg, section, x_opt, x_pool);
561251881Speter
562251881Speter              /* Append the plain text preceding the expansion. */
563251881Speter              len = name_start - FMT_START_LEN - copy_from;
564251881Speter              if (buf == NULL)
565251881Speter                {
566251881Speter                  buf = svn_stringbuf_ncreate(copy_from, len, x_pool);
567251881Speter                  cfg->x_values = TRUE;
568251881Speter                }
569251881Speter              else
570251881Speter                svn_stringbuf_appendbytes(buf, copy_from, len);
571251881Speter
572251881Speter              /* Append the expansion and adjust parse pointers. */
573251881Speter              svn_stringbuf_appendcstr(buf, cstring);
574251881Speter              parse_from = name_end + FMT_END_LEN;
575251881Speter              copy_from = parse_from;
576251881Speter            }
577251881Speter          else
578251881Speter            /* Though ConfigParser considers the failure to resolve
579251881Speter               the requested expansion an exception condition, we
580251881Speter               consider it to be plain text, and look for the start of
581251881Speter               the next one. */
582251881Speter            parse_from = name_end + FMT_END_LEN;
583251881Speter        }
584251881Speter      else
585251881Speter        /* Though ConfigParser treats unterminated format specifiers
586251881Speter           as an exception condition, we consider them to be plain
587251881Speter           text.  The fact that there are no more format specifier
588251881Speter           endings means we're done parsing. */
589251881Speter        parse_from = NULL;
590251881Speter    }
591251881Speter
592251881Speter  if (buf != NULL)
593251881Speter    {
594251881Speter      /* Copy the remainder of the plain text. */
595251881Speter      svn_stringbuf_appendcstr(buf, copy_from);
596251881Speter      *opt_x_valuep = buf->data;
597251881Speter    }
598251881Speter  else
599251881Speter    *opt_x_valuep = NULL;
600251881Speter}
601251881Speter
602251881Speterstatic cfg_section_t *
603251881Spetersvn_config_addsection(svn_config_t *cfg,
604251881Speter                      const char *section)
605251881Speter{
606251881Speter  cfg_section_t *s;
607251881Speter  const char *hash_key;
608251881Speter
609251881Speter  s = apr_palloc(cfg->pool, sizeof(cfg_section_t));
610251881Speter  s->name = apr_pstrdup(cfg->pool, section);
611251881Speter  if(cfg->section_names_case_sensitive)
612251881Speter    hash_key = s->name;
613251881Speter  else
614251881Speter    hash_key = make_hash_key(apr_pstrdup(cfg->pool, section));
615251881Speter  s->options = apr_hash_make(cfg->pool);
616251881Speter  svn_hash_sets(cfg->sections, hash_key, s);
617251881Speter
618251881Speter  return s;
619251881Speter}
620251881Speter
621251881Speterstatic void
622251881Spetersvn_config_create_option(cfg_option_t **opt,
623251881Speter                         const char *option,
624251881Speter                         const char *value,
625251881Speter                         svn_boolean_t option_names_case_sensitive,
626251881Speter                         apr_pool_t *pool)
627251881Speter{
628251881Speter  cfg_option_t *o;
629251881Speter
630251881Speter  o = apr_palloc(pool, sizeof(cfg_option_t));
631251881Speter  o->name = apr_pstrdup(pool, option);
632251881Speter  if(option_names_case_sensitive)
633251881Speter    o->hash_key = o->name;
634251881Speter  else
635251881Speter    o->hash_key = make_hash_key(apr_pstrdup(pool, option));
636251881Speter
637251881Speter  o->value = apr_pstrdup(pool, value);
638251881Speter  o->x_value = NULL;
639251881Speter  o->expanded = FALSE;
640251881Speter
641251881Speter  *opt = o;
642251881Speter}
643251881Speter
644251881Speter
645251881Spetervoid
646251881Spetersvn_config_get(svn_config_t *cfg, const char **valuep,
647251881Speter               const char *section, const char *option,
648251881Speter               const char *default_value)
649251881Speter{
650251881Speter  *valuep = default_value;
651251881Speter  if (cfg)
652251881Speter    {
653251881Speter      cfg_section_t *sec;
654251881Speter      cfg_option_t *opt = find_option(cfg, section, option, &sec);
655251881Speter      if (opt != NULL)
656251881Speter        {
657251881Speter          make_string_from_option(valuep, cfg, sec, opt, NULL);
658251881Speter        }
659251881Speter      else
660251881Speter        /* before attempting to expand an option, check for the placeholder.
661251881Speter         * If none is there, there is no point in calling expand_option_value.
662251881Speter         */
663251881Speter        if (default_value && strchr(default_value, '%'))
664251881Speter          {
665251881Speter            apr_pool_t *tmp_pool = svn_pool_create(cfg->x_pool);
666251881Speter            const char *x_default;
667251881Speter            expand_option_value(cfg, sec, default_value, &x_default, tmp_pool);
668251881Speter            if (x_default)
669251881Speter              {
670251881Speter                svn_stringbuf_set(cfg->tmp_value, x_default);
671251881Speter                *valuep = cfg->tmp_value->data;
672251881Speter              }
673251881Speter            svn_pool_destroy(tmp_pool);
674251881Speter          }
675251881Speter    }
676251881Speter}
677251881Speter
678251881Speter
679251881Speter
680251881Spetervoid
681251881Spetersvn_config_set(svn_config_t *cfg,
682251881Speter               const char *section, const char *option,
683251881Speter               const char *value)
684251881Speter{
685251881Speter  cfg_section_t *sec;
686251881Speter  cfg_option_t *opt;
687251881Speter
688251881Speter  remove_expansions(cfg);
689251881Speter
690251881Speter  opt = find_option(cfg, section, option, &sec);
691251881Speter  if (opt != NULL)
692251881Speter    {
693251881Speter      /* Replace the option's value. */
694251881Speter      opt->value = apr_pstrdup(cfg->pool, value);
695251881Speter      opt->expanded = FALSE;
696251881Speter      return;
697251881Speter    }
698251881Speter
699251881Speter  /* Create a new option */
700251881Speter  svn_config_create_option(&opt, option, value,
701251881Speter                           cfg->option_names_case_sensitive,
702251881Speter                           cfg->pool);
703251881Speter
704251881Speter  if (sec == NULL)
705251881Speter    {
706251881Speter      /* Even the section doesn't exist. Create it. */
707251881Speter      sec = svn_config_addsection(cfg, section);
708251881Speter    }
709251881Speter
710251881Speter  svn_hash_sets(sec->options, opt->hash_key, opt);
711251881Speter}
712251881Speter
713251881Speter
714251881Speter
715251881Speter/* Set *BOOLP to true or false depending (case-insensitively) on INPUT.
716251881Speter   If INPUT is null, set *BOOLP to DEFAULT_VALUE.
717251881Speter
718251881Speter   INPUT is a string indicating truth or falsehood in any of the usual
719251881Speter   ways: "true"/"yes"/"on"/etc, "false"/"no"/"off"/etc.
720251881Speter
721251881Speter   If INPUT is neither NULL nor a recognized string, return an error
722251881Speter   with code SVN_ERR_BAD_CONFIG_VALUE; use SECTION and OPTION in
723251881Speter   constructing the error string. */
724251881Speterstatic svn_error_t *
725251881Speterget_bool(svn_boolean_t *boolp, const char *input, svn_boolean_t default_value,
726251881Speter         const char *section, const char *option)
727251881Speter{
728251881Speter  svn_tristate_t value = svn_tristate__from_word(input);
729251881Speter
730251881Speter  if (value == svn_tristate_true)
731251881Speter    *boolp = TRUE;
732251881Speter  else if (value == svn_tristate_false)
733251881Speter    *boolp = FALSE;
734251881Speter  else if (input == NULL) /* no value provided */
735251881Speter    *boolp = default_value;
736251881Speter
737251881Speter  else if (section) /* unrecognized value */
738251881Speter    return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
739251881Speter                             _("Config error: invalid boolean "
740251881Speter                               "value '%s' for '[%s] %s'"),
741251881Speter                             input, section, option);
742251881Speter  else
743251881Speter    return svn_error_createf(SVN_ERR_BAD_CONFIG_VALUE, NULL,
744251881Speter                             _("Config error: invalid boolean "
745251881Speter                               "value '%s' for '%s'"),
746251881Speter                             input, option);
747251881Speter
748251881Speter  return SVN_NO_ERROR;
749251881Speter}
750251881Speter
751251881Speter
752251881Spetersvn_error_t *
753251881Spetersvn_config_get_bool(svn_config_t *cfg, svn_boolean_t *valuep,
754251881Speter                    const char *section, const char *option,
755251881Speter                    svn_boolean_t default_value)
756251881Speter{
757251881Speter  const char *tmp_value;
758251881Speter  svn_config_get(cfg, &tmp_value, section, option, NULL);
759251881Speter  return get_bool(valuep, tmp_value, default_value, section, option);
760251881Speter}
761251881Speter
762251881Speter
763251881Speter
764251881Spetervoid
765251881Spetersvn_config_set_bool(svn_config_t *cfg,
766251881Speter                    const char *section, const char *option,
767251881Speter                    svn_boolean_t value)
768251881Speter{
769251881Speter  svn_config_set(cfg, section, option,
770251881Speter                 (value ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE));
771251881Speter}
772251881Speter
773251881Spetersvn_error_t *
774251881Spetersvn_config_get_int64(svn_config_t *cfg,
775251881Speter                     apr_int64_t *valuep,
776251881Speter                     const char *section,
777251881Speter                     const char *option,
778251881Speter                     apr_int64_t default_value)
779251881Speter{
780251881Speter  const char *tmp_value;
781251881Speter  svn_config_get(cfg, &tmp_value, section, option, NULL);
782251881Speter  if (tmp_value)
783251881Speter    return svn_cstring_strtoi64(valuep, tmp_value,
784251881Speter                                APR_INT64_MIN, APR_INT64_MAX, 10);
785251881Speter
786251881Speter  *valuep = default_value;
787251881Speter  return SVN_NO_ERROR;
788251881Speter}
789251881Speter
790251881Spetervoid
791251881Spetersvn_config_set_int64(svn_config_t *cfg,
792251881Speter                     const char *section,
793251881Speter                     const char *option,
794251881Speter                     apr_int64_t value)
795251881Speter{
796251881Speter  svn_config_set(cfg, section, option,
797251881Speter                 apr_psprintf(cfg->pool, "%" APR_INT64_T_FMT, value));
798251881Speter}
799251881Speter
800251881Spetersvn_error_t *
801251881Spetersvn_config_get_yes_no_ask(svn_config_t *cfg, const char **valuep,
802251881Speter                          const char *section, const char *option,
803251881Speter                          const char* default_value)
804251881Speter{
805251881Speter  const char *tmp_value;
806251881Speter
807251881Speter  svn_config_get(cfg, &tmp_value, section, option, NULL);
808251881Speter
809251881Speter  if (! tmp_value)
810251881Speter    tmp_value = default_value;
811251881Speter
812251881Speter  if (tmp_value && (0 == svn_cstring_casecmp(tmp_value, SVN_CONFIG_ASK)))
813251881Speter    {
814251881Speter      *valuep = SVN_CONFIG_ASK;
815251881Speter    }
816251881Speter  else
817251881Speter    {
818251881Speter      svn_boolean_t bool_val;
819251881Speter      /* We already incorporated default_value into tmp_value if
820251881Speter         necessary, so the FALSE below will be ignored unless the
821251881Speter         caller is doing something it shouldn't be doing. */
822251881Speter      SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option));
823251881Speter      *valuep = bool_val ? SVN_CONFIG_TRUE : SVN_CONFIG_FALSE;
824251881Speter    }
825251881Speter
826251881Speter  return SVN_NO_ERROR;
827251881Speter}
828251881Speter
829251881Spetersvn_error_t *
830251881Spetersvn_config_get_tristate(svn_config_t *cfg, svn_tristate_t *valuep,
831251881Speter                        const char *section, const char *option,
832251881Speter                        const char *unknown_value,
833251881Speter                        svn_tristate_t default_value)
834251881Speter{
835251881Speter  const char *tmp_value;
836251881Speter
837251881Speter  svn_config_get(cfg, &tmp_value, section, option, NULL);
838251881Speter
839251881Speter  if (! tmp_value)
840251881Speter    {
841251881Speter      *valuep = default_value;
842251881Speter    }
843251881Speter  else if (0 == svn_cstring_casecmp(tmp_value, unknown_value))
844251881Speter    {
845251881Speter      *valuep = svn_tristate_unknown;
846251881Speter    }
847251881Speter  else
848251881Speter    {
849251881Speter      svn_boolean_t bool_val;
850251881Speter      /* We already incorporated default_value into tmp_value if
851251881Speter         necessary, so the FALSE below will be ignored unless the
852251881Speter         caller is doing something it shouldn't be doing. */
853251881Speter      SVN_ERR(get_bool(&bool_val, tmp_value, FALSE, section, option));
854251881Speter      *valuep = bool_val ? svn_tristate_true : svn_tristate_false;
855251881Speter    }
856251881Speter
857251881Speter  return SVN_NO_ERROR;
858251881Speter}
859251881Speter
860251881Speterint
861251881Spetersvn_config_enumerate_sections(svn_config_t *cfg,
862251881Speter                              svn_config_section_enumerator_t callback,
863251881Speter                              void *baton)
864251881Speter{
865251881Speter  apr_hash_index_t *sec_ndx;
866251881Speter  int count = 0;
867251881Speter  apr_pool_t *subpool = svn_pool_create(cfg->x_pool);
868251881Speter
869251881Speter  for (sec_ndx = apr_hash_first(subpool, cfg->sections);
870251881Speter       sec_ndx != NULL;
871251881Speter       sec_ndx = apr_hash_next(sec_ndx))
872251881Speter    {
873251881Speter      void *sec_ptr;
874251881Speter      cfg_section_t *sec;
875251881Speter
876251881Speter      apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
877251881Speter      sec = sec_ptr;
878251881Speter      ++count;
879251881Speter      if (!callback(sec->name, baton))
880251881Speter        break;
881251881Speter    }
882251881Speter
883251881Speter  svn_pool_destroy(subpool);
884251881Speter  return count;
885251881Speter}
886251881Speter
887251881Speter
888251881Speterint
889251881Spetersvn_config_enumerate_sections2(svn_config_t *cfg,
890251881Speter                               svn_config_section_enumerator2_t callback,
891251881Speter                               void *baton, apr_pool_t *pool)
892251881Speter{
893251881Speter  apr_hash_index_t *sec_ndx;
894251881Speter  apr_pool_t *iteration_pool;
895251881Speter  int count = 0;
896251881Speter
897251881Speter  iteration_pool = svn_pool_create(pool);
898251881Speter  for (sec_ndx = apr_hash_first(pool, cfg->sections);
899251881Speter       sec_ndx != NULL;
900251881Speter       sec_ndx = apr_hash_next(sec_ndx))
901251881Speter    {
902251881Speter      void *sec_ptr;
903251881Speter      cfg_section_t *sec;
904251881Speter
905251881Speter      apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr);
906251881Speter      sec = sec_ptr;
907251881Speter      ++count;
908251881Speter      svn_pool_clear(iteration_pool);
909251881Speter      if (!callback(sec->name, baton, iteration_pool))
910251881Speter        break;
911251881Speter    }
912251881Speter  svn_pool_destroy(iteration_pool);
913251881Speter
914251881Speter  return count;
915251881Speter}
916251881Speter
917251881Speter
918251881Speter
919251881Speterint
920251881Spetersvn_config_enumerate(svn_config_t *cfg, const char *section,
921251881Speter                     svn_config_enumerator_t callback, void *baton)
922251881Speter{
923251881Speter  cfg_section_t *sec;
924251881Speter  apr_hash_index_t *opt_ndx;
925251881Speter  int count;
926251881Speter  apr_pool_t *subpool;
927251881Speter
928251881Speter  find_option(cfg, section, NULL, &sec);
929251881Speter  if (sec == NULL)
930251881Speter    return 0;
931251881Speter
932251881Speter  subpool = svn_pool_create(cfg->x_pool);
933251881Speter  count = 0;
934251881Speter  for (opt_ndx = apr_hash_first(subpool, sec->options);
935251881Speter       opt_ndx != NULL;
936251881Speter       opt_ndx = apr_hash_next(opt_ndx))
937251881Speter    {
938251881Speter      void *opt_ptr;
939251881Speter      cfg_option_t *opt;
940251881Speter      const char *temp_value;
941251881Speter
942251881Speter      apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
943251881Speter      opt = opt_ptr;
944251881Speter
945251881Speter      ++count;
946251881Speter      make_string_from_option(&temp_value, cfg, sec, opt, NULL);
947251881Speter      if (!callback(opt->name, temp_value, baton))
948251881Speter        break;
949251881Speter    }
950251881Speter
951251881Speter  svn_pool_destroy(subpool);
952251881Speter  return count;
953251881Speter}
954251881Speter
955251881Speter
956251881Speterint
957251881Spetersvn_config_enumerate2(svn_config_t *cfg, const char *section,
958251881Speter                      svn_config_enumerator2_t callback, void *baton,
959251881Speter                      apr_pool_t *pool)
960251881Speter{
961251881Speter  cfg_section_t *sec;
962251881Speter  apr_hash_index_t *opt_ndx;
963251881Speter  apr_pool_t *iteration_pool;
964251881Speter  int count;
965251881Speter
966251881Speter  find_option(cfg, section, NULL, &sec);
967251881Speter  if (sec == NULL)
968251881Speter    return 0;
969251881Speter
970251881Speter  iteration_pool = svn_pool_create(pool);
971251881Speter  count = 0;
972251881Speter  for (opt_ndx = apr_hash_first(pool, sec->options);
973251881Speter       opt_ndx != NULL;
974251881Speter       opt_ndx = apr_hash_next(opt_ndx))
975251881Speter    {
976251881Speter      void *opt_ptr;
977251881Speter      cfg_option_t *opt;
978251881Speter      const char *temp_value;
979251881Speter
980251881Speter      apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr);
981251881Speter      opt = opt_ptr;
982251881Speter
983251881Speter      ++count;
984251881Speter      make_string_from_option(&temp_value, cfg, sec, opt, NULL);
985251881Speter      svn_pool_clear(iteration_pool);
986251881Speter      if (!callback(opt->name, temp_value, baton, iteration_pool))
987251881Speter        break;
988251881Speter    }
989251881Speter  svn_pool_destroy(iteration_pool);
990251881Speter
991251881Speter  return count;
992251881Speter}
993251881Speter
994251881Speter
995251881Speter
996251881Speter/* Baton for search_groups() */
997251881Speterstruct search_groups_baton
998251881Speter{
999251881Speter  const char *key;          /* Provided by caller of svn_config_find_group */
1000251881Speter  const char *match;        /* Filled in by search_groups */
1001251881Speter  apr_pool_t *pool;
1002251881Speter};
1003251881Speter
1004251881Speter
1005251881Speter/* This is an `svn_config_enumerator_t' function, and BATON is a
1006251881Speter * `struct search_groups_baton *'.
1007251881Speter */
1008251881Speterstatic svn_boolean_t search_groups(const char *name,
1009251881Speter                                   const char *value,
1010251881Speter                                   void *baton,
1011251881Speter                                   apr_pool_t *pool)
1012251881Speter{
1013251881Speter  struct search_groups_baton *b = baton;
1014251881Speter  apr_array_header_t *list;
1015251881Speter
1016251881Speter  list = svn_cstring_split(value, ",", TRUE, pool);
1017251881Speter  if (svn_cstring_match_glob_list(b->key, list))
1018251881Speter    {
1019251881Speter      /* Fill in the match and return false, to stop enumerating. */
1020251881Speter      b->match = apr_pstrdup(b->pool, name);
1021251881Speter      return FALSE;
1022251881Speter    }
1023251881Speter  else
1024251881Speter    return TRUE;
1025251881Speter}
1026251881Speter
1027251881Speter
1028251881Speterconst char *svn_config_find_group(svn_config_t *cfg, const char *key,
1029251881Speter                                  const char *master_section,
1030251881Speter                                  apr_pool_t *pool)
1031251881Speter{
1032251881Speter  struct search_groups_baton gb;
1033251881Speter
1034251881Speter  gb.key = key;
1035251881Speter  gb.match = NULL;
1036251881Speter  gb.pool = pool;
1037251881Speter  (void) svn_config_enumerate2(cfg, master_section, search_groups, &gb, pool);
1038251881Speter  return gb.match;
1039251881Speter}
1040251881Speter
1041251881Speter
1042251881Speterconst char*
1043251881Spetersvn_config_get_server_setting(svn_config_t *cfg,
1044251881Speter                              const char* server_group,
1045251881Speter                              const char* option_name,
1046251881Speter                              const char* default_value)
1047251881Speter{
1048251881Speter  const char *retval;
1049251881Speter  svn_config_get(cfg, &retval, SVN_CONFIG_SECTION_GLOBAL,
1050251881Speter                 option_name, default_value);
1051251881Speter  if (server_group)
1052251881Speter    {
1053251881Speter      svn_config_get(cfg, &retval, server_group, option_name, retval);
1054251881Speter    }
1055251881Speter  return retval;
1056251881Speter}
1057251881Speter
1058251881Speter
1059251881Spetersvn_error_t *
1060251881Spetersvn_config_dup(svn_config_t **cfgp,
1061251881Speter               svn_config_t *src,
1062251881Speter               apr_pool_t *pool)
1063251881Speter{
1064251881Speter  apr_hash_index_t *sectidx;
1065251881Speter  apr_hash_index_t *optidx;
1066251881Speter
1067251881Speter  *cfgp = 0;
1068251881Speter  SVN_ERR(svn_config_create2(cfgp, FALSE, FALSE, pool));
1069251881Speter
1070251881Speter  (*cfgp)->x_values = src->x_values;
1071251881Speter  (*cfgp)->section_names_case_sensitive = src->section_names_case_sensitive;
1072251881Speter  (*cfgp)->option_names_case_sensitive = src->option_names_case_sensitive;
1073251881Speter
1074251881Speter  for (sectidx = apr_hash_first(pool, src->sections);
1075251881Speter       sectidx != NULL;
1076251881Speter       sectidx = apr_hash_next(sectidx))
1077251881Speter  {
1078251881Speter    const void *sectkey;
1079251881Speter    void *sectval;
1080251881Speter    apr_ssize_t sectkeyLength;
1081251881Speter    cfg_section_t * srcsect;
1082251881Speter    cfg_section_t * destsec;
1083251881Speter
1084251881Speter    apr_hash_this(sectidx, &sectkey, &sectkeyLength, &sectval);
1085251881Speter    srcsect = sectval;
1086251881Speter
1087251881Speter    destsec = svn_config_addsection(*cfgp, srcsect->name);
1088251881Speter
1089251881Speter    for (optidx = apr_hash_first(pool, srcsect->options);
1090251881Speter         optidx != NULL;
1091251881Speter         optidx = apr_hash_next(optidx))
1092251881Speter    {
1093251881Speter      const void *optkey;
1094251881Speter      void *optval;
1095251881Speter      apr_ssize_t optkeyLength;
1096251881Speter      cfg_option_t *srcopt;
1097251881Speter      cfg_option_t *destopt;
1098251881Speter
1099251881Speter      apr_hash_this(optidx, &optkey, &optkeyLength, &optval);
1100251881Speter      srcopt = optval;
1101251881Speter
1102251881Speter      svn_config_create_option(&destopt, srcopt->name, srcopt->value,
1103251881Speter                               (*cfgp)->option_names_case_sensitive,
1104251881Speter                               pool);
1105251881Speter
1106251881Speter      destopt->value = apr_pstrdup(pool, srcopt->value);
1107251881Speter      destopt->x_value = apr_pstrdup(pool, srcopt->x_value);
1108251881Speter      destopt->expanded = srcopt->expanded;
1109251881Speter      apr_hash_set(destsec->options,
1110251881Speter                   apr_pstrdup(pool, (const char*)optkey),
1111251881Speter                   optkeyLength, destopt);
1112251881Speter    }
1113251881Speter  }
1114251881Speter
1115251881Speter  return SVN_NO_ERROR;
1116251881Speter}
1117251881Speter
1118251881Spetersvn_error_t *
1119251881Spetersvn_config_copy_config(apr_hash_t **cfg_hash,
1120251881Speter                       apr_hash_t *src_hash,
1121251881Speter                       apr_pool_t *pool)
1122251881Speter{
1123251881Speter  apr_hash_index_t *cidx;
1124251881Speter
1125251881Speter  *cfg_hash = apr_hash_make(pool);
1126251881Speter  for (cidx = apr_hash_first(pool, src_hash);
1127251881Speter       cidx != NULL;
1128251881Speter       cidx = apr_hash_next(cidx))
1129251881Speter  {
1130251881Speter    const void *ckey;
1131251881Speter    void *cval;
1132251881Speter    apr_ssize_t ckeyLength;
1133251881Speter    svn_config_t * srcconfig;
1134251881Speter    svn_config_t * destconfig;
1135251881Speter
1136251881Speter    apr_hash_this(cidx, &ckey, &ckeyLength, &cval);
1137251881Speter    srcconfig = cval;
1138251881Speter
1139251881Speter    SVN_ERR(svn_config_dup(&destconfig, srcconfig, pool));
1140251881Speter
1141251881Speter    apr_hash_set(*cfg_hash,
1142251881Speter                 apr_pstrdup(pool, (const char*)ckey),
1143251881Speter                 ckeyLength, destconfig);
1144251881Speter  }
1145251881Speter
1146251881Speter  return SVN_NO_ERROR;
1147251881Speter}
1148251881Speter
1149251881Spetersvn_error_t*
1150251881Spetersvn_config_get_server_setting_int(svn_config_t *cfg,
1151251881Speter                                  const char *server_group,
1152251881Speter                                  const char *option_name,
1153251881Speter                                  apr_int64_t default_value,
1154251881Speter                                  apr_int64_t *result_value,
1155251881Speter                                  apr_pool_t *pool)
1156251881Speter{
1157251881Speter  const char* tmp_value;
1158251881Speter  char *end_pos;
1159251881Speter
1160251881Speter  tmp_value = svn_config_get_server_setting(cfg, server_group,
1161251881Speter                                            option_name, NULL);
1162251881Speter  if (tmp_value == NULL)
1163251881Speter    *result_value = default_value;
1164251881Speter  else
1165251881Speter    {
1166251881Speter      /* read tmp_value as an int now */
1167251881Speter      *result_value = apr_strtoi64(tmp_value, &end_pos, 0);
1168251881Speter
1169251881Speter      if (*end_pos != 0)
1170251881Speter        {
1171251881Speter          return svn_error_createf
1172251881Speter            (SVN_ERR_BAD_CONFIG_VALUE, NULL,
1173251881Speter             _("Config error: invalid integer value '%s'"),
1174251881Speter             tmp_value);
1175251881Speter        }
1176251881Speter    }
1177251881Speter
1178251881Speter  return SVN_NO_ERROR;
1179251881Speter}
1180251881Speter
1181251881Spetersvn_error_t *
1182251881Spetersvn_config_get_server_setting_bool(svn_config_t *cfg,
1183251881Speter                                   svn_boolean_t *valuep,
1184251881Speter                                   const char *server_group,
1185251881Speter                                   const char *option_name,
1186251881Speter                                   svn_boolean_t default_value)
1187251881Speter{
1188251881Speter  const char* tmp_value;
1189251881Speter  tmp_value = svn_config_get_server_setting(cfg, server_group,
1190251881Speter                                            option_name, NULL);
1191251881Speter  return get_bool(valuep, tmp_value, default_value,
1192251881Speter                  server_group, option_name);
1193251881Speter}
1194251881Speter
1195251881Speter
1196251881Spetersvn_boolean_t
1197251881Spetersvn_config_has_section(svn_config_t *cfg, const char *section)
1198251881Speter{
1199251881Speter  cfg_section_t *sec;
1200251881Speter
1201251881Speter  /* Canonicalize the hash key */
1202251881Speter  svn_stringbuf_set(cfg->tmp_key, section);
1203251881Speter  if (! cfg->section_names_case_sensitive)
1204251881Speter    make_hash_key(cfg->tmp_key->data);
1205251881Speter
1206251881Speter  sec = svn_hash_gets(cfg->sections, cfg->tmp_key->data);
1207251881Speter  return sec != NULL;
1208251881Speter}
1209