diff --git a/include/ini_file/ini_file.cpp b/include/ini_file/ini_file.cpp new file mode 100755 index 0000000..5380b43 --- /dev/null +++ b/include/ini_file/ini_file.cpp @@ -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 + +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
sec; + boost::shared_ptr 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 and then '=' + out << static_cast(_param) + << static_cast(_param) + << '='; + + // output , 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(_section) + << '[' << static_cast(_section) << ']' << std::endl + << static_cast(_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 diff --git a/include/ini_file/ini_file.hpp b/include/ini_file/ini_file.hpp new file mode 100755 index 0000000..15ff4a0 --- /dev/null +++ b/include/ini_file/ini_file.hpp @@ -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 +#include +#include +#include +#include + +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 > param_map_t; +} +struct param_map : details::param_map_t +{ + void insert(boost::shared_ptr _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 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 > section_map_t; +} +struct section_map : details::section_map_t +{ + void insert(boost::shared_ptr
_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
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