diff --git a/mrw/configfile.cpp b/mrw/configfile.cpp index 5548ac0..0be203f 100644 --- a/mrw/configfile.cpp +++ b/mrw/configfile.cpp @@ -1,7 +1,7 @@ /** @file $Id$ - + $Date$ $Author$ @@ -9,6 +9,9 @@ @license LGPL, see file COPYING $Log$ + Revision 1.2 2005/01/28 07:49:32 marc + Save configuration using file.hpp + Revision 1.1 2005/01/07 00:31:38 marc initial version @@ -20,12 +23,13 @@ #include #include #include +#include #include mrw::ConfigFileReader::Value& -mrw::ConfigFileReader::operator()(const std::string& section, - const std::string& name, - const std::string& default_) + 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; @@ -38,26 +42,9 @@ mrw::ConfigFileReader& mrw::ConfigFileReader::load(const std::string& filename) } 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; + return parse(mrw::File::read(_filename)); } -#include -using namespace std; mrw::ConfigFileReader& mrw::ConfigFileReader::parse(const std::string& file) throw(std::exception) { _values.erase(_values.begin(), _values.end()); @@ -142,7 +129,7 @@ mrw::ConfigFileReader& mrw::ConfigFileWriter& #endif mrw::ConfigFileWriter::reload() throw(std::exception) { - return parse(_file=readFile()); + return parse(_file=mrw::File::read(_filename)); } mrw::ConfigFileWriter& mrw::ConfigFileWriter::save() throw(std::exception) { @@ -193,10 +180,6 @@ mrw::ConfigFileWriter& mrw::ConfigFileWriter::save() throw(std::exception) { _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+"'"); + if (changed) mrw::File::save(_filename, _file); return *this; } diff --git a/mrw/configfile.hpp b/mrw/configfile.hpp index 8ba0e5e..9d75740 100644 --- a/mrw/configfile.hpp +++ b/mrw/configfile.hpp @@ -9,11 +9,14 @@ @license LGPL, see file COPYING $Log$ + Revision 1.2 2005/01/28 07:49:32 marc + Save configuration using file.hpp + Revision 1.1 2005/01/07 00:31:38 marc initial version -*/ + */ #ifndef __MRW_CONFIGFILE_HPP__ #define __MRW_CONFIGFILE_HPP__ @@ -24,6 +27,8 @@ namespace mrw { /** @defgroup config Configuration File Handler + @pre #include + Read configuration parameters from a file. @section configSyntax Configuration File Syntax @@ -141,12 +146,12 @@ namespace mrw { [Global] # start of section "Global" - multi line text = this is a text - that is longer than one - line! + 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 ' + # either in " or in ' @endverbatim @section configFileCode Code Sample @@ -159,202 +164,302 @@ namespace mrw { } catch (...) { // file read or evaluation error } @endcode - */ + */ //@{ - /// Parse configuration file and access the contents. - /** Parse a configuration file that consists of sections containing + //============================================================================ + /** @brief 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. */ + + @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 { + + //............................................................... typedefs 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; + + //------------------------------------------------------------------ Value + /// A configuration file value. + class Value { + + //............................................................ methods + public: + + /** @brief 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; + } + + /** @brief 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; + } + + /** @brief 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; + } + + //............................................................ methods + 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) { + } + + //.......................................................... variables + protected: + + std::string value; + bool changed; + std::string::size_type start; + std::string::size_type end; + + //............................................................ methods + private: + + Value(); // not implemented, must be initialized + Value& operator=(const Value&); // not implemented, no assignment + + }; + //------------------------------------------------------------------------ + + //................................................................ methods + public: + + /** @brief Uninitialized construction. + + Uninitialized construction. Use this constructor, if you + want to call @ref load() later. + */ + ConfigFileReader() throw() {} + + /** @brief 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(); } - /// 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; + + /// Copy construct from other ConfigFileReader. + ConfigFileReader(const ConfigFileReader& o) throw(): + _filename(o._filename), _values(o._values) { } - /// 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; + + virtual ~ConfigFileReader() throw() {} + + /// Copy from other ConfigFileReader. + ConfigFileReader& operator=(const ConfigFileReader& o) { + _filename = o._filename; + _values = o._values; 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; - } + + /** @brief 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); + + /** @brief Load and parse a new file. + + Load and parse a new file. + + @param filename the name of the file to load + @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); + + /** @brief 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); + + //............................................................... typedefs 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 > Values; - typedef std::map 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; + + typedef std::map< std::string, std::map > Values; + typedef std::map Sections; + + //.............................................................. variables + protected: + + std::string _filename; + Values _values; + Sections _sections; + + //................................................................ methods + protected: + + 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); }; + //============================================================================ /** @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. */ + + @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 ConfigFileWriter&, - but the compiler sais:
- ../mrw/configfile.hpp:295: - sorry, unimplemented: adjusting pointers for - covariant returns
- 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; + + //................................................................ methods + public: + + /** @brief Uninitialized construction. + + @copydoc ConfigFileReader() + */ + ConfigFileWriter() throw() {} + + /** @brief Parse a file at construction. + + @copydoc ConfigFileReader(const std::string&) + */ + 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 + /** @brief Reload the last file again. + + @copydoc mrw::ConfigFileReader::reload() + + @bug Bug in GNU g++ compiler: + return type should be ConfigFileWriter&, + but the compiler sais:
+ ../mrw/configfile.hpp:295: + sorry, unimplemented: adjusting pointers for + covariant returns
+ 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 + /** @brief Reload the last file again. + + @copydoc mrw::ConfigFileReader::reload() + */ + virtual ConfigFileWriter& reload() throw(std::exception); +# endif + + /** @brief 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); + + //.............................................................. variables + protected: + + std::string _file; + }; //@} diff --git a/mrw/file.hpp b/mrw/file.hpp index 9e7248e..e5633aa 100644 --- a/mrw/file.hpp +++ b/mrw/file.hpp @@ -1,3 +1,4 @@ + /** @file $Id$ @@ -9,39 +10,305 @@ @license LGPL, see file COPYING $Log$ + Revision 1.2 2005/01/28 07:49:32 marc + Save configuration using file.hpp + Revision 1.1 2005/01/07 00:31:38 marc initial version - 1 2 3 4 5 6 7 8 + 1 2 3 4 5 6 7 8 5678901234567890123456789012345678901234567890123456789012345678901234567890 -*/ + */ #ifndef __MRW_FILE_HPP__ #define __MRW_FILE_HPP__ #include #include #include +#include +#include namespace mrw { + + /** @defgroup sysFile File and System Utilities + + @brief By now, some utilies for file handling, i.e. a copy command. + + Some file and system specific utilities are missing in C++ and + often there is even no good alternative in C libraries. + */ + //@{ + + //============================================================================ + /** @brief File handling utilities. + + Utilities for file access in C++. + */ 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<(), sz); // hack to get the buffer + if (!is.good() && is.eof()) + throw mrw::invalid_argument("Cannot read file: '"+filename+"'"); + return contents; + }; + + /** @brief Save a string to a file. + + A string is stored in a file, the whole file is overwritten by + the contents of the string. This is the counterpart of + read(const std::string&). + + @throw mrw::invalid_argument if write fails + @param filename the name of the output file + @param contents the text to be written to the file + */ + static void save(const std::string& filename, const std::string& contents) + throw(std::exception) { + std::ofstream file(filename.c_str()); + if (!(file<. and + .. (self anf top) + */ + Dir(const std::string& dir, bool ignoreDots=true) throw(std::exception): + _ignoreDots(ignoreDots), _dir(opendir(dir.c_str())) { + if (!_dir) + throw mrw::invalid_argument("Cannot read directory: '"+dir+'\''); + } + + /// Directory is closed automatically in the destructor. + ~Dir() throw() { + closedir(_dir); + } + + /** @brief Advance to the next directory entry. + + Advance to the next directory entry. + + @code + mrw::Dir dir("/home"); + while (dir) ... + @endcode + + @return + - @c true if an entry has been found + - @c false if there are no more entries left + + @warning If you call this method again after @c false was + returned, behaviour is unspecified, but a crash + is probable. + */ + operator bool() throw() { + static const std::string D("."), DD(".."); + static dirent* fake; + if (readdir_r(_dir, &_entry.entry(), &fake)) return false; + if (_ignoreDots && _entry==Entry::DIR && (D==_entry() || D==_entry())) + return operator bool(); + return true; + } + + /** @brief Get the actual directory entry. + + Returns the actual directory entry. + + @code + mrw::Dir dir("/home"); + while (dir) { + dirent entry(dir()); + ... + } + @endcode + + @return the actual directory entry + + @warning You must first call operator bool(), otherwise the + behaviour is undefined, but a crash is probable. + */ + const Entry& operator()() { + return _entry; + } + + //.............................................................. variables + private: + + bool _ignoreDots; + DIR* _dir; + Entry _entry; + }; + + //@} } #endif