|
43 | 43 | #include <log4cplus/internal/env.h>
|
44 | 44 | #include <log4cplus/helpers/loglog.h>
|
45 | 45 | #include <log4cplus/exception.h>
|
| 46 | +#include <log4cplus/configurator.h> |
46 | 47 |
|
47 | 48 | #if defined (LOG4CPLUS_WITH_UNIT_TESTS)
|
48 | 49 | #include <catch.hpp>
|
@@ -188,6 +189,111 @@ imbue_file_from_flags (tistream & file, unsigned flags)
|
188 | 189 | } // namespace
|
189 | 190 |
|
190 | 191 |
|
| 192 | +/** |
| 193 | + * Perform variable substitution in string <code>val</code> from |
| 194 | + * environment variables. |
| 195 | + * |
| 196 | + * <p>The variable substitution delimeters are <b>${</b> and <b>}</b>. |
| 197 | + * |
| 198 | + * <p>For example, if the System properties contains "key=value", then |
| 199 | + * the call |
| 200 | + * <pre> |
| 201 | + * string s; |
| 202 | + * substEnvironVars(s, "Value of key is ${key}."); |
| 203 | + * </pre> |
| 204 | + * |
| 205 | + * will set the variable <code>s</code> to "Value of key is value.". |
| 206 | + * |
| 207 | + * <p>If no value could be found for the specified key, then |
| 208 | + * substitution defaults to the empty string. |
| 209 | + * |
| 210 | + * <p>For example, if there is no environment variable "inexistentKey", |
| 211 | + * then the call |
| 212 | + * |
| 213 | + * <pre> |
| 214 | + * string s; |
| 215 | + * substEnvironVars(s, "Value of inexistentKey is [${inexistentKey}]"); |
| 216 | + * </pre> |
| 217 | + * will set <code>s</code> to "Value of inexistentKey is []" |
| 218 | + * |
| 219 | + * @param val The string on which variable substitution is performed. |
| 220 | + * @param dest The result. |
| 221 | + */ |
| 222 | +bool |
| 223 | +substVars (tstring & dest, const tstring & val, |
| 224 | + helpers::Properties const & props, helpers::LogLog& loglog, |
| 225 | + unsigned flags) |
| 226 | +{ |
| 227 | + static tchar const DELIM_START[] = LOG4CPLUS_TEXT("${"); |
| 228 | + static tchar const DELIM_STOP[] = LOG4CPLUS_TEXT("}"); |
| 229 | + static std::size_t const DELIM_START_LEN = 2; |
| 230 | + static std::size_t const DELIM_STOP_LEN = 1; |
| 231 | + |
| 232 | + tstring::size_type i = 0; |
| 233 | + tstring::size_type var_start, var_end; |
| 234 | + tstring pattern (val); |
| 235 | + tstring key; |
| 236 | + tstring replacement; |
| 237 | + bool changed = false; |
| 238 | + bool const empty_vars |
| 239 | + = !! (flags & PropertyConfigurator::fAllowEmptyVars); |
| 240 | + bool const shadow_env |
| 241 | + = !! (flags & PropertyConfigurator::fShadowEnvironment); |
| 242 | + bool const rec_exp |
| 243 | + = !! (flags & PropertyConfigurator::fRecursiveExpansion); |
| 244 | + |
| 245 | + while (true) |
| 246 | + { |
| 247 | + // Find opening paren of variable substitution. |
| 248 | + var_start = pattern.find(DELIM_START, i); |
| 249 | + if (var_start == tstring::npos) |
| 250 | + { |
| 251 | + dest = pattern; |
| 252 | + return changed; |
| 253 | + } |
| 254 | + |
| 255 | + // Find closing paren of variable substitution. |
| 256 | + var_end = pattern.find(DELIM_STOP, var_start); |
| 257 | + if (var_end == tstring::npos) |
| 258 | + { |
| 259 | + tostringstream buffer; |
| 260 | + buffer << '"' << pattern |
| 261 | + << "\" has no closing brace. " |
| 262 | + << "Opening brace at position " << var_start << "."; |
| 263 | + loglog.error(buffer.str()); |
| 264 | + dest = val; |
| 265 | + return false; |
| 266 | + } |
| 267 | + |
| 268 | + key.assign (pattern, var_start + DELIM_START_LEN, |
| 269 | + var_end - (var_start + DELIM_START_LEN)); |
| 270 | + replacement.clear (); |
| 271 | + if (shadow_env) |
| 272 | + replacement = props.getProperty (key); |
| 273 | + if (! shadow_env || (! empty_vars && replacement.empty ())) |
| 274 | + internal::get_env_var (replacement, key); |
| 275 | + |
| 276 | + if (empty_vars || ! replacement.empty ()) |
| 277 | + { |
| 278 | + // Substitute the variable with its value in place. |
| 279 | + pattern.replace (var_start, var_end - var_start + DELIM_STOP_LEN, |
| 280 | + replacement); |
| 281 | + changed = true; |
| 282 | + if (rec_exp) |
| 283 | + // Retry expansion on the same spot. |
| 284 | + continue; |
| 285 | + else |
| 286 | + // Move beyond the just substituted part. |
| 287 | + i = var_start + replacement.size (); |
| 288 | + } |
| 289 | + else |
| 290 | + // Nothing has been subtituted, just move beyond the |
| 291 | + // unexpanded variable. |
| 292 | + i = var_end + DELIM_STOP_LEN; |
| 293 | + } // end while loop |
| 294 | + |
| 295 | +} // end substVars() |
| 296 | + |
191 | 297 |
|
192 | 298 | ///////////////////////////////////////////////////////////////////////////////
|
193 | 299 | // Properties ctors and dtor
|
@@ -256,14 +362,17 @@ Properties::init(tistream& input)
|
256 | 362 | tstring included (buffer, 8) ;
|
257 | 363 | trim_ws (included);
|
258 | 364 |
|
| 365 | + tstring subIncluded; |
| 366 | + helpers::substVars(subIncluded, included, *this, helpers::getLogLog(), 0); |
| 367 | + |
259 | 368 | tifstream file;
|
260 | 369 | imbue_file_from_flags (file, flags);
|
261 | 370 |
|
262 |
| - file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(included).c_str(), |
| 371 | + file.open (LOG4CPLUS_FSTREAM_PREFERED_FILE_NAME(subIncluded).c_str(), |
263 | 372 | std::ios::binary);
|
264 | 373 | if (! file.good ())
|
265 | 374 | helpers::getLogLog ().error (
|
266 |
| - LOG4CPLUS_TEXT ("could not open file ") + included); |
| 375 | + LOG4CPLUS_TEXT ("could not open file ") + subIncluded); |
267 | 376 |
|
268 | 377 | init (file);
|
269 | 378 | }
|
|
0 commit comments