| #include "config_parser.hpp" |
| |
| #include <stdplus/exception.hpp> |
| #include <stdplus/fd/create.hpp> |
| #include <stdplus/fd/line.hpp> |
| #include <utility> |
| |
| namespace phosphor |
| { |
| namespace network |
| { |
| namespace config |
| { |
| |
| Parser::Parser(const fs::path& filename) |
| { |
| setFile(filename); |
| } |
| |
| const ValueList& Parser::getValues(std::string_view section, |
| std::string_view key) const noexcept |
| { |
| static const ValueList empty; |
| auto sit = sections.find(section); |
| if (sit == sections.end()) |
| { |
| return empty; |
| } |
| |
| auto kit = sit->second.find(key); |
| if (kit == sit->second.end()) |
| { |
| return empty; |
| } |
| |
| return kit->second; |
| } |
| |
| inline bool isspace(char c) noexcept |
| { |
| return c == ' ' || c == '\t'; |
| } |
| |
| inline bool iscomment(char c) noexcept |
| { |
| return c == '#' || c == ';'; |
| } |
| |
| static void removePadding(std::string_view& str) noexcept |
| { |
| size_t idx = str.size(); |
| for (; idx > 0 && isspace(str[idx - 1]); idx--) |
| ; |
| str.remove_suffix(str.size() - idx); |
| |
| idx = 0; |
| for (; idx < str.size() && isspace(str[idx]); idx++) |
| ; |
| str.remove_prefix(idx); |
| } |
| |
| struct Parse |
| { |
| SectionMap sections; |
| KeyValuesMap* section = nullptr; |
| |
| void pumpSection(std::string_view line) |
| { |
| auto cpos = line.find(']'); |
| auto s = line.substr(0, cpos); |
| auto it = sections.find(s); |
| if (it == sections.end()) |
| { |
| std::tie(it, std::ignore) = |
| sections.emplace(Section(s), KeyValuesMap{}); |
| } |
| section = &it->second; |
| } |
| |
| void pumpKV(std::string_view line) |
| { |
| auto epos = line.find('='); |
| if (epos == line.npos) |
| { |
| return; |
| } |
| if (section == nullptr) |
| { |
| return; |
| } |
| auto k = line.substr(0, epos); |
| removePadding(k); |
| auto v = line.substr(epos + 1); |
| removePadding(v); |
| |
| auto it = section->find(k); |
| if (it == section->end()) |
| { |
| std::tie(it, std::ignore) = section->emplace(Key(k), ValueList{}); |
| } |
| it->second.emplace_back(v); |
| } |
| |
| void pump(std::string_view line) |
| { |
| for (size_t i = 0; i < line.size(); ++i) |
| { |
| auto c = line[i]; |
| if (iscomment(c)) |
| { |
| return; |
| } |
| else if (c == '[') |
| { |
| return pumpSection(line.substr(i + 1)); |
| } |
| else if (!isspace(c)) |
| { |
| return pumpKV(line.substr(i)); |
| } |
| } |
| } |
| }; |
| |
| void Parser::setFile(const fs::path& filename) |
| { |
| Parse parse; |
| |
| try |
| { |
| auto fd = stdplus::fd::open(filename.c_str(), |
| stdplus::fd::OpenAccess::ReadOnly); |
| stdplus::fd::LineReader reader(fd); |
| while (true) |
| { |
| parse.pump(*reader.readLine()); |
| } |
| } |
| catch (...) |
| { |
| // TODO: Pass exceptions once callers can handle them |
| } |
| |
| this->sections = std::move(parse.sections); |
| } |
| |
| } // namespace config |
| } // namespace network |
| } // namespace phosphor |