libi2ncommon: (reinhard) added global_config module (as separate lib and package...
authorReinhard Pfau <reinhard.pfau@intra2net.com>
Tue, 26 Aug 2008 10:50:09 +0000 (10:50 +0000)
committerReinhard Pfau <reinhard.pfau@intra2net.com>
Tue, 26 Aug 2008 10:50:09 +0000 (10:50 +0000)
Makefile.am
configlib/Makefile.am [new file with mode: 0644]
configlib/i2n_global_config.cpp [new file with mode: 0644]
configlib/i2n_global_config.hpp [new file with mode: 0644]
configure.in
libi2ncommon.spec
libi2ncommon_config.pc.in [new file with mode: 0644]

index 3dcc619..b4a6b0a 100644 (file)
@@ -2,11 +2,11 @@
 # have all needed files, that a GNU package needs
 AUTOMAKE_OPTIONS = foreign 1.4
 
-SUBDIRS = src test
+SUBDIRS = src configlib test
 
 # Install the pkg-config file:
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = libi2ncommon.pc
+pkgconfig_DATA = libi2ncommon.pc libi2ncommon_config.pc
 
 if AUTOCHECK
 all: config.h
diff --git a/configlib/Makefile.am b/configlib/Makefile.am
new file mode 100644 (file)
index 0000000..3889c49
--- /dev/null
@@ -0,0 +1,18 @@
+# set the include path found by configure
+INCLUDES = -I$(top_srcdir)/src $(all_includes) @LIBGETTEXT_CFLAGS@ \
+       @LIBICONV_CFLAGS@
+
+METASOURCES = AUTO
+
+lib_LTLIBRARIES = libi2ncommon_config.la
+
+include_HEADERS = i2n_global_config.hpp
+
+# 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
+#  example, the version is 2.1.2. (3:2:1)
+
+libi2ncommon_config_la_LDFLAGS = -version-info @LIBI2NCOMMON_LIB_VERSION@
+
+libi2ncommon_config_la_LIBADD =
+libi2ncommon_config_la_SOURCES = i2n_global_config.cpp
diff --git a/configlib/i2n_global_config.cpp b/configlib/i2n_global_config.cpp
new file mode 100644 (file)
index 0000000..5c4c1e8
--- /dev/null
@@ -0,0 +1,437 @@
+/** @file
+ *
+ * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
+ * 
+ * @copyright &copy; Copyright 2008 by Intra2net AG
+ * @license commercial
+ * @contact info@intra2net.com
+ */
+
+#include "i2n_global_config.hpp"
+
+
+#include <set>
+#include <map>
+
+#include <filefunc.hxx>
+#include <stringfunc.hxx>
+#include <i2n_configdata.hpp>
+#include <i2n_configfile.hpp>
+#include <logfunc.hpp>
+#include <tracefunc.hpp>
+
+//#define NOISEDEBUG
+#undef NOISEDEBUG
+
+#ifdef NOISEDEBUG
+#include <iostream>
+#include <iomanip>
+#define DOUT(msg) std::cout << msg << std::endl
+#else
+#define DOUT(msg) do {} while (0)
+#endif
+
+
+namespace I2n
+{
+
+namespace Config
+{
+
+
+namespace Detail
+{
+
+
+} // eo namespace Detail
+
+
+
+namespace
+{
+
+
+Logger::PartLogger& module_logger()
+{
+    static Logger::PartLogger _logger(HERE);
+    return _logger;
+} // eo module_logger()
+
+
+
+std::string config_file_name;
+
+ConfigData config_data;
+
+
+/*
+**
+*/
+
+
+struct HideOut
+: public Detail::Thing
+{
+    HideOut(
+        const std::string& section,
+        const std::string& key,
+        const Detail::FeedFunction& feed,
+        const Detail::FeedFunction2& feed2);
+
+    virtual ~HideOut();
+
+    Detail::FeedFunction m_feed;
+    Detail::FeedFunction2 m_feed2;
+    std::string  m_section;
+    std::string  m_key;
+}; // eo struct HideOut
+
+typedef boost::shared_ptr< HideOut > HideOutPtr;
+
+
+class HideOutMap
+: public GroupedKeyValueData<
+    std::string,
+    std::string,
+    HideOut*
+>
+{
+    public:
+        HideOutMap();
+        virtual ~HideOutMap();
+
+    public:
+
+        static int Instances;
+}; // eo class HideOutMap
+
+int HideOutMap::Instances= 0;
+
+HideOutMap::HideOutMap()
+{
+    DOUT("HideOutMap::HideOutMap()");
+    ++Instances;
+} // eo HideOutMap::HideOutMap()
+
+
+HideOutMap::~HideOutMap()
+{
+    DOUT("HideOutMap::~HideOutMap()");
+    --Instances;
+} // eo HideOutMap::~HideOutMap()
+
+
+HideOutMap& hideout_map()
+{
+    static HideOutMap the_hideout_map;
+    DOUT("hideout_map()");
+    return the_hideout_map;
+} // eo hideout_map()
+
+
+// implementation of HideOut:
+
+
+HideOut::HideOut(
+    const std::string& section,
+    const std::string& key,
+    const Detail::FeedFunction& feed,
+    const Detail::FeedFunction2& feed2)
+: m_section(section)
+, m_key(key)
+, m_feed(feed)
+, m_feed2(feed2)
+{
+    hideout_map()[section][key]+= this;
+} // eo HideOut::HideOut(const FeedFunction&)
+
+
+
+HideOut::~HideOut()
+{
+    if (HideOutMap::Instances)
+    {
+        hideout_map()[m_section].removeValue(m_key,this);
+    }
+} // eo HideOut::~HideOut()
+
+
+
+/*
+**
+*/
+
+
+/**
+ * @brief distributes (new) values to the active config variables.
+ * @param old_config_data reference to the old config data (for determining the deltas).
+ * @return @a true if new values could be converted without an error.
+ */
+bool feedEm( ConfigData& old_config_data )
+{
+    SCOPETRACKER();
+    bool result= true;
+    HideOutMap::KeyListType section_list;
+    hideout_map().getKeys(section_list);
+    for(HideOutMap::KeyListType::const_iterator section_it = section_list.begin();
+        section_it != section_list.end();
+        ++section_it)
+    {
+        std::string section( *section_it );
+        DOUT("process section \"" << section << "\"");
+        HideOutMap::GroupDataType::KeyListType key_list;
+        hideout_map()[section].getKeys(key_list);
+        for(HideOutMap::GroupDataType::KeyListType::const_iterator key_it= key_list.begin();
+            key_it != key_list.end();
+            ++key_it)
+        {
+            std::string key( *key_it );
+            DOUT("process key \"" << key << "\"");
+            bool has_new_data= config_data.hasKey(section, key);
+            bool has_old_data= old_config_data.hasKey(section, key);
+            if (not has_new_data and not has_old_data)
+            {
+                // we don't have data and we didn't had data... well, nothing to do:
+                DOUT("no data");
+                continue;
+            }
+            if (has_new_data)
+            {
+                DOUT("has (new) data");
+                StringList values;
+                config_data[section].getValues(key, values);
+                std::string value( config_data[section][key] );
+                if (has_old_data)
+                {
+                    StringList old_values;
+                    old_config_data[section].getValues(key, old_values);
+                    if (values == old_values)
+                    {
+                        // value didn't change, so we can skip this case.
+                        DOUT("data is same as before");
+                        continue;
+                    }
+                }
+                // at this point we need to publish (new or changed) value:
+                HideOutMap::GroupDataType::ValueListType func_list;
+                hideout_map()[section].getValues(key, func_list);
+                for(HideOutMap::GroupDataType::ValueListType::iterator func_it= func_list.begin();
+                    func_it != func_list.end();
+                    ++func_it)
+                {
+                    DOUT("  feed iteration");
+                    if (not (*func_it)) //paranoia
+                    {
+                        continue;
+                    }
+                    if ( (*func_it)->m_feed)
+                    {
+                        if ( not (*func_it)->m_feed( value ) )
+                        {
+                            module_logger().error() << "unable to publish [" <<section << "]"
+                                << " \"" << key << "\"  : \"" << value << "\""
+                            ;
+                            result= false;
+                        }
+                        continue;
+                    }
+                    if ( (*func_it)->m_feed2)
+                    {
+                        if ( not (*func_it)->m_feed2( values ) )
+                        {
+                            module_logger().error() << "unable to publish [" <<section << "]"
+                                << " \"" << key << "\"  : ...\"" << value << "\""
+                            ;
+                            result= false;
+                        }
+                        continue;
+                    }
+                    module_logger().error() << "no feeder";
+                }
+                continue;
+            }
+            // at this point we don't have (new) data, but we had old data...
+            //TODO how to handle this case? (reset to initial value??)
+            // for now, we ignore it.
+        }
+    }
+    return result;
+} // eo feedEm(ConfigData&,ConfigData&)
+
+
+/*
+**
+*/
+
+
+} // eo namespace <anonymous>
+
+
+/************************************************************************\
+\************************************************************************/
+
+
+namespace Detail
+{
+
+
+FlowerShop seymour(
+    const std::string& section,
+    const std::string& key,
+    const FeedFunction& feed)
+{
+    DOUT("seymor(\"" << section << "\", \"" << key << "\",FeedFunction)");
+    FlowerShop result( new HideOut( section, key, feed, 0 ) );
+    if (not config_data.empty())
+    {
+        if (config_data.hasKey(section, key))
+        {
+            feed( config_data[section][key] );
+        }
+    }
+    return result;
+} // eo seymour(const std::string&,const std::string&,const FeedFunction&)
+
+
+FlowerShop seymour(
+    const std::string& section,
+    const std::string& key,
+    const FeedFunction2& feed)
+{
+    DOUT("seymor(\"" << section << "\", \"" << key << "\",FeedFunction2)");
+    FlowerShop result( new HideOut( section, key, 0, feed ) );
+    if (not config_data.empty())
+    {
+        if (config_data.hasKey(section, key))
+        {
+            StringList values;
+            config_data[section].getValues(key, values);
+            feed( values );
+        }
+    }
+    return result;
+} // eo seymour(const std::string&,const std::string&,const FeedFunction2&)
+
+
+FlowerShop seymour(FlowerShop shop, const FeedFunction& feed)
+{
+    if (!shop)
+    {
+        // no shop; no coordinates; no useful stuff to do...
+        return shop;
+    }
+    HideOutPtr ptr = boost::shared_dynamic_cast< HideOut >(shop);
+    if (!ptr)
+    {
+        // again, no coordinates...
+        return ptr;
+    }
+    FlowerShop result( new HideOut( ptr->m_section, ptr->m_key, feed, 0 ) );
+    if (not config_data.empty())
+    {
+        if (config_data.hasKey(ptr->m_section, ptr->m_key))
+        {
+            feed( config_data[ptr->m_section][ptr->m_key] );
+        }
+    }
+    return result;
+} // eo seymour(FlowerShop,const FeedFunction&)
+
+
+FlowerShop seymour(FlowerShop shop, const FeedFunction2& feed)
+{
+    if (!shop)
+    {
+        // no shop; no coordinates; no useful stuff to do...
+        return shop;
+    }
+    HideOutPtr ptr = boost::shared_dynamic_cast< HideOut >(shop);
+    if (!ptr)
+    {
+        // again, no coordinates...
+        return ptr;
+    }
+    FlowerShop result( new HideOut( ptr->m_section, ptr->m_key, 0, feed ) );
+    if (not config_data.empty())
+    {
+        if (config_data.hasKey(ptr->m_section, ptr->m_key))
+        {
+            StringList values;
+            config_data[ptr->m_section].getValues(ptr->m_key, values);
+            feed( values );
+        }
+    }
+    return result;
+} // eo seymour(FlowerShop,const FeedFunction&)
+
+
+} // eo namespace Detail
+
+
+
+/**
+ * @brief reloads the configuration from the last (known) config file.
+ * @return @a true if config was succesfully reloaded.
+ */
+bool reload()
+{
+    ConfigData old_config_data;
+    ConfigData new_config_data;
+    if (config_file_name.empty())
+    {
+        return false;
+    }
+    bool loaded= load_ini_config_file(config_file_name, new_config_data);
+    bool publish_successful= true;
+    if (loaded)
+    {
+        module_logger().debug() << "new_config_data.empty(): " << new_config_data.empty();
+        // save old data
+        old_config_data.swap( config_data );
+        // and install the new data
+        new_config_data.swap( config_data );
+
+        // react on the config: publish the values:
+        publish_successful = feedEm( old_config_data );
+    }
+    return loaded and publish_successful;
+} // reload()
+
+
+
+
+/**
+ * @brief sets the path of the config file and loads it.
+ * @param path the path to the config file.
+ * @return @a true iff the config could be loaded and all values pushed into their config vars.
+ */
+bool set_config_file(const std::string& path)
+{
+    if (not config_file_name.empty())
+    {
+        // WTF?!...
+        // a new config file.. well... why not?
+    }
+    Stat stat(path);
+    if (not stat or not stat.is_regular_file())
+    {
+        return false;
+    }
+    config_file_name= path;
+    return reload();
+} // eo set_config_file(const std::string&)
+
+
+/**
+ * @brief returns the current config file path.
+ * @return the current path.
+ */
+std::string get_config_file()
+{
+    return config_file_name;
+} // eo get_config_file()
+
+
+} // eo namespace config
+
+} // eo namespace I2n
diff --git a/configlib/i2n_global_config.hpp b/configlib/i2n_global_config.hpp
new file mode 100644 (file)
index 0000000..82a03ac
--- /dev/null
@@ -0,0 +1,454 @@
+/** @file
+ * @brief provides config file reading and automatic propagation of the values.
+ *
+ * @author Reinhard Pfau \<Reinhard.Pfau@intra2net.com\>
+ * 
+ * @copyright &copy; Copyright 2008 by Intra2net AG
+ * @license commercial
+ * @contact info@intra2net.com
+ *
+ * Basic idea of this module is that one need only to declare its config vars of
+ * the type Config::Var\< T \> and pass the desired section and key from the
+ * (INI style) config file where the value for this var should be searched.
+ * The string value from the config file is converted to the desired type using a
+ * converter class (a default is provided and uses a conversion based on string_to template
+ * from libi2ncommon).
+ *
+ * Populating the var is automagically done when the config is read or reread or when
+ * the variable is defined.
+ *
+ *
+ * @todo review. consolidate. beautify.
+ * @todo the converter should be better named as "validator" since they do not only convert...
+ * @todo support for std::set<> ?
+ */
+
+#ifndef __I2N_GLOBAL_CONFIG_HPP__
+#define __I2N_GLOBAL_CONFIG_HPP__
+
+#include <string>
+#include <functional>
+#include <vector>
+#include <list>
+#include <ostream>
+#include <sstream>
+#include <stringfunc.hxx>
+#include <boost/shared_ptr.hpp>
+#include <boost/static_assert.hpp>
+#include <boost/type_traits.hpp>
+#include <boost/function.hpp>
+#include <boost/bind.hpp>
+#include <boost/foreach.hpp>
+
+
+namespace I2n
+{
+
+namespace Config
+{
+
+template<
+    typename ValueType,
+    class Converter
+>
+class Var;
+
+
+typedef std::vector< std::string > StringList;
+
+/**
+ * @brief contains the "magic" details of the config module
+ * (i.e. all the stuff which must be declared here, but U shouldn't use it!)
+ */
+namespace Detail {
+
+
+typedef boost::function< bool(const std::string&) > FeedFunction;
+typedef boost::function< bool(const StringList&) > FeedFunction2;
+
+
+struct Thing
+{
+    virtual ~Thing() {}
+}; // eo struct Thing
+
+typedef boost::shared_ptr< Thing > FlowerShop;
+
+
+
+
+FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction& feed);
+FlowerShop seymour(const std::string& section, const std::string& key, const FeedFunction2& feed);
+FlowerShop seymour(FlowerShop shop, const FeedFunction& feed);
+FlowerShop seymour(FlowerShop shop, const FeedFunction2& feed);
+
+/*
+** type magics:
+*/
+
+/**
+ * @brief determines if a type is one of the supported list containers.
+ * @tparam Container the type to test for supported list type.
+ *
+ * currently we support std::list<> and std::vector<> (and derivates).
+ */
+template< class Container >
+struct is_list_container
+{
+    static Container gen();
+
+    template< typename T >
+    static boost::type_traits::yes_type c1( const std::vector< T >& );
+
+    template< typename T >
+    static boost::type_traits::yes_type c1( const std::list< T >& );
+
+    static boost::type_traits::no_type c1(...);
+
+    BOOST_STATIC_CONSTANT( bool, value= ( sizeof(c1(gen())) == sizeof(boost::type_traits::yes_type) ) );
+};
+
+
+template< class C, bool is_list >
+struct extract_type_impl
+{
+    typedef typename boost::remove_reference< typename boost::remove_const< C >::type>::type type;
+};
+
+template< class C >
+struct extract_type_impl< C, true >
+{
+    typedef typename boost::remove_reference<
+        typename boost::remove_const< typename C::value_type >::type
+    >::type type;
+};
+
+template< class C >
+struct extract_type
+: public extract_type_impl< C, is_list_container< C >::value >
+{
+};
+
+
+/*
+**
+*/
+
+template<
+    typename ValueType,
+    class Converter,
+    bool wantList
+>
+class OuterSpace
+{
+    public:
+        typedef ValueType result_type;
+        typedef typename boost::remove_reference< ValueType >::type unref_value_type;
+        typedef typename boost::remove_const< unref_value_type>::type base_value_type;
+        typedef typename boost::add_const<
+            typename boost::add_reference< base_value_type >::type
+        >::type const_ref_value_type;
+
+        typedef FeedFunction FeedFunctionType;
+
+    protected:
+        friend class Var<ValueType, Converter>;
+
+        OuterSpace(ValueType initial_value)
+        : Value(initial_value)
+        , InitialValue(initial_value)
+        {
+        }
+
+        OuterSpace(const OuterSpace& other)
+        : Value( other.Value)
+        , InitialValue( other.InitialValue)
+        {
+        }
+
+        bool audreyII(const std::string& v)
+        {
+            bool res= Converter()(v,Value);
+            if (!res) Value= InitialValue;
+            return res;
+        } // eo audreyII(const std::string&)
+
+        base_value_type Value;
+        base_value_type InitialValue;
+}; // eo class OuterSpace
+
+
+template<
+    typename ValueType,
+    class Converter
+>
+class OuterSpace< ValueType, Converter, true >
+{
+    public:
+        typedef ValueType result_type;
+        typedef typename boost::remove_reference< ValueType >::type unref_value_type;
+        typedef typename boost::remove_const< unref_value_type>::type base_value_type;
+        typedef typename boost::add_const<
+            typename boost::add_reference< base_value_type >::type
+        >::type const_ref_value_type;
+
+        typedef FeedFunction2 FeedFunctionType;
+
+    protected:
+        friend class Var<ValueType, Converter>;
+
+        OuterSpace(ValueType initial_value)
+        : Value(initial_value)
+        , InitialValue(initial_value)
+        {
+        }
+
+        bool audreyII(const StringList& v)
+        {
+            Converter convert;
+            Value.clear();
+            bool res= true;
+            BOOST_FOREACH(const std::string& s, v)
+            {
+                typename base_value_type::value_type value;
+                if (not convert(s,value))
+                {
+                    res = false;
+                    break;
+                }
+                Value.push_back( value );
+            }
+            if (not res) Value= InitialValue;
+            return res;
+        } // eo audreyII(const std::string&)
+
+        base_value_type Value;
+        base_value_type InitialValue;
+}; // eo class OuterSpace
+
+} // eo namespace Detail
+
+
+/**
+ * @brief default converter for the Var class.
+ * @tparam ValueType the type of the result value (which the input should be converted to)
+ *
+ * Uses stringTo to convert the values.
+ *
+ * @see i2n::stringTo
+ */
+template<
+    typename ValueType
+>
+struct DefaultConverter
+: public std::binary_function< std::string, ValueType&, bool >
+{
+
+    bool operator () ( const std::string& str, ValueType& v )
+    {
+        return string_to< ValueType >( str, v );
+    } // eo operator()(const std::string&,ValueType&)
+
+}; // eo struct DefaultConverter
+
+
+/**
+ * @brief specialized converter for std::string result type.
+ *
+ * just copies the input to the result var and returns true.
+ */
+template<> struct DefaultConverter< std::string >
+: public std::binary_function< std::string, std::string&, bool >
+{
+
+    bool operator () ( const std::string& str, std::string& v )
+    {
+        v= str;
+        return true;
+    } // eo operator()(const std::string&,std::string&)
+
+};  // eo struct DefaultConverter< std::string >
+
+
+
+/**
+ * @brief specialized converter for int types which accepts also octal and hex notation as input.
+ * @tparam ValueType the type of the result value (which the input should be converted to)
+ */
+template<
+    typename ValueType
+>
+struct AutoIntConverter
+: public std::binary_function< std::string, ValueType&, bool >
+{
+
+    bool operator () ( const std::string& str, ValueType& v )
+    {
+        std::istringstream istr(str);
+        if (has_prefix(str,"0x"))
+        {
+            istr.get(); istr.get();
+            istr.setf( std::ios::hex, std::ios::basefield );
+        }
+        else if (has_prefix(str,"0") or has_prefix(str,"-0"))
+        {
+            istr.setf( std::ios::oct, std::ios::basefield );
+        }
+        istr >> v;
+        return istr.eof();
+    } // eo operator()(const std::string&,ValueType&)
+
+}; // eo struct AutoIntConverter
+
+
+
+/**
+ * @brief represents a configuration variable with automatic update.
+ * @tparam ValueType type of the value this variable should hold.
+ * @tparam Converter a converter class which converts a string (from config file) to the desired
+ * type.
+ * Needs to be derived from std::binary_function (taking a string as first arg, a reference to the
+ * desired type as second and returning bool (@a true if conversion was succesful).
+ *
+ * Basic idea is to pass a point (section, key) in the config where the value for this
+ * variable is stored. The config value (a string) should be converted to the desired value (type).
+ * When the config is loaded (or reloaded) the var (content) is automatically updated.
+ *
+ * @see DefaultConverter
+ *
+ * @bug value accessing methods are @a const, but the result type may allow changing the internal value...
+ */
+template<
+    typename ValueType,
+    class Converter = DefaultConverter<
+        typename Detail::extract_type< ValueType >::type
+    >
+>
+class Var
+: public Detail::OuterSpace<
+    ValueType, Converter,
+    Detail::is_list_container< ValueType >::value >
+{
+        BOOST_STATIC_ASSERT(( boost::is_base_of<
+            std::binary_function<
+                std::string,
+                typename boost::add_reference<
+                    typename Detail::extract_type< ValueType >::type
+                >::type,
+                bool >,
+            Converter >::value ));
+
+        typedef Detail::OuterSpace<
+            ValueType, Converter,
+            Detail::is_list_container< ValueType >::value
+        > MySpace;
+
+    public:
+
+        typedef typename MySpace::result_type result_type;
+        typedef typename MySpace::base_value_type base_value_type;
+
+    public:
+
+        /**
+         * @brief constructor with config location and initial value.
+         * @param section the section in the config where the value is located in.
+         * @param key the key (in the section) which identifies the value.
+         * @param initial_value the initial value.
+         */
+        Var(const std::string& section,
+            const std::string& key,
+            ValueType initial_value)
+        : MySpace(initial_value)
+        {
+            FlowerShop= Detail::seymour(
+                section, key,
+                typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) );
+        }
+
+
+        /**
+         * @brief constructor with config location (key in global section) and initial value.
+         * @param key the key (in the global section) which identifies the value.
+         * @param initial_value the initial value.
+         */
+        Var(const std::string& key,
+            ValueType initial_value)
+        : MySpace(initial_value)
+        {
+            FlowerShop= Detail::seymour(
+                "", key,
+                typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) );
+        }
+
+
+        /**
+         * @brief operator for accessing the value.
+         * @return the current value.
+         */
+        result_type operator()() const { return MySpace::Value; }
+
+
+        /**
+         * @brief method for accessing the value.
+         * @return the current value.
+         */
+        result_type get_value() const { return MySpace::Value; }
+
+
+        /**
+         * @brief copy constructor.
+         * @param other the instance to copy from.
+         */
+        Var(const Var& other)
+        : MySpace( other )
+        {
+            FlowerShop= Detail::seymour(
+                other.FlowerShop,
+                typename MySpace::FeedFunctionType( boost::bind( &MySpace::audreyII, this, _1 ) ) );
+        } // eo Var(const Var&)
+
+
+        /**
+         * @brief cast operator for the underlying value type. delivers the value.
+         * @return the current value.
+         *
+         * The cast operator allows the instance to be used whereever the underlying value type
+         * is expected.
+         */
+        operator result_type () const { return MySpace::Value; }
+
+
+    private:
+
+        Detail::FlowerShop FlowerShop;
+
+}; // eo class Var
+
+
+
+/**
+ * @brief convenience: \<\< operator which streams the current value of a config var.
+ */
+template <
+    typename ValueType,
+    class Converter
+>
+std::ostream& operator<<(std::ostream& o, const Var< ValueType, Converter >& v)
+{
+    return o << v();
+} // eo operator<<(std::ostream&,const Var< ValueType, Converter>&
+
+
+bool set_config_file(const std::string& path);
+
+std::string get_config_file();
+
+bool reload();
+
+
+} // eo namespace Config
+
+} // eo namespace I2n
+
+#endif
index f14562c..0dfdac1 100644 (file)
@@ -35,4 +35,5 @@ AC_SUBST(LIBICONV_LIBS)
 
 AM_PATH_CPPUNIT(1.8.0)
 
-AC_OUTPUT(Doxyfile Makefile src/Makefile libi2ncommon.pc test/Makefile)
+AC_OUTPUT(Doxyfile Makefile configlib/Makefile libi2ncommon.pc src/Makefile \
+       test/Makefile libi2ncommon_config.pc)
index 21a94d4..9235b41 100644 (file)
@@ -26,6 +26,18 @@ Requires: boost-devel >= 1.32.0
 %description devel
 library with functions common in Intra2net programs
 
+
+%package config
+Summary:    library with a config module
+Group:      Intranator
+Requires:   libi2ncommon = %{version}
+
+%description config
+library with a config module.
+The config module provides a global configuration system with decentralized
+declaration of the config variables.
+
+
 %prep
 %setup -q
 
@@ -57,3 +69,9 @@ rm -fr $RPM_BUILD_ROOT
 %{prefix}/lib/*.*a*
 %{prefix}/lib/pkgconfig/*.pc
 %{prefix}/include/
+
+%files config
+%defattr(-,root,root)
+%doc LICENSE
+%{prefix}/lib/libi2ncommon_config.so*
+
diff --git a/libi2ncommon_config.pc.in b/libi2ncommon_config.pc.in
new file mode 100644 (file)
index 0000000..307000f
--- /dev/null
@@ -0,0 +1,11 @@
+prefix=@prefix@
+exec_prefix=@exec_prefix@
+libdir=@libdir@
+includedir=@includedir@
+
+Name: libi2ncommon_config
+Description: library with config module common in some Intra2net programs
+Requires: libi2ncommon
+Version: @VERSION@
+Libs: -L${libdir} -li2ncommon_config
+Cflags: -I${includedir}