diff --git a/src/utils/configuration.cpp b/src/utils/configuration.cpp index 28deee8..bd1ccf0 100644 --- a/src/utils/configuration.cpp +++ b/src/utils/configuration.cpp @@ -9,6 +9,7 @@ #include #include +#include #define epicsExportSharedSymbols #include @@ -139,105 +140,63 @@ void Properties::list() } } -SystemConfigurationImpl::SystemConfigurationImpl() : - _properties(new Properties()) +bool Configuration::getPropertyAsBoolean(const std::string &name, const bool defaultValue) const { - // no exception, default value is taken - //_ibuffer.exceptions ( ifstream::failbit | ifstream::badbit ); - //_obuffer.exceptions ( ifstream::failbit | ifstream::badbit ); -} + string value = getPropertyAsString(name, defaultValue ? "1" : "0"); + std::transform(value.begin(), value.end(), value.begin(), ::tolower); -SystemConfigurationImpl::~SystemConfigurationImpl() -{ -} - -bool SystemConfigurationImpl::getPropertyAsBoolean(const string &name, const bool defaultValue) -{ - /* - bool retval; - _ibuffer.clear(); - _obuffer.clear(); - _obuffer.str(""); - _obuffer << defaultValue; - _ibuffer.str(getPropertyAsString(name,_obuffer.str())); - _ibuffer >> retval; - if (_ibuffer.fail() || _ibuffer.bad()) - return defaultValue; - else - return retval; - */ - - string value = getPropertyAsString(name, defaultValue ? "1" : "0"); - std::transform(value.begin(), value.end(), value.begin(), ::tolower); - - bool isTrue = (value == "1") || (value == "true") || (value == "yes"); + bool isTrue = (value == "1") || (value == "true") || (value == "yes"); if (isTrue) return true; - bool isFalse = (value == "0") || (value == "false") || (value == "no"); + bool isFalse = (value == "0") || (value == "false") || (value == "no"); if (isFalse) return false; - // invalid value + // invalid value return defaultValue; } -int32 SystemConfigurationImpl::getPropertyAsInteger(const string &name, const int32 defaultValue) +epics::pvData::int32 Configuration::getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) const { - int32 retval = defaultValue; - _ibuffer.clear(); - _obuffer.clear(); - _obuffer.str(""); - _obuffer << defaultValue; - _ibuffer.str(getPropertyAsString(name, _obuffer.str())); - _ibuffer >> retval; - if (_ibuffer.fail() || _ibuffer.bad()) + epicsInt32 ret; + std::string val(getPropertyAsString(name, "")); + + if(epicsParseInt32(val.c_str(), &ret, 0, NULL)) return defaultValue; - else - return retval; + return ret; } -float SystemConfigurationImpl::getPropertyAsFloat(const string &name, const float defaultValue) +float Configuration::getPropertyAsFloat(const std::string &name, const float defaultValue) const { - float retval; - _ibuffer.clear(); - _obuffer.clear(); - _obuffer.str(""); - _obuffer << defaultValue; - _ibuffer.str(getPropertyAsString(name, _obuffer.str())); - _ibuffer >> retval; - if (_ibuffer.fail() || _ibuffer.bad()) + float ret; + std::string val(getPropertyAsString(name, "")); + + if(epicsParseFloat(val.c_str(), &ret, NULL)) return defaultValue; - else - return retval; + return ret; } -float SystemConfigurationImpl::getPropertyAsDouble(const string &name, const double defaultValue) +double Configuration::getPropertyAsDouble(const std::string &name, const double defaultValue) const { - float retval; - _ibuffer.clear(); - _obuffer.clear(); - _obuffer.str(""); - _obuffer << defaultValue; - _ibuffer.str(getPropertyAsString(name, _obuffer.str())); - _ibuffer >> retval; - if (_ibuffer.fail() || _ibuffer.bad()) + double ret; + std::string val(getPropertyAsString(name, "")); + + if(epicsParseDouble(val.c_str(), &ret, NULL)) return defaultValue; - else - return retval; + return ret; } -string SystemConfigurationImpl::getPropertyAsString(const string &name, const string &defaultValue) +std::string Configuration::getPropertyAsString(const std::string &name, const std::string &defaultValue) const { - const char* val = getenv(name.c_str()); - if(val != NULL) - { - return _properties->getProperty(name, string(val)); - } - return _properties->getProperty(name, defaultValue); + std::string val; + if(tryGetPropertyAsString(name, &val)) + return val; + else + return defaultValue; } -bool SystemConfigurationImpl::getPropertyAsAddress(const std::string& name, osiSockAddr* addr) +bool Configuration::getPropertyAsAddress(const std::string& name, osiSockAddr* addr) const { unsigned short dftport=0; if(addr->sa.sa_family==AF_INET) @@ -253,19 +212,41 @@ bool SystemConfigurationImpl::getPropertyAsAddress(const std::string& name, osiS return true; } -bool SystemConfigurationImpl::hasProperty(const string &key) +bool Configuration::hasProperty(const std::string &name) const { - const char* val = getenv(key.c_str()); - return (val != NULL) || _properties->hasProperty(key); + return tryGetPropertyAsString(name, NULL); } -ConfigurationProviderImpl::ConfigurationProviderImpl() +bool ConfigurationMap::tryGetPropertyAsString(const std::string& name, std::string* val) const { - + properties_t::const_iterator it = properties.find(name); + if(it==properties.end()) + return false; + if(val) + *val = it->second; + return true; } -ConfigurationProviderImpl::~ConfigurationProviderImpl() +bool ConfigurationEnviron::tryGetPropertyAsString(const std::string& name, std::string* val) const { + const char *env = getenv(name.c_str()); + if(!env || !*env) + return false; + if(val) + *val = env; + return true; +} + +bool ConfigurationStack::tryGetPropertyAsString(const std::string& name, std::string* val) const +{ + for(confs_t::const_reverse_iterator it = confs.rbegin(), end = confs.rend(); + it!=end; ++it) + { + Configuration& conf = **it; + if(conf.tryGetPropertyAsString(name, val)) + return true; + } + return false; } void ConfigurationProviderImpl::registerConfiguration(const string &name, Configuration::shared_pointer const & configuration) diff --git a/src/utils/configuration.h b/src/utils/configuration.h index 555cbc5..5b4fb60 100644 --- a/src/utils/configuration.h +++ b/src/utils/configuration.h @@ -39,8 +39,8 @@ namespace pvAccess { class epicsShareClass Properties { public: - Properties(); - Properties(const std::string &fileName); + Properties() EPICS_DEPRECATED; + Properties(const std::string &fileName) EPICS_DEPRECATED; inline void setProperty(const std::string &key,const std::string &value) { _properties[key] = value; } @@ -57,14 +57,16 @@ public: void load(std::istream& strm); void list(); - size_t size() const {return _properties.size();} + inline size_t size() const {return _properties.size();} private: typedef std::map _properties_t; _properties_t _properties; std::string _fileName; +public: + inline const _properties_t& map() const {return _properties;} }; - +class ConfigurationStack; /** * Configuration @@ -87,7 +89,7 @@ public: * * @return environment variable value as bool or default value if it does not exist. */ - virtual bool getPropertyAsBoolean(const std::string &name, const bool defaultValue) = 0; + bool getPropertyAsBoolean(const std::string &name, const bool defaultValue) const; /** * Get the environment variable specified by name or return default value * if it does not exist. @@ -97,7 +99,7 @@ public: * * @return environment variable value as int32 or default value if it does not exist. */ - virtual epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) = 0; + epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue) const; /** * Get the environment variable specified by name or return default value * if it does not exist. @@ -107,7 +109,7 @@ public: * * @return environment variable value as float or default value if it does not exist. */ - virtual float getPropertyAsFloat(const std::string &name, const float defaultValue) = 0; + float getPropertyAsFloat(const std::string &name, const float defaultValue) const; /** * Get the environment variable specified by name or return default value * if it does not exist. @@ -117,7 +119,7 @@ public: * * @return environment variable value as double or default value if it does not exist. */ - virtual float getPropertyAsDouble(const std::string &name, const double defaultValue) = 0; + double getPropertyAsDouble(const std::string &name, const double defaultValue) const; /** * Get the environment variable specified by name or return default value * if it does not exist. @@ -127,7 +129,7 @@ public: * * @return environment variable value as std::string or default value if it does not exist. */ - virtual std::string getPropertyAsString(const std::string &name, const std::string &defaultValue) = 0; + std::string getPropertyAsString(const std::string &name, const std::string &defaultValue) const; /** * Fetch and parse as a socket address and port number (address family set accordingly). * At present only numeric addresses are parsed (eg. "127.0.0.1:4242"). @@ -138,28 +140,53 @@ public: * @pram addr pointer to the address struct to be filled in * @return true if addr now contains an address, false otherwise */ - virtual bool getPropertyAsAddress(const std::string& name, osiSockAddr* addr) = 0; + bool getPropertyAsAddress(const std::string& name, osiSockAddr* addr) const; - virtual bool hasProperty(const std::string &name) = 0; + bool hasProperty(const std::string &name) const; + +protected: + friend class ConfigurationStack; + virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const = 0; }; -class epicsShareClass SystemConfigurationImpl: public Configuration +//! Lookup configuration strings from an in memory store +class epicsShareClass ConfigurationMap: public Configuration { public: - SystemConfigurationImpl(); - ~SystemConfigurationImpl(); - bool getPropertyAsBoolean(const std::string &name, const bool defaultValue); - epics::pvData::int32 getPropertyAsInteger(const std::string &name, const epics::pvData::int32 defaultValue); - float getPropertyAsFloat(const std::string &name, const float defaultValue); - float getPropertyAsDouble(const std::string &name, const double defaultValue); - std::string getPropertyAsString(const std::string &name, const std::string &defaultValue); - bool getPropertyAsAddress(const std::string& name, osiSockAddr* addr); - bool hasProperty(const std::string &name); - std::auto_ptr _properties; + typedef std::map properties_t; + properties_t properties; private: - std::istringstream _ibuffer; - std::ostringstream _obuffer; + virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const; +}; +//! Lookup configuration strings from the process environment +class epicsShareClass ConfigurationEnviron: public Configuration +{ +private: + virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const; +}; + +typedef ConfigurationEnviron SystemConfigurationImpl; + +//! Lookup configuration strings from a heap of sub-Configurations. +//! Most recently push'd is checked first. +class epicsShareClass ConfigurationStack : public Configuration +{ + typedef std::vector > confs_t; + confs_t confs; + virtual bool tryGetPropertyAsString(const std::string& name, std::string* val) const; +public: + inline void push_back(const confs_t::value_type& conf) { + confs.push_back(conf); + } + inline confs_t::value_type pop_back() { + if(confs.empty()) + throw std::runtime_error("Stack empty"); + confs_t::value_type ret(confs.back()); + confs.pop_back(); + return ret; + } + inline size_t size() const {return confs.size();} }; /** @@ -193,11 +220,11 @@ public: class ConfigurationProviderImpl: public ConfigurationProvider { public: - ConfigurationProviderImpl(); + ConfigurationProviderImpl() {} /** * Destructor. Note: Registered configurations will be deleted!! */ - ~ConfigurationProviderImpl(); + ~ConfigurationProviderImpl() {} Configuration::shared_pointer getConfiguration(const std::string &name); void registerConfiguration(const std::string &name, Configuration::shared_pointer const & configuration); private: