config_parser: Cleanups and modern c++ standards
This was exposing many functions and semantics that are unused by the
application. The goal is to simplify the interface and convert to using
types like `string_view` and referenceable lists where possible.
Change-Id: I4cba6326f9a96a943d384165e656f8589f931959
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/config_parser.cpp b/src/config_parser.cpp
index 1525c5c..a6b7e36 100644
--- a/src/config_parser.cpp
+++ b/src/config_parser.cpp
@@ -1,12 +1,8 @@
#include "config_parser.hpp"
-#include <algorithm>
#include <fstream>
-#include <list>
-#include <phosphor-logging/log.hpp>
#include <regex>
#include <string>
-#include <unordered_map>
namespace phosphor
{
@@ -15,126 +11,61 @@
namespace config
{
-using namespace phosphor::logging;
-
-Parser::Parser(const fs::path& filePath)
+Parser::Parser(const fs::path& filename)
{
- setFile(filePath);
+ setFile(filename);
}
-std::tuple<ReturnCode, KeyValueMap>
- Parser::getSection(const std::string& section)
+const ValueList& Parser::getValues(std::string_view section,
+ std::string_view key) const noexcept
{
- auto it = sections.find(section);
- if (it == sections.end())
+ static const ValueList empty;
+ auto sit = sections.find(section);
+ if (sit == sections.end())
{
- KeyValueMap keyValues;
- return std::make_tuple(ReturnCode::SECTION_NOT_FOUND,
- std::move(keyValues));
+ return empty;
}
- 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)
+ auto kit = sit->second.find(key);
+ if (kit == sit->second.end())
{
- return std::make_tuple(rc, std::move(values));
+ return empty;
}
- 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;
+ return kit->second;
}
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())
+ auto sit = sections.find(section);
+ if (sit == sections.end())
{
- values = std::move(it->second);
+ std::tie(sit, std::ignore) = sections.emplace(section, KeyValuesMap{});
}
- values.insert(std::make_pair(key, value));
-
- if (it != sections.end())
+ auto kit = sit->second.find(key);
+ if (kit == sit->second.end())
{
- it->second = std::move(values);
+ std::tie(kit, std::ignore) = sit->second.emplace(key, ValueList{});
}
- else
- {
- sections.insert(std::make_pair(section, std::move(values)));
- }
+ kit->second.push_back(value);
}
-#if 0
-void Parser::print()
+void Parser::setFile(const fs::path& filename)
{
- 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(filePath, std::fstream::in);
-
+ std::fstream stream(filename, std::fstream::in);
if (!stream.is_open())
{
return;
}
// clear all the section data.
sections.clear();
- parse(stream);
-}
-
-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);)
+ for (std::string line; std::getline(stream, line);)
{
if (line.empty() || std::regex_match(line, pieces, commentRegex))
{
diff --git a/src/config_parser.hpp b/src/config_parser.hpp
index 8af4a34..3065162 100644
--- a/src/config_parser.hpp
+++ b/src/config_parser.hpp
@@ -1,9 +1,8 @@
#pragma once
#include <filesystem>
-#include <map>
#include <string>
-#include <tuple>
+#include <string_view>
#include <unordered_map>
#include <vector>
@@ -14,82 +13,56 @@
namespace config
{
+struct string_hash : public std::hash<std::string_view>
+{
+ using is_transparent = void;
+};
+
+using Key = std::string;
using Section = std::string;
-using KeyValueMap = std::multimap<std::string, std::string>;
-using ValueList = std::vector<std::string>;
+using Value = std::string;
+using ValueList = std::vector<Value>;
+using KeyValuesMap =
+ std::unordered_map<Key, ValueList, string_hash, std::equal_to<>>;
+using SectionMap =
+ std::unordered_map<Section, KeyValuesMap, string_hash, std::equal_to<>>;
namespace fs = std::filesystem;
-enum class ReturnCode
-{
- SUCCESS = 0x0,
- SECTION_NOT_FOUND = 0x1,
- KEY_NOT_FOUND = 0x2,
-};
-
class Parser
{
public:
Parser() = default;
/** @brief Constructor
- * @param[in] fileName - Absolute path of the file which will be parsed.
+ * @param[in] filename - Absolute path of the file which will be parsed.
*/
- Parser(const fs::path& fileName);
+ Parser(const fs::path& filename);
/** @brief Get the values of the given key and section.
* @param[in] section - section name.
* @param[in] key - key to look for.
- * @returns the tuple of return code and the
- * values associated with the key.
+ * @returns The ValueList or nullptr if no key + section exists.
*/
-
- std::tuple<ReturnCode, ValueList> getValues(const std::string& section,
- const std::string& key);
+ const ValueList& getValues(std::string_view section,
+ std::string_view key) const noexcept;
/** @brief Set the value of the given key and section.
* @param[in] section - section name.
* @param[in] key - key name.
* @param[in] value - value.
*/
-
void setValue(const std::string& section, const std::string& key,
const std::string& value);
/** @brief Set the file name and parse it.
- * @param[in] fileName - Absolute path of the file.
+ * @param[in] filename - Absolute path of the file.
*/
-
- void setFile(const fs::path& fileName);
+ void setFile(const fs::path& filename);
private:
- /** @brief Parses the given file and fills the data.
- * @param[in] stream - inputstream.
- */
-
- void parse(std::istream& stream);
-
- /** @brief Get all the key values of the given section.
- * @param[in] section - section name.
- * @returns the tuple of return code and the map of (key,value).
- */
-
- std::tuple<ReturnCode, KeyValueMap> getSection(const std::string& section);
-
- /** @brief checks that whether the value exist in the
- * given section.
- * @param[in] section - section name.
- * @param[in] key - key name.
- * @param[in] value - value.
- * @returns true if exist otherwise false.
- */
-
- bool isValueExist(const std::string& section, const std::string& key,
- const std::string& value);
-
- std::unordered_map<Section, KeyValueMap> sections;
- fs::path filePath;
+ SectionMap sections;
};
} // namespace config
diff --git a/src/dhcp_configuration.cpp b/src/dhcp_configuration.cpp
index 6fb24d0..0605a6a 100644
--- a/src/dhcp_configuration.cpp
+++ b/src/dhcp_configuration.cpp
@@ -4,6 +4,8 @@
#include "network_manager.hpp"
+#include <fmt/format.h>
+
#include <phosphor-logging/elog-errors.hpp>
#include <phosphor-logging/log.hpp>
#include <xyz/openbmc_project/Common/error.hpp>
@@ -87,25 +89,16 @@
confPath /= fileName;
// systemd default behaviour is all DHCP fields should be enabled by
// default.
- auto propValue = true;
config::Parser parser(confPath);
- auto rc = config::ReturnCode::SUCCESS;
- config::ValueList values{};
- std::tie(rc, values) = parser.getValues("DHCP", prop);
-
- if (rc != config::ReturnCode::SUCCESS)
+ const auto& values = parser.getValues("DHCP", prop);
+ if (values.empty())
{
- log<level::DEBUG>("Unable to get the value from section DHCP",
- entry("PROP=%s", prop.c_str()), entry("RC=%d", rc));
- return propValue;
+ auto msg = fmt::format("Missing config section DHCP[{}]", prop);
+ log<level::NOTICE>(msg.c_str(), entry("PROP=%s", prop.c_str()));
+ return true;
}
-
- if (values[0] == "false")
- {
- propValue = false;
- }
- return propValue;
+ return values.back() != "false";
}
} // namespace dhcp
} // namespace network
diff --git a/src/ethernet_interface.cpp b/src/ethernet_interface.cpp
index 7f4f930..825ce62 100644
--- a/src/ethernet_interface.cpp
+++ b/src/ethernet_interface.cpp
@@ -809,17 +809,8 @@
std::string fileName = systemd::config::networkFilePrefix +
interfaceName() + systemd::config::networkFileSuffix;
confPath /= fileName;
- ServerList servers;
config::Parser parser(confPath.string());
- auto rc = config::ReturnCode::SUCCESS;
-
- std::tie(rc, servers) = parser.getValues("Network", "DNS");
- if (rc != config::ReturnCode::SUCCESS)
- {
- log<level::DEBUG>("Unable to get the value for network[DNS]",
- entry("RC=%d", rc));
- }
- return servers;
+ return parser.getValues("Network", "DNS");
}
ServerList EthernetInterface::getNameServerFromResolvd()
@@ -963,17 +954,14 @@
std::string fileName = systemd::config::networkFilePrefix +
interfaceName() + systemd::config::networkFileSuffix;
confPath /= fileName;
- config::ValueList values;
- config::Parser parser(confPath.string());
- auto rc = config::ReturnCode::SUCCESS;
- std::tie(rc, values) = parser.getValues("Network", "IPv6AcceptRA");
- if (rc != config::ReturnCode::SUCCESS)
+ config::Parser parser(confPath);
+ const auto& values = parser.getValues("Network", "IPv6AcceptRA");
+ if (values.empty())
{
- log<level::DEBUG>("Unable to get the value for Network[IPv6AcceptRA]",
- entry("rc=%d", rc));
+ log<level::NOTICE>("Unable to get the value for Network[IPv6AcceptRA]");
return false;
}
- return (values[0] == "true");
+ return values.back() == "true";
}
ServerList EthernetInterface::getNTPServersFromConf()
@@ -984,18 +972,8 @@
interfaceName() + systemd::config::networkFileSuffix;
confPath /= fileName;
- ServerList servers;
config::Parser parser(confPath.string());
- auto rc = config::ReturnCode::SUCCESS;
-
- std::tie(rc, servers) = parser.getValues("Network", "NTP");
- if (rc != config::ReturnCode::SUCCESS)
- {
- log<level::DEBUG>("Unable to get the value for Network[NTP]",
- entry("rc=%d", rc));
- }
-
- return servers;
+ return parser.getValues("Network", "NTP");
}
ServerList EthernetInterface::ntpServers(ServerList servers)
diff --git a/src/util.cpp b/src/util.cpp
index 803d26e..de0bc9d 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -376,27 +376,22 @@
systemd::config::networkFileSuffix;
confPath /= fileName;
- auto rc = config::ReturnCode::SUCCESS;
- config::ValueList values;
config::Parser parser(confPath.string());
-
- std::tie(rc, values) = parser.getValues("Network", "DHCP");
- if (rc != config::ReturnCode::SUCCESS)
+ const auto& values = parser.getValues("Network", "DHCP");
+ if (values.empty())
{
- log<level::DEBUG>("Unable to get the value for Network[DHCP]",
- entry("RC=%d", rc));
+ log<level::NOTICE>("Unable to get the value for Network[DHCP]");
return dhcp;
}
- // There will be only single value for DHCP key.
- if (values[0] == "true")
+ if (values.back() == "true")
{
dhcp = EthernetInterfaceIntf::DHCPConf::both;
}
- else if (values[0] == "ipv4")
+ else if (values.back() == "ipv4")
{
dhcp = EthernetInterfaceIntf::DHCPConf::v4;
}
- else if (values[0] == "ipv6")
+ else if (values.back() == "ipv6")
{
dhcp = EthernetInterfaceIntf::DHCPConf::v6;
}