C++ Library containing a lot of needful things: Stack Trace, Command Line Parser, Resource Handling, Configuration Files, Unix Command Execution, Directories, Regular Expressions, Tokenizer, Function Trace, Standard Extensions.
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
363 lines
14 KiB
363 lines
14 KiB
20 years ago
|
/** @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
|