lokinet/llarp/config/ini.cpp

168 lines
4.6 KiB
C++
Raw Normal View History

#include <config/ini.hpp>
2019-09-01 12:10:49 +00:00
#include <util/logging/logger.hpp>
#include <util/str.hpp>
2019-07-16 22:37:41 +00:00
#include <cctype>
2019-01-22 14:13:26 +00:00
#include <fstream>
#include <list>
#include <iostream>
#include <cassert>
2019-01-22 14:13:26 +00:00
namespace llarp
{
bool
ConfigParser::LoadFile(std::string_view fname)
2019-01-22 14:13:26 +00:00
{
std::string name{fname};
2019-01-22 14:13:26 +00:00
{
std::ifstream f(name, std::ios::in | std::ios::binary);
if (!f.is_open())
2019-01-22 14:13:26 +00:00
return false;
f.seekg(0, std::ios::end);
m_Data.resize(f.tellg());
f.seekg(0, std::ios::beg);
if (m_Data.size() == 0)
2019-01-22 14:13:26 +00:00
return false;
f.read(m_Data.data(), m_Data.size());
}
m_FileName = name;
2019-01-22 14:13:26 +00:00
return Parse();
}
bool
ConfigParser::LoadFromStr(std::string_view str)
2019-01-22 14:13:26 +00:00
{
m_Data.resize(str.size());
std::copy(str.begin(), str.end(), m_Data.begin());
m_FileName = "<anonymous string>";
2019-01-22 14:13:26 +00:00
return Parse();
}
void
ConfigParser::Clear()
{
m_Config.clear();
m_Data.clear();
}
static bool
2019-01-22 15:16:35 +00:00
whitespace(char ch)
{
return std::isspace(static_cast<unsigned char>(ch)) != 0;
2019-01-22 15:16:35 +00:00
}
2019-01-22 14:13:26 +00:00
bool
ConfigParser::Parse()
{
std::list<std::string_view> lines;
2019-01-22 14:13:26 +00:00
{
auto itr = m_Data.begin();
// split into lines
while (itr != m_Data.end())
2019-01-22 14:13:26 +00:00
{
auto beg = itr;
while (itr != m_Data.end() && *itr != '\n' && *itr != '\r')
2019-01-22 14:13:26 +00:00
++itr;
2019-01-22 15:16:35 +00:00
lines.emplace_back(std::addressof(*beg), std::distance(beg, itr));
if (itr == m_Data.end())
2019-01-22 14:13:26 +00:00
break;
++itr;
}
}
std::string_view sectName;
size_t lineno = 0;
for (const auto& line : lines)
2019-01-22 14:13:26 +00:00
{
lineno++;
std::string_view realLine;
2019-01-22 14:13:26 +00:00
auto comment = line.find_first_of(';');
if (comment == std::string_view::npos)
2019-01-22 14:13:26 +00:00
comment = line.find_first_of('#');
if (comment == std::string_view::npos)
2019-01-22 14:13:26 +00:00
realLine = line;
else
realLine = line.substr(0, comment);
// blank or commented line?
if (realLine.size() == 0)
2019-01-22 14:13:26 +00:00
continue;
// find delimiters
auto sectOpenPos = realLine.find_first_of('[');
auto sectClosPos = realLine.find_first_of(']');
auto kvDelim = realLine.find_first_of('=');
if (sectOpenPos != std::string_view::npos && sectClosPos != std::string_view::npos
&& kvDelim == std::string_view::npos)
2019-01-22 14:13:26 +00:00
{
// section header
// clamp whitespaces
++sectOpenPos;
while (whitespace(realLine[sectOpenPos]) && sectOpenPos != sectClosPos)
2019-01-22 14:13:26 +00:00
++sectOpenPos;
--sectClosPos;
while (whitespace(realLine[sectClosPos]) && sectClosPos != sectOpenPos)
2019-01-22 14:13:26 +00:00
--sectClosPos;
// set section name
sectName = realLine.substr(sectOpenPos, sectClosPos);
}
else if (kvDelim != std::string_view::npos)
2019-01-22 14:13:26 +00:00
{
// key value pair
std::string_view::size_type k_start = 0;
std::string_view::size_type k_end = kvDelim;
std::string_view::size_type v_start = kvDelim + 1;
std::string_view::size_type v_end = realLine.size() - 1;
2019-01-22 14:13:26 +00:00
// clamp whitespaces
while (whitespace(realLine[k_start]) && k_start != kvDelim)
2019-01-22 14:13:26 +00:00
++k_start;
while (whitespace(realLine[k_end - 1]) && k_end != k_start)
2019-01-22 14:13:26 +00:00
--k_end;
while (whitespace(realLine[v_start]) && v_start != v_end)
2019-01-22 14:13:26 +00:00
++v_start;
while (whitespace(realLine[v_end]))
2019-01-22 14:13:26 +00:00
--v_end;
// sect.k = v
std::string_view k = realLine.substr(k_start, k_end - k_start);
std::string_view v = realLine.substr(v_start, 1 + (v_end - v_start));
if (k.size() == 0 || v.size() == 0)
{
LogError(m_FileName, " invalid line (", lineno, "): '", line, "'");
return false;
}
SectionValues_t& sect = m_Config[str(sectName)];
LogDebug(m_FileName, ": ", sectName, ".", k, "=", v);
2020-02-25 17:33:39 +00:00
sect.emplace(str(k), str(v)); // str()'s here for gcc 5 compat
2019-01-22 14:13:26 +00:00
}
else // malformed?
{
LogError(m_FileName, " invalid line (", lineno, "): '", line, "'");
2019-01-22 14:13:26 +00:00
return false;
}
2019-01-22 14:13:26 +00:00
}
return true;
}
void
ConfigParser::IterAll(std::function<void(std::string_view, const SectionValues_t&)> visit)
2019-01-22 14:13:26 +00:00
{
for (const auto& item : m_Config)
2019-01-22 14:13:26 +00:00
visit(item.first, item.second);
}
bool
ConfigParser::VisitSection(
const char* name, std::function<bool(const SectionValues_t& sect)> visit) const
2019-01-22 14:13:26 +00:00
{
// m_Config is effectively:
// unordered_map< string, unordered_multimap< string, string >>
// in human terms: a map of of sections
// where a section is a multimap of k:v pairs
2019-01-22 14:13:26 +00:00
auto itr = m_Config.find(name);
if (itr == m_Config.end())
2019-01-22 14:13:26 +00:00
return false;
return visit(itr->second);
}
} // namespace llarp