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.
470 lines
16 KiB
470 lines
16 KiB
/** @file |
|
|
|
$Id$ |
|
|
|
$Date$ |
|
$Author$ |
|
|
|
@copy © Marc Wäckerlin |
|
@license LGPL, see file <a href="license.html">COPYING</a> |
|
|
|
$Log$ |
|
Revision 1.3 2005/11/29 12:39:42 marc |
|
make it compilable with gcc 4.0.2 and newer doxygen |
|
|
|
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__ |
|
|
|
#include <string> |
|
#include <map> |
|
|
|
namespace mrw { |
|
|
|
/** @defgroup config Configuration File Handler |
|
|
|
@pre \#include <mrw/configfile.hpp> |
|
|
|
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 |
|
*/ |
|
//@{ |
|
|
|
//============================================================================ |
|
/** @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. |
|
*/ |
|
class ConfigFileReader { |
|
|
|
//............................................................... typedefs |
|
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: |
|
|
|
/** @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(); |
|
} |
|
|
|
/// 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; |
|
} |
|
|
|
/** @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: |
|
|
|
typedef std::map< std::string, std::map<std::string, Value> > Values; |
|
typedef std::map<std::string, std::string::size_type> 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. |
|
*/ |
|
class ConfigFileWriter: virtual public ConfigFileReader { |
|
|
|
//................................................................ 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 <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 |
|
/** @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; |
|
|
|
}; |
|
|
|
//@} |
|
} |
|
#endif
|
|
|