1 #pragma once 2 3 #include <filesystem> 4 #include <functional> 5 #include <optional> 6 #include <string> 7 #include <string_view> 8 #include <unordered_map> 9 #include <vector> 10 11 namespace phosphor 12 { 13 namespace network 14 { 15 namespace config 16 { 17 18 /** @brief Compare in (case insensitive) vs expected (sensitive) */ 19 bool icaseeq(std::string_view in, std::string_view expected) noexcept; 20 /** @brief Turns a systemd bool string into a c++ bool */ 21 std::optional<bool> parseBool(std::string_view in) noexcept; 22 23 namespace fs = std::filesystem; 24 25 fs::path pathForIntfConf(const fs::path& dir, std::string_view intf); 26 fs::path pathForIntfDev(const fs::path& dir, std::string_view intf); 27 28 template <typename T, typename Check> 29 class Checked 30 { 31 public: 32 struct unchecked 33 {}; 34 35 template <typename... Args> Checked(Args &&...args)36 constexpr Checked(Args&&... args) : t(conCheck(std::forward<Args>(args)...)) 37 {} 38 39 template <typename... Args> Checked(unchecked,Args &&...args)40 constexpr Checked(unchecked, Args&&... args) : 41 t(std::forward<Args>(args)...) 42 {} 43 get() const44 constexpr const T& get() const noexcept 45 { 46 return t; 47 } 48 operator const T&() const49 constexpr operator const T&() const noexcept 50 { 51 return t; 52 } 53 54 template <typename T2, typename Check2> operator ==(const Checked<T2,Check2> & rhs) const55 constexpr bool operator==(const Checked<T2, Check2>& rhs) const noexcept 56 { 57 static_assert(std::is_same_v<Check2, Check>); 58 return t == rhs.t; 59 } 60 operator ==(const auto & rhs) const61 constexpr bool operator==(const auto& rhs) const noexcept 62 { 63 return t == rhs; 64 } 65 66 private: 67 T t; 68 69 template <typename... Args> conCheck(Args &&...args)70 static constexpr T conCheck(Args&&... args) 71 { 72 T t(std::forward<Args>(args)...); 73 Check{}(t); 74 return t; 75 } 76 }; 77 78 struct KeyCheck 79 { 80 void operator()(std::string_view s); 81 }; 82 struct SectionCheck 83 { 84 void operator()(std::string_view s); 85 }; 86 struct ValueCheck 87 { 88 void operator()(std::string_view s); 89 }; 90 91 struct string_hash : public std::hash<std::string_view> 92 { 93 using is_transparent = void; 94 95 template <typename T> operator ()phosphor::network::config::string_hash96 inline size_t operator()(const Checked<std::string, T>& t) const 97 { 98 return static_cast<const std::hash<std::string_view>&>(*this)(t.get()); 99 } 100 template <typename T> operator ()phosphor::network::config::string_hash101 inline size_t operator()(const T& t) const 102 { 103 return static_cast<const std::hash<std::string_view>&>(*this)(t); 104 } 105 }; 106 107 using Key = Checked<std::string, KeyCheck>; 108 using Section = Checked<std::string, SectionCheck>; 109 using Value = Checked<std::string, ValueCheck>; 110 using ValueList = std::vector<Value>; 111 using KeyValuesMap = 112 std::unordered_map<Key, ValueList, string_hash, std::equal_to<>>; 113 using KeyValuesMapList = std::vector<KeyValuesMap>; 114 using SectionMapInt = 115 std::unordered_map<Section, KeyValuesMapList, string_hash, std::equal_to<>>; 116 117 class SectionMap : public SectionMapInt 118 { 119 public: 120 const std::string* getLastValueString(std::string_view section, 121 std::string_view key) const noexcept; getValues(std::string_view section,std::string_view key,auto && conv) const122 inline auto getValues(std::string_view section, std::string_view key, 123 auto&& conv) const 124 { 125 std::vector<std::invoke_result_t<decltype(conv), const Value&>> values; 126 auto sit = find(section); 127 if (sit == end()) 128 { 129 return values; 130 } 131 for (const auto& secv : sit->second) 132 { 133 auto kit = secv.find(key); 134 if (kit == secv.end()) 135 { 136 continue; 137 } 138 for (auto v : kit->second) 139 { 140 values.push_back(conv(v)); 141 } 142 } 143 return values; 144 } 145 std::vector<std::string> getValueStrings(std::string_view section, 146 std::string_view key) const; 147 }; 148 149 class Parser 150 { 151 public: 152 SectionMap map; 153 154 Parser() = default; 155 156 /** @brief Constructor 157 * @param[in] filename - Absolute path of the file which will be parsed. 158 */ 159 Parser(const fs::path& filename); 160 161 /** @brief Determine if the loaded file exists */ getFileExists() const162 inline bool getFileExists() const noexcept 163 { 164 return fileExists; 165 } 166 167 /** @brief Determine if there were warnings parsing the file 168 * @return The number of parsing issues in the file 169 */ getWarnings() const170 inline const std::vector<std::string>& getWarnings() const noexcept 171 { 172 return warnings; 173 } 174 175 /** @brief Get the filename last parsed successfully 176 * @return file path 177 */ getFilename() const178 inline const fs::path& getFilename() const noexcept 179 { 180 return filename; 181 } 182 183 /** @brief Set the file name and parse it. 184 * @param[in] filename - Absolute path of the file. 185 */ 186 void setFile(const fs::path& filename); 187 188 /** @brief Write the current config to a file */ 189 void writeFile() const; 190 void writeFile(const fs::path& filename); 191 192 private: 193 bool fileExists = false; 194 fs::path filename; 195 std::vector<std::string> warnings; 196 }; 197 198 } // namespace config 199 } // namespace network 200 } // namespace phosphor 201