|
1 | 1 | /* |
2 | | - * Copyright (c) 2020, 2024, Oracle and/or its affiliates. All rights reserved. |
| 2 | + * Copyright (c) 2020, 2025, Oracle and/or its affiliates. All rights reserved. |
3 | 3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. |
4 | 4 | * |
5 | 5 | * This code is free software; you can redistribute it and/or modify it |
|
25 | 25 |
|
26 | 26 | #include "kludge_c++11.h" |
27 | 27 |
|
| 28 | +#include <set> |
28 | 29 | #include <fstream> |
29 | 30 | #include <algorithm> |
30 | 31 | #include "CfgFile.h" |
| 32 | +#include "SysInfo.h" |
31 | 33 | #include "Log.h" |
32 | 34 | #include "Toolbox.h" |
33 | 35 | #include "FileUtils.h" |
34 | 36 | #include "ErrorHandling.h" |
| 37 | +#include "StringProcessing.h" |
35 | 38 |
|
36 | 39 |
|
37 | 40 | const CfgFile::Properties& CfgFile::getProperties( |
@@ -60,38 +63,82 @@ CfgFile& CfgFile::setPropertyValue(const SectionName& sectionName, |
60 | 63 |
|
61 | 64 | namespace { |
62 | 65 |
|
63 | | -tstring expandMacros(const tstring& str, const CfgFile::Macros& macros) { |
64 | | - tstring reply = str; |
65 | | - CfgFile::Macros::const_iterator it = macros.begin(); |
66 | | - const CfgFile::Macros::const_iterator end = macros.end(); |
67 | | - for (; it != end; ++it) { |
68 | | - reply = tstrings::replace(reply, it->first, it->second); |
| 66 | +template <typename CfgFileType, typename OpType> |
| 67 | +void iterateProperties(CfgFileType& cfgFile, OpType& op) { |
| 68 | + for (auto mapIt = cfgFile.begin(), mapEnd = cfgFile.end(); mapIt != mapEnd; ++mapIt) { |
| 69 | + for (auto propertyIt = mapIt->second.begin(), propertyEnd = mapIt->second.end(); propertyIt != propertyEnd; ++propertyIt) { |
| 70 | + for (auto strIt = propertyIt->second.begin(), strEnd = propertyIt->second.end(); strIt != strEnd; ++strIt) { |
| 71 | + op(strIt); |
| 72 | + } |
| 73 | + } |
69 | 74 | } |
70 | | - return reply; |
71 | 75 | } |
72 | 76 |
|
| 77 | +struct tokenize_strings { |
| 78 | + void operator () (tstring_array::const_iterator& strIt) { |
| 79 | + const auto tokens = StringProcessing::tokenize(*strIt); |
| 80 | + values.push_back(tokens); |
| 81 | + } |
| 82 | + |
| 83 | + std::set<tstring> variableNames() const { |
| 84 | + std::set<tstring> allVariableNames; |
| 85 | + for (auto it = values.begin(), end = values.end(); it != end; ++it) { |
| 86 | + const auto variableNames = StringProcessing::extractVariableNames(*it); |
| 87 | + allVariableNames.insert(variableNames.begin(), variableNames.end()); |
| 88 | + } |
| 89 | + |
| 90 | + return allVariableNames; |
| 91 | + } |
| 92 | + |
| 93 | + std::vector<StringProcessing::TokenizedString> values; |
| 94 | +}; |
| 95 | + |
| 96 | +class expand_macros { |
| 97 | +public: |
| 98 | + expand_macros(const CfgFile::Macros& m, |
| 99 | + std::vector<StringProcessing::TokenizedString>::iterator iter) : macros(m), curTokenizedString(iter) { |
| 100 | + } |
| 101 | + |
| 102 | + void operator () (tstring_array::iterator& strIt) { |
| 103 | + StringProcessing::expandVariables(*curTokenizedString, macros); |
| 104 | + auto newStr = StringProcessing::stringify(*curTokenizedString); |
| 105 | + ++curTokenizedString; |
| 106 | + if (*strIt != newStr) { |
| 107 | + LOG_TRACE(tstrings::any() << "Map [" << *strIt << "] into [" << newStr << "]"); |
| 108 | + } |
| 109 | + strIt->swap(newStr); |
| 110 | + } |
| 111 | + |
| 112 | +private: |
| 113 | + const CfgFile::Macros& macros; |
| 114 | + std::vector<StringProcessing::TokenizedString>::iterator curTokenizedString; |
| 115 | +}; |
| 116 | + |
73 | 117 | } // namespace |
74 | 118 |
|
75 | 119 | CfgFile CfgFile::expandMacros(const Macros& macros) const { |
76 | 120 | CfgFile copyCfgFile = *this; |
77 | 121 |
|
78 | | - PropertyMap::iterator mapIt = copyCfgFile.data.begin(); |
79 | | - const PropertyMap::iterator mapEnd = copyCfgFile.data.end(); |
80 | | - for (; mapIt != mapEnd; ++mapIt) { |
81 | | - Properties::iterator propertyIt = mapIt->second.begin(); |
82 | | - const Properties::iterator propertyEnd = mapIt->second.end(); |
83 | | - for (; propertyIt != propertyEnd; ++propertyIt) { |
84 | | - tstring_array::iterator strIt = propertyIt->second.begin(); |
85 | | - const tstring_array::iterator strEnd = propertyIt->second.end(); |
86 | | - for (; strIt != strEnd; ++strIt) { |
87 | | - tstring newValue; |
88 | | - while ((newValue = ::expandMacros(*strIt, macros)) != *strIt) { |
89 | | - strIt->swap(newValue); |
90 | | - } |
| 122 | + tokenize_strings tokenizedStrings; |
| 123 | + iterateProperties(static_cast<const CfgFile::PropertyMap&>(copyCfgFile.data), tokenizedStrings); |
| 124 | + |
| 125 | + Macros allMacros(macros); |
| 126 | + |
| 127 | + const auto variableNames = tokenizedStrings.variableNames(); |
| 128 | + for (auto it = variableNames.begin(), end = variableNames.end(); it != end; ++it) { |
| 129 | + if (macros.find(*it) == macros.end()) { |
| 130 | + // Not one of the reserved macro names. Assuming an environment variable. |
| 131 | + const auto envVarName = *it; |
| 132 | + if (SysInfo::isEnvVariableSet(envVarName)) { |
| 133 | + const auto envVarValue = SysInfo::getEnvVariable(envVarName); |
| 134 | + allMacros[envVarName] = envVarValue; |
91 | 135 | } |
92 | 136 | } |
93 | 137 | } |
94 | 138 |
|
| 139 | + expand_macros expandMacros(allMacros, tokenizedStrings.values.begin()); |
| 140 | + iterateProperties(copyCfgFile.data, expandMacros); |
| 141 | + |
95 | 142 | return copyCfgFile; |
96 | 143 | } |
97 | 144 |
|
|
0 commit comments