diff --git a/include/log4cplus/helpers/property.h b/include/log4cplus/helpers/property.h index b7b96c74b..fa81bc3f9 100644 --- a/include/log4cplus/helpers/property.h +++ b/include/log4cplus/helpers/property.h @@ -155,6 +155,15 @@ namespace log4cplus { bool get_type_val_worker (ValType & val, log4cplus::tstring const & key) const; }; + + + class LogLog; + + + bool + substVars (tstring & dest, const tstring & val, + Properties const & props, LogLog& loglog, + unsigned flags); } // end namespace helpers } diff --git a/src/configurator.cxx b/src/configurator.cxx index 9750b1365..7a3a701a5 100644 --- a/src/configurator.cxx +++ b/src/configurator.cxx @@ -61,114 +61,6 @@ void initializeLog4cplus(); namespace { - static tchar const DELIM_START[] = LOG4CPLUS_TEXT("${"); - static tchar const DELIM_STOP[] = LOG4CPLUS_TEXT("}"); - static std::size_t const DELIM_START_LEN = 2; - static std::size_t const DELIM_STOP_LEN = 1; - - - /** - * Perform variable substitution in string val from - * environment variables. - * - *

The variable substitution delimeters are ${ and }. - * - *

For example, if the System properties contains "key=value", then - * the call - *

-     * string s;
-     * substEnvironVars(s, "Value of key is ${key}.");
-     * 
- * - * will set the variable s to "Value of key is value.". - * - *

If no value could be found for the specified key, then - * substitution defaults to the empty string. - * - *

For example, if there is no environment variable "inexistentKey", - * then the call - * - *

-     * string s;
-     * substEnvironVars(s, "Value of inexistentKey is [${inexistentKey}]");
-     * 
- * will set s to "Value of inexistentKey is []" - * - * @param val The string on which variable substitution is performed. - * @param dest The result. - */ - static - bool - substVars (tstring & dest, const tstring & val, - helpers::Properties const & props, helpers::LogLog& loglog, - unsigned flags) - { - tstring::size_type i = 0; - tstring::size_type var_start, var_end; - tstring pattern (val); - tstring key; - tstring replacement; - bool changed = false; - bool const empty_vars - = !! (flags & PropertyConfigurator::fAllowEmptyVars); - bool const shadow_env - = !! (flags & PropertyConfigurator::fShadowEnvironment); - bool const rec_exp - = !! (flags & PropertyConfigurator::fRecursiveExpansion); - - while (true) - { - // Find opening paren of variable substitution. - var_start = pattern.find(DELIM_START, i); - if (var_start == tstring::npos) - { - dest = pattern; - return changed; - } - - // Find closing paren of variable substitution. - var_end = pattern.find(DELIM_STOP, var_start); - if (var_end == tstring::npos) - { - tostringstream buffer; - buffer << '"' << pattern - << "\" has no closing brace. " - << "Opening brace at position " << var_start << "."; - loglog.error(buffer.str()); - dest = val; - return false; - } - - key.assign (pattern, var_start + DELIM_START_LEN, - var_end - (var_start + DELIM_START_LEN)); - replacement.clear (); - if (shadow_env) - replacement = props.getProperty (key); - if (! shadow_env || (! empty_vars && replacement.empty ())) - internal::get_env_var (replacement, key); - - if (empty_vars || ! replacement.empty ()) - { - // Substitute the variable with its value in place. - pattern.replace (var_start, var_end - var_start + DELIM_STOP_LEN, - replacement); - changed = true; - if (rec_exp) - // Retry expansion on the same spot. - continue; - else - // Move beyond the just substituted part. - i = var_start + replacement.size (); - } - else - // Nothing has been subtituted, just move beyond the - // unexpanded variable. - i = var_end + DELIM_STOP_LEN; - } // end while loop - - } // end substVars() - - //! Translates encoding in ProtpertyConfigurator::PCFlags //! to helpers::Properties::PFlags static @@ -369,7 +261,7 @@ PropertyConfigurator::replaceEnvironVariables() val = properties.getProperty(key); subKey.clear (); - if (substVars(subKey, key, properties, helpers::getLogLog(), flags)) + if (helpers::substVars(subKey, key, properties, helpers::getLogLog(), flags)) { properties.removeProperty(key); properties.setProperty(subKey, val); @@ -377,7 +269,7 @@ PropertyConfigurator::replaceEnvironVariables() } subVal.clear (); - if (substVars(subVal, val, properties, helpers::getLogLog(), flags)) + if (helpers::substVars(subVal, val, properties, helpers::getLogLog(), flags)) { properties.setProperty(subKey, subVal); changed = true; diff --git a/src/property.cxx b/src/property.cxx index 53e8c1d11..924fe83b3 100644 --- a/src/property.cxx +++ b/src/property.cxx @@ -43,6 +43,7 @@ #include #include #include +#include #if defined (LOG4CPLUS_WITH_UNIT_TESTS) #include @@ -188,6 +189,111 @@ imbue_file_from_flags (tistream & file, unsigned flags) } // namespace +/** + * Perform variable substitution in string val from + * environment variables. + * + *

The variable substitution delimeters are ${ and }. + * + *

For example, if the System properties contains "key=value", then + * the call + *

+ * string s;
+ * substEnvironVars(s, "Value of key is ${key}.");
+ * 
+ * + * will set the variable s to "Value of key is value.". + * + *

If no value could be found for the specified key, then + * substitution defaults to the empty string. + * + *

For example, if there is no environment variable "inexistentKey", + * then the call + * + *

+ * string s;
+ * substEnvironVars(s, "Value of inexistentKey is [${inexistentKey}]");
+ * 
+ * will set s to "Value of inexistentKey is []" + * + * @param val The string on which variable substitution is performed. + * @param dest The result. + */ +bool +substVars (tstring & dest, const tstring & val, + helpers::Properties const & props, helpers::LogLog& loglog, + unsigned flags) +{ + static tchar const DELIM_START[] = LOG4CPLUS_TEXT("${"); + static tchar const DELIM_STOP[] = LOG4CPLUS_TEXT("}"); + static std::size_t const DELIM_START_LEN = 2; + static std::size_t const DELIM_STOP_LEN = 1; + + tstring::size_type i = 0; + tstring::size_type var_start, var_end; + tstring pattern (val); + tstring key; + tstring replacement; + bool changed = false; + bool const empty_vars + = !! (flags & PropertyConfigurator::fAllowEmptyVars); + bool const shadow_env + = !! (flags & PropertyConfigurator::fShadowEnvironment); + bool const rec_exp + = !! (flags & PropertyConfigurator::fRecursiveExpansion); + + while (true) + { + // Find opening paren of variable substitution. + var_start = pattern.find(DELIM_START, i); + if (var_start == tstring::npos) + { + dest = pattern; + return changed; + } + + // Find closing paren of variable substitution. + var_end = pattern.find(DELIM_STOP, var_start); + if (var_end == tstring::npos) + { + tostringstream buffer; + buffer << '"' << pattern + << "\" has no closing brace. " + << "Opening brace at position " << var_start << "."; + loglog.error(buffer.str()); + dest = val; + return false; + } + + key.assign (pattern, var_start + DELIM_START_LEN, + var_end - (var_start + DELIM_START_LEN)); + replacement.clear (); + if (shadow_env) + replacement = props.getProperty (key); + if (! shadow_env || (! empty_vars && replacement.empty ())) + internal::get_env_var (replacement, key); + + if (empty_vars || ! replacement.empty ()) + { + // Substitute the variable with its value in place. + pattern.replace (var_start, var_end - var_start + DELIM_STOP_LEN, + replacement); + changed = true; + if (rec_exp) + // Retry expansion on the same spot. + continue; + else + // Move beyond the just substituted part. + i = var_start + replacement.size (); + } + else + // Nothing has been subtituted, just move beyond the + // unexpanded variable. + i = var_end + DELIM_STOP_LEN; + } // end while loop + +} // end substVars() + /////////////////////////////////////////////////////////////////////////////// // Properties ctors and dtor @@ -256,14 +362,17 @@ Properties::init(tistream& input) tstring included (buffer, 8) ; trim_ws (included); + tstring subIncluded; + helpers::substVars(subIncluded, included, *this, helpers::getLogLog(), 0); + tifstream file; imbue_file_from_flags (file, flags); - file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(included).c_str(), + file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(subIncluded).c_str(), std::ios::binary); if (! file.good ()) helpers::getLogLog ().error ( - LOG4CPLUS_TEXT ("could not open file ") + included); + LOG4CPLUS_TEXT ("could not open file ") + subIncluded); init (file); }