blob: 90d53d19f46cd6ffddf0dbd03118bc03502da7be [file] [log] [blame]
Christopher Meis59ef1e72025-04-16 08:53:25 +02001#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
Alexander Hansen0ab32b32025-06-27 14:50:33 +020016namespace em_utils
17{
18
19constexpr const char* templateChar = "$";
20
Christopher Meis59ef1e72025-04-16 08:53:25 +020021bool 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.
62std::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
80std::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