libi2ncommon: (reinhard) added configdata and configfile module from connd.
authorReinhard Pfau <reinhard.pfau@intra2net.com>
Tue, 26 Aug 2008 09:59:29 +0000 (09:59 +0000)
committerReinhard Pfau <reinhard.pfau@intra2net.com>
Tue, 26 Aug 2008 09:59:29 +0000 (09:59 +0000)
src/Makefile.am
src/i2n_configdata.hpp [new file with mode: 0644]
src/i2n_configfile.cpp [new file with mode: 0644]
src/i2n_configfile.hpp [new file with mode: 0644]

index bfe30bd..a5a6b2f 100644 (file)
@@ -5,13 +5,14 @@ INCLUDES = -I$(top_srcdir)/src @LIBGETTEXT_CFLAGS@ @LIBICONV_CFLAGS@ $(all_inclu
 # the library search path.
 lib_LTLIBRARIES = libi2ncommon.la
 include_HEADERS = containerfunc.hpp daemonfunc.hpp filefunc.hxx \
-       insocketstream.hxx ip_type.hxx ipfunc.hxx log_macros.hpp logfunc.hpp logread.hxx \
-       oftmpstream.hxx pidfile.hpp pipestream.hxx pointer_func.hpp signalfunc.hpp \
-       source_track_basics.hpp stringfunc.hxx timefunc.hxx tracefunc.hpp userfunc.hpp
+       i2n_configdata.hpp i2n_configfile.hpp insocketstream.hxx ip_type.hxx ipfunc.hxx \
+       log_macros.hpp logfunc.hpp logread.hxx oftmpstream.hxx pidfile.hpp pipestream.hxx \
+       pointer_func.hpp signalfunc.hpp source_track_basics.hpp stringfunc.hxx timefunc.hxx \
+       tracefunc.hpp userfunc.hpp
 libi2ncommon_la_SOURCES = containerfunc.cpp daemonfunc.cpp filefunc.cpp \
-       ipfunc.cpp logfunc.cpp logread.cpp oftmpstream.cpp pidfile.cpp pointer_func.cpp \
-       signalfunc.cpp source_track_basics.cpp stringfunc.cpp timefunc.cpp tracefunc.cpp \
-       userfunc.cpp
+       i2n_configfile.cpp ipfunc.cpp logfunc.cpp logread.cpp oftmpstream.cpp pidfile.cpp \
+       pointer_func.cpp signalfunc.cpp source_track_basics.cpp stringfunc.cpp timefunc.cpp \
+       tracefunc.cpp userfunc.cpp
 
 # Note:  If you specify a:b:c as the version in the next line,
 #  the library that is made has version (a-c).c.b.  In this
diff --git a/src/i2n_configdata.hpp b/src/i2n_configdata.hpp
new file mode 100644 (file)
index 0000000..8db82ba
--- /dev/null
@@ -0,0 +1,786 @@
+/** @file
+ *
+ * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
+ * 
+ * @copyright &copy; Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+#ifndef __I2N_CONFIGDATA_HPP__
+#define __I2N_CONFIGDATA_HPP__
+
+#include <vector>
+#include <map>
+#include <algorithm>
+#include <sstream>
+
+
+namespace I2n
+{
+
+
+
+/**
+ * key-value data storage with some additional features.
+ * This class is meant to hold data from config files.
+ *
+ * Basic ideas:
+ *
+ * - the keys are remembered in the order they are put into the list
+ * - each key can hold multiple values
+ * - the values for each key are remembered in the order they were added
+ * - if a single value for a key is requested than the last value is returned.
+ * .
+ * @tparam KeyType the type for the keys
+ * @tparam ValueType the type for the values.
+ */
+template <
+    class KeyType,
+    class ValueType
+>
+class KeyValueData
+{
+    public:
+
+        typedef std::vector<KeyType> KeyListType;
+        typedef std::vector<ValueType> ValueListType;
+        typedef std::map<KeyType, ValueListType> StorageType;
+
+    public:
+
+        /**
+         * @brief adaptor class for accessing values within the list for a given key.
+         * 
+         * This is returned by KeyValueList::operator[](const std::string&) for
+         * more convenient access.
+         * 
+         * This class is designed to be used in transient contexts.
+         */
+        class ValueAdaptor
+        {
+                // make parent class my friend since the constructors are private!
+                friend class KeyValueData;
+
+            public:
+
+                /**
+                 * cast operator for ValueType.
+                 * @return the (last) value for the key
+                 */
+                operator ValueType () const
+                {
+                    return m_kv.getValue(m_key);
+                } // eo operator ValueType() const
+
+
+                /**
+                 * cast operator for ValueListType.
+                 * @return the value list for the key.
+                 */
+                operator ValueListType () const
+                {
+                    return m_kv.getValues(m_key);
+                } // eo operator ValueListType() const
+
+
+                /**
+                 * performs setValue().
+                 * @param value the value which should be set for the key.
+                 * @return reference to this (for chaining).
+                 */
+                ValueAdaptor& operator = (const ValueType& value)
+                {
+                    m_kv.setValue(m_key,value);
+                    return *this;
+                } // eo operator =(const ValueType&)
+
+
+                /**
+                 * performs setValues()
+                 * @param values the new values (/value list) which should be set for the key.
+                 * @return reference to this (for chaining).
+                 */
+                ValueAdaptor& operator = (const ValueListType& values)
+                {
+                    m_kv.setValues(m_key, values);
+                    return *this;
+                } // eo operator =(const ValueListType&);
+
+
+                /**
+                 * performs addValue().
+                 * @param value the value which should be added to the value list for the key,
+                 * @return reference to this (for chaining).
+                 */
+                ValueAdaptor& operator += (const ValueType& value)
+                {
+                    m_kv.addValue(m_key,value);
+                    return *this;
+                } // eo operator +=(const ValueType&)
+
+
+                /**
+                 * performs addValues().
+                 * @param values the new values (/value list) which should be added to the value list for the key.
+                 * @return reference to this (for chaining).
+                 */
+                ValueAdaptor& operator += (const ValueListType& values)
+                {
+                    m_kv.addValues(m_key, values);
+                    return *this;
+                } // eo operator +=(const ValueListType)
+
+
+            private:
+
+                ValueAdaptor(KeyValueData& kv, const KeyType& key)
+                : m_kv(kv)
+                , m_key(key)
+                {
+                }
+
+                ValueAdaptor(const ValueAdaptor& other)
+                : m_kv(other.m_kv)
+                , m_key(other.m_key)
+                {
+                }
+
+                ValueAdaptor& operator =(const ValueAdaptor&);
+
+            private:
+                KeyValueData& m_kv;
+                KeyType       m_key;
+        }; // eo class ValueAdaptor
+
+    public:
+
+        KeyValueData()
+        {
+        } // eo KeyValueData
+
+
+
+        ~KeyValueData()
+        {
+        } // eo ~KeyValueData
+
+
+
+        /**
+        * set a value for a key.
+        * This erases an existing value list for that key and set's a new (single) value.
+        * @param key the key.
+        * @param value the value.
+        */
+        KeyValueData& setValue(const KeyType& key, const ValueType& value)
+        {
+            typename StorageType::iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                m_key_list.push_back(key);
+                m_storage[key].push_back(value);
+            }
+            else
+            {
+                it->second.clear();
+                it->second.push_back(value);
+            }
+            return *this;
+        } // eo setValue(const KeyType&,const ValueType&)
+
+
+
+        /**
+        * set a new value list for a key.
+        * Erases the key when the new value list is empty.
+        * Else the value list for the key is replaced with the new values.
+        * @param key the key
+        * @param values the new value list.
+        */
+        KeyValueData& setValues(const KeyType& key, const ValueListType& values)
+        {
+            typename StorageType::iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                m_key_list.push_back(key);
+                m_storage[key]= values;
+            }
+            else
+            {
+                if (values.empty())
+                {
+                    deleteKey(key);
+                }
+                else
+                {
+                    it->second= values;
+                }
+            }
+            return *this;
+        } // eo setValues(const KeyType&,const ValueListType&)
+
+
+
+        /**
+        * adds a new value to the value list of a key.
+        *
+        * @param key the key
+        * @param value the new value
+        */
+        KeyValueData& addValue(const KeyType& key, const ValueType& value)
+        {
+            typename StorageType::iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                m_key_list.push_back(key);
+                m_storage[key].push_back(value);
+            }
+            else
+            {
+                it->second.push_back(value);
+            }
+            return *this;
+        } // eo addValue(const KeyType&,const ValueType&)
+
+
+
+        /**
+        * adds new values to the value list of a key.
+        *
+        * @param key the key
+        * @param values the new value list
+        */
+        KeyValueData& addValues(const KeyType& key, const ValueListType& values)
+        {
+            typename StorageType::iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                m_key_list.push_back(key);
+                m_storage[key]= values;
+            }
+            else
+            {
+                std::copy(values.begin(), values.end(), std::back_inserter(it->second));
+            }
+            return *this;
+        } // eo addValues(const KeyType&,const ValueListType&)
+
+
+
+        /**
+         * @brief removes a value from a value list of a key.
+         * @param key the key.
+         * @param value the value which should be removed (once).
+         * @return self reference.
+         * @note only the first occurance of the value is removed!
+         */
+        KeyValueData& removeValue(const KeyType& key, const ValueType& value)
+        {
+            typename StorageType::iterator it= m_storage.find(key);
+            if (it != m_storage.end())
+            {
+                for( typename ValueListType::iterator it_val= it->second.begin();
+                    it_val != it->second.end();
+                    ++it_val)
+                {
+                    if ( *it_val == value)
+                    {
+                        it->second.erase(it_val);
+                        break;
+                    }
+                }
+                if (it->second.empty())
+                {
+                    deleteKey( key );
+                }
+            }
+            return *this;
+        } // eo removeValue
+
+
+        /**
+         * retrieve the (single) value for a key.
+         * If the value list of the key has multiple values, the last one returned.
+         * @param key the key
+         * @param[out] value the resulting value if found
+         * @return @a true iff the key has a value (i,e, the key exits).
+         */
+        bool getValue(const KeyType& key, ValueType& value) const
+        {
+            typename StorageType::const_iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                return false;
+            }
+            else
+            {
+                value= it->second.back();
+                return true;
+            }
+        } // eo getValue(const KeyType&, ValueType&)
+
+
+
+        /**
+         * retrieve the value list for a key.
+         * @param key the key
+         * @param[out] values the resulting value list if found
+         * @return @a true iff the key has values (i,e, the key exits).
+         */
+        bool getValues(const KeyType& key, ValueListType& values) const
+        {
+            typename StorageType::const_iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                return false;
+            }
+            else
+            {
+                values= it->second;
+                return true;
+            }
+        } // eo getValues(const KeyType&, ValueListType&)
+
+
+
+        /**
+         * retrieve the (single) value for a key.
+         * If the value list of the key has multiple values, the last one returned.
+         * @param key the key
+         * @return the value of the key (default contructed value if key not found)
+         */
+        ValueType getValue(const KeyType& key) const
+        {
+            ValueType value;
+            getValue( key, value);
+            return value;
+        } // eo getValue(const KeyType&)
+
+
+
+        /**
+         * retrieve the value list for a key.
+         * @param key the key
+         * @return the value of the key (empty if key not found)
+         */
+        ValueListType getValues(const KeyType& key) const
+        {
+            ValueListType values;
+            getValues( key, values);
+            return values;
+        } // eo getValues(const KeyType&)
+
+
+
+        /**
+         * retrieve the (single) value for a key.
+         * If the value list of the key has multiple values, the last one returned.
+         * If the key wasn't found (i.e. no value) then the default value is returned.
+         * @param key the key
+         * @param default_value the value which is returned if the key wasn't found.
+         * @return the value of the key (default_value if key not found)
+         */
+        ValueType getValueOrDefault(const KeyType& key, const ValueType& default_value) const
+        {
+            ValueType value;
+            if (getValue( key, value))
+            {
+                return value;
+            }
+            return default_value;
+        } // eo getValueOrDefault(const KeyType&,const ValueType&)
+
+
+
+        /**
+        * removes a key (and it's values) from the list.
+        * @param key the key.
+        */
+        void deleteKey(const KeyType& key)
+        {
+            typename StorageType::iterator it= m_storage.find(key);
+            if (it == m_storage.end())
+            {
+                return;
+            }
+            m_storage.erase(it);
+            typename KeyListType::iterator itk= std::find(m_key_list.begin(), m_key_list.end(), key);
+            if (itk != m_key_list.end())
+            {
+                m_key_list.erase(itk);
+            }
+        } // eo deleteKey(const KeyType&)
+
+
+
+        /**
+        * returns if a key exists in the list.
+        * @param key the key which should be looked for.
+        * @return @a true if the key is in the list.
+        */
+        bool hasKey(const KeyType& key) const
+        {
+            return (m_storage.find(key) != m_storage.end());
+        } // eo hasKey(const KeyType&)
+
+
+
+        /**
+        * delivers the list of keys.
+        * @param[out] result_list the key list
+        */
+        void getKeys(KeyListType& result_list) const
+        {
+            result_list= m_key_list;
+        } // eo getKeys(KeyListType&) const
+
+
+
+        /**
+         * deliviers the list of keys.
+         * @return the list of keys.
+         */
+        KeyListType getKeys() const
+        {
+            return m_key_list;
+        } // eo getKeys() const
+
+
+
+        /**
+         * returns if the list is empty (i.e. has no keys)
+         * @return @a true iff the list has no keys (and values).
+         */
+        bool empty() const
+        {
+            return m_key_list.empty();
+        } // eo empty
+
+
+
+        /**
+         * @brief index operator for more readable access.
+         * @param key the key which should be indexed.
+         * @return an instance of ValueAdaptor initialized with the key.
+         */
+        ValueAdaptor operator [] (const KeyType& key)
+        {
+            return ValueAdaptor(*this, key);
+        } // eo operator[](const KeyType&)
+
+
+        /**
+         * @brief returns if the current iunstance is equal to another one (of the same type).
+         * @param rhs the orher instance to compare with.
+         * @return @a true iff the two instances are equal.
+         */
+        bool operator==( const KeyValueData& rhs)
+        {
+            return m_key_list == rhs.m_key_list and m_storage == rhs.m_storage;
+        } // eo operator==(const KeyValueData&)
+
+
+        /**
+         * @brief clears the list.
+         * 
+         * Well, it just deletes all entries.
+         */
+        void clear()
+        {
+            m_storage.clear();
+            m_key_list.clear();
+        } // eo clear
+
+
+        /**
+         * @brief exchanges the internal data with another instance.
+         * @param other 
+         */
+        void swap(KeyValueData& other)
+        {
+            if (this != &other)
+            {
+                m_storage.swap( other.m_storage );
+                m_key_list.swap( other.m_key_list );
+            }
+        } // eo swap(KeyValueData&)
+
+
+    protected:
+
+        /**
+         * returns a reference to the last value of the value list for a given key; creating it if the key doesn't
+         * already exist.
+         * This method is only for derived classes to optimize accessing of the values.
+         * @param key the key for which the reference is needed.
+         * @return reference to the last value of the value list for the key.
+         */
+        ValueType& getValueRef(const KeyType& key)
+        {
+            typename KeyListType::iterator it=
+              std::find( m_key_list.begin(), m_key_list.end(), key );
+            if (it == m_key_list.end())
+            {
+                m_key_list.push_back(key);
+            }
+            if (m_storage[key].empty())
+            {
+                ValueType v;
+                m_storage[key].push_back( v );
+            }
+            return m_storage[key].back();
+        } // eo getValueRef(const KeyType&)
+
+
+        /**
+         * @brief returns a reference to the last value of the value list for a given key.
+         * @param key the key for which the reference is needed.
+         * @return reference to the last value of the value list for the key or to internal
+         *  value if no values are existing.
+         *
+         * This method is only for derived classes to optimize accessing of the values.
+         *
+         * @note The method returns a reference to an internal value if no approbiate value
+         * exists! It's up to the derived class to deal with that.
+         */
+        const ValueType& getConstValueRef(const KeyType& key) const
+        {
+            static ValueType empty_value;
+            typename StorageType::const_iterator storage_it= m_storage.find(key);
+            if (storage_it == m_storage.end()
+                or storage_it->second.empty() )
+            {
+                return empty_value;
+            }
+            return storage_it->second.back();
+        } // eo getConstValueRef(const KeyType&)
+
+
+        /**
+         * @brief returns a reference to the value list for a given key.
+         * @param key the key for which the reference is needed.
+         * @return reference to the value list for the key.
+         *
+         * This method is only for derived classes to optimize accessing of the values.
+         *
+         * @note The method returns a reference to an internal value if no approbiate value
+         * exists! It's up to the derived class to deal with that.
+         */
+        const ValueListType& getConstValuesRef(const KeyType& key) const
+        {
+            static ValueListType empty_value;
+            typename StorageType::const_iterator storage_it= m_storage.find(key);
+            if ( storage_it == m_storage.end() )
+            {
+                return empty_value;
+            }
+            return storage_it->second;
+        } // eo getConstValuesRef(const KeyType&)
+
+
+
+    private:
+
+        StorageType m_storage;
+        KeyListType m_key_list;
+
+}; // eo KeyValueData
+
+
+
+
+/**
+ * grouped key value list.
+ * This (template) class provides storage for groups whose values are key-value lists.
+ * Basically it's a key-value list, wohse values are another key-value list.
+ *
+ * If used with std::string for all key types, it provides a storage suitable for holding they
+ * (for example) the content of INI style config files.
+ *
+ * @param GroupKeyType type for the group keys.
+ * @param KeyType type for the keys (within a group)
+ * @param ValueType type for the values (within a group)
+ */
+template<
+    class GroupKeyType,
+    class KeyType,
+    class ValueType
+>
+class GroupedKeyValueData
+: public KeyValueData<GroupKeyType, KeyValueData<KeyType,ValueType> >
+{
+        typedef KeyValueData<GroupKeyType, KeyValueData<KeyType,ValueType> > inherited;
+
+    public:
+
+        typedef KeyValueData<KeyType,ValueType> GroupDataType;
+
+    public:
+
+        GroupedKeyValueData()
+        {
+        }
+
+
+        ~GroupedKeyValueData()
+        {
+        }
+
+
+        /*
+        ** overridden methods:
+        */
+
+        /**
+         * add (new) group data to a group.
+         * This differs from KeyValueData::addValue in a way that it merges the group data into
+         * an existing group instead of appending a new data group.
+         * @param group_key the key of the group.
+         * @param value the new data which should be added to the group.
+         */
+        void addValue(const GroupKeyType& group_key, const GroupDataType& value)
+        {
+            if (value.empty())
+            {
+                return;
+            }
+            GroupDataType& group_data= getValueRef(group_key);
+
+            typename GroupDataType::KeyListType keys = value.getKeys();
+            for(typename GroupDataType::KeyListType::const_iterator it_key= keys.begin();
+                it_key != keys.end();
+                ++it_key)
+            {
+                typename GroupDataType::ValueListType values= value.getValues(*it_key);
+                if (values.empty()) continue;
+                group_data.addValues( *it_key, value.getValues(*it_key) );
+            }
+        } // eo addValue(const GroupKey&,const GroupData&)
+
+
+        /**
+         * set new group values.
+         * This differs from KeyValueData::setValues in a way that it merges all values to a single
+         * data group.
+         * @param group_key the key of the group.
+         * @param values the list of data grups which are merged together to the new group value.
+         */
+        void setValues(const GroupKeyType& group_key, const typename inherited::ValueListType& values)
+        {
+            if (values.empty())
+            {
+                inherited::deleteKey(group_key);
+                return;
+            }
+            // note: since (the overridden method) addValue() already does what we need,
+            // we just clear the data and iterate over the new values list:
+            getValueRef(group_key).clear();
+            for(typename inherited::ValueListType::const_iterator it= values.begin();
+                it != values.end();
+                ++it)
+            {
+                addValue(group_key, *it);
+            }
+            if ( getValueRef(group_key).empty())
+            {
+                deleteKey(group_key);
+            }
+        } // eo setValues(const GroupKeyType&,const ValueListType&)
+
+
+        /**
+         * add new group values.
+         * This differs from KeyValueList::addValues in a way that the new values are merged into
+         * a single data groupo.
+         * @param group_key 
+         * @param values 
+         */
+        void addValues(const GroupKeyType& group_key, const typename inherited::ValueListType& values)
+        {
+            if (values.empty())
+            {
+                return;
+            }
+            // like in setValues(); we just use our new addValue() to do the job:
+            for(typename inherited::ValueListType::const_iterator it= values.begin();
+                it != values.end();
+                ++it)
+            {
+                addValue(group_key, *it);
+            }
+        } // eo addValues(const GroupKeyType&,const ValueListType&)
+
+
+
+        /*
+        ** additional methods:
+        */
+
+
+        GroupDataType& operator[](const GroupKeyType& key)
+        {
+            return getValueRef(key);
+        } // eo operator [](const groupKey&)
+
+
+        const GroupDataType& operator[](const GroupKeyType& key) const
+        {
+            return getConstValueRef(key);
+        } // eo operator [](const groupKey&) const
+
+
+        /**
+         * check if a group exists (alias for hasKey(const GroupKey&) const).
+         * @param group_key the key og the group which is looked for.
+         * @return @a true iff the group exists.
+         */
+        bool hasGroup(const GroupKeyType& group_key) const
+        {
+            return inherited::hasKey(group_key);
+        } // eo hasGroup(const GroupKeyType&) const
+
+
+        /**
+         * check if a key within a group exists.
+         * @param group_key the group which should be looked in.
+         * @param key the key which should be tested.
+         * @return @a true iff the group exists and the key exists within that group.
+         */
+        bool hasKey(const GroupKeyType& group_key, const KeyType& key) const
+        {
+            if (!hasGroup(group_key))
+            {
+                return false;
+            }
+            return getConstValueRef(group_key).hasKey(key);
+        } // eo hasKey(const GroupKeyType&,const KeyType&) const
+
+
+
+}; // eo GroupedKeyValueData
+
+
+
+/*
+** typedef the most common case; suitable for holding the content of
+** INI style config files.
+*/
+
+
+typedef GroupedKeyValueData<
+    std::string,
+    std::string,
+    std::string
+> ConfigData;
+
+typedef ConfigData::GroupDataType ConfigSectionData;
+
+
+
+} // eo namespace I2n
+
+
+
+#endif
diff --git a/src/i2n_configfile.cpp b/src/i2n_configfile.cpp
new file mode 100644 (file)
index 0000000..5e74417
--- /dev/null
@@ -0,0 +1,124 @@
+/** @file
+ *
+ * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
+ * 
+ * @copyright &copy; Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+//#define NOISEDEBUG
+
+#include "i2n_configfile.hpp"
+
+#include <algorithm>
+#include <iterator>
+#include <fstream>
+
+#include <stringfunc.hxx>
+
+
+#ifdef NOISEDEBUG
+#include <iostream>
+#define DOUT(msg) std::cout << msg << std::endl
+#else
+#define DOUT(msg) do {} while (0)
+#endif
+
+
+
+namespace I2n
+{
+
+/**
+ * loads config data from INI style configuration file.
+ * File is processed line by line.
+ * Empty lines are ignored; lines starting with '#' or ';' are ignored too (they are
+ * expected to be comments).
+ * Lines consisting of a bracketed expression like '[group]' start a new group.
+ * Other lines have to be in the form 'key = value' and define a key-value assignment in the current
+ * group.
+ * @param filename path to the config file which is read.
+ * @param[out] result the resulting config data.
+ * @param decoder (optional) decoder for the values.
+ * @return @a true if the file was succesfully parsed.
+ */
+bool load_ini_config_file(
+    const std::string& filename,
+    ConfigData& result,
+    const ValueDecoder& decoder
+)
+{
+    std::ifstream f;
+    f.open(filename.c_str());
+    if (!f.good() )
+    {
+        return false;
+    }
+    return load_ini_config(f,result);
+} // eo load_ini_config_file(const std::string&,ConfigData&)
+
+
+/**
+ * loads config data from INI style configuration file.
+ * File is processed line by line.
+ * Empty lines are ignored; lines starting with '#' or ';' are ignored too (they are
+ * expected to be comments).
+ * Lines consisting of a bracketed expression like '[group]' start a new group.
+ * Other lines have to be in the form 'key = value' and define a key-value assignment in the current
+ * group.
+ * @param f istream to read the data from.
+ * @param[out] result the resulting config data.
+ * @param decoder (optional) decoder for the values.
+ * @return @a true if the file was successfully parsed.
+ */
+bool load_ini_config(
+    std::istream& f,
+    ConfigData& result,
+    const ValueDecoder& decoder
+)
+{
+    result.clear();
+    if (!f.good())
+    {
+        return false;
+    }
+    std::string group("");
+    while (!f.eof() && f.good())
+    {
+        std::string line;
+        getline(f,line);
+        trim_mod(line);
+        if (line.empty() || line[0] == '#'|| line[0]==';') 
+        {
+            continue;
+        }
+        if (line[0] == '[' && line[line.size()-1] == ']')
+        {
+            // start new group:
+            group= line.substr(1, line.size()-2);
+            result[group];
+            continue;
+        }
+        std::string key, value;
+        if (pair_split(line,key,value,'='))
+        {
+            if (decoder)
+            {
+                value= decoder(value);
+            }
+            result[group][key]+= value;
+        }
+        else
+        {
+            // bad line....
+            //TODO: spit more information?!
+            return false;
+        }
+    }
+    return true;
+} // eo load_ini_config
+
+
+} // eo namespace I2n
diff --git a/src/i2n_configfile.hpp b/src/i2n_configfile.hpp
new file mode 100644 (file)
index 0000000..e4dbb61
--- /dev/null
@@ -0,0 +1,50 @@
+/** @file
+ *
+ * contains stuff for simple config files.
+ *
+ * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
+ * 
+ * @copyright &copy; Copyright 2007-2008 by Intra2net AG
+ * @license commercial
+ *
+ * info@intra2net.com
+ */
+
+#ifndef __I2N_CONFIGFILE_HPP__
+#define __I2N_CONFIGFILE_HPP__
+
+#include <string>
+#include <istream>
+#include <boost/function.hpp>
+
+#include "i2n_configdata.hpp"
+
+namespace I2n
+{
+
+
+/*
+**
+*/
+
+typedef boost::function< std::string(const std::string&) > ValueDecoder;
+
+
+bool load_ini_config_file(
+    const std::string& filename,
+    ConfigData& result,
+    const ValueDecoder& decoder = ValueDecoder()
+);
+
+
+bool load_ini_config(
+    std::istream& f,
+    ConfigData& result,
+    const ValueDecoder& decoder = ValueDecoder()
+);
+
+
+
+} // eo namespace I2n
+
+#endif