initial version
This commit is contained in:
		
							
								
								
									
										202
									
								
								mrw/configfile.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										202
									
								
								mrw/configfile.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,202 @@
 | 
				
			|||||||
 | 
					/** @file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Id$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Date$
 | 
				
			||||||
 | 
					    $Author$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @copy © Marc Wäckerlin
 | 
				
			||||||
 | 
					    @license LGPL, see file <a href="license.html">COPYING</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Log$
 | 
				
			||||||
 | 
					    Revision 1.1  2005/01/07 00:31:38  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         1         2         3         4         5         6         7         8
 | 
				
			||||||
 | 
					    5678901234567890123456789012345678901234567890123456789012345678901234567890
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/configfile.hpp>
 | 
				
			||||||
 | 
					#include <mrw/exception.hpp>
 | 
				
			||||||
 | 
					#include <mrw/string.hpp>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					mrw::ConfigFileReader::Value&
 | 
				
			||||||
 | 
					mrw::ConfigFileReader::operator()(const std::string& section,
 | 
				
			||||||
 | 
					                                  const std::string& name,
 | 
				
			||||||
 | 
					                                  const std::string& default_)
 | 
				
			||||||
 | 
					  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) {
 | 
				
			||||||
 | 
					  return parse(readFile());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					std::string mrw::ConfigFileReader::readFile() const throw(std::exception) {
 | 
				
			||||||
 | 
					  std::string fileContents; // declaration as first allows optimization
 | 
				
			||||||
 | 
					  std::ifstream file(_filename.c_str());
 | 
				
			||||||
 | 
					  if (!file)
 | 
				
			||||||
 | 
					    throw mrw::invalid_argument("Error file not found: '"+_filename+"'");
 | 
				
			||||||
 | 
					  file.seekg(0, std::ios::end);
 | 
				
			||||||
 | 
					  int size(file.tellg());
 | 
				
			||||||
 | 
					  fileContents.resize(size); // make buffer long enough to store all
 | 
				
			||||||
 | 
					  file.seekg(0, std::ios::beg);
 | 
				
			||||||
 | 
					  file.read(fileContents.begin().operator->(), size); // hack to get the buffer
 | 
				
			||||||
 | 
					  if (!file.good() && file.eof())
 | 
				
			||||||
 | 
					    throw mrw::invalid_argument("Error reading file: '"+_filename+"'");  
 | 
				
			||||||
 | 
					  return fileContents;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <iostream>
 | 
				
			||||||
 | 
					using namespace std;
 | 
				
			||||||
 | 
					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) {
 | 
				
			||||||
 | 
					  return parse(_file=readFile());
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					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();
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					  if (!changed) return *this;
 | 
				
			||||||
 | 
					  // save to file
 | 
				
			||||||
 | 
					  std::ofstream file(_filename.c_str());
 | 
				
			||||||
 | 
					  if (!(file<<_file))
 | 
				
			||||||
 | 
					    throw mrw::invalid_argument("Cannot write file '"+_filename+"'");
 | 
				
			||||||
 | 
					  return *this;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										362
									
								
								mrw/configfile.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										362
									
								
								mrw/configfile.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,362 @@
 | 
				
			|||||||
 | 
					/** @file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Id$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Date$
 | 
				
			||||||
 | 
					    $Author$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @copy © Marc Wäckerlin
 | 
				
			||||||
 | 
					    @license LGPL, see file <a href="license.html">COPYING</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Log$
 | 
				
			||||||
 | 
					    Revision 1.1  2005/01/07 00:31:38  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#ifndef __MRW_CONFIGFILE_HPP__
 | 
				
			||||||
 | 
					#define __MRW_CONFIGFILE_HPP__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <map>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace mrw {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** @defgroup config Configuration File Handler
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Read configuration parameters from a file.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @section configSyntax Configuration File Syntax
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configSyntaxSection Sections: [Section]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Syntax (regular expression):
 | 
				
			||||||
 | 
					      <code>\\[([^[=#]*)\\]</code>
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      A configuration file consists of none or more sections. The
 | 
				
			||||||
 | 
					      sections start with tag <code>[Section Name]</code>, where
 | 
				
			||||||
 | 
					      <code>Section Name</code> is the name of the section.
 | 
				
			||||||
 | 
					      The default section has an empty name.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configSyntaxVariables Variables: name = value
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Syntax (regular expression):
 | 
				
			||||||
 | 
					      <code>^[^[\\n\\t ]*([^[=#\\n]]+)[\\n\\t ]*=[\\n\\t ]*([^[=#]]*)[\\n\\t ]*</code>
 | 
				
			||||||
 | 
					      or
 | 
				
			||||||
 | 
					      <code>^[^[\\n\\t ]*([^[=#\\n]]+)[\\n\\t ]*=[\\n\\t ]*("[^"]]*")[\\n\\t ]*</code>
 | 
				
			||||||
 | 
					      or
 | 
				
			||||||
 | 
					      <code>^[^[\\n\\t ]*([^[=#\\n]]+)[\\n\\t ]*=[\\n\\t ]*('[^']]*')[\\n\\t ]*</code>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      In the section, there are variable definitions in the form of
 | 
				
			||||||
 | 
					      <code>name=value</code>, where <code>name</code> is the name of
 | 
				
			||||||
 | 
					      the variable and <code>value</code> is it's contents. White
 | 
				
			||||||
 | 
					      spaces at the begin or end of the name and the value are
 | 
				
			||||||
 | 
					      stripped. Whitespaces inside a name or value remain
 | 
				
			||||||
 | 
					      unchanged. Please note that a variable name starts at the begoin
 | 
				
			||||||
 | 
					      of line and ends before the equal sign, while the contents
 | 
				
			||||||
 | 
					      starts after the equal sign and ends before the next token
 | 
				
			||||||
 | 
					      starts. If you need a token inside a value, or a variable must
 | 
				
			||||||
 | 
					      start or end with white spaces, you can enclose it in either
 | 
				
			||||||
 | 
					      <code>"</code> or <code>'</code> quotes. If a value is quoted
 | 
				
			||||||
 | 
					      and the quoting is not terminated, then the contents is taken up
 | 
				
			||||||
 | 
					      to the end of file. Please note that the same quote must not
 | 
				
			||||||
 | 
					      occur inside the value. All possible tokens are: <code>[</code>,
 | 
				
			||||||
 | 
					      <code>#</code> and <code>=</code>. All other characters are not
 | 
				
			||||||
 | 
					      treated in a special way.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configSyntaxComments Comments: #
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      Comments start with <code>#</code> and end at the end of the
 | 
				
			||||||
 | 
					      line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configSyntaxSpecial Special Characters \\n, [, ], #, =, ", '
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      I have chosen a syntax that is downwards compatible with the
 | 
				
			||||||
 | 
					      common Unix configuration file syntax, but with a grammar as
 | 
				
			||||||
 | 
					      loose as possible and with as few restrictions as
 | 
				
			||||||
 | 
					      possible. Special characters have only special meanings in
 | 
				
			||||||
 | 
					      certain contexts. In other contexts, they can be used with no
 | 
				
			||||||
 | 
					      restrictions.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      The following characters are treated in a special way:
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - <code>[</code> and <code>]</code> enclose a section name. A
 | 
				
			||||||
 | 
					      section name may contain any arbitrary character, including new
 | 
				
			||||||
 | 
					      line and white spaces, except a <code>]</code>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - <code>\\n</code> (begin of line or file) and <code>=</code>
 | 
				
			||||||
 | 
					      enclose a variable name. In other circumstances (except in
 | 
				
			||||||
 | 
					      comments), a new line has no special meaning. A <code>=</code>
 | 
				
			||||||
 | 
					      inside a value is allowed only if the value is quoted. A
 | 
				
			||||||
 | 
					      variable name may contain any arbitrary character, including
 | 
				
			||||||
 | 
					      white spaces, except a new line or <code>=</code>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - <code>=</code> and one out of <code>[</code>, <code>#</code>
 | 
				
			||||||
 | 
					      and the begin of a line that contains <code>=</code> enclose a
 | 
				
			||||||
 | 
					      variable contents if the contents is not quoted. A variable's
 | 
				
			||||||
 | 
					      contents may contain any arbitrary character, including new line
 | 
				
			||||||
 | 
					      and white spaces, except a <code>]</code>, <code>#</code> or the
 | 
				
			||||||
 | 
					      begin of a line that contains <code>=</code>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - <code>"</code> or <code>'</code> may enclose a variables
 | 
				
			||||||
 | 
					      contents. These characters have only a special meaning, if a
 | 
				
			||||||
 | 
					      variable's contents starts with one of them. Then the variable's
 | 
				
			||||||
 | 
					      contents may contain any arbitrary character, except the same
 | 
				
			||||||
 | 
					      quote itself, which marks the end of the contents.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      - <code>#</code> and <code>\\n</code> (end of line or file)
 | 
				
			||||||
 | 
					      enclose a comment. A variable name may contain any arbitrary
 | 
				
			||||||
 | 
					      character, including white spaces, except a new line.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configSyntaxRestrictions Restrictions
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @attention Due to the actual syntax, it is impossible that a
 | 
				
			||||||
 | 
					      variable's contents contains the following combination:
 | 
				
			||||||
 | 
					      <code>"</code> @b and <code>'</code> @b and one out of
 | 
				
			||||||
 | 
					      <code>[</code>, <code>=</code> and <code>#</code>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @attention If a variable's contents contains heading or trailing
 | 
				
			||||||
 | 
					      white spaces or one out of <code>[</code>, <code>=</code> and
 | 
				
			||||||
 | 
					      <code>#</code>, then it must be quoted either with
 | 
				
			||||||
 | 
					      <code>"</code> or with <code>'</code>.
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @section configFile Example File
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configFileSamp1 Nice Example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @verbatim
 | 
				
			||||||
 | 
					      [Section 1]
 | 
				
			||||||
 | 
					      name1 = value1
 | 
				
			||||||
 | 
					      name2 = value2
 | 
				
			||||||
 | 
					      [Section 2]
 | 
				
			||||||
 | 
					      name1 = value1
 | 
				
			||||||
 | 
					      name2 = value2
 | 
				
			||||||
 | 
					      @endverbatim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @subsection configFileSamp2 Enhanced Example
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @verbatim
 | 
				
			||||||
 | 
					      # this is in the global section, named ""
 | 
				
			||||||
 | 
					      this is a variable name = this is a variable contents
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      [Global] # start of section "Global"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      multi line text = this is a text
 | 
				
			||||||
 | 
					                        that is longer than one
 | 
				
			||||||
 | 
					                        line!
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      1234 = "var=17" # if you need an equal inside a text, enclose it
 | 
				
			||||||
 | 
					                      # either in " or in '
 | 
				
			||||||
 | 
					      @endverbatim
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @section configFileCode Code Sample
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					      @code
 | 
				
			||||||
 | 
					      try {
 | 
				
			||||||
 | 
					        const char* home(getenv("HOME"));
 | 
				
			||||||
 | 
					        mrw::ConfigFileReader config(home?home+"/.myprogram":".myprogram");
 | 
				
			||||||
 | 
					        std::string userName(config("User Info", "Name"));
 | 
				
			||||||
 | 
					      } catch (...) { // file read or evaluation error
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      @endcode
 | 
				
			||||||
 | 
					   */
 | 
				
			||||||
 | 
					  //@{
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /// Parse configuration file and access the contents.
 | 
				
			||||||
 | 
					  /** Parse a configuration file that consists of sections containing
 | 
				
			||||||
 | 
					      variables with values. This class does not store anything in the
 | 
				
			||||||
 | 
					      file, even if variables have changed.
 | 
				
			||||||
 | 
					      @see If you want %to save changes %to the file, use
 | 
				
			||||||
 | 
					           @ref ConfigFileWriter.
 | 
				
			||||||
 | 
					      @see For details, see @ref configSyntax. */
 | 
				
			||||||
 | 
					  class ConfigFileReader {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    /// A configuration file value.
 | 
				
			||||||
 | 
					    class Value {
 | 
				
			||||||
 | 
					    public:
 | 
				
			||||||
 | 
					      /// Get the value string.
 | 
				
			||||||
 | 
					      /** Get the value string. Trailing and leading white spaces have
 | 
				
			||||||
 | 
					          been truncated. If the variable was quoted, quotes have been
 | 
				
			||||||
 | 
					          removed.
 | 
				
			||||||
 | 
					          @return the variable's value as string */
 | 
				
			||||||
 | 
					      operator const std::string&() const throw() {
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      /// Get the value string.
 | 
				
			||||||
 | 
					      /** Alternative access to the variable's contents. Trailing and
 | 
				
			||||||
 | 
					          leading white spaces have been truncated. If the variable
 | 
				
			||||||
 | 
					          was quoted, quotes have been removed.
 | 
				
			||||||
 | 
					          @return the variable's value as string */
 | 
				
			||||||
 | 
					      const std::string& operator()() const throw() {
 | 
				
			||||||
 | 
					        return value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      /// Assign a new value.
 | 
				
			||||||
 | 
					      /** Assign a new value. The new value is lost if you use the
 | 
				
			||||||
 | 
					          ConfigFileReader, but it is stored in the destructor, if you
 | 
				
			||||||
 | 
					          use the ConfigFileWriter instead. */
 | 
				
			||||||
 | 
					      Value& operator=(const std::string& newValue) throw() {
 | 
				
			||||||
 | 
					        changed = true;
 | 
				
			||||||
 | 
					        value = newValue;
 | 
				
			||||||
 | 
					        return *this;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      /// Compare the value to a string.
 | 
				
			||||||
 | 
					      bool operator==(const std::string& o) const throw() {
 | 
				
			||||||
 | 
					        return o==value;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      /// Compare a string to the value.
 | 
				
			||||||
 | 
					      friend bool operator==(const std::string& o, const Value& v) throw() {
 | 
				
			||||||
 | 
					        return v==o;
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					    protected:
 | 
				
			||||||
 | 
					      friend class ConfigFileReader;
 | 
				
			||||||
 | 
					      friend class ConfigFileWriter;
 | 
				
			||||||
 | 
					      Value(const std::string& v,
 | 
				
			||||||
 | 
					            std::string::size_type s, std::string::size_type e) throw():
 | 
				
			||||||
 | 
					        value(v), changed(false), start(s), end(e) {
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      Value(const std::string& v) throw():
 | 
				
			||||||
 | 
					        value(v), changed(true), start(0), end(0) {
 | 
				
			||||||
 | 
					      }
 | 
				
			||||||
 | 
					      std::string value;
 | 
				
			||||||
 | 
					      bool changed;
 | 
				
			||||||
 | 
					      std::string::size_type start;
 | 
				
			||||||
 | 
					      std::string::size_type end;
 | 
				
			||||||
 | 
					    private:
 | 
				
			||||||
 | 
					      Value(); // not implemented, must be initialized
 | 
				
			||||||
 | 
					      Value& operator=(const Value&); // not implemented, no assignment
 | 
				
			||||||
 | 
					    };
 | 
				
			||||||
 | 
					    /// Uninitialized construction.
 | 
				
			||||||
 | 
					    /** Uninitialized construction. Use this constructor, if you want
 | 
				
			||||||
 | 
					        to call @ref load() later. */
 | 
				
			||||||
 | 
					    ConfigFileReader() throw() {}
 | 
				
			||||||
 | 
					    /// Parse a file at construction.
 | 
				
			||||||
 | 
					    /** This should be the normal case: load and parse the file at
 | 
				
			||||||
 | 
					        construction.
 | 
				
			||||||
 | 
					        @param filename the name of the file to read
 | 
				
			||||||
 | 
					        @throw mrw::invalid_argument
 | 
				
			||||||
 | 
					                - if the file does not exist
 | 
				
			||||||
 | 
					                - if reading the file fails
 | 
				
			||||||
 | 
					                - if there is an unterminated section name in the file
 | 
				
			||||||
 | 
					                - if there is an empty variable name in the file */
 | 
				
			||||||
 | 
					    ConfigFileReader(const std::string& filename) throw(std::exception):
 | 
				
			||||||
 | 
					      _filename(filename) {
 | 
				
			||||||
 | 
					      reload();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// Copy construct from other ConfigFileReader.
 | 
				
			||||||
 | 
					    ConfigFileReader(const ConfigFileReader& o) throw():
 | 
				
			||||||
 | 
					      _filename(o._filename), _values(o._values) {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    virtual ~ConfigFileReader() throw() {}
 | 
				
			||||||
 | 
					    /// Copy from other ConfigFileReader.
 | 
				
			||||||
 | 
					    ConfigFileReader& operator=(const ConfigFileReader& o) {
 | 
				
			||||||
 | 
					      _filename = o._filename;
 | 
				
			||||||
 | 
					      _values = o._values;
 | 
				
			||||||
 | 
					      return *this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// Access a value read from the file.
 | 
				
			||||||
 | 
					    /** Access a value read from the file.
 | 
				
			||||||
 | 
					        @param section the section in the configuration file
 | 
				
			||||||
 | 
					        @param name the variable name
 | 
				
			||||||
 | 
					        @param default_ the default value that is set, if the variable is
 | 
				
			||||||
 | 
					               not configured
 | 
				
			||||||
 | 
					        @return the Value you are looking for */
 | 
				
			||||||
 | 
					    Value& operator()(const std::string& section, const std::string& name,
 | 
				
			||||||
 | 
					                      const std::string& default_)
 | 
				
			||||||
 | 
					      throw(std::bad_exception);
 | 
				
			||||||
 | 
					    /// Load and parse a new file.
 | 
				
			||||||
 | 
					    /** Load and parse a new file.
 | 
				
			||||||
 | 
					        @throw mrw::invalid_argument
 | 
				
			||||||
 | 
					                - if the file does not exist
 | 
				
			||||||
 | 
					                - if reading the file fails
 | 
				
			||||||
 | 
					                - if there is an unterminated section name in the file
 | 
				
			||||||
 | 
					                - if there is an empty variable name in the file */
 | 
				
			||||||
 | 
					    ConfigFileReader& load(const std::string& filename) throw(std::exception);
 | 
				
			||||||
 | 
					    /// Reload the last file again.
 | 
				
			||||||
 | 
					    /** Reload the last file again.
 | 
				
			||||||
 | 
					        @throw mrw::invalid_argument
 | 
				
			||||||
 | 
					                - if the file does not exist
 | 
				
			||||||
 | 
					                - if reading the file fails
 | 
				
			||||||
 | 
					                - if there is an unterminated section name in the file
 | 
				
			||||||
 | 
					                - if there is an empty variable name in the file */
 | 
				
			||||||
 | 
					    virtual ConfigFileReader& reload() throw(std::exception);
 | 
				
			||||||
 | 
					  protected:
 | 
				
			||||||
 | 
					    typedef std::map< std::string, std::map<std::string, Value> > Values;
 | 
				
			||||||
 | 
					    typedef std::map<std::string, std::string::size_type> Sections;
 | 
				
			||||||
 | 
					    std::string readFile() const throw(std::exception);
 | 
				
			||||||
 | 
					    ConfigFileReader& parse(const std::string& file) throw(std::exception);
 | 
				
			||||||
 | 
					    std::string parseSection(const std::string& file,
 | 
				
			||||||
 | 
					                             std::string::size_type& pos)
 | 
				
			||||||
 | 
					      const throw(std::exception);
 | 
				
			||||||
 | 
					    Values::mapped_type::value_type parseValue(const std::string& file,
 | 
				
			||||||
 | 
					                                               std::string::size_type& pos)
 | 
				
			||||||
 | 
					      const throw(std::exception);
 | 
				
			||||||
 | 
					    std::string parseComment(const std::string& file,
 | 
				
			||||||
 | 
					                             std::string::size_type& pos)
 | 
				
			||||||
 | 
					      const throw(std::bad_exception);
 | 
				
			||||||
 | 
					    std::string _filename;
 | 
				
			||||||
 | 
					    Values _values;
 | 
				
			||||||
 | 
					    Sections _sections;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  /** @brief Parse configuration file and offer read / write
 | 
				
			||||||
 | 
					             access to the contents.
 | 
				
			||||||
 | 
					      
 | 
				
			||||||
 | 
					      Parse a configuration file that consists of sections containing
 | 
				
			||||||
 | 
					      variables with values. This class stores the file in the destructor
 | 
				
			||||||
 | 
					      if variables have changed.
 | 
				
			||||||
 | 
					      @see If you want %to leave the file untouched, use
 | 
				
			||||||
 | 
					           @ref ConfigFileReader.
 | 
				
			||||||
 | 
					      @see For details, see @ref configSyntax. */
 | 
				
			||||||
 | 
					  class ConfigFileWriter: virtual public ConfigFileReader {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    /// Uninitialized construction.
 | 
				
			||||||
 | 
					    /** @copydoc ConfigFileReader() */
 | 
				
			||||||
 | 
					    ConfigFileWriter() throw() {}
 | 
				
			||||||
 | 
					    /// Parse a file at construction.
 | 
				
			||||||
 | 
					    /** @copydoc ConfigFileReader(const std::string& filename) */
 | 
				
			||||||
 | 
					    ConfigFileWriter(const std::string& filename) throw(std::exception){
 | 
				
			||||||
 | 
					      load(filename);
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// Copy construct from other ConfigFileWriter.
 | 
				
			||||||
 | 
					    ConfigFileWriter(const ConfigFileWriter& o) throw():
 | 
				
			||||||
 | 
					      ConfigFileReader(o) {
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// The file is stored at destruction.
 | 
				
			||||||
 | 
					    virtual ~ConfigFileWriter() throw() {
 | 
				
			||||||
 | 
					      save();
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					    /// Copy from other ConfigFileWriter.
 | 
				
			||||||
 | 
					    ConfigFileWriter& operator=(const ConfigFileWriter& o) {
 | 
				
			||||||
 | 
					      ConfigFileReader::operator=(o);
 | 
				
			||||||
 | 
					      return *this;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					// GNU g++ prior to 3.4 does not implement covariant returns
 | 
				
			||||||
 | 
					#   if __GNUC__ == 3 && __GNUC_MINOR__ < 4
 | 
				
			||||||
 | 
					    /// Reload the last file again.
 | 
				
			||||||
 | 
					    /** @copydoc mrw::ConfigFileReader::reload()
 | 
				
			||||||
 | 
					        @bug Bug in GNU g++ compiler:
 | 
				
			||||||
 | 
					             return type should be <code>ConfigFileWriter&</code>,
 | 
				
			||||||
 | 
					             but the compiler sais:<br>
 | 
				
			||||||
 | 
					             <code>../mrw/configfile.hpp:295:
 | 
				
			||||||
 | 
					                  sorry, unimplemented: adjusting pointers for
 | 
				
			||||||
 | 
					                  covariant returns</code><br>
 | 
				
			||||||
 | 
					             The problem is fixed since GNU g++ 3.4, so the signature
 | 
				
			||||||
 | 
					             will be changed as soon as you upgrade to the new compiler
 | 
				
			||||||
 | 
					             version. */
 | 
				
			||||||
 | 
					    virtual ConfigFileReader& reload() throw(std::exception);
 | 
				
			||||||
 | 
					#   else
 | 
				
			||||||
 | 
					    /// Reload the last file again.
 | 
				
			||||||
 | 
					    /** @copydoc mrw::ConfigFileReader::reload() */
 | 
				
			||||||
 | 
					    virtual ConfigFileWriter& reload() throw(std::exception);
 | 
				
			||||||
 | 
					#   endif
 | 
				
			||||||
 | 
					    /// Saves changes back to the file.
 | 
				
			||||||
 | 
					    /** All changed parameters are stored in the configuration
 | 
				
			||||||
 | 
					        file. The rest of the file is left untouched. */
 | 
				
			||||||
 | 
					    ConfigFileWriter& save() throw(std::exception);
 | 
				
			||||||
 | 
					  protected:
 | 
				
			||||||
 | 
					    std::string _file;
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					  //@}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										16
									
								
								mrw/configfile.ini
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										16
									
								
								mrw/configfile.ini
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,16 @@
 | 
				
			|||||||
 | 
					 xxx=yyy        # this is a comment 
 | 
				
			||||||
 | 
					[Section]  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         abc=
 | 
				
			||||||
 | 
					  def=hallo welt
 | 
				
			||||||
 | 
						ghi= 
 | 
				
			||||||
 | 
					      jkl= mn
 | 
				
			||||||
 | 
					      op qr
 | 
				
			||||||
 | 
					      st
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  [Other Section]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1234="5678=90"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					here we are = some contents # comments
 | 
				
			||||||
 | 
					  here=
 | 
				
			||||||
							
								
								
									
										24
									
								
								mrw/configfile.ini.result
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										24
									
								
								mrw/configfile.ini.result
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,24 @@
 | 
				
			|||||||
 | 
					 xxx=0        # this is a comment 
 | 
				
			||||||
 | 
					[Section]  
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         abc=1
 | 
				
			||||||
 | 
					  def="Und=Tschuess"
 | 
				
			||||||
 | 
						ghi=3 
 | 
				
			||||||
 | 
					      jkl= 4
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  
 | 
				
			||||||
 | 
					guguseli zwei = dadaa
 | 
				
			||||||
 | 
					guguseli drei = dadaa
 | 
				
			||||||
 | 
					guguseli = dadaa
 | 
				
			||||||
 | 
					[Other Section]
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					  1234=5
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					here we are = 6 # comments
 | 
				
			||||||
 | 
					  here=7
 | 
				
			||||||
 | 
					yes = .
 | 
				
			||||||
 | 
					no no no = .
 | 
				
			||||||
 | 
					no no = .
 | 
				
			||||||
 | 
					[New Section]
 | 
				
			||||||
 | 
					a first one = sgadd
 | 
				
			||||||
 | 
					one more = .
 | 
				
			||||||
							
								
								
									
										3
									
								
								mrw/configfile_check.sh
									
									
									
									
									
										Executable file
									
								
							
							
						
						
									
										3
									
								
								mrw/configfile_check.sh
									
									
									
									
									
										Executable file
									
								
							@@ -0,0 +1,3 @@
 | 
				
			|||||||
 | 
					#! /bin/bash
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					test -z "`diff configfile2.ini configfile.ini.result`" && rm configfile2.ini
 | 
				
			||||||
							
								
								
									
										66
									
								
								mrw/configfile_test.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										66
									
								
								mrw/configfile_test.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,66 @@
 | 
				
			|||||||
 | 
					/** @file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Id$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Date$
 | 
				
			||||||
 | 
					    $Author$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @copy © Marc Wäckerlin
 | 
				
			||||||
 | 
					    @license LGPL, see file <a href="license.html">COPYING</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Log$
 | 
				
			||||||
 | 
					    Revision 1.1  2005/01/07 00:31:38  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/configfile.hpp>
 | 
				
			||||||
 | 
					#include <mrw/file.hpp>
 | 
				
			||||||
 | 
					#include <cppunit/TestFixture.h>
 | 
				
			||||||
 | 
					#include <cppunit/ui/text/TestRunner.h>
 | 
				
			||||||
 | 
					#include <cppunit/extensions/HelperMacros.h>
 | 
				
			||||||
 | 
					#include <cppunit/extensions/TestFactoryRegistry.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					class ConfigFileTest: public CppUnit::TestFixture { 
 | 
				
			||||||
 | 
					public:
 | 
				
			||||||
 | 
					  void CheckFile() {
 | 
				
			||||||
 | 
					    mrw::File::copy("configfile.ini", "configfile2.ini");
 | 
				
			||||||
 | 
					    mrw::ConfigFileWriter config("configfile2.ini");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("", "xxx", ".")=="yyy");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "abc", ".")=="");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "def", ".")=="hallo welt");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "ghi", ".")=="");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "jkl", ".")=="mn\n      op qr\n      st");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Other Section", "1234", ".")=="5678=90");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Other Section", "here we are", ".")
 | 
				
			||||||
 | 
					                   =="some contents");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Other Section", "here", ".")=="");
 | 
				
			||||||
 | 
					    config("", "xxx", ".")="0";
 | 
				
			||||||
 | 
					    config("Section", "abc", ".")="1";
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("New Section", "a first one", "sgadd")=="sgadd");
 | 
				
			||||||
 | 
					    config("Section", "def", ".")="Und=Tschuess";
 | 
				
			||||||
 | 
					    config("Section", "ghi", ".")="3";
 | 
				
			||||||
 | 
					    config("Section", "jkl", ".")="4";
 | 
				
			||||||
 | 
					    config("Other Section", "1234", ".")="5";
 | 
				
			||||||
 | 
					    config("Other Section", "here we are", ".")="6";
 | 
				
			||||||
 | 
					    config("Other Section", "here", ".")="7";
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Other Section", "no no", ".")==".");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Other Section", "no no no", ".")==".");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Other Section", "yes", ".")==".");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "guguseli", "dadaa")=="dadaa");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "guguseli zwei", "dadaa")=="dadaa");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("Section", "guguseli drei", "dadaa")=="dadaa");
 | 
				
			||||||
 | 
					    CPPUNIT_ASSERT(config("New Section", "one more", ".")==".");
 | 
				
			||||||
 | 
					  }
 | 
				
			||||||
 | 
					  CPPUNIT_TEST_SUITE(ConfigFileTest);
 | 
				
			||||||
 | 
					  CPPUNIT_TEST(CheckFile);
 | 
				
			||||||
 | 
					  CPPUNIT_TEST_SUITE_END();
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					CPPUNIT_TEST_SUITE_REGISTRATION(ConfigFileTest);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main() {
 | 
				
			||||||
 | 
					  CppUnit::TextUi::TestRunner runner;
 | 
				
			||||||
 | 
					  runner.addTest(CppUnit::TestFactoryRegistry::getRegistry().makeTest());
 | 
				
			||||||
 | 
					  return runner.run() ? 0 : 1;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										47
									
								
								mrw/file.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								mrw/file.hpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,47 @@
 | 
				
			|||||||
 | 
					/** @file
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Id$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Date$
 | 
				
			||||||
 | 
					    $Author$
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    @copy © Marc Wäckerlin
 | 
				
			||||||
 | 
					    @license LGPL, see file <a href="license.html">COPYING</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    $Log$
 | 
				
			||||||
 | 
					    Revision 1.1  2005/01/07 00:31:38  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					         1         2         3         4         5         6         7         8
 | 
				
			||||||
 | 
					    5678901234567890123456789012345678901234567890123456789012345678901234567890
 | 
				
			||||||
 | 
					*/
 | 
				
			||||||
 | 
					#ifndef __MRW_FILE_HPP__
 | 
				
			||||||
 | 
					#define __MRW_FILE_HPP__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <mrw/exception.hpp>
 | 
				
			||||||
 | 
					#include <string>
 | 
				
			||||||
 | 
					#include <fstream>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					namespace mrw {
 | 
				
			||||||
 | 
					  class File {
 | 
				
			||||||
 | 
					  public:
 | 
				
			||||||
 | 
					    static void copy(std::string from, std::string to) throw (std::exception) {
 | 
				
			||||||
 | 
					      std::ifstream is(from.c_str());
 | 
				
			||||||
 | 
					      if (!is)
 | 
				
			||||||
 | 
					        throw mrw::invalid_argument("Cannot read file: '"+from+"'");
 | 
				
			||||||
 | 
					      is.seekg(0, std::ios::end);
 | 
				
			||||||
 | 
					      int size(is.tellg());
 | 
				
			||||||
 | 
					      std::string contents(size, 0); // make buffer long enough to store all
 | 
				
			||||||
 | 
					      is.seekg(0, std::ios::beg);
 | 
				
			||||||
 | 
					      is.read(contents.begin().operator->(), size); // hack to get the buffer
 | 
				
			||||||
 | 
					      if (!is.good() && is.eof())
 | 
				
			||||||
 | 
					        throw mrw::invalid_argument("Cannot read file: '"+from+"'");
 | 
				
			||||||
 | 
					      std::ofstream os(to.c_str());
 | 
				
			||||||
 | 
					      os<<contents;
 | 
				
			||||||
 | 
					      if (!os) throw mrw::invalid_argument("Cannot write file: '"+to+"'");
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					  };
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
@@ -9,6 +9,9 @@
 | 
				
			|||||||
    @license LGPL, see file <a href="license.html">COPYING</a>
 | 
					    @license LGPL, see file <a href="license.html">COPYING</a>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    $Log$
 | 
					    $Log$
 | 
				
			||||||
 | 
					    Revision 1.2  2005/01/07 00:35:17  marc
 | 
				
			||||||
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    Revision 1.1  2004/12/17 16:26:58  marc
 | 
					    Revision 1.1  2004/12/17 16:26:58  marc
 | 
				
			||||||
    initial version
 | 
					    initial version
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@@ -24,7 +27,6 @@
 | 
				
			|||||||
#include <cppunit/extensions/HelperMacros.h>
 | 
					#include <cppunit/extensions/HelperMacros.h>
 | 
				
			||||||
#include <cppunit/extensions/TestFactoryRegistry.h>
 | 
					#include <cppunit/extensions/TestFactoryRegistry.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <iostream>
 | 
					 | 
				
			||||||
class TokenizerTest: public CppUnit::TestFixture { 
 | 
					class TokenizerTest: public CppUnit::TestFixture { 
 | 
				
			||||||
public:
 | 
					public:
 | 
				
			||||||
  void CheckNonGreedy() {
 | 
					  void CheckNonGreedy() {
 | 
				
			||||||
 
 | 
				
			|||||||
		Reference in New Issue
	
	Block a user