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