| #include "config_parser.hpp" |
| #include <phosphor-logging/log.hpp> |
| |
| #include <fstream> |
| #include <string> |
| #include <algorithm> |
| #include <unordered_map> |
| #include <regex> |
| #include <list> |
| |
| namespace phosphor |
| { |
| namespace network |
| { |
| namespace config |
| { |
| |
| using namespace phosphor::logging; |
| |
| Parser::Parser(const fs::path& filePath) |
| { |
| setFile(filePath); |
| } |
| |
| |
| std::tuple<ReturnCode, KeyValueMap> Parser::getSection(const std::string& section) |
| { |
| auto it = sections.find(section); |
| if (it == sections.end()) |
| { |
| KeyValueMap keyValues; |
| return std::make_tuple(ReturnCode::SECTION_NOT_FOUND, |
| std::move(keyValues)); |
| } |
| |
| return std::make_tuple(ReturnCode::SUCCESS, it->second); |
| } |
| |
| std::tuple<ReturnCode, ValueList> Parser::getValues(const std::string& section, |
| const std::string& key) |
| { |
| ValueList values; |
| KeyValueMap keyValues {}; |
| auto rc = ReturnCode::SUCCESS; |
| |
| std::tie(rc, keyValues) = getSection(section); |
| if (rc != ReturnCode::SUCCESS) |
| { |
| return std::make_tuple(rc, std::move(values)); |
| } |
| |
| auto it = keyValues.find(key); |
| if (it == keyValues.end()) |
| { |
| return std::make_tuple(ReturnCode::KEY_NOT_FOUND, std::move(values)); |
| } |
| |
| for (; it != keyValues.end() && key == it->first; it++) |
| { |
| values.push_back(it->second); |
| } |
| |
| return std::make_tuple(ReturnCode::SUCCESS, std::move(values)); |
| } |
| |
| |
| bool Parser::isValueExist(const std::string& section, const std::string& key, |
| const std::string& value) |
| { |
| auto rc = ReturnCode::SUCCESS; |
| ValueList values; |
| std::tie(rc, values) = getValues(section, key); |
| |
| if (rc != ReturnCode::SUCCESS) |
| { |
| return false; |
| } |
| auto it = std::find(values.begin(), values.end(), value); |
| return it != std::end(values) ? true : false; |
| } |
| |
| void Parser::setValue(const std::string& section, const std::string& key, |
| const std::string& value) |
| { |
| KeyValueMap values; |
| auto it = sections.find(section); |
| if (it != sections.end()) |
| { |
| values = std::move(it->second); |
| } |
| values.insert(std::make_pair(key, value)); |
| |
| if (it != sections.end()) |
| { |
| it->second = std::move(values); |
| } |
| else |
| { |
| sections.insert(std::make_pair(section, std::move(values))); |
| } |
| } |
| |
| #if 0 |
| void Parser::print() |
| { |
| for (auto section : sections) |
| { |
| std::cout << "[" << section.first << "]\n\n"; |
| for (auto keyValue : section.second) |
| { |
| std::cout << keyValue.first << "=" << keyValue.second << "\n"; |
| } |
| } |
| } |
| #endif |
| |
| void Parser::setFile(const fs::path& filePath) |
| { |
| this->filePath = filePath; |
| std::fstream stream; |
| stream.open(filePath.string(), std::fstream::in); |
| |
| if (!stream.is_open()) |
| { |
| return; |
| } |
| //clear all the section data. |
| sections.clear(); |
| parse(stream); |
| stream.close(); |
| } |
| |
| void Parser::parse(std::istream& in) |
| { |
| static const std::regex commentRegex |
| { |
| R"x(\s*[;#])x" |
| }; |
| static const std::regex sectionRegex |
| { |
| R"x(\s*\[([^\]]+)\])x" |
| }; |
| static const std::regex valueRegex |
| { |
| R"x(\s*(\S[^ \t=]*)\s*=\s*(\S+)\s*$)x" |
| }; |
| std::string section; |
| std::smatch pieces; |
| for (std::string line; std::getline(in, line);) |
| { |
| if (line.empty() || std::regex_match(line, pieces, commentRegex)) |
| { |
| // skip comment lines and blank lines |
| } |
| else if (std::regex_match(line, pieces, sectionRegex)) |
| { |
| if (pieces.size() == 2) |
| { |
| section = pieces[1].str(); |
| } |
| } |
| else if (std::regex_match(line, pieces, valueRegex)) |
| { |
| if (pieces.size() == 3) |
| { |
| setValue(section, pieces[1].str(), pieces[2].str()); |
| } |
| } |
| } |
| } |
| |
| }//namespace config |
| }//namespace network |
| }//namespace phosphor |