2019-07-02 21:28:28 +00:00
|
|
|
#include <config/ini.hpp>
|
2019-09-01 12:10:49 +00:00
|
|
|
|
|
|
|
#include <util/logging/logger.hpp>
|
2019-07-02 21:28:28 +00:00
|
|
|
|
2019-07-16 22:37:41 +00:00
|
|
|
#include <cctype>
|
2019-01-22 14:13:26 +00:00
|
|
|
#include <fstream>
|
|
|
|
#include <list>
|
|
|
|
#include <iostream>
|
|
|
|
|
|
|
|
namespace llarp
|
|
|
|
{
|
|
|
|
bool
|
2019-07-02 21:28:28 +00:00
|
|
|
ConfigParser::LoadFile(string_view fname)
|
2019-01-22 14:13:26 +00:00
|
|
|
{
|
2019-07-02 21:28:28 +00:00
|
|
|
std::string name{fname};
|
2019-01-22 14:13:26 +00:00
|
|
|
{
|
2019-07-02 21:28:28 +00:00
|
|
|
std::ifstream f(name, std::ios::in | std::ios::binary);
|
2019-01-22 14:13:26 +00:00
|
|
|
if(!f.is_open())
|
|
|
|
return false;
|
|
|
|
f.seekg(0, std::ios::end);
|
|
|
|
m_Data.resize(f.tellg());
|
|
|
|
f.seekg(0, std::ios::beg);
|
|
|
|
if(m_Data.size() == 0)
|
|
|
|
return false;
|
|
|
|
f.read(m_Data.data(), m_Data.size());
|
|
|
|
}
|
2019-07-02 21:28:28 +00:00
|
|
|
m_FileName = name;
|
2019-01-22 14:13:26 +00:00
|
|
|
return Parse();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2019-07-17 08:48:13 +00:00
|
|
|
ConfigParser::LoadFromStr(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());
|
2019-05-03 13:39:25 +00:00
|
|
|
m_FileName = "<anonymous string>";
|
2019-01-22 14:13:26 +00:00
|
|
|
return Parse();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ConfigParser::Clear()
|
|
|
|
{
|
|
|
|
m_Config.clear();
|
|
|
|
m_Data.clear();
|
|
|
|
}
|
|
|
|
|
2019-01-22 17:24:19 +00:00
|
|
|
static bool
|
2019-01-22 15:16:35 +00:00
|
|
|
whitespace(char ch)
|
|
|
|
{
|
2019-01-22 17:24:19 +00:00
|
|
|
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()
|
|
|
|
{
|
2020-02-23 02:23:19 +00:00
|
|
|
std::list< string_view > lines;
|
2019-01-22 14:13:26 +00:00
|
|
|
{
|
|
|
|
auto itr = m_Data.begin();
|
|
|
|
// split into lines
|
|
|
|
while(itr != m_Data.end())
|
|
|
|
{
|
|
|
|
auto beg = itr;
|
|
|
|
while(itr != m_Data.end() && *itr != '\n' && *itr != '\r')
|
|
|
|
++itr;
|
2019-01-22 15:16:35 +00:00
|
|
|
lines.emplace_back(std::addressof(*beg), std::distance(beg, itr));
|
2019-01-22 14:13:26 +00:00
|
|
|
if(itr == m_Data.end())
|
|
|
|
break;
|
|
|
|
++itr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2020-02-23 02:23:19 +00:00
|
|
|
string_view sectName;
|
2019-05-03 13:39:25 +00:00
|
|
|
size_t lineno = 0;
|
2019-01-22 14:13:26 +00:00
|
|
|
for(const auto& line : lines)
|
|
|
|
{
|
2019-05-05 13:51:48 +00:00
|
|
|
lineno++;
|
2020-02-23 02:23:19 +00:00
|
|
|
string_view realLine;
|
2019-01-22 14:13:26 +00:00
|
|
|
auto comment = line.find_first_of(';');
|
2020-02-23 02:23:19 +00:00
|
|
|
if(comment == string_view::npos)
|
2019-01-22 14:13:26 +00:00
|
|
|
comment = line.find_first_of('#');
|
2020-02-23 02:23:19 +00:00
|
|
|
if(comment == 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)
|
|
|
|
continue;
|
|
|
|
// find delimiters
|
|
|
|
auto sectOpenPos = realLine.find_first_of('[');
|
|
|
|
auto sectClosPos = realLine.find_first_of(']');
|
|
|
|
auto kvDelim = realLine.find_first_of('=');
|
2020-02-23 02:23:19 +00:00
|
|
|
if(sectOpenPos != string_view::npos && sectClosPos != string_view::npos
|
|
|
|
&& kvDelim == string_view::npos)
|
2019-01-22 14:13:26 +00:00
|
|
|
{
|
|
|
|
// section header
|
|
|
|
|
|
|
|
// clamp whitespaces
|
|
|
|
++sectOpenPos;
|
2019-01-22 15:16:35 +00:00
|
|
|
while(whitespace(realLine[sectOpenPos]) && sectOpenPos != sectClosPos)
|
2019-01-22 14:13:26 +00:00
|
|
|
++sectOpenPos;
|
|
|
|
--sectClosPos;
|
2019-01-22 15:16:35 +00:00
|
|
|
while(whitespace(realLine[sectClosPos]) && sectClosPos != sectOpenPos)
|
2019-01-22 14:13:26 +00:00
|
|
|
--sectClosPos;
|
|
|
|
// set section name
|
|
|
|
sectName = realLine.substr(sectOpenPos, sectClosPos);
|
|
|
|
}
|
2020-02-23 02:23:19 +00:00
|
|
|
else if(kvDelim != string_view::npos)
|
2019-01-22 14:13:26 +00:00
|
|
|
{
|
|
|
|
// key value pair
|
2020-02-23 02:23:19 +00:00
|
|
|
string_view::size_type k_start = 0;
|
|
|
|
string_view::size_type k_end = kvDelim;
|
|
|
|
string_view::size_type v_start = kvDelim + 1;
|
|
|
|
string_view::size_type v_end = realLine.size() - 1;
|
2019-01-22 14:13:26 +00:00
|
|
|
// clamp whitespaces
|
2019-01-22 15:16:35 +00:00
|
|
|
while(whitespace(realLine[k_start]) && k_start != kvDelim)
|
2019-01-22 14:13:26 +00:00
|
|
|
++k_start;
|
2019-02-07 14:35:02 +00:00
|
|
|
while(whitespace(realLine[k_end - 1]) && k_end != k_start)
|
2019-01-22 14:13:26 +00:00
|
|
|
--k_end;
|
2019-01-22 15:16:35 +00:00
|
|
|
while(whitespace(realLine[v_start]) && v_start != v_end)
|
2019-01-22 14:13:26 +00:00
|
|
|
++v_start;
|
2019-01-22 15:16:35 +00:00
|
|
|
while(whitespace(realLine[v_end]))
|
2019-01-22 14:13:26 +00:00
|
|
|
--v_end;
|
|
|
|
|
|
|
|
// sect.k = v
|
2020-02-23 02:23:19 +00:00
|
|
|
string_view k = realLine.substr(k_start, k_end - k_start);
|
|
|
|
string_view v = realLine.substr(v_start, 1 + (v_end - v_start));
|
2019-05-03 13:39:25 +00:00
|
|
|
if(k.size() == 0 || v.size() == 0)
|
|
|
|
{
|
2019-05-05 13:51:48 +00:00
|
|
|
LogError(m_FileName, " invalid line (", lineno, "): '", line, "'");
|
2019-05-03 13:39:25 +00:00
|
|
|
return false;
|
|
|
|
}
|
2020-02-25 15:48:16 +00:00
|
|
|
Section_t& sect = m_Config[str(sectName)];
|
2019-07-08 15:26:06 +00:00
|
|
|
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?
|
2019-05-03 13:39:25 +00:00
|
|
|
{
|
2019-05-05 13:51:48 +00:00
|
|
|
LogError(m_FileName, " invalid line (", lineno, "): '", line, "'");
|
2019-01-22 14:13:26 +00:00
|
|
|
return false;
|
2019-05-03 13:39:25 +00:00
|
|
|
}
|
2019-01-22 14:13:26 +00:00
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ConfigParser::IterAll(
|
2020-02-23 02:23:19 +00:00
|
|
|
std::function< void(string_view, const Section_t&) > visit)
|
2019-01-22 14:13:26 +00:00
|
|
|
{
|
|
|
|
for(const auto& item : m_Config)
|
|
|
|
visit(item.first, item.second);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ConfigParser::VisitSection(
|
|
|
|
const char* name,
|
|
|
|
std::function< bool(const Section_t& sect) > visit) const
|
|
|
|
{
|
|
|
|
auto itr = m_Config.find(name);
|
|
|
|
if(itr == m_Config.end())
|
|
|
|
return false;
|
|
|
|
return visit(itr->second);
|
|
|
|
}
|
|
|
|
} // namespace llarp
|