1 #include "config_parser.hpp" 2 3 #include <stdplus/exception.hpp> 4 #include <stdplus/fd/create.hpp> 5 #include <stdplus/fd/line.hpp> 6 #include <utility> 7 8 namespace phosphor 9 { 10 namespace network 11 { 12 namespace config 13 { 14 15 Parser::Parser(const fs::path& filename) 16 { 17 setFile(filename); 18 } 19 20 const ValueList& Parser::getValues(std::string_view section, 21 std::string_view key) const noexcept 22 { 23 static const ValueList empty; 24 auto sit = sections.find(section); 25 if (sit == sections.end()) 26 { 27 return empty; 28 } 29 30 auto kit = sit->second.find(key); 31 if (kit == sit->second.end()) 32 { 33 return empty; 34 } 35 36 return kit->second; 37 } 38 39 inline bool isspace(char c) noexcept 40 { 41 return c == ' ' || c == '\t'; 42 } 43 44 inline bool iscomment(char c) noexcept 45 { 46 return c == '#' || c == ';'; 47 } 48 49 static void removePadding(std::string_view& str) noexcept 50 { 51 size_t idx = str.size(); 52 for (; idx > 0 && isspace(str[idx - 1]); idx--) 53 ; 54 str.remove_suffix(str.size() - idx); 55 56 idx = 0; 57 for (; idx < str.size() && isspace(str[idx]); idx++) 58 ; 59 str.remove_prefix(idx); 60 } 61 62 struct Parse 63 { 64 SectionMap sections; 65 KeyValuesMap* section = nullptr; 66 67 void pumpSection(std::string_view line) 68 { 69 auto cpos = line.find(']'); 70 auto s = line.substr(0, cpos); 71 auto it = sections.find(s); 72 if (it == sections.end()) 73 { 74 std::tie(it, std::ignore) = 75 sections.emplace(Section(s), KeyValuesMap{}); 76 } 77 section = &it->second; 78 } 79 80 void pumpKV(std::string_view line) 81 { 82 auto epos = line.find('='); 83 if (epos == line.npos) 84 { 85 return; 86 } 87 if (section == nullptr) 88 { 89 return; 90 } 91 auto k = line.substr(0, epos); 92 removePadding(k); 93 auto v = line.substr(epos + 1); 94 removePadding(v); 95 96 auto it = section->find(k); 97 if (it == section->end()) 98 { 99 std::tie(it, std::ignore) = section->emplace(Key(k), ValueList{}); 100 } 101 it->second.emplace_back(v); 102 } 103 104 void pump(std::string_view line) 105 { 106 for (size_t i = 0; i < line.size(); ++i) 107 { 108 auto c = line[i]; 109 if (iscomment(c)) 110 { 111 return; 112 } 113 else if (c == '[') 114 { 115 return pumpSection(line.substr(i + 1)); 116 } 117 else if (!isspace(c)) 118 { 119 return pumpKV(line.substr(i)); 120 } 121 } 122 } 123 }; 124 125 void Parser::setFile(const fs::path& filename) 126 { 127 Parse parse; 128 129 try 130 { 131 auto fd = stdplus::fd::open(filename.c_str(), 132 stdplus::fd::OpenAccess::ReadOnly); 133 stdplus::fd::LineReader reader(fd); 134 while (true) 135 { 136 parse.pump(*reader.readLine()); 137 } 138 } 139 catch (...) 140 { 141 // TODO: Pass exceptions once callers can handle them 142 } 143 144 this->sections = std::move(parse.sections); 145 } 146 147 } // namespace config 148 } // namespace network 149 } // namespace phosphor 150