blob: 26226d490d8ab344fc6724f6913c340363cf3a8c [file] [log] [blame]
#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