blob: d5eb30b9dd2cb3d49c72839194cb79368737edc8 [file] [log] [blame]
Alexander Hansen4e1142d2025-07-25 17:07:27 +02001// SPDX-License-Identifier: Apache-2.0
2// SPDX-FileCopyrightText: Copyright 2017 Intel Corporation
James Feist3cb5fec2018-01-23 14:41:51 -08003
Brad Bishope45d8c72022-05-25 15:12:53 -04004#include "utils.hpp"
James Feist481c5d52019-08-13 14:40:40 -07005
James Feist481c5d52019-08-13 14:40:40 -07006#include <boost/algorithm/string/classification.hpp>
James Feist481c5d52019-08-13 14:40:40 -07007#include <boost/algorithm/string/replace.hpp>
8#include <boost/algorithm/string/split.hpp>
9#include <boost/container/flat_map.hpp>
10#include <boost/lexical_cast.hpp>
Alexander Hansen8feb0452025-09-15 14:29:20 +020011#include <phosphor-logging/lg2.hpp>
James Feist1df06a42019-04-11 14:23:04 -070012#include <sdbusplus/bus/match.hpp>
James Feist3cb5fec2018-01-23 14:41:51 -080013
George Liuce8d1d02025-08-25 08:58:25 +080014#include <algorithm>
15#include <cctype>
James Feist8c505da2020-05-28 10:06:33 -070016#include <filesystem>
Andrew Jefferya9c58922021-06-01 09:28:59 +093017#include <map>
George Liuce8d1d02025-08-25 08:58:25 +080018#include <ranges>
James Feist8c505da2020-05-28 10:06:33 -070019#include <regex>
George Liuce8d1d02025-08-25 08:58:25 +080020#include <string_view>
21#include <utility>
James Feist8c505da2020-05-28 10:06:33 -070022
Ed Tanous072e25d2018-12-16 21:45:20 -080023namespace fs = std::filesystem;
James Feist3cb5fec2018-01-23 14:41:51 -080024
James Feista465ccc2019-02-08 12:51:01 -080025bool findFiles(const fs::path& dirPath, const std::string& matchString,
26 std::vector<fs::path>& foundPaths)
James Feist3cb5fec2018-01-23 14:41:51 -080027{
James Feista3c180a2018-08-09 16:06:04 -070028 if (!fs::exists(dirPath))
Ed Tanous07d467b2021-02-23 14:48:37 -080029 {
James Feist3cb5fec2018-01-23 14:41:51 -080030 return false;
Ed Tanous07d467b2021-02-23 14:48:37 -080031 }
James Feist3cb5fec2018-01-23 14:41:51 -080032
James Feista3c180a2018-08-09 16:06:04 -070033 std::regex search(matchString);
James Feist3cb5fec2018-01-23 14:41:51 -080034 std::smatch match;
James Feista465ccc2019-02-08 12:51:01 -080035 for (const auto& p : fs::directory_iterator(dirPath))
James Feist3cb5fec2018-01-23 14:41:51 -080036 {
37 std::string path = p.path().string();
James Feistc95cb142018-02-26 10:41:42 -080038 if (std::regex_search(path, match, search))
James Feist3cb5fec2018-01-23 14:41:51 -080039 {
James Feista3c180a2018-08-09 16:06:04 -070040 foundPaths.emplace_back(p.path());
James Feist3cb5fec2018-01-23 14:41:51 -080041 }
42 }
43 return true;
James Feistb4383f42018-08-06 16:54:10 -070044}
45
Andrew Jefferya9c58922021-06-01 09:28:59 +093046bool findFiles(const std::vector<fs::path>&& dirPaths,
47 const std::string& matchString,
48 std::vector<fs::path>& foundPaths)
49{
50 std::map<fs::path, fs::path> paths;
51 std::regex search(matchString);
52 std::smatch match;
53 for (const auto& dirPath : dirPaths)
54 {
55 if (!fs::exists(dirPath))
Bruce Mitchella6d47332021-12-13 10:18:03 -060056 {
Andrew Jefferya9c58922021-06-01 09:28:59 +093057 continue;
Bruce Mitchella6d47332021-12-13 10:18:03 -060058 }
Andrew Jefferya9c58922021-06-01 09:28:59 +093059
Alexander Hansend8e86032025-04-25 14:49:15 +020060 for (const auto& p : fs::recursive_directory_iterator(dirPath))
Andrew Jefferya9c58922021-06-01 09:28:59 +093061 {
Alexander Hansend8e86032025-04-25 14:49:15 +020062 std::error_code ec;
63 if (p.is_directory(ec))
64 {
65 continue;
66 }
67
Andrew Jefferya9c58922021-06-01 09:28:59 +093068 std::string path = p.path().string();
69 if (std::regex_search(path, match, search))
70 {
71 paths[p.path().filename()] = p.path();
72 }
73 }
74 }
75
76 for (const auto& [key, value] : paths)
77 {
78 foundPaths.emplace_back(value);
79 }
80
81 return !foundPaths.empty();
82}
83
Nikhil Potaded8884f12019-03-27 13:27:13 -070084bool getI2cDevicePaths(const fs::path& dirPath,
85 boost::container::flat_map<size_t, fs::path>& busPaths)
86{
87 if (!fs::exists(dirPath))
88 {
89 return false;
90 }
91
92 // Regex for matching the path
93 std::regex searchPath(std::string(R"(i2c-\d+$)"));
94 // Regex for matching the bus numbers
95 std::regex searchBus(std::string(R"(\w[^-]*$)"));
96 std::smatch matchPath;
97 std::smatch matchBus;
98 for (const auto& p : fs::directory_iterator(dirPath))
99 {
100 std::string path = p.path().string();
101 if (std::regex_search(path, matchPath, searchPath))
102 {
103 if (std::regex_search(path, matchBus, searchBus))
104 {
105 size_t bus = stoul(*matchBus.begin());
106 busPaths.insert(std::pair<size_t, fs::path>(bus, p.path()));
107 }
108 }
109 }
110
111 return true;
112}
113
Brad Bishop5d525412020-08-26 08:50:50 -0400114/// \brief JSON/DBus matching Callable for std::variant (visitor)
115///
116/// Default match JSON/DBus match implementation
Andrew Jefferyeab49292022-04-05 14:42:20 +0930117/// \tparam T The concrete DBus value type from DBusValueVariant
Brad Bishop5d525412020-08-26 08:50:50 -0400118template <typename T>
119struct MatchProbe
120{
121 /// \param probe the probe statement to match against
122 /// \param value the property value being matched to a probe
123 /// \return true if the dbusValue matched the probe otherwise false
124 static bool match(const nlohmann::json& probe, const T& value)
125 {
126 return probe == value;
127 }
128};
129
130/// \brief JSON/DBus matching Callable for std::variant (visitor)
131///
132/// std::string specialization of MatchProbe enabling regex matching
133template <>
134struct MatchProbe<std::string>
135{
136 /// \param probe the probe statement to match against
137 /// \param value the string value being matched to a probe
138 /// \return true if the dbusValue matched the probe otherwise false
139 static bool match(const nlohmann::json& probe, const std::string& value)
140 {
141 if (probe.is_string())
142 {
143 try
144 {
145 std::regex search(probe);
146 std::smatch regMatch;
147 return std::regex_search(value, regMatch, search);
148 }
149 catch (const std::regex_error&)
150 {
Alexander Hansen8feb0452025-09-15 14:29:20 +0200151 lg2::error(
152 "Syntax error in regular expression: {PROBE} will never match",
153 "PROBE", probe);
Brad Bishop5d525412020-08-26 08:50:50 -0400154 }
155 }
156
157 // Skip calling nlohmann here, since it will never match a non-string
158 // to a std::string
159 return false;
160 }
161};
162
163/// \brief Forwarding JSON/DBus matching Callable for std::variant (visitor)
164///
165/// Forward calls to the correct template instantiation of MatchProbe
166struct MatchProbeForwarder
167{
168 explicit MatchProbeForwarder(const nlohmann::json& probe) : probeRef(probe)
169 {}
170 const nlohmann::json& probeRef;
171
172 template <typename T>
173 bool operator()(const T& dbusValue) const
174 {
175 return MatchProbe<T>::match(probeRef, dbusValue);
176 }
177};
178
Andrew Jefferyeab49292022-04-05 14:42:20 +0930179bool matchProbe(const nlohmann::json& probe, const DBusValueVariant& dbusValue)
Brad Bishop3cb8a602020-08-25 17:40:54 -0400180{
Brad Bishop5d525412020-08-26 08:50:50 -0400181 return std::visit(MatchProbeForwarder(probe), dbusValue);
182}
George Liuce8d1d02025-08-25 08:58:25 +0800183
184inline char asciiToLower(char c)
185{
186 // Converts a character to lower case without relying on std::locale
187 if ('A' <= c && c <= 'Z')
188 {
189 c -= static_cast<char>('A' - 'a');
190 }
191 return c;
192}
193
194std::pair<FirstIndex, LastIndex> iFindFirst(std::string_view str,
195 std::string_view sub)
196{
197 if (sub.empty())
198 {
199 return {std::string_view::npos, std::string_view::npos};
200 }
201 auto result = std::ranges::search(str, sub, [](char a, char b) {
202 return asciiToLower(a) == asciiToLower(b);
203 });
204
205 if (!result.empty())
206 {
207 size_t start = static_cast<size_t>(
208 std::ranges::distance(str.begin(), result.begin()));
209 return {start, start + sub.size()};
210 }
211
212 return {std::string_view::npos, std::string_view::npos};
213}