Save configuration using file.hpp

master
Marc Wäckerlin 20 years ago
parent 4e91c2fe11
commit baa21d8110
  1. 37
      mrw/configfile.cpp
  2. 467
      mrw/configfile.hpp
  3. 303
      mrw/file.hpp

@ -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/28 07:49:32 marc
Save configuration using file.hpp
Revision 1.1 2005/01/07 00:31:38 marc Revision 1.1 2005/01/07 00:31:38 marc
initial version initial version
@ -20,12 +23,13 @@
#include <mrw/configfile.hpp> #include <mrw/configfile.hpp>
#include <mrw/exception.hpp> #include <mrw/exception.hpp>
#include <mrw/string.hpp> #include <mrw/string.hpp>
#include <mrw/file.hpp>
#include <fstream> #include <fstream>
mrw::ConfigFileReader::Value& mrw::ConfigFileReader::Value&
mrw::ConfigFileReader::operator()(const std::string& section, mrw::ConfigFileReader::operator()(const std::string& section,
const std::string& name, const std::string& name,
const std::string& default_) const std::string& default_)
throw(std::bad_exception) { throw(std::bad_exception) {
_values[section].insert(std::make_pair(name, Value(default_))); _values[section].insert(std::make_pair(name, Value(default_)));
return _values[section].find(name)->second; 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) { mrw::ConfigFileReader& mrw::ConfigFileReader::reload() throw(std::exception) {
return parse(readFile()); return parse(mrw::File::read(_filename));
}
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) mrw::ConfigFileReader& mrw::ConfigFileReader::parse(const std::string& file)
throw(std::exception) { throw(std::exception) {
_values.erase(_values.begin(), _values.end()); _values.erase(_values.begin(), _values.end());
@ -142,7 +129,7 @@ mrw::ConfigFileReader&
mrw::ConfigFileWriter& mrw::ConfigFileWriter&
#endif #endif
mrw::ConfigFileWriter::reload() throw(std::exception) { 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) { 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(); _sections[sec->first] = _file.size();
} }
} }
if (!changed) return *this; if (changed) mrw::File::save(_filename, _file);
// save to file
std::ofstream file(_filename.c_str());
if (!(file<<_file))
throw mrw::invalid_argument("Cannot write file '"+_filename+"'");
return *this; return *this;
} }

@ -9,11 +9,14 @@
@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/28 07:49:32 marc
Save configuration using file.hpp
Revision 1.1 2005/01/07 00:31:38 marc Revision 1.1 2005/01/07 00:31:38 marc
initial version initial version
*/ */
#ifndef __MRW_CONFIGFILE_HPP__ #ifndef __MRW_CONFIGFILE_HPP__
#define __MRW_CONFIGFILE_HPP__ #define __MRW_CONFIGFILE_HPP__
@ -24,6 +27,8 @@ namespace mrw {
/** @defgroup config Configuration File Handler /** @defgroup config Configuration File Handler
@pre #include <mrw/configfile.hpp>
Read configuration parameters from a file. Read configuration parameters from a file.
@section configSyntax Configuration File Syntax @section configSyntax Configuration File Syntax
@ -141,12 +146,12 @@ namespace mrw {
[Global] # start of section "Global" [Global] # start of section "Global"
multi line text = this is a text multi line text = this is a text
that is longer than one that is longer than one
line! line!
1234 = "var=17" # if you need an equal inside a text, enclose it 1234 = "var=17" # if you need an equal inside a text, enclose it
# either in " or in ' # either in " or in '
@endverbatim @endverbatim
@section configFileCode Code Sample @section configFileCode Code Sample
@ -159,202 +164,302 @@ namespace mrw {
} catch (...) { // file read or evaluation error } catch (...) { // file read or evaluation error
} }
@endcode @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 variables with values. This class does not store anything in the
file, even if variables have changed. file, even if variables have changed.
@see If you want %to save changes %to the file, use
@ref ConfigFileWriter. @see If you want %to save changes %to the file, use @ref ConfigFileWriter.
@see For details, see @ref configSyntax. */ @see For details, see @ref configSyntax.
*/
class ConfigFileReader { class ConfigFileReader {
public:
/// A configuration file value. //............................................................... typedefs
class Value { public:
//------------------------------------------------------------------ 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: public:
/// Get the value string.
/** Get the value string. Trailing and leading white spaces have /** @brief Uninitialized construction.
been truncated. If the variable was quoted, quotes have been
removed. Uninitialized construction. Use this constructor, if you
@return the variable's value as string */ want to call @ref load() later.
operator const std::string&() const throw() { */
return value; 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 /// Copy construct from other ConfigFileReader.
leading white spaces have been truncated. If the variable ConfigFileReader(const ConfigFileReader& o) throw():
was quoted, quotes have been removed. _filename(o._filename), _values(o._values) {
@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 virtual ~ConfigFileReader() throw() {}
ConfigFileReader, but it is stored in the destructor, if you
use the ConfigFileWriter instead. */ /// Copy from other ConfigFileReader.
Value& operator=(const std::string& newValue) throw() { ConfigFileReader& operator=(const ConfigFileReader& o) {
changed = true; _filename = o._filename;
value = newValue; _values = o._values;
return *this; return *this;
} }
/// Compare the value to a string.
bool operator==(const std::string& o) const throw() { /** @brief Access a value read from the file.
return o==value;
} Access a value read from the file.
/// Compare a string to the value.
friend bool operator==(const std::string& o, const Value& v) throw() { @param section the section in the configuration file
return v==o; @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: protected:
friend class ConfigFileReader;
friend class ConfigFileWriter; typedef std::map< std::string, std::map<std::string, Value> > Values;
Value(const std::string& v, typedef std::map<std::string, std::string::size_type> Sections;
std::string::size_type s, std::string::size_type e) throw():
value(v), changed(false), start(s), end(e) { //.............................................................. variables
} protected:
Value(const std::string& v) throw():
value(v), changed(true), start(0), end(0) { std::string _filename;
} Values _values;
std::string value; Sections _sections;
bool changed;
std::string::size_type start; //................................................................ methods
std::string::size_type end; protected:
private:
Value(); // not implemented, must be initialized ConfigFileReader& parse(const std::string& file) throw(std::exception);
Value& operator=(const Value&); // not implemented, no assignment
}; std::string parseSection(const std::string& file,
/// Uninitialized construction. std::string::size_type& pos)
/** Uninitialized construction. Use this constructor, if you want const throw(std::exception);
to call @ref load() later. */
ConfigFileReader() throw() {} Values::mapped_type::value_type parseValue(const std::string& file,
/// Parse a file at construction. std::string::size_type& pos)
/** This should be the normal case: load and parse the file at const throw(std::exception);
construction.
@param filename the name of the file to read std::string parseComment(const std::string& file,
@throw mrw::invalid_argument std::string::size_type& pos)
- if the file does not exist const throw(std::bad_exception);
- 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&nbsp;/ write /** @brief Parse configuration file and offer read&nbsp;/ write
access to the contents. access to the contents.
Parse a configuration file that consists of sections containing Parse a configuration file that consists of sections containing
variables with values. This class stores the file in the destructor variables with values. This class stores the file in the destructor
if variables have changed. if variables have changed.
@see If you want %to leave the file untouched, use
@ref ConfigFileReader. @see If you want %to leave the file untouched, use @ref ConfigFileReader.
@see For details, see @ref configSyntax. */ @see For details, see @ref configSyntax.
*/
class ConfigFileWriter: virtual public ConfigFileReader { class ConfigFileWriter: virtual public ConfigFileReader {
public:
/// Uninitialized construction. //................................................................ methods
/** @copydoc ConfigFileReader() */ public:
ConfigFileWriter() throw() {}
/// Parse a file at construction. /** @brief Uninitialized construction.
/** @copydoc ConfigFileReader(const std::string& filename) */
ConfigFileWriter(const std::string& filename) throw(std::exception){ @copydoc ConfigFileReader()
load(filename); */
} ConfigFileWriter() throw() {}
/// Copy construct from other ConfigFileWriter.
ConfigFileWriter(const ConfigFileWriter& o) throw(): /** @brief Parse a file at construction.
ConfigFileReader(o) {
} @copydoc ConfigFileReader(const std::string&)
/// The file is stored at destruction. */
virtual ~ConfigFileWriter() throw() { ConfigFileWriter(const std::string& filename) throw(std::exception) {
save(); load(filename);
} }
/// Copy from other ConfigFileWriter.
ConfigFileWriter& operator=(const ConfigFileWriter& o) { /// Copy construct from other ConfigFileWriter.
ConfigFileReader::operator=(o); ConfigFileWriter(const ConfigFileWriter& o) throw():
return *this; ConfigFileReader(o) {
} }
// GNU g++ prior to 3.4 does not implement covariant returns
# if __GNUC__ == 3 && __GNUC_MINOR__ < 4 /// The file is stored at destruction.
/// Reload the last file again. virtual ~ConfigFileWriter() throw() {
/** @copydoc mrw::ConfigFileReader::reload() save();
@bug Bug in GNU g++ compiler: }
return type should be <code>ConfigFileWriter&</code>,
but the compiler sais:<br> /// Copy from other ConfigFileWriter.
<code>../mrw/configfile.hpp:295: ConfigFileWriter& operator=(const ConfigFileWriter& o) {
sorry, unimplemented: adjusting pointers for ConfigFileReader::operator=(o);
covariant returns</code><br> return *this;
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. */ // GNU g++ prior to 3.4 does not implement covariant returns
virtual ConfigFileReader& reload() throw(std::exception); # if __GNUC__ == 3 && __GNUC_MINOR__ < 4
# else /** @brief Reload the last file again.
/// Reload the last file again.
/** @copydoc mrw::ConfigFileReader::reload() */ @copydoc mrw::ConfigFileReader::reload()
virtual ConfigFileWriter& reload() throw(std::exception);
# endif @bug Bug in GNU g++ compiler:
/// Saves changes back to the file. return type should be <code>ConfigFileWriter&</code>,
/** All changed parameters are stored in the configuration but the compiler sais:<br>
file. The rest of the file is left untouched. */ <code>../mrw/configfile.hpp:295:
ConfigFileWriter& save() throw(std::exception); sorry, unimplemented: adjusting pointers for
protected: covariant returns</code><br>
std::string _file; 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;
}; };
//@} //@}

@ -1,3 +1,4 @@
/** @file /** @file
$Id$ $Id$
@ -9,39 +10,305 @@
@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/28 07:49:32 marc
Save configuration using file.hpp
Revision 1.1 2005/01/07 00:31:38 marc Revision 1.1 2005/01/07 00:31:38 marc
initial version initial version
1 2 3 4 5 6 7 8 1 2 3 4 5 6 7 8
5678901234567890123456789012345678901234567890123456789012345678901234567890 5678901234567890123456789012345678901234567890123456789012345678901234567890
*/ */
#ifndef __MRW_FILE_HPP__ #ifndef __MRW_FILE_HPP__
#define __MRW_FILE_HPP__ #define __MRW_FILE_HPP__
#include <mrw/exception.hpp> #include <mrw/exception.hpp>
#include <string> #include <string>
#include <fstream> #include <fstream>
#include <sys/types.h>
#include <dirent.h>
namespace mrw { 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 { class File {
public:
static void copy(std::string from, std::string to) throw (std::exception) { //................................................................ methods
std::ifstream is(from.c_str()); public:
if (!is)
throw mrw::invalid_argument("Cannot read file: '"+from+"'"); /** @brief Copy a file.
is.seekg(0, std::ios::end);
int size(is.tellg()); Copy a file to a new location.
std::string contents(size, 0); // make buffer long enough to store all
is.seekg(0, std::ios::beg); First the source file is fully read into memory, then written
is.read(contents.begin().operator->(), size); // hack to get the buffer to the destination. If the source file cannot be fully read,
if (!is.good() && is.eof()) the destination is left untouched.
throw mrw::invalid_argument("Cannot read file: '"+from+"'");
std::ofstream os(to.c_str()); @throw mrw::invalid_argument if read or write fails
os<<contents; @param from the source file name
if (!os) throw mrw::invalid_argument("Cannot write file: '"+to+"'"); @param to the destination file name
} @note If the destination file already exists, it will be overwritten.
*/
static void copy(const std::string& from,
const std::string& to) throw(std::exception) {
std::ofstream os(to.c_str());
os<<read(from);
if (!os) throw mrw::invalid_argument("Cannot write file: '"+to+"'");
}
/** @brief Read a file fully into memory.
Read a file fully into memory.
@throw mrw::invalid_argument if read fails
@param filename the file to read
@return the file's contents
*/
static std::string read(const std::string& filename)
throw(std::exception) {
std::string contents; // declare on top to allow compiler optimization
std::ifstream is(filename.c_str());
std::string::size_type sz(size(is, filename));
contents.resize(sz); // make buffer long enough to store all
is.read(contents.begin().operator->(), 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<<contents))
throw mrw::invalid_argument("Cannot write file '"+filename+"'");
}
/** @brief Get the size of a file
Get the size of a file.
@throw mrw::invalid_argument if read fails
@param filename the file name
@return the file's size
*/
static std::string::size_type size(const std::string& filename)
throw(std::exception) {
std::ifstream is(filename.c_str());
if (!is)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
is.seekg(0, std::ios::end);
if (!is)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
return is.tellg();
}
/** @brief Get the size of a file
Get the size of a file.
@throw mrw::invalid_argument if read fails
@param file the filestream
@param filename the name of the file (required for the exception)
@return the file's size
*/
static std::string::size_type size(std::ifstream& file,
const std::string& filename = "")
throw(std::exception) {
if (!file)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
file.seekg(0, std::ios::end);
std::string::size_type sz(file.tellg());
file.seekg(0, std::ios::beg);
if (!file)
throw mrw::invalid_argument("Cannot get size of file: '"
+filename+"'");
return sz;
}
};
//============================================================================
class Dir {
//............................................................... typedefs
public:
//------------------------------------------------------------------ Entry
class Entry {
//........................................................... typedefs
public:
/** @brief The type of the actual file.
The type of the actual file.
@note On some systems UNKNOWN is the only
value returned.
*/
enum FileType {
UNKNOWN = DT_UNKNOWN, ///< The type is unknown.
REGULAR = DT_REG, ///< A regular file.
DIR = DT_DIR, ///< A directory.
FIFO = DT_FIFO, ///< A named pipe, or FIFO.
SOCKET = DT_SOCK, ///< A local-domain socket.
CHAR = DT_CHR, ///< A character device.
BLOCK = DT_BLK ///< A block device.
};
//............................................................ methods
public:
Entry(): _new(true) {}
/// Get the name of the actual file.
operator const std::string&() throw(std::bad_exception) {
if (_new) { // only convert to string once
_new = false;
_name = _dirent.d.d_name;
}
return _name;
}
/// Get the name of the actual file.
const std::string& operator()() throw(std::bad_exception) {
return *this;
}
/// Get the type of the actual file.
operator FileType() const throw() {
return FileType(_dirent.d.d_type);
}
//.......................................................... variables
private:
friend class Dir;
union { // for portability reasons, see "info readdir_r"
dirent d;
char b[offsetof (struct dirent, d_name) + NAME_MAX + 1];
} _dirent;
bool _new;
std::string _name;
//............................................................ methods
private:
dirent& entry() throw() {
_new = true;
return _dirent.d;
}
};
//------------------------------------------------------------------------
//................................................................ methods
public:
/** @brief Open a directory for reading the file list.
Open a directory for reading the file list.
@throw mrw::invalid_argument if directory cannot be opened
@param dir name of the directory to open
@param ignoreDots ignore directories <code>.<code> and
<code>..</code> (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 #endif

Loading…
Cancel
Save