📄 config.c
字号:
/* * config.c : reading configuration information * * ==================================================================== * Copyright (c) 2000-2004 CollabNet. All rights reserved. * * This software is licensed as described in the file COPYING, which * you should have received as part of this distribution. The terms * are also available at http://subversion.tigris.org/license-1.html. * If newer versions of this license are posted there, you may use a * newer version instead, at your option. * * This software consists of voluntary contributions made by many * individuals. For exact contribution history, see the revision * history and logs, available at http://subversion.tigris.org/. * ==================================================================== */#define APR_WANT_STRFUNC#define APR_WANT_MEMFUNC#include <apr_want.h>#include <apr_general.h>#include <apr_lib.h>#include "svn_error.h"#include "svn_pools.h"#include "config_impl.h"#include "svn_private_config.h"/* Section table entries. */typedef struct cfg_section_t cfg_section_t;struct cfg_section_t{ /* The section name. */ const char *name; /* The section name, converted into a hash key. */ const char *hash_key; /* Table of cfg_option_t's. */ apr_hash_t *options;};/* Option table entries. */typedef struct cfg_option_t cfg_option_t;struct cfg_option_t{ /* The option name. */ const char *name; /* The option name, converted into a hash key. */ const char *hash_key; /* The unexpanded option value. */ const char *value; /* The expanded option value. */ const char *x_value; /* Expansion flag. If this is TRUE, this value has already been expanded. In this case, if x_value is NULL, no expansions were necessary, and value should be used directly. */ svn_boolean_t expanded;};svn_error_t *svn_config_read(svn_config_t **cfgp, const char *file, svn_boolean_t must_exist, apr_pool_t *pool){ svn_config_t *cfg = apr_palloc(pool, sizeof(*cfg)); svn_error_t *err; cfg->sections = apr_hash_make(pool); cfg->pool = pool; cfg->x_pool = svn_pool_create(pool); cfg->x_values = FALSE; cfg->tmp_key = svn_stringbuf_create("", pool); cfg->tmp_value = svn_stringbuf_create("", pool); /* Yes, this is platform-specific code in Subversion, but there's no practical way to migrate it into APR, as it's simultaneously Subversion-specific and Windows-specific. Even if we eventually want to have APR offer a generic config-reading interface, it makes sense to test it here first and migrate it later. */#ifdef WIN32 if (0 == strncmp(file, SVN_REGISTRY_PREFIX, SVN_REGISTRY_PREFIX_LEN)) err = svn_config__parse_registry(cfg, file + SVN_REGISTRY_PREFIX_LEN, must_exist, pool); else#endif /* WIN32 */ err = svn_config__parse_file(cfg, file, must_exist, pool); if (err != SVN_NO_ERROR) return err; else *cfgp = cfg; return SVN_NO_ERROR;}/* Read various configuration sources into *CFGP, in this order, with * later reads overriding the results of earlier ones: * * 1. SYS_REGISTRY_PATH (only on Win32, but ignored if NULL) * * 2. SYS_FILE_PATH (everywhere, but ignored if NULL) * * 3. USR_REGISTRY_PATH (only on Win32, but ignored if NULL) * * 4. USR_FILE_PATH (everywhere, but ignored if NULL) * * Allocate *CFGP in POOL. Even if no configurations are read, * allocate an empty *CFGP. */static svn_error_t *read_all(svn_config_t **cfgp, const char *sys_registry_path, const char *usr_registry_path, const char *sys_file_path, const char *usr_file_path, apr_pool_t *pool){ svn_boolean_t red_config = FALSE; /* "red" is the past tense of "read" */ /*** Read system-wide configurations first... ***/#ifdef WIN32 if (sys_registry_path) { SVN_ERR(svn_config_read(cfgp, sys_registry_path, FALSE, pool)); red_config = TRUE; }#endif /* WIN32 */ if (sys_file_path) { if (red_config) SVN_ERR(svn_config_merge(*cfgp, sys_file_path, FALSE)); else { SVN_ERR(svn_config_read(cfgp, sys_file_path, FALSE, pool)); red_config = TRUE; } } /*** ...followed by per-user configurations. ***/#ifdef WIN32 if (usr_registry_path) { if (red_config) SVN_ERR(svn_config_merge(*cfgp, usr_registry_path, FALSE)); else { SVN_ERR(svn_config_read(cfgp, usr_registry_path, FALSE, pool)); red_config = TRUE; } }#endif /* WIN32 */ if (usr_file_path) { if (red_config) SVN_ERR(svn_config_merge(*cfgp, usr_file_path, FALSE)); else { SVN_ERR(svn_config_read(cfgp, usr_file_path, FALSE, pool)); red_config = TRUE; } } if (! red_config) *cfgp = NULL; return SVN_NO_ERROR;}static svn_error_t *get_category_config(svn_config_t **cfg, const char *config_dir, const char *category, apr_pool_t *pool){ const char *usr_reg_path = NULL, *sys_reg_path = NULL; const char *usr_cfg_path, *sys_cfg_path; *cfg = NULL; if (! config_dir) {#ifdef WIN32 sys_reg_path = apr_pstrcat(pool, SVN_REGISTRY_SYS_CONFIG_PATH, category, NULL); usr_reg_path = apr_pstrcat(pool, SVN_REGISTRY_USR_CONFIG_PATH, category, NULL);#endif /* WIN32 */ SVN_ERR(svn_config__sys_config_path(&sys_cfg_path, category, pool)); } else sys_cfg_path = NULL; SVN_ERR(svn_config__user_config_path(config_dir, &usr_cfg_path, category, pool)); SVN_ERR(read_all(cfg, sys_reg_path, usr_reg_path, sys_cfg_path, usr_cfg_path, pool)); return SVN_NO_ERROR;}svn_error_t *svn_config_get_config(apr_hash_t **cfg_hash, const char *config_dir, apr_pool_t *pool){ svn_config_t *cfg; *cfg_hash = apr_hash_make(pool); #define CATLEN (sizeof(SVN_CONFIG_CATEGORY_SERVERS) - 1) SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_SERVERS, pool)); if (cfg) apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_SERVERS, CATLEN, cfg);#undef CATLEN#define CATLEN (sizeof(SVN_CONFIG_CATEGORY_CONFIG) - 1) SVN_ERR(get_category_config(&cfg, config_dir, SVN_CONFIG_CATEGORY_CONFIG, pool)); if (cfg) apr_hash_set(*cfg_hash, SVN_CONFIG_CATEGORY_CONFIG, CATLEN, cfg);#undef CATLEN return SVN_NO_ERROR;}/* Iterate through CFG, passing BATON to CALLBACK for every (SECTION, OPTION) pair. Stop if CALLBACK returns TRUE. Allocate from POOL. */static voidfor_each_option(svn_config_t *cfg, void *baton, apr_pool_t *pool, svn_boolean_t callback(void *same_baton, cfg_section_t *section, cfg_option_t *option)){ apr_hash_index_t *sec_ndx; for (sec_ndx = apr_hash_first(pool, cfg->sections); sec_ndx != NULL; sec_ndx = apr_hash_next(sec_ndx)) { void *sec_ptr; cfg_section_t *sec; apr_hash_index_t *opt_ndx; apr_hash_this(sec_ndx, NULL, NULL, &sec_ptr); sec = sec_ptr; for (opt_ndx = apr_hash_first(pool, sec->options); opt_ndx != NULL; opt_ndx = apr_hash_next(opt_ndx)) { void *opt_ptr; cfg_option_t *opt; apr_hash_this(opt_ndx, NULL, NULL, &opt_ptr); opt = opt_ptr; if (callback(baton, sec, opt)) return; } }}static svn_boolean_tmerge_callback(void *baton, cfg_section_t *section, cfg_option_t *option){ svn_config_set(baton, section->name, option->name, option->value); return FALSE;}svn_error_t *svn_config_merge(svn_config_t *cfg, const char *file, svn_boolean_t must_exist){ /* The original config hash shouldn't change if there's an error while reading the confguration, so read into a temporary table. ### We could use a tmp subpool for this, since merge_cfg is going to be tossed afterwards. Premature optimization, though? */ svn_config_t *merge_cfg; SVN_ERR(svn_config_read(&merge_cfg, file, must_exist, cfg->pool)); /* Now copy the new options into the original table. */ for_each_option(merge_cfg, cfg, merge_cfg->pool, merge_callback); return SVN_NO_ERROR;}/* Remove variable expansions from CFG. Walk through the options tree, killing all expanded values, then clear the expanded value pool. */static svn_boolean_trmex_callback(void *baton, cfg_section_t *section, cfg_option_t *option){ /* Only clear the `expanded' flag if the value actually contains variable expansions. */ if (option->expanded && option->x_value != NULL) { option->x_value = NULL; option->expanded = FALSE; } return FALSE;}static voidremove_expansions(svn_config_t *cfg){ if (!cfg->x_values) return; for_each_option(cfg, NULL, cfg->x_pool, rmex_callback); apr_pool_clear(cfg->x_pool); cfg->x_values = FALSE;}/* Canonicalize a string for hashing. Modifies KEY in place. */static APR_INLINE char *make_hash_key(char *key){ register char *p; for (p = key; *p != 0; ++p) *p = apr_tolower(*p); return key;}/* Return a pointer to an option in CFG, or NULL if it doesn't exist. if SECTIONP is non-null, return a pointer to the option's section. OPTION may be NULL. */static cfg_option_t *find_option(svn_config_t *cfg, const char *section, const char *option, cfg_section_t **sectionp){ void *sec_ptr; /* Canonicalize the hash key */ svn_stringbuf_set(cfg->tmp_key, section); make_hash_key(cfg->tmp_key->data); sec_ptr = apr_hash_get(cfg->sections, cfg->tmp_key->data, cfg->tmp_key->len); if (sectionp != NULL) *sectionp = sec_ptr; if (sec_ptr != NULL && option != NULL) { cfg_section_t *sec = sec_ptr; cfg_option_t *opt; /* Canonicalize the option key */ svn_stringbuf_set(cfg->tmp_key, option); make_hash_key(cfg->tmp_key->data); opt = apr_hash_get(sec->options, cfg->tmp_key->data, cfg->tmp_key->len); /* NOTE: ConfigParser's sections are case sensitive. */ if (opt == NULL && apr_strnatcasecmp(section, SVN_CONFIG__DEFAULT_SECTION) != 0) /* Options which aren't found in the requested section are also sought after in the default section. */ opt = find_option(cfg, SVN_CONFIG__DEFAULT_SECTION, option, &sec); return opt; } return NULL;}/* Has a bi-directional dependency with make_string_from_option(). */static voidexpand_option_value(svn_config_t *cfg, cfg_section_t *section, const char *opt_value, const char **opt_x_valuep, apr_pool_t *x_pool);/* Set *VALUEP according to the OPT's value. A value for X_POOL must only ever be passed into this function by expand_option_value(). */static voidmake_string_from_option(const char **valuep, svn_config_t *cfg, cfg_section_t *section, cfg_option_t *opt, apr_pool_t* x_pool){ /* Expand the option value if necessary. */ if (!opt->expanded) { apr_pool_t *tmp_pool = (x_pool ? x_pool : svn_pool_create(cfg->x_pool)); expand_option_value(cfg, section, opt->value, &opt->x_value, tmp_pool); opt->expanded = TRUE; if (!x_pool) { /* Grab the fully expanded value from tmp_pool before its disappearing act. */ if (opt->x_value) opt->x_value = apr_pstrmemdup(cfg->x_pool, opt->x_value, strlen(opt->x_value)); svn_pool_destroy(tmp_pool); } } if (opt->x_value) *valuep = opt->x_value; else *valuep = opt->value;}/* Start of variable-replacement placeholder */#define FMT_START "%("#define FMT_START_LEN (sizeof(FMT_START) - 1)/* End of variable-replacement placeholder */#define FMT_END ")s"#define FMT_END_LEN (sizeof(FMT_END) - 1)/* Expand OPT_VALUE (which may be NULL) in SECTION into *OPT_X_VALUEP.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -