1 #include "utils.hpp" 2 3 #include "../variant_visitors.hpp" 4 #include "expression.hpp" 5 6 #include <boost/algorithm/string/classification.hpp> 7 #include <boost/algorithm/string/find.hpp> 8 #include <boost/algorithm/string/predicate.hpp> 9 #include <boost/algorithm/string/replace.hpp> 10 #include <boost/algorithm/string/split.hpp> 11 #include <sdbusplus/bus/match.hpp> 12 13 #include <fstream> 14 #include <iostream> 15 16 namespace em_utils 17 { 18 19 constexpr const char* templateChar = "$"; 20 21 bool fwVersionIsSame() 22 { 23 std::ifstream version(versionFile); 24 if (!version.good()) 25 { 26 std::cerr << "Can't read " << versionFile << "\n"; 27 return false; 28 } 29 30 std::string versionData; 31 std::string line; 32 while (std::getline(version, line)) 33 { 34 versionData += line; 35 } 36 37 std::string expectedHash = 38 std::to_string(std::hash<std::string>{}(versionData)); 39 40 std::filesystem::create_directory(configurationOutDir); 41 std::ifstream hashFile(versionHashFile); 42 if (hashFile.good()) 43 { 44 std::string hashString; 45 hashFile >> hashString; 46 47 if (expectedHash == hashString) 48 { 49 return true; 50 } 51 hashFile.close(); 52 } 53 54 std::ofstream output(versionHashFile); 55 output << expectedHash; 56 return false; 57 } 58 59 // Replaces the template character like the other version of this function, 60 // but checks all properties on all interfaces provided to do the substitution 61 // with. 62 std::optional<std::string> templateCharReplace( 63 nlohmann::json::iterator& keyPair, const DBusObject& object, 64 const size_t index, const std::optional<std::string>& replaceStr) 65 { 66 for (const auto& [_, interface] : object) 67 { 68 auto ret = templateCharReplace(keyPair, interface, index, replaceStr); 69 if (ret) 70 { 71 return ret; 72 } 73 } 74 return std::nullopt; 75 } 76 77 // finds the template character (currently set to $) and replaces the value with 78 // the field found in a dbus object i.e. $ADDRESS would get populated with the 79 // ADDRESS field from a object on dbus 80 std::optional<std::string> templateCharReplace( 81 nlohmann::json::iterator& keyPair, const DBusInterface& interface, 82 const size_t index, const std::optional<std::string>& replaceStr) 83 { 84 std::optional<std::string> ret = std::nullopt; 85 86 if (keyPair.value().type() == nlohmann::json::value_t::object || 87 keyPair.value().type() == nlohmann::json::value_t::array) 88 { 89 for (auto nextLayer = keyPair.value().begin(); 90 nextLayer != keyPair.value().end(); nextLayer++) 91 { 92 templateCharReplace(nextLayer, interface, index, replaceStr); 93 } 94 return ret; 95 } 96 97 std::string* strPtr = keyPair.value().get_ptr<std::string*>(); 98 if (strPtr == nullptr) 99 { 100 return ret; 101 } 102 103 boost::replace_all(*strPtr, std::string(templateChar) + "index", 104 std::to_string(index)); 105 if (replaceStr) 106 { 107 boost::replace_all(*strPtr, *replaceStr, std::to_string(index)); 108 } 109 110 for (const auto& [propName, propValue] : interface) 111 { 112 std::string templateName = templateChar + propName; 113 boost::iterator_range<std::string::const_iterator> find = 114 boost::ifind_first(*strPtr, templateName); 115 if (!find) 116 { 117 continue; 118 } 119 120 size_t start = find.begin() - strPtr->begin(); 121 122 // check for additional operations 123 if ((start == 0U) && find.end() == strPtr->end()) 124 { 125 std::visit([&](auto&& val) { keyPair.value() = val; }, propValue); 126 return ret; 127 } 128 129 constexpr const std::array<char, 5> mathChars = {'+', '-', '%', '*', 130 '/'}; 131 size_t nextItemIdx = start + templateName.size() + 1; 132 133 if (nextItemIdx > strPtr->size() || 134 std::find(mathChars.begin(), mathChars.end(), 135 strPtr->at(nextItemIdx)) == mathChars.end()) 136 { 137 std::string val = std::visit(VariantToStringVisitor(), propValue); 138 boost::ireplace_all(*strPtr, templateName, val); 139 continue; 140 } 141 142 // save the prefix 143 std::string prefix = strPtr->substr(0, start); 144 145 // operate on the rest 146 std::string end = strPtr->substr(nextItemIdx); 147 148 std::vector<std::string> split; 149 boost::split(split, end, boost::is_any_of(" ")); 150 151 // need at least 1 operation and number 152 if (split.size() < 2) 153 { 154 std::cerr << "Syntax error on template replacement of " << *strPtr 155 << "\n"; 156 for (const std::string& data : split) 157 { 158 std::cerr << data << " "; 159 } 160 std::cerr << "\n"; 161 continue; 162 } 163 164 // we assume that the replacement is a number, because we can 165 // only do math on numbers.. we might concatenate strings in the 166 // future, but thats later 167 int number = std::visit(VariantToIntVisitor(), propValue); 168 auto exprBegin = split.begin(); 169 auto exprEnd = split.end(); 170 171 number = expression::evaluate(number, exprBegin, exprEnd); 172 173 std::string replaced(find.begin(), find.end()); 174 while (exprBegin != exprEnd) 175 { 176 replaced.append(" ").append(*exprBegin++); 177 } 178 ret = replaced; 179 180 std::string result = prefix + std::to_string(number); 181 while (exprEnd != split.end()) 182 { 183 result.append(" ").append(*exprEnd++); 184 } 185 keyPair.value() = result; 186 187 // We probably just invalidated the pointer abovei, 188 // reset and continue to handle multiple templates 189 strPtr = keyPair.value().get_ptr<std::string*>(); 190 if (strPtr == nullptr) 191 { 192 break; 193 } 194 } 195 196 strPtr = keyPair.value().get_ptr<std::string*>(); 197 if (strPtr == nullptr) 198 { 199 return ret; 200 } 201 202 std::string_view strView = *strPtr; 203 int base = 10; 204 if (boost::starts_with(strView, "0x")) 205 { 206 strView.remove_prefix(2); 207 base = 16; 208 } 209 210 uint64_t temp = 0; 211 const char* strDataEndPtr = strView.data() + strView.size(); 212 const std::from_chars_result res = 213 std::from_chars(strView.data(), strDataEndPtr, temp, base); 214 if (res.ec == std::errc{} && res.ptr == strDataEndPtr) 215 { 216 keyPair.value() = temp; 217 } 218 219 return ret; 220 } 221 222 } // namespace em_utils 223