Added "boost-extras" ini_file parser 1.0

This commit is contained in:
2015-12-30 22:44:21 +01:00
parent 1ae6ba5b12
commit bfa3d3e992
2 changed files with 494 additions and 0 deletions
+309
View File
@@ -0,0 +1,309 @@
//
// Copyright (c) 2006 Alexis Wilke
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Find documentation on the home website:
//
// http://boost-extras.sourceforge.net/
// http://boost-extras.sourceforge.net/ini_file/ini_file.html
//
#include "ini_file.hpp"
#include <iostream>
namespace ini_file
{
const param param_map::m_empty("");
const section section_map::m_empty("");
std::istream& operator >> (std::istream& in, section_map& _section_map)
{
boost::shared_ptr<section> sec;
boost::shared_ptr<param> par;
std::string result, comment, name;
char c, quote;
const char *s, *e;
int line, i;
line = 0;
while(!in.eof() && !!in) {
++line;
getline(in, result);
//std::cout << "Line = <<" << result << ">>" << std::endl;
if(result.size() == 0) continue;
switch(c = result[0]) {
case ';':
// comment
if(comment.size() > 0) {
comment += "\n";
}
s = result.c_str() + 1;
while(isspace(*s)) {
++s;
}
comment += s;
break;
case '[':
// section
s = result.c_str() + 1;
e = result.c_str() + result.size();
while(s < e && isspace(s[0])) {
++s;
}
while(e > s && isspace(e[-1])) {
--e;
}
if(e[-1] != ']') {
// name must end with ']' + optional spaces
throw ini_exceptions::invalid_section_name();
}
--e;
while(e > s && isspace(e[-1])) {
--e;
}
if(e == s) {
// name mustn't be empty
throw ini_exceptions::invalid_section_name();
}
// valid section name, create section
sec.reset(new section(result.substr(s - result.c_str(), e - s)));
sec->set_comment(comment);
comment.clear();
_section_map.insert(sec);
break;
default:
// make sure the variable starts with a letter or _
// (there is no spec. for that, but it feels sensical;
// should that apply to section names?)
if((c >= 'a' || c <= 'z')
&& (c >= 'A' || c <= 'Z')
&& c == '_') {
if(isspace(c)) {
// note the loop does not test 'result[0]'
// since we just checked it (it's in 'c')
i = result.size() - 1;
while(i > 0 && isspace(result[i])) {
--i;
}
if(i == 0) {
// empty line with just spaces
continue;
}
}
// unsure what this is
throw ini_exceptions::invalid_param_name();
}
if(!sec) {
// variables before a section is not valid
throw ini_exceptions::param_without_section();
}
s = result.c_str();
e = s + 1;
while(!isspace(*e) && *e != '=') {
++e;
}
// This case cannot happen since we start with e = s + 1.
//if(e == s) {
// // empty variable names are not acceptable
// throw ini_exceptions::invalid_param_name();
//}
par.reset(new param(result.substr(0, e - s)));
while(isspace(*e)) {
++e;
}
if(*e != '=') {
// variable names must be followed by '='
throw ini_exceptions::invalid_parameter();
}
++e;
while(isspace(*e)) {
++e;
}
quote = *e;
if(quote == '"' || quote == '\'') {
// quoted value
++e;
s = e;
while(*e != quote && *e != '\0') {
// allow escaping, but keep the backslashes
// TODO: which is wrong!
if(*e == '\\' && e[1] == quote) {
++e;
}
++e;
}
if(*e != quote) {
throw ini_exceptions::invalid_quotation();
}
// warning: we ignore what follows
}
else {
s = e;
e = result.c_str() + result.size();
while(e > s && isspace(e[-1])) {
--e;
}
}
par->set_value(result.substr(s - result.c_str(), e - s));
par->set_comment(comment);
comment.clear();
sec->insert(par);
break;
}
}
return in;
}
namespace details
{
std::ostream& operator << (std::ostream& out, const name& _name)
{
return out << _name.get_name();
}
std::ostream& operator << (std::ostream& out, const comment& _comment)
{
// TODO:
// we would need a filter for comments, but I'm not too sure we can
// do that (i.e. add a filter, write the comment, remove the filter)
bool new_line = true;
std::string::const_iterator i;
std::string::const_iterator end = _comment.get_comment().end();
for(i = _comment.get_comment().begin(); i != end; ++i) {
if(*i == '\r' || *i == '\n') {
out << *i;
new_line = true;
}
else {
if(new_line) {
out << "; ";
}
new_line = false;
out << *i;
}
}
if(!new_line) {
out << std::endl;
}
return out;
}
}
std::ostream& operator << (std::ostream& out, const param& _param)
{
if(_param.get_name().size() == 0) {
if(_param.get_value().size() == 0) {
return out;
}
throw ini_exceptions::param_name_missing();
}
// output <comment> and then '<name>='
out << static_cast<const details::comment&>(_param)
<< static_cast<const details::name&>(_param)
<< '=';
// output <value>, check whether we need quotation
const std::string& value = _param.get_value();
const char *s = value.c_str();
const char *e = s + value.size();
if(*s == '"' || *s == '\'' || isspace(*s) || (e > s && isspace(e[-1]))) {
// need quotation to not lose any data
char quote = '\0';
while(*s != '\0') {
if(*s == '\'') {
quote = '"';
break;
}
if(*s == '"') {
quote = '\'';
break;
}
++s;
}
s = value.c_str();
out << quote;
while(*s != '\0') {
if(*s == quote) {
out << "\\";
}
out << *s;
++s;
}
out << quote;
}
else {
// no quotation necessary
out << value;
}
out << std::endl;
}
std::ostream& operator << (std::ostream& out, const param_map& _param_map)
{
param_map::const_iterator i = _param_map.begin();
param_map::const_iterator end = _param_map.end();
while(i != end) {
out << *(*i).second;
++i;
}
return out;
}
std::ostream& operator << (std::ostream& out, const section& _section)
{
if(_section.get_name().size() == 0) {
if(_section.size() == 0) {
return out;
}
throw ini_exceptions::section_name_missing();
}
return out
<< static_cast<const details::comment&>(_section)
<< '[' << static_cast<const details::name&>(_section) << ']' << std::endl
<< static_cast<const param_map&>(_section);
}
std::ostream& operator << (std::ostream& out, const section_map& _section_map)
{
section_map::const_iterator i = _section_map.begin();
section_map::const_iterator end = _section_map.end();
while(i != end) {
out << *(*i).second;
out << std::endl;
++i;
}
return out;
}
} // namespace ini_file
// vim: ts=4
+185
View File
@@ -0,0 +1,185 @@
//
// Copyright (c) 2006 Alexis Wilke
//
// Boost Software License - Version 1.0 - August 17th, 2003
//
// Permission is hereby granted, free of charge, to any person or organization
// obtaining a copy of the software and accompanying documentation covered by
// this license (the "Software") to use, reproduce, display, distribute,
// execute, and transmit the Software, and to prepare derivative works of the
// Software, and to permit third-parties to whom the Software is furnished to
// do so, all subject to the following:
//
// The copyright notices in the Software and this entire statement, including
// the above license grant, this restriction and the following disclaimer,
// must be included in all copies of the Software, in whole or in part, and
// all derivative works of the Software, unless such copies or derivative
// works are solely in the form of machine-executable object code generated by
// a source language processor.
//
// 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, TITLE AND NON-INFRINGEMENT. IN NO EVENT
// SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
// FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
// ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
//
// Find documentation on the home website:
//
// http://boost-extras.sourceforge.net/
// http://boost-extras.sourceforge.net/ini_file/ini_file.html
//
#ifndef BOOST_EXTRAS_INI_FILE
#define BOOST_EXTRAS_INI_FILE 1
#include <boost/shared_ptr.hpp>
#include <exception>
#include <string>
#include <map>
#include <iostream>
namespace ini_file
{
namespace ini_exceptions
{
class ini_file_exception : std::exception {};
class section_name_missing : ini_file_exception {};
class invalid_section_name : ini_file_exception {};
class param_name_missing : ini_file_exception {};
class invalid_param_name : ini_file_exception {};
class invalid_parameter : ini_file_exception {};
class param_without_section : ini_file_exception {};
class invalid_quotation : ini_file_exception {};
} // namespace ini_exceptions
namespace details
{
struct name
{
name(const std::string& _name) : m_name(_name) {}
virtual ~name() {}
//void set_name(const std::string& _name) { m_name = _name; }
const std::string& get_name() const { return m_name; }
private:
const std::string m_name;
};
extern std::ostream& operator << (std::ostream& out, const name& _name);
struct comment
{
virtual ~comment() {}
void set_comment(const std::string& _comment) { m_comment = _comment; }
const std::string& get_comment() const { return m_comment; }
private:
std::string m_comment;
};
extern std::ostream& operator << (std::ostream& out, const comment& _comment);
} // namespace details
struct param : details::name, details::comment
{
param(const std::string& _name) : details::name(_name) {}
void set_value(const std::string& _value) { m_value = _value; }
const std::string& get_value() const { return m_value; }
param& operator = (const std::string& _value) { set_value(_value); return *this; }
operator const std::string& () const { return m_value; }
private:
std::string m_value;
};
namespace details
{
typedef std::map<std::string, boost::shared_ptr<param> > param_map_t;
}
struct param_map : details::param_map_t
{
void insert(boost::shared_ptr<param> _p)
{
if(_p) {
details::param_map_t::insert(details::param_map_t::value_type(_p->get_name(), _p));
}
}
param& operator [] (const std::string& _name)
{
details::param_map_t::iterator i = details::param_map_t::find(_name);
if(i == end()) {
boost::shared_ptr<param> p(new param(_name));
insert(p);
return *p;
}
return *i->second;
}
const param& operator [] (const std::string& _name) const
{
details::param_map_t::const_iterator i = details::param_map_t::find(_name);
if(i == end()) return m_empty;
return *i->second;
}
private:
static const param m_empty;
};
struct section : details::name, details::comment, param_map
{
section(const std::string& _name) : details::name(_name) {}
};
namespace details
{
typedef std::map<std::string, boost::shared_ptr<section> > section_map_t;
}
struct section_map : details::section_map_t
{
void insert(boost::shared_ptr<section> _s)
{
if(_s) {
details::section_map_t::insert(details::section_map_t::value_type(_s->get_name(), _s));
}
}
const section& operator [] (const std::string& _name) const
{
details::section_map_t::const_iterator i = details::section_map_t::find(_name);
if(i == end()) return m_empty;
return *i->second;
}
section& operator [] (const std::string& _name)
{
details::section_map_t::iterator i = details::section_map_t::find(_name);
if(i == end()) {
boost::shared_ptr<section> s(new section(_name));
insert(s);
return *s;
}
return *i->second;
}
private:
static const section m_empty;
};
extern std::istream& operator >> (std::istream& in, section_map& _section_map);
extern std::ostream& operator << (std::ostream& out, const param& _param);
extern std::ostream& operator << (std::ostream& out, const section& _section);
extern std::ostream& operator << (std::ostream& out, const param_map& _param_map);
extern std::ostream& operator << (std::ostream& out, const section_map& _section_map);
} // namespace ini_file
#endif // #ifdef BOOST_EXTRAS_INI_FILE
// vim: ts=4