/// // Copyright (C) 2002 - 2004, Fredrik Arnerup & Rasmus Kaj, See COPYING /// #include "configfile.h" #include #include #include #include "stringutil.h" namespace Config{ // BoolVar void BoolVar::print(std::ostream &out) const { for(Bools::const_iterator i = values.begin(); i != values.end(); i++) out << (i == values.begin() ? "" : " ") << (*i ? "true" : "false"); } void BoolVar::parse(const std::string &input) { Bools tmp; std::istringstream in(input); while(in) { std::string word; in >> word; if(word == "true") tmp.push_back(true); else if(word == "false") tmp.push_back(false); else if(word.empty()) break; else throw(std::runtime_error("\"" + word + "\" is not a truth value")); } values = tmp; } // StringVar // replace " with \" static std::string escape(const std::string s) { std::string tmp; for(std::string::const_iterator i = s.begin(); i != s.end(); i++) { if(*i == '"') tmp += "\\\""; else tmp += *i; } return tmp; } // replace \" with " static std::string unescape(const std::string s) { std::string tmp; for(std::string::const_iterator i = s.begin(); i != s.end(); i++) { if(*i == '\\') { i++; if(i == s.end()) tmp += '\\'; else if(*i == '"') tmp += '"'; else tmp += "\\" + *i; } else tmp += *i; } return tmp; } void StringVar::print(std::ostream &out) const { for(Strings::const_iterator i = values.begin(); i != values.end(); i++) out << (i == values.begin() ? "" : " ") << '"' << escape(*i) << '"'; } void StringVar::parse(const std::string &input) { Strings tmp; bool quote = false; // true if we are inside a quoted string int i = 0; while(i < int(input.length())) { if(whitespace(input[i])) i++; else { if(input[i] == '"') { quote = true; i++; } int j = i; // save start pos of string while(i < int(input.length())) { if(input[i] == '"') { if(input[i - 1] == '\\') i++; else if(quote) { quote = false; break; } else { throw std::runtime_error("quotation mark is not escaped"); } } else if(!quote && whitespace(input[i])) { break; } else { i++; } } if(quote) throw std::runtime_error("unmatched quotation mark"); tmp.push_back(unescape(input.substr(j, i-j))); i++; } // No check is performed to see if there is whitespace after an // ending quotation mark. // Hence, stuff like "foo""bar" or "foo"bar is allowed. } values = tmp; } // FloatVar void FloatVar::print(std::ostream &out) const { for(Floats::const_iterator i = values.begin(); i != values.end(); i++) out << (i == values.begin() ? "" : " ") << *i; } void FloatVar::parse(const std::string &input) { Floats tmp; std::istringstream in(input); float value; while(in >> value) tmp.push_back(value); values = tmp; } // File void File::declare_var(Var *var) { vars.push_back(var); } void File::read(const std::string &filename) { int line_number = 0; std::ifstream in(filename.c_str()); if(!in) { error("Could not read " + filename); return; } while(in) { std::string line; std::getline(in, line); line_number++; line = strip_whitespace(line); // A comment start with # and can only occur on a line of its own. if(line.empty() || line[0] == '#') continue; int pos = line.find_first_of('='); if(pos >= int(line.length())) { // no equality sign found error("line " + tostr(line_number) + ": \"=\" missing"); continue; } std::string name = strip_whitespace(line.substr(0, pos)); try { Vars::iterator i; for(i = vars.begin(); i != vars.end(); i++) { if(name == (*i)->name) { (*i)->parse(line.substr(pos + 1)); break; } } if(i == vars.end() && !ignore_unknown) error("line " + tostr(line_number) + ": variable \"" + name + "\" is unknown"); } catch (const std::runtime_error &e) { error("line " + tostr(line_number) + ": " + e.what()); } } } void File::write(const std::string &filename) { std::ofstream out(filename.c_str()); if(!out) { error("Could not write to \"" + filename + '"'); return; } for(Vars::const_iterator i = vars.begin(); i != vars.end(); i++) { out << (*i)->name << " = "; (*i)->print(out); out << std::endl; } } } #ifdef TEST // test program int main() { using namespace Config; File file; BoolVar a("Pippilotta"); a.values.push_back(true); StringVar b("Rullgardina"); b.values.push_back("foobar"); FloatVar c("Krusmynta"); c.values.push_back(3.6); c.values.push_back(2.1); file.declare_var(&a); file.declare_var(&b); file.declare_var(&c); file.read("/tmp/config_test"); file.write("/tmp/config_test2"); return 0; } #endif