Archived
1
0
This repository has been archived on 2023-08-12. You can view files and clone it, but cannot push or open issues or pull requests.
nntpchan/contrib/backends/nntpchan-daemon/daemon/ini.hpp

198 lines
5.3 KiB
C++
Raw Normal View History

2017-10-17 19:29:56 +05:00
/**
2016-10-15 18:12:01 +05:00
* The MIT License (MIT)
* Copyright (c) <2015> <carriez.md@gmail.com>
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to
* deal in the Software without restriction, including without limitation the
* rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
* sell copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
2017-10-17 19:29:56 +05:00
* The above copyright notice and this permission notice shall be included in
2016-10-15 18:12:01 +05:00
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
2017-10-17 19:29:56 +05:00
*
2016-10-15 18:12:01 +05:00
*/
2017-10-17 19:29:56 +05:00
2016-10-15 18:12:01 +05:00
#ifndef INI_HPP
#define INI_HPP
#include <cassert>
2017-10-17 19:29:56 +05:00
#include <cstring>
#include <fstream>
#include <iostream>
2016-10-15 18:12:01 +05:00
#include <list>
2017-10-17 19:29:56 +05:00
#include <map>
2016-10-15 18:12:01 +05:00
#include <stdexcept>
#include <string>
2017-10-17 19:29:56 +05:00
namespace INI
{
2016-10-15 18:12:01 +05:00
2017-10-17 19:29:56 +05:00
struct Level
2016-10-15 18:12:01 +05:00
{
Level() : parent(NULL), depth(0) {}
2017-10-17 19:29:56 +05:00
Level(Level *p) : parent(p), depth(0) {}
2016-10-15 18:12:01 +05:00
typedef std::map<std::string, std::string> value_map_t;
typedef std::map<std::string, Level> section_map_t;
typedef std::list<value_map_t::const_iterator> values_t;
typedef std::list<section_map_t::const_iterator> sections_t;
value_map_t values;
section_map_t sections;
values_t ordered_values; // original order in the ini file
sections_t ordered_sections;
2017-10-17 19:29:56 +05:00
Level *parent;
2016-10-15 18:12:01 +05:00
size_t depth;
2017-10-17 19:29:56 +05:00
const std::string &operator[](const std::string &name) { return values[name]; }
Level &operator()(const std::string &name) { return sections[name]; }
2016-10-15 18:12:01 +05:00
};
class Parser
{
public:
2017-10-17 19:29:56 +05:00
Parser(const char *fn);
Parser(std::istream &f) : f_(&f), ln_(0) { parse(top_); }
Level &top() { return top_; }
void dump(std::ostream &s) { dump(s, top(), ""); }
2016-10-15 18:12:01 +05:00
private:
2017-10-17 19:29:56 +05:00
void dump(std::ostream &s, const Level &l, const std::string &sname);
void parse(Level &l);
void parseSLine(std::string &sname, size_t &depth);
void err(const char *s);
2016-10-15 18:12:01 +05:00
private:
Level top_;
std::ifstream f0_;
2017-10-17 19:29:56 +05:00
std::istream *f_;
2016-10-15 18:12:01 +05:00
std::string line_;
size_t ln_;
};
2017-10-17 19:29:56 +05:00
inline void Parser::err(const char *s)
2016-10-15 18:12:01 +05:00
{
char buf[256];
sprintf(buf, "%s on line #%ld", s, ln_);
throw std::runtime_error(buf);
}
2017-10-17 19:29:56 +05:00
inline std::string trim(const std::string &s)
2016-10-15 18:12:01 +05:00
{
char p[] = " \t\r\n";
long sp = 0;
long ep = s.length() - 1;
for (; sp <= ep; ++sp)
2017-10-17 19:29:56 +05:00
if (!strchr(p, s[sp]))
break;
2016-10-15 18:12:01 +05:00
for (; ep >= 0; --ep)
2017-10-17 19:29:56 +05:00
if (!strchr(p, s[ep]))
break;
return s.substr(sp, ep - sp + 1);
2016-10-15 18:12:01 +05:00
}
2017-10-17 19:29:56 +05:00
inline Parser::Parser(const char *fn) : f0_(fn), f_(&f0_), ln_(0)
{
if (!f0_)
2016-10-15 18:12:01 +05:00
throw std::runtime_error(std::string("failed to open file: ") + fn);
2017-10-17 19:29:56 +05:00
parse(top_);
2016-10-15 18:12:01 +05:00
}
2017-10-17 19:29:56 +05:00
inline void Parser::parseSLine(std::string &sname, size_t &depth)
2016-10-15 18:12:01 +05:00
{
depth = 0;
for (; depth < line_.length(); ++depth)
2017-10-17 19:29:56 +05:00
if (line_[depth] != '[')
break;
2016-10-15 18:12:01 +05:00
2017-10-17 19:29:56 +05:00
sname = line_.substr(depth, line_.length() - 2 * depth);
2016-10-15 18:12:01 +05:00
}
2017-10-17 19:29:56 +05:00
inline void Parser::parse(Level &l)
2016-10-15 18:12:01 +05:00
{
2017-10-17 19:29:56 +05:00
while (std::getline(*f_, line_))
{
2016-10-15 18:12:01 +05:00
++ln_;
2017-10-17 19:29:56 +05:00
if (line_[0] == '#' || line_[0] == ';')
continue;
2016-10-15 18:12:01 +05:00
line_ = trim(line_);
2017-10-17 19:29:56 +05:00
if (line_.empty())
continue;
if (line_[0] == '[')
{
2016-10-15 18:12:01 +05:00
size_t depth;
std::string sname;
parseSLine(sname, depth);
2017-10-17 19:29:56 +05:00
Level *lp = NULL;
Level *parent = &l;
2016-10-15 18:12:01 +05:00
if (depth > l.depth + 1)
err("section with wrong depth");
2017-10-17 19:29:56 +05:00
if (l.depth == depth - 1)
2016-10-15 18:12:01 +05:00
lp = &l.sections[sname];
2017-10-17 19:29:56 +05:00
else
{
2016-10-15 18:12:01 +05:00
lp = l.parent;
size_t n = l.depth - depth;
2017-10-17 19:29:56 +05:00
for (size_t i = 0; i < n; ++i)
lp = lp->parent;
2016-10-15 18:12:01 +05:00
parent = lp;
lp = &lp->sections[sname];
}
if (lp->depth != 0)
err("duplicate section name on the same level");
2017-10-17 19:29:56 +05:00
if (!lp->parent)
{
2016-10-15 18:12:01 +05:00
lp->depth = depth;
lp->parent = parent;
}
parent->ordered_sections.push_back(parent->sections.find(sname));
parse(*lp);
2017-10-17 19:29:56 +05:00
}
else
{
2016-10-15 18:12:01 +05:00
size_t n = line_.find('=');
if (n == std::string::npos)
err("no '=' found");
2017-10-17 19:29:56 +05:00
std::pair<Level::value_map_t::const_iterator, bool> res =
l.values.insert(std::make_pair(trim(line_.substr(0, n)), trim(line_.substr(n + 1, line_.length() - n - 1))));
2016-10-15 18:12:01 +05:00
if (!res.second)
err("duplicated key found");
l.ordered_values.push_back(res.first);
}
}
}
2017-10-17 19:29:56 +05:00
inline void Parser::dump(std::ostream &s, const Level &l, const std::string &sname)
2016-10-15 18:12:01 +05:00
{
2017-10-17 19:29:56 +05:00
if (!sname.empty())
s << '\n';
for (size_t i = 0; i < l.depth; ++i)
s << '[';
if (!sname.empty())
s << sname;
for (size_t i = 0; i < l.depth; ++i)
s << ']';
if (!sname.empty())
s << std::endl;
2016-10-15 18:12:01 +05:00
for (Level::values_t::const_iterator it = l.ordered_values.begin(); it != l.ordered_values.end(); ++it)
s << (*it)->first << '=' << (*it)->second << std::endl;
2017-10-17 19:29:56 +05:00
for (Level::sections_t::const_iterator it = l.ordered_sections.begin(); it != l.ordered_sections.end(); ++it)
{
assert((*it)->second.depth == l.depth + 1);
2016-10-15 18:12:01 +05:00
dump(s, (*it)->second, (*it)->first);
}
}
}
#endif // INI_HPP