// // 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