1 #include "config_parser.hpp" 2 3 #include <algorithm> 4 #include <fstream> 5 #include <list> 6 #include <phosphor-logging/log.hpp> 7 #include <regex> 8 #include <string> 9 #include <unordered_map> 10 11 namespace phosphor 12 { 13 namespace network 14 { 15 namespace config 16 { 17 18 using namespace phosphor::logging; 19 20 Parser::Parser(const fs::path& filePath) 21 { 22 setFile(filePath); 23 } 24 25 std::tuple<ReturnCode, KeyValueMap> 26 Parser::getSection(const std::string& section) 27 { 28 auto it = sections.find(section); 29 if (it == sections.end()) 30 { 31 KeyValueMap keyValues; 32 return std::make_tuple(ReturnCode::SECTION_NOT_FOUND, 33 std::move(keyValues)); 34 } 35 36 return std::make_tuple(ReturnCode::SUCCESS, it->second); 37 } 38 39 std::tuple<ReturnCode, ValueList> Parser::getValues(const std::string& section, 40 const std::string& key) 41 { 42 ValueList values; 43 KeyValueMap keyValues{}; 44 auto rc = ReturnCode::SUCCESS; 45 46 std::tie(rc, keyValues) = getSection(section); 47 if (rc != ReturnCode::SUCCESS) 48 { 49 return std::make_tuple(rc, std::move(values)); 50 } 51 52 auto it = keyValues.find(key); 53 if (it == keyValues.end()) 54 { 55 return std::make_tuple(ReturnCode::KEY_NOT_FOUND, std::move(values)); 56 } 57 58 for (; it != keyValues.end() && key == it->first; it++) 59 { 60 values.push_back(it->second); 61 } 62 63 return std::make_tuple(ReturnCode::SUCCESS, std::move(values)); 64 } 65 66 bool Parser::isValueExist(const std::string& section, const std::string& key, 67 const std::string& value) 68 { 69 auto rc = ReturnCode::SUCCESS; 70 ValueList values; 71 std::tie(rc, values) = getValues(section, key); 72 73 if (rc != ReturnCode::SUCCESS) 74 { 75 return false; 76 } 77 auto it = std::find(values.begin(), values.end(), value); 78 return it != std::end(values) ? true : false; 79 } 80 81 void Parser::setValue(const std::string& section, const std::string& key, 82 const std::string& value) 83 { 84 KeyValueMap values; 85 auto it = sections.find(section); 86 if (it != sections.end()) 87 { 88 values = std::move(it->second); 89 } 90 values.insert(std::make_pair(key, value)); 91 92 if (it != sections.end()) 93 { 94 it->second = std::move(values); 95 } 96 else 97 { 98 sections.insert(std::make_pair(section, std::move(values))); 99 } 100 } 101 102 #if 0 103 void Parser::print() 104 { 105 for (auto section : sections) 106 { 107 std::cout << "[" << section.first << "]\n\n"; 108 for (auto keyValue : section.second) 109 { 110 std::cout << keyValue.first << "=" << keyValue.second << "\n"; 111 } 112 } 113 } 114 #endif 115 116 void Parser::setFile(const fs::path& filePath) 117 { 118 this->filePath = filePath; 119 std::fstream stream; 120 stream.open(filePath.string(), std::fstream::in); 121 122 if (!stream.is_open()) 123 { 124 return; 125 } 126 // clear all the section data. 127 sections.clear(); 128 parse(stream); 129 stream.close(); 130 } 131 132 void Parser::parse(std::istream& in) 133 { 134 static const std::regex commentRegex{R"x(\s*[;#])x"}; 135 static const std::regex sectionRegex{R"x(\s*\[([^\]]+)\])x"}; 136 static const std::regex valueRegex{R"x(\s*(\S[^ \t=]*)\s*=\s*(\S+)\s*$)x"}; 137 std::string section; 138 std::smatch pieces; 139 for (std::string line; std::getline(in, line);) 140 { 141 if (line.empty() || std::regex_match(line, pieces, commentRegex)) 142 { 143 // skip comment lines and blank lines 144 } 145 else if (std::regex_match(line, pieces, sectionRegex)) 146 { 147 if (pieces.size() == 2) 148 { 149 section = pieces[1].str(); 150 } 151 } 152 else if (std::regex_match(line, pieces, valueRegex)) 153 { 154 if (pieces.size() == 3) 155 { 156 setValue(section, pieces[1].str(), pieces[2].str()); 157 } 158 } 159 } 160 } 161 162 } // namespace config 163 } // namespace network 164 } // namespace phosphor 165