config.h

Go to the documentation of this file.
00001 /*
00002  *  Copyright (C) 2004-2005 Alo Sarv <madcat_@users.sourceforge.net>
00003  *
00004  *  This program is free software; you can redistribute it and/or modify
00005  *  it under the terms of the GNU General Public License as published by
00006  *  the Free Software Foundation; either version 2 of the License, or
00007  *  (at your option) any later version.
00008  *
00009  *  This program is distributed in the hope that it will be useful,
00010  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00011  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00012  *  GNU General Public License for more details.
00013  *
00014  *  You should have received a copy of the GNU General Public License
00015  *  along with this program; if not, write to the Free Software
00016  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
00017  */
00018 
00019 /** @file Config.h Interface for Config class. */
00020 
00021 #ifndef __CONFIG_H__
00022 #define __CONFIG_H__
00023 
00024 #include <map>
00025 #include <string>
00026 #include <hn/osdep.h>
00027 #include <boost/lexical_cast.hpp>
00028 
00029 /**
00030  * Generic configuration storage class
00031  *
00032  * Config class is capable of storing key/value pairs of arbitary type in a
00033  * structured hierarchy. Values can be stored at either top-level, or at
00034  * sub-dirs. Accessing keys can be done either using full path of the key,
00035  * e.g. prepending "/" character before the key location, or using combination
00036  * of setPath() and read() calls.
00037  *
00038  * Internally the data is stored as strings, and converted to requested types
00039  * on request. Thus, it is possible to write apples and read back oranges, as
00040  * long as:
00041  * - both types can be converted to std::string using boost::lexical_cast
00042  * - the stored type can be converted from std::string to destination type using
00043  *   boost::lexical_cast.
00044  * .
00045  *
00046  * Config class is also capable of storing the stored values in physical file
00047  * between sessions, using save() and load() methods. The file format is not
00048  * 100% compatible with standard configuration files, but attempts to be as
00049  * close as possible. The actual format of the file stored on disk:
00050  *
00051  * \code
00052  * [Boo]
00053  * Boolean=1
00054  * [Floating/Yeah]
00055  * Pi=3.141
00056  * [Test]
00057  * HelloWorld=Good Morning
00058  * []
00059  * Integer Value=10
00060  * Doh=0
00061  * \endcode
00062  *
00063  * \note Using multi-word names for keys is allowed.
00064  */
00065 class DLLEXPORT Config {
00066 public:
00067         /**
00068          * Default constructor.
00069          */
00070         Config();
00071 
00072         /**
00073          * Constructs and loads from file.
00074          *
00075          * @param filename    File to read data from.
00076          *
00077          */
00078         Config(const std::string &filename);
00079 
00080         /**
00081          * Virtual destructor.
00082          */
00083         virtual ~Config();
00084 
00085         /**
00086          * Loads data from file.
00087          *
00088          * @param filename    File to read data from.
00089          */
00090         virtual void load(const std::string &filename);
00091 
00092         /**
00093          * Saves values into same file as used during loading.
00094          */
00095         virtual void save() const { save(m_configFile); }
00096 
00097         /**
00098          * Saves values into specified file.
00099          *
00100          * @param filename   File to save values to.
00101          */
00102         virtual void save(const std::string &filename) const;
00103 
00104         /**
00105          * Reads stored value into variable, or default value if not found.
00106          *
00107          * @param key    String key of value searched for.
00108          * @param val    Pointer to variable to store found data in.
00109          * @param def    Default value, used if no value was found in map.
00110          *
00111          * The two template classes here are neccesery, because we can get
00112          * input like float + double, and compilers don't seem to like that.
00113          */
00114         template<typename C, typename D>
00115         void read(const std::string &key, C *val, const D &def) const {
00116                 CHECK_THROW(val);
00117                 CHECK_THROW(key.size());
00118 
00119                 CIter i;
00120                 // key with absolute path, handle at first
00121                 if (key.at(0) == '/') {
00122                         i = m_values.find(key);
00123                 } else {
00124                         i = m_values.find(m_curPath + key);
00125                 }
00126 
00127                 if (i != m_values.end()) {
00128                         *val = boost::lexical_cast<C>((*i).second);
00129                 } else {
00130                         *val = def;
00131                 }
00132         }
00133 
00134         /**
00135          * Overloaded version of Read function returning the value read.
00136          *
00137          * @param key   Key to search for.
00138          * @param def   Default value to use if key is not found.
00139          *
00140          * @return      Value of found key, or default value if not found.
00141          */
00142         template<typename C>
00143         C read(const std::string &key, const C &def) const {
00144                 C tmp;
00145                 read(key, &tmp, def);
00146                 return tmp;
00147         }
00148 
00149         /**
00150          * Stores key/value pair.
00151          *
00152          * @param key    String key for later retrieval.
00153          * @param val    Value to be stored.
00154          */
00155         template<typename T>
00156         void write(const std::string &key, const T &val) {
00157                 CHECK_THROW(key.size());
00158 
00159                 std::string toWrite = boost::lexical_cast<std::string>(val);
00160                 if (key.at(0) == '/') {
00161                         m_values[key] = toWrite;
00162                 } else {
00163                         m_values[m_curPath + key] = toWrite;
00164                 }
00165         }
00166 
00167         /**
00168          * Sets current directory.
00169          *
00170          * @param dir    Directory to change to.
00171          */
00172         void setPath(const std::string &dir);
00173 
00174         /**
00175          * Returns number of elements stored by this instance.
00176          *
00177          * @return    Number of values stored by this instance.
00178          */
00179         size_t size() const { return m_values.size(); }
00180 
00181         /**
00182          * Dump the entire stored contents to std::cerr (for debugging)
00183          */
00184         void dump() const;
00185 
00186 protected:
00187         //! Constant iterator for internal data storage
00188         typedef std::map<std::string, std::string>::const_iterator CIter;
00189         //! Access to begin iterator
00190         CIter begin() const { return m_values.begin(); }
00191         //! Access to end iterator
00192         CIter end() const { return m_values.end(); }
00193 private:
00194         std::string m_configFile;           //!< File name used during loading
00195         std::string m_curPath;                       //!< Current directory
00196         std::map<std::string, std::string> m_values; //!< Actual data storage
00197 
00198         typedef std::map<std::string, std::string>::iterator Iter;
00199 };
00200 
00201 #endif