C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
194 lines
7.6 KiB
194 lines
7.6 KiB
20 years ago
|
/** @file
|
||
|
|
||
|
$Id$
|
||
20 years ago
|
|
||
20 years ago
|
$Date$
|
||
|
$Author$
|
||
|
|
||
|
@copy © Marc Wäckerlin
|
||
|
@license LGPL, see file <a href="license.html">COPYING</a>
|
||
|
|
||
|
$Log$
|
||
19 years ago
|
Revision 1.3 2005/11/29 12:39:42 marc
|
||
|
make it compilable with gcc 4.0.2 and newer doxygen
|
||
|
|
||
20 years ago
|
Revision 1.2 2005/01/28 07:49:32 marc
|
||
13 years ago
|
Save configuration using file.hxx
|
||
20 years ago
|
|
||
20 years ago
|
Revision 1.1 2005/01/07 00:31:38 marc
|
||
|
initial version
|
||
|
|
||
|
|
||
|
1 2 3 4 5 6 7 8
|
||
|
5678901234567890123456789012345678901234567890123456789012345678901234567890
|
||
|
*/
|
||
|
|
||
13 years ago
|
#include <mrw/configfile.hxx>
|
||
|
#include <mrw/exception.hxx>
|
||
|
#include <mrw/string.hxx>
|
||
|
#include <mrw/file.hxx>
|
||
20 years ago
|
#include <fstream>
|
||
|
|
||
|
mrw::ConfigFileReader::Value&
|
||
20 years ago
|
mrw::ConfigFileReader::operator()(const std::string& section,
|
||
|
const std::string& name,
|
||
|
const std::string& default_)
|
||
20 years ago
|
throw(std::bad_exception) {
|
||
|
_values[section].insert(std::make_pair(name, Value(default_)));
|
||
|
return _values[section].find(name)->second;
|
||
|
}
|
||
|
|
||
|
mrw::ConfigFileReader& mrw::ConfigFileReader::load(const std::string& filename)
|
||
|
throw(std::exception) {
|
||
|
_filename = filename;
|
||
|
return reload();
|
||
|
}
|
||
|
|
||
|
mrw::ConfigFileReader& mrw::ConfigFileReader::reload() throw(std::exception) {
|
||
20 years ago
|
return parse(mrw::File::read(_filename));
|
||
20 years ago
|
}
|
||
|
|
||
|
mrw::ConfigFileReader& mrw::ConfigFileReader::parse(const std::string& file)
|
||
|
throw(std::exception) {
|
||
|
_values.erase(_values.begin(), _values.end());
|
||
|
std::string section;
|
||
|
for (std::string::size_type pos(0);
|
||
|
(pos=file.find_first_of("[=#", pos))!=std::string::npos; ++pos) {
|
||
|
switch (file[pos]) {
|
||
|
case '[': _sections[section]=pos; section=parseSection(file, pos); break;
|
||
|
case '=': _values[section].insert(parseValue(file, pos)); break;
|
||
|
case '#': parseComment(file, pos); break;
|
||
|
};
|
||
|
}
|
||
|
_sections[section]=file.size();
|
||
|
return *this;
|
||
|
}
|
||
|
|
||
|
std::string mrw::ConfigFileReader::parseSection(const std::string& file,
|
||
|
std::string::size_type& pos)
|
||
|
const throw(std::exception) {
|
||
|
std::string::size_type start(pos);
|
||
|
if ((pos=file.find(']', pos))==std::string::npos)
|
||
|
throw mrw::invalid_argument
|
||
|
("section not terminated in file '"+_filename+"'\n"
|
||
|
"environment is: "+file.substr(start-10>0?start-10:0));
|
||
|
return file.substr(start+1, pos-start-1);
|
||
|
}
|
||
|
|
||
|
mrw::ConfigFileReader::Values::mapped_type::value_type
|
||
|
mrw::ConfigFileReader::parseValue(const std::string& file,
|
||
|
std::string::size_type& pos)
|
||
|
const throw(std::exception) {
|
||
|
// find the begin of the variable name
|
||
|
std::string::size_type startName(file.rfind('\n', pos));
|
||
|
if (startName==std::string::npos) startName=0;
|
||
|
startName=file.find_first_not_of("\n\t ", startName);
|
||
|
if (startName==pos)
|
||
|
throw mrw::invalid_argument
|
||
|
("empty variable name in file '"+_filename+"'\n"
|
||
|
"environment is: "+file.substr(startName-10>0?startName-10:0, pos+10));
|
||
|
// find the end of the variable name
|
||
|
std::string::size_type endName(file.find_last_not_of("\n\t ", pos-1)+1);
|
||
|
// find the begin of the variable contents
|
||
|
std::string::size_type startVal(file.find_first_not_of("\n\t ", ++pos));
|
||
|
if (startVal==std::string::npos)
|
||
|
return std::make_pair // end of file, empty value
|
||
|
(file.substr(startName, endName-startName), Value("", pos, pos));
|
||
|
// find the end of the variable contents
|
||
|
std::string::size_type realStart(startVal); // doesn't cut the first quote
|
||
|
std::string::size_type endVal(file[startVal]=='"' ? // quoted with "
|
||
|
file.find('"', ++startVal) :
|
||
|
file[startVal]=='\'' ? // quoted with '
|
||
|
file.find('\'', ++startVal) :
|
||
|
file.find_first_of("[=#", startVal)); // normal
|
||
|
if (endVal!=std::string::npos && file[endVal]=='=')
|
||
|
endVal=file.rfind('\n', endVal); // jump before following variable name
|
||
|
endVal = file.find_last_not_of("\n\t ", // remove trailing white spaces
|
||
|
endVal!=std::string::npos?endVal-1:endVal)+1;
|
||
|
std::string::size_type realEnd(endVal!=std::string::npos && // quotes?
|
||
|
(file[realStart]=='"' && file[endVal]=='"' ||
|
||
|
file[realStart]=='\'' && file[endVal]=='\'')
|
||
|
? endVal+1 : endVal);
|
||
|
if (endVal<=startVal)
|
||
|
return std::make_pair // empty value
|
||
|
(file.substr(startName, endName-startName), Value("", pos, pos));
|
||
|
return std::make_pair // normal case
|
||
|
(file.substr(startName, endName-startName),
|
||
|
Value(file.substr(startVal, endVal-startVal), realStart, pos=realEnd));
|
||
|
}
|
||
|
|
||
|
std::string mrw::ConfigFileReader::parseComment(const std::string& file,
|
||
|
std::string::size_type& pos)
|
||
|
const throw(std::bad_exception) {
|
||
|
std::string::size_type start(pos);
|
||
|
pos = file.find('\n', pos);
|
||
|
return file.substr(start, pos-start);
|
||
|
}
|
||
|
|
||
|
// GNU g++ prior to 3.4 does not implement covariant returns
|
||
|
#if __GNUC__ == 3 && __GNUC_MINOR__ < 4
|
||
|
mrw::ConfigFileReader&
|
||
|
#else
|
||
|
mrw::ConfigFileWriter&
|
||
|
#endif
|
||
|
mrw::ConfigFileWriter::reload() throw(std::exception) {
|
||
19 years ago
|
#if __GNUC__ == 3 && __GNUC_MINOR__ < 4
|
||
20 years ago
|
return parse(_file=mrw::File::read(_filename));
|
||
19 years ago
|
#else
|
||
|
return dynamic_cast<mrw::ConfigFileWriter&>
|
||
|
(parse(_file=mrw::File::read(_filename)));
|
||
|
#endif
|
||
20 years ago
|
}
|
||
|
|
||
|
mrw::ConfigFileWriter& mrw::ConfigFileWriter::save() throw(std::exception) {
|
||
|
if (_filename=="") return *this;
|
||
|
// work in changes
|
||
|
bool changed(false);
|
||
|
for (Values::iterator sec(_values.begin()); sec!=_values.end(); ++sec)
|
||
|
for (Values::mapped_type::iterator var(sec->second.begin());
|
||
|
var!=sec->second.end(); ++var)
|
||
|
if (var->second.changed) {
|
||
|
var->second.changed = false;
|
||
|
changed = true;
|
||
|
// check if we need quoting
|
||
|
std::string value(var->second.value);
|
||
|
if (value.find_first_of("[=#")!=std::string::npos)
|
||
|
if (value.find('"')==std::string::npos)
|
||
|
value = '"'+value+'"';
|
||
|
else if (value.find('\'')==std::string::npos)
|
||
|
value = '\''+value+'\'';
|
||
|
else
|
||
|
throw mrw::invalid_argument("Configuration value is not quotable: "
|
||
|
+value);
|
||
|
// recalculate all positions
|
||
|
if (var->second.start &&
|
||
|
value.size() != var->second.end-var->second.start) {
|
||
|
int diff(value.size()-var->second.end+var->second.start);
|
||
|
for (Values::iterator sec2(_values.begin());
|
||
|
sec2!=_values.end(); ++sec2)
|
||
|
for (Values::mapped_type::iterator var2(sec2->second.begin());
|
||
|
var2!=sec2->second.end(); ++var2)
|
||
|
if (var2->second.start>var->second.end) {
|
||
|
var2->second.start += diff;
|
||
|
var2->second.end += diff;
|
||
|
}
|
||
|
for (Sections::iterator sec2(_sections.begin());
|
||
|
sec2!=_sections.end(); ++sec2)
|
||
|
if (sec2->second>=var->second.end) sec2->second += diff;
|
||
|
}
|
||
|
// set the new value
|
||
|
if (var->second.start) // simple change
|
||
|
_file.replace(var->second.start, var->second.end-var->second.start,
|
||
|
value);
|
||
|
else if (_sections.find(sec->first)!=_sections.end()) // new value
|
||
|
_file.insert(_sections[sec->first], "\n"+var->first+" = "+value
|
||
|
+(_file[_sections[sec->first]]=='\n'?"":"\n"));
|
||
|
else { // even a new section
|
||
|
_file+="\n["+sec->first+"]\n"+var->first+" = "+value;
|
||
|
_sections[sec->first] = _file.size();
|
||
|
}
|
||
|
}
|
||
20 years ago
|
if (changed) mrw::File::save(_filename, _file);
|
||
20 years ago
|
return *this;
|
||
|
}
|