|  | #pragma once | 
|  |  | 
|  | #include <filesystem> | 
|  | #include <functional> | 
|  | #include <optional> | 
|  | #include <string> | 
|  | #include <string_view> | 
|  | #include <unordered_map> | 
|  | #include <vector> | 
|  |  | 
|  | namespace phosphor | 
|  | { | 
|  | namespace network | 
|  | { | 
|  | namespace config | 
|  | { | 
|  |  | 
|  | /** @brief Compare in (case insensitive) vs expected (sensitive) */ | 
|  | bool icaseeq(std::string_view in, std::string_view expected) noexcept; | 
|  | /** @brief Turns a systemd bool string into a c++ bool */ | 
|  | std::optional<bool> parseBool(std::string_view in) noexcept; | 
|  |  | 
|  | namespace fs = std::filesystem; | 
|  |  | 
|  | fs::path pathForIntfConf(const fs::path& dir, std::string_view intf); | 
|  | fs::path pathForIntfDev(const fs::path& dir, std::string_view intf); | 
|  |  | 
|  | template <typename T, typename Check> | 
|  | class Checked | 
|  | { | 
|  | public: | 
|  | struct unchecked | 
|  | {}; | 
|  |  | 
|  | template <typename... Args> | 
|  | constexpr Checked(Args&&... args) : t(conCheck(std::forward<Args>(args)...)) | 
|  | {} | 
|  |  | 
|  | template <typename... Args> | 
|  | constexpr Checked(unchecked, Args&&... args) : | 
|  | t(std::forward<Args>(args)...) | 
|  | {} | 
|  |  | 
|  | constexpr const T& get() const noexcept | 
|  | { | 
|  | return t; | 
|  | } | 
|  |  | 
|  | constexpr operator const T&() const noexcept | 
|  | { | 
|  | return t; | 
|  | } | 
|  |  | 
|  | template <typename T2, typename Check2> | 
|  | constexpr bool operator==(const Checked<T2, Check2>& rhs) const noexcept | 
|  | { | 
|  | static_assert(std::is_same_v<Check2, Check>); | 
|  | return t == rhs.t; | 
|  | } | 
|  |  | 
|  | constexpr bool operator==(const auto& rhs) const noexcept | 
|  | { | 
|  | return t == rhs; | 
|  | } | 
|  |  | 
|  | private: | 
|  | T t; | 
|  |  | 
|  | template <typename... Args> | 
|  | static constexpr T conCheck(Args&&... args) | 
|  | { | 
|  | T t(std::forward<Args>(args)...); | 
|  | Check{}(t); | 
|  | return t; | 
|  | } | 
|  | }; | 
|  |  | 
|  | struct KeyCheck | 
|  | { | 
|  | void operator()(std::string_view s); | 
|  | }; | 
|  | struct SectionCheck | 
|  | { | 
|  | void operator()(std::string_view s); | 
|  | }; | 
|  | struct ValueCheck | 
|  | { | 
|  | void operator()(std::string_view s); | 
|  | }; | 
|  |  | 
|  | struct string_hash : public std::hash<std::string_view> | 
|  | { | 
|  | using is_transparent = void; | 
|  |  | 
|  | template <typename T> | 
|  | inline size_t operator()(const Checked<std::string, T>& t) const | 
|  | { | 
|  | return static_cast<const std::hash<std::string_view>&>(*this)(t.get()); | 
|  | } | 
|  | template <typename T> | 
|  | inline size_t operator()(const T& t) const | 
|  | { | 
|  | return static_cast<const std::hash<std::string_view>&>(*this)(t); | 
|  | } | 
|  | }; | 
|  |  | 
|  | using Key = Checked<std::string, KeyCheck>; | 
|  | using Section = Checked<std::string, SectionCheck>; | 
|  | using Value = Checked<std::string, ValueCheck>; | 
|  | using ValueList = std::vector<Value>; | 
|  | using KeyValuesMap = | 
|  | std::unordered_map<Key, ValueList, string_hash, std::equal_to<>>; | 
|  | using KeyValuesMapList = std::vector<KeyValuesMap>; | 
|  | using SectionMapInt = | 
|  | std::unordered_map<Section, KeyValuesMapList, string_hash, std::equal_to<>>; | 
|  |  | 
|  | class SectionMap : public SectionMapInt | 
|  | { | 
|  | public: | 
|  | const std::string* getLastValueString(std::string_view section, | 
|  | std::string_view key) const noexcept; | 
|  | inline auto getValues(std::string_view section, std::string_view key, | 
|  | auto&& conv) const | 
|  | { | 
|  | std::vector<std::invoke_result_t<decltype(conv), const Value&>> values; | 
|  | auto sit = find(section); | 
|  | if (sit == end()) | 
|  | { | 
|  | return values; | 
|  | } | 
|  | for (const auto& secv : sit->second) | 
|  | { | 
|  | auto kit = secv.find(key); | 
|  | if (kit == secv.end()) | 
|  | { | 
|  | continue; | 
|  | } | 
|  | for (auto v : kit->second) | 
|  | { | 
|  | values.push_back(conv(v)); | 
|  | } | 
|  | } | 
|  | return values; | 
|  | } | 
|  | std::vector<std::string> getValueStrings(std::string_view section, | 
|  | std::string_view key) const; | 
|  | }; | 
|  |  | 
|  | class Parser | 
|  | { | 
|  | public: | 
|  | SectionMap map; | 
|  |  | 
|  | Parser() = default; | 
|  |  | 
|  | /** @brief Constructor | 
|  | *  @param[in] filename - Absolute path of the file which will be parsed. | 
|  | */ | 
|  | Parser(const fs::path& filename); | 
|  |  | 
|  | /** @brief Determine if the loaded file exists */ | 
|  | inline bool getFileExists() const noexcept | 
|  | { | 
|  | return fileExists; | 
|  | } | 
|  |  | 
|  | /** @brief Determine if there were warnings parsing the file | 
|  | *  @return The number of parsing issues in the file | 
|  | */ | 
|  | inline const std::vector<std::string>& getWarnings() const noexcept | 
|  | { | 
|  | return warnings; | 
|  | } | 
|  |  | 
|  | /** @brief Get the filename last parsed successfully | 
|  | *  @return file path | 
|  | */ | 
|  | inline const fs::path& getFilename() const noexcept | 
|  | { | 
|  | return filename; | 
|  | } | 
|  |  | 
|  | /** @brief Set the file name and parse it. | 
|  | *  @param[in] filename - Absolute path of the file. | 
|  | */ | 
|  | void setFile(const fs::path& filename); | 
|  |  | 
|  | /** @brief Write the current config to a file */ | 
|  | void writeFile() const; | 
|  | void writeFile(const fs::path& filename); | 
|  |  | 
|  | private: | 
|  | bool fileExists = false; | 
|  | fs::path filename; | 
|  | std::vector<std::string> warnings; | 
|  | }; | 
|  |  | 
|  | } // namespace config | 
|  | } // namespace network | 
|  | } // namespace phosphor |