Added "boost-extras" ini_file parser 1.0
This commit is contained in:
Executable
+309
@@ -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
|
||||
Executable
+185
@@ -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
|
||||
Reference in New Issue
Block a user