From c7863f2a7b01debee664d24ebd7fd61e56dd7d12 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Thu, 7 Mar 2024 14:09:47 -0500 Subject: [PATCH 1/5] Initial Properties refactoring --- cpp/include/Ice/Communicator.h | 5 ++- cpp/include/Ice/Properties.h | 81 ++++++++++------------------------ cpp/src/Ice/Properties.cpp | 4 +- cpp/src/Ice/PropertiesI.cpp | 40 ++++++++--------- cpp/src/Ice/PropertiesI.h | 42 +++++++++--------- 5 files changed, 69 insertions(+), 103 deletions(-) diff --git a/cpp/include/Ice/Communicator.h b/cpp/include/Ice/Communicator.h index eaa716ffb52..86fb1801e09 100644 --- a/cpp/include/Ice/Communicator.h +++ b/cpp/include/Ice/Communicator.h @@ -13,11 +13,14 @@ #include "Initialize.h" #include "PluginF.h" #include "Properties.h" -#include "ProxyF.h" +#include "Proxy.h" namespace Ice { +class LocatorPrx; +class RouterPrx; + /** * The central object in Ice. One or more communicators can be instantiated for an Ice application. * @see Logger diff --git a/cpp/include/Ice/Properties.h b/cpp/include/Ice/Properties.h index 0d750707652..2e4361f5b13 100644 --- a/cpp/include/Ice/Properties.h +++ b/cpp/include/Ice/Properties.h @@ -2,42 +2,16 @@ // Copyright (c) ZeroC, Inc. All rights reserved. // -#ifndef __Ice_Properties_h__ -#define __Ice_Properties_h__ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#ifndef ICE_API -# if defined(ICE_STATIC_LIBS) -# define ICE_API /**/ -# elif defined(ICE_API_EXPORTS) -# define ICE_API ICE_DECLSPEC_EXPORT -# else -# define ICE_API ICE_DECLSPEC_IMPORT -# endif -#endif - -namespace Ice -{ +#ifndef ICE_PROPERTIES_H +#define ICE_PROPERTIES_H -class Properties; +#include "Config.h" +#include "Ice/BuiltinSequences.h" +#include "Ice/PropertyDict.h" -} +#include +#include -/// \cond INTERNAL namespace Ice { @@ -47,11 +21,11 @@ namespace Ice * application-name[.category[.sub-category]].name. * \headerfile Ice/Ice.h */ -class ICE_CLASS(ICE_API) Properties +class ICE_API Properties { public: - ICE_MEMBER(ICE_API) virtual ~Properties(); + virtual ~Properties() = default; /** * Get a property by key. If the property is not set, an empty string is returned. @@ -59,7 +33,7 @@ class ICE_CLASS(ICE_API) Properties * @return The property value. * @see #setProperty */ - virtual ::std::string getProperty(const ::std::string& key) noexcept = 0; + virtual std::string getProperty(std::string_view key) noexcept = 0; /** * Get a property by key. If the property is not set, the given default value is returned. @@ -68,7 +42,7 @@ class ICE_CLASS(ICE_API) Properties * @return The property value or the default value. * @see #setProperty */ - virtual ::std::string getPropertyWithDefault(const ::std::string& key, const ::std::string& value) noexcept = 0; + virtual std::string getPropertyWithDefault(std::string_view key, std::string_view value) noexcept = 0; /** * Get a property as an integer. If the property is not set, 0 is returned. @@ -76,7 +50,7 @@ class ICE_CLASS(ICE_API) Properties * @return The property value interpreted as an integer. * @see #setProperty */ - virtual int getPropertyAsInt(const ::std::string& key) noexcept = 0; + virtual int getPropertyAsInt(std::string_view key) noexcept = 0; /** * Get a property as an integer. If the property is not set, the given default value is returned. @@ -85,7 +59,7 @@ class ICE_CLASS(ICE_API) Properties * @return The property value interpreted as an integer, or the default value. * @see #setProperty */ - virtual int getPropertyAsIntWithDefault(const ::std::string& key, int value) noexcept = 0; + virtual int getPropertyAsIntWithDefault(std::string_view key, int value) noexcept = 0; /** * Get a property as a list of strings. The strings must be separated by whitespace or comma. If the property is @@ -97,7 +71,7 @@ class ICE_CLASS(ICE_API) Properties * @return The property value interpreted as a list of strings. * @see #setProperty */ - virtual ::Ice::StringSeq getPropertyAsList(const ::std::string& key) noexcept = 0; + virtual StringSeq getPropertyAsList(std::string_view key) noexcept = 0; /** * Get a property as a list of strings. The strings must be separated by whitespace or comma. If the property is @@ -110,7 +84,7 @@ class ICE_CLASS(ICE_API) Properties * @return The property value interpreted as list of strings, or the default value. * @see #setProperty */ - virtual ::Ice::StringSeq getPropertyAsListWithDefault(const ::std::string& key, const StringSeq& value) noexcept = 0; + virtual StringSeq getPropertyAsListWithDefault(std::string_view key, const StringSeq& value) noexcept = 0; /** * Get all properties whose keys begins with prefix. If prefix is an empty string, then all @@ -118,7 +92,7 @@ class ICE_CLASS(ICE_API) Properties * @param prefix The prefix to search for (empty string if none). * @return The matching property set. */ - virtual ::Ice::PropertyDict getPropertiesForPrefix(const ::std::string& prefix) noexcept = 0; + virtual PropertyDict getPropertiesForPrefix(std::string_view prefix) noexcept = 0; /** * Set a property. To unset a property, set it to the empty string. @@ -126,14 +100,14 @@ class ICE_CLASS(ICE_API) Properties * @param value The property value. * @see #getProperty */ - virtual void setProperty(const ::std::string& key, const ::std::string& value) = 0; + virtual void setProperty(std::string_view key, std::string_view value) = 0; /** * Get a sequence of command-line options that is equivalent to this property set. Each element of the returned * sequence is a command-line option of the form --key=value. * @return The command line options for this property set. */ - virtual ::Ice::StringSeq getCommandLineOptions() noexcept = 0; + virtual StringSeq getCommandLineOptions() noexcept = 0; /** * Convert a sequence of command-line options into properties. All options that begin with @@ -143,7 +117,7 @@ class ICE_CLASS(ICE_API) Properties * @param options The command-line options. * @return The command-line options that do not start with the specified prefix, in their original order. */ - virtual ::Ice::StringSeq parseCommandLineOptions(const ::std::string& prefix, const StringSeq& options) = 0; + virtual StringSeq parseCommandLineOptions(std::string_view prefix, const StringSeq& options) = 0; /** * Convert a sequence of command-line options into properties. All options that begin with one of the following @@ -152,32 +126,23 @@ class ICE_CLASS(ICE_API) Properties * @param options The command-line options. * @return The command-line options that do not start with one of the listed prefixes, in their original order. */ - virtual ::Ice::StringSeq parseIceCommandLineOptions(const StringSeq& options) = 0; + virtual StringSeq parseIceCommandLineOptions(const StringSeq& options) = 0; /** * Load properties from a file. * @param file The property file. */ - virtual void load(const ::std::string& file) = 0; + virtual void load(std::string_view file) = 0; /** * Create a copy of this property set. * @return A copy of this property set. */ - virtual ::std::shared_ptr<::Ice::Properties> clone() noexcept = 0; + virtual std::shared_ptr clone() noexcept = 0; }; -} -/// \endcond - -/// \cond INTERNAL -namespace Ice -{ - -using PropertiesPtr = ::std::shared_ptr; +using PropertiesPtr = std::shared_ptr; } -/// \endcond -#include #endif diff --git a/cpp/src/Ice/Properties.cpp b/cpp/src/Ice/Properties.cpp index 46afc599341..074354a0dbe 100644 --- a/cpp/src/Ice/Properties.cpp +++ b/cpp/src/Ice/Properties.cpp @@ -4,6 +4,4 @@ #include -Ice::Properties::~Properties() -{ -} +// empty for now diff --git a/cpp/src/Ice/PropertiesI.cpp b/cpp/src/Ice/PropertiesI.cpp index 85d962e9b2a..7e2db682f4b 100644 --- a/cpp/src/Ice/PropertiesI.cpp +++ b/cpp/src/Ice/PropertiesI.cpp @@ -18,7 +18,7 @@ using namespace Ice; using namespace IceInternal; string -Ice::PropertiesI::getProperty(const string& key) noexcept +Ice::PropertiesI::getProperty(string_view key) noexcept { lock_guard lock(_mutex); @@ -30,12 +30,12 @@ Ice::PropertiesI::getProperty(const string& key) noexcept } else { - return string(); + return string{}; } } string -Ice::PropertiesI::getPropertyWithDefault(const string& key, const string& value) noexcept +Ice::PropertiesI::getPropertyWithDefault(string_view key, string_view value) noexcept { lock_guard lock(_mutex); @@ -47,18 +47,18 @@ Ice::PropertiesI::getPropertyWithDefault(const string& key, const string& value) } else { - return value; + return string{value}; } } int32_t -Ice::PropertiesI::getPropertyAsInt(const string& key) noexcept +Ice::PropertiesI::getPropertyAsInt(string_view key) noexcept { return getPropertyAsIntWithDefault(key, 0); } int32_t -Ice::PropertiesI::getPropertyAsIntWithDefault(const string& key, int32_t value) noexcept +Ice::PropertiesI::getPropertyAsIntWithDefault(string_view key, int32_t value) noexcept { lock_guard lock(_mutex); @@ -80,13 +80,13 @@ Ice::PropertiesI::getPropertyAsIntWithDefault(const string& key, int32_t value) } Ice::StringSeq -Ice::PropertiesI::getPropertyAsList(const string& key) noexcept +Ice::PropertiesI::getPropertyAsList(string_view key) noexcept { return getPropertyAsListWithDefault(key, StringSeq()); } Ice::StringSeq -Ice::PropertiesI::getPropertyAsListWithDefault(const string& key, const StringSeq& value) noexcept +Ice::PropertiesI::getPropertyAsListWithDefault(string_view key, const StringSeq& value) noexcept { lock_guard lock(_mutex); @@ -114,7 +114,7 @@ Ice::PropertiesI::getPropertyAsListWithDefault(const string& key, const StringSe } PropertyDict -Ice::PropertiesI::getPropertiesForPrefix(const string& prefix) noexcept +Ice::PropertiesI::getPropertiesForPrefix(string_view prefix) noexcept { lock_guard lock(_mutex); @@ -132,12 +132,12 @@ Ice::PropertiesI::getPropertiesForPrefix(const string& prefix) noexcept } void -Ice::PropertiesI::setProperty(const string& key, const string& value) +Ice::PropertiesI::setProperty(string_view key, string_view value) { // // Trim whitespace // - string currentKey = IceUtilInternal::trim(key); + string currentKey = IceUtilInternal::trim(string{key}); if(currentKey.empty()) { throw InitializationException(__FILE__, __LINE__, "Attempt to set property with empty key"); @@ -244,9 +244,9 @@ Ice::PropertiesI::getCommandLineOptions() noexcept } StringSeq -Ice::PropertiesI::parseCommandLineOptions(const string& prefix, const StringSeq& options) +Ice::PropertiesI::parseCommandLineOptions(string_view prefix, const StringSeq& options) { - string pfx = prefix; + string pfx = string{prefix}; if(!pfx.empty() && pfx[pfx.size() - 1] != '.') { pfx += '.'; @@ -288,7 +288,7 @@ Ice::PropertiesI::parseIceCommandLineOptions(const StringSeq& options) } void -Ice::PropertiesI::load(const std::string& file) +Ice::PropertiesI::load(string_view file) { StringConverterPtr stringConverter = getProcessStringConverter(); @@ -369,7 +369,7 @@ Ice::PropertiesI::load(const std::string& file) static_cast(expandedValue.size())) == 0) { ostringstream os; - os << "could not expand variable in property `" << name << "', key: `" + file + "':\n"; + os << "could not expand variable in property `" << name << "', key: `" + string{file} + "':\n"; os << IceUtilInternal::lastErrorToString(); getProcessLogger()->warning(os.str()); continue; @@ -390,10 +390,10 @@ Ice::PropertiesI::load(const std::string& file) else #endif { - ifstream in(IceUtilInternal::streamFilename(file).c_str()); + ifstream in(IceUtilInternal::streamFilename(string{file}).c_str()); if(!in) { - throw FileException(__FILE__, __LINE__, file); + throw FileException(__FILE__, __LINE__, string{file}); } string line; @@ -522,7 +522,7 @@ Ice::PropertiesI::PropertiesI(StringSeq& args, const PropertiesPtr& defaults) } void -Ice::PropertiesI::parseLine(const string& line, const StringConverterPtr& converter) +Ice::PropertiesI::parseLine(string_view line, const StringConverterPtr& converter) { string key; string value; @@ -679,7 +679,7 @@ Ice::PropertiesI::parseLine(const string& line, const StringConverterPtr& conver if((state == Key && key.length() != 0) || (state == Value && key.length() == 0)) { - getProcessLogger()->warning("invalid config file entry: \"" + line + "\""); + getProcessLogger()->warning("invalid config file entry: \"" + string{line} + "\""); return; } else if(key.length() == 0) @@ -730,7 +730,7 @@ Ice::PropertiesI::loadConfig() IceUtilInternal::splitString(value, ",", files); for(vector::const_iterator i = files.begin(); i != files.end(); ++i) { - load(IceUtilInternal::trim(*i)); + load(IceUtilInternal::trim(string{*i})); } PropertyValue pv(value, true); diff --git a/cpp/src/Ice/PropertiesI.h b/cpp/src/Ice/PropertiesI.h index e70e4060ae4..c4d65474c27 100644 --- a/cpp/src/Ice/PropertiesI.h +++ b/cpp/src/Ice/PropertiesI.h @@ -5,8 +5,8 @@ #ifndef ICE_PROPERTIES_I_H #define ICE_PROPERTIES_I_H -#include -#include +#include "Ice/Properties.h" +#include "Ice/StringConverter.h" #include #include @@ -14,24 +14,24 @@ namespace Ice { -class PropertiesI : public Properties +class PropertiesI final : public Properties { public: - virtual std::string getProperty(const std::string&) noexcept; - virtual std::string getPropertyWithDefault(const std::string&, const std::string&) noexcept; - virtual std::int32_t getPropertyAsInt(const std::string&) noexcept; - virtual std::int32_t getPropertyAsIntWithDefault(const std::string&, std::int32_t) noexcept; - virtual Ice::StringSeq getPropertyAsList(const std::string&) noexcept; - virtual Ice::StringSeq getPropertyAsListWithDefault(const std::string&, const Ice::StringSeq&) noexcept; - - virtual PropertyDict getPropertiesForPrefix(const std::string&) noexcept; - virtual void setProperty(const std::string&, const std::string&); - virtual StringSeq getCommandLineOptions() noexcept; - virtual StringSeq parseCommandLineOptions(const std::string&, const StringSeq&); - virtual StringSeq parseIceCommandLineOptions(const StringSeq&); - virtual void load(const std::string&); - virtual PropertiesPtr clone() noexcept; + std::string getProperty(std::string_view) noexcept final; + std::string getPropertyWithDefault(std::string_view, std::string_view) noexcept final; + std::int32_t getPropertyAsInt(std::string_view) noexcept final; + std::int32_t getPropertyAsIntWithDefault(std::string_view, std::int32_t) noexcept final; + Ice::StringSeq getPropertyAsList(std::string_view) noexcept final; + Ice::StringSeq getPropertyAsListWithDefault(std::string_view, const Ice::StringSeq&) noexcept final; + + PropertyDict getPropertiesForPrefix(std::string_view) noexcept final; + void setProperty(std::string_view, std::string_view) final; + StringSeq getCommandLineOptions() noexcept final; + StringSeq parseCommandLineOptions(std::string_view, const StringSeq&) final; + StringSeq parseIceCommandLineOptions(const StringSeq&) final; + void load(std::string_view) final; + PropertiesPtr clone() noexcept final; std::set getUnusedProperties(); @@ -42,7 +42,7 @@ class PropertiesI : public Properties private: - void parseLine(const std::string&, const StringConverterPtr&); + void parseLine(std::string_view, const StringConverterPtr&); void loadConfig(); @@ -53,8 +53,8 @@ class PropertiesI : public Properties { } - PropertyValue(const std::string& v, bool u) : - value(v), + PropertyValue(std::string_view v, bool u) : + value(std::string{v}), used(u) { } @@ -62,7 +62,7 @@ class PropertiesI : public Properties std::string value; bool used; }; - std::map _properties; + std::map> _properties; std::mutex _mutex; }; From 5c75038d6ffeaa480ade5a6927c1bc7db1cb2b21 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Thu, 7 Mar 2024 14:44:14 -0500 Subject: [PATCH 2/5] Merge Properties and PropertiesI --- cpp/include/Ice/Properties.h | 85 ++- cpp/src/Ice/IPEndpointI.cpp | 2 +- cpp/src/Ice/Initialize.cpp | 6 +- cpp/src/Ice/Instance.cpp | 5 +- cpp/src/Ice/Properties.cpp | 728 ++++++++++++++++++- cpp/src/Ice/PropertiesI.cpp | 739 -------------------- cpp/src/Ice/PropertiesI.h | 71 -- cpp/src/Ice/msbuild/ice/ice.vcxproj | 1 - cpp/src/Ice/msbuild/ice/ice.vcxproj.filters | 3 - 9 files changed, 801 insertions(+), 839 deletions(-) delete mode 100644 cpp/src/Ice/PropertiesI.cpp delete mode 100644 cpp/src/Ice/PropertiesI.h diff --git a/cpp/include/Ice/Properties.h b/cpp/include/Ice/Properties.h index 2e4361f5b13..5515ecded71 100644 --- a/cpp/include/Ice/Properties.h +++ b/cpp/include/Ice/Properties.h @@ -8,9 +8,11 @@ #include "Config.h" #include "Ice/BuiltinSequences.h" #include "Ice/PropertyDict.h" +#include "StringConverter.h" +#include +#include #include -#include namespace Ice { @@ -19,13 +21,33 @@ namespace Ice * A property set used to configure Ice and Ice applications. Properties are key/value pairs, with both keys and * values being strings. By convention, property keys should have the form * application-name[.category[.sub-category]].name. + * This class is thread-safe: multiple threads can safely read and write the properties without their own + * synchronization. * \headerfile Ice/Ice.h */ -class ICE_API Properties +class ICE_API Properties final { public: - virtual ~Properties() = default; + /** + * Default constructor. + */ + Properties() = default; + + /** + * Copy constructor. + * @param source The property set to copy. + */ + Properties(const Properties& source); + + /** + * Constructs a property from command-line arguments and a default property set. + * @param args The command-line arguments. Property arguments are removed from this sequence. + * @param defaults The default property set. + */ + Properties(StringSeq& args, const std::shared_ptr& defaults); + + Properties& operator=(const Properties& rhs) = delete; /** * Get a property by key. If the property is not set, an empty string is returned. @@ -33,7 +55,7 @@ class ICE_API Properties * @return The property value. * @see #setProperty */ - virtual std::string getProperty(std::string_view key) noexcept = 0; + std::string getProperty(std::string_view key) noexcept; /** * Get a property by key. If the property is not set, the given default value is returned. @@ -42,7 +64,7 @@ class ICE_API Properties * @return The property value or the default value. * @see #setProperty */ - virtual std::string getPropertyWithDefault(std::string_view key, std::string_view value) noexcept = 0; + std::string getPropertyWithDefault(std::string_view key, std::string_view value) noexcept; /** * Get a property as an integer. If the property is not set, 0 is returned. @@ -50,7 +72,7 @@ class ICE_API Properties * @return The property value interpreted as an integer. * @see #setProperty */ - virtual int getPropertyAsInt(std::string_view key) noexcept = 0; + int getPropertyAsInt(std::string_view key) noexcept; /** * Get a property as an integer. If the property is not set, the given default value is returned. @@ -59,7 +81,7 @@ class ICE_API Properties * @return The property value interpreted as an integer, or the default value. * @see #setProperty */ - virtual int getPropertyAsIntWithDefault(std::string_view key, int value) noexcept = 0; + int getPropertyAsIntWithDefault(std::string_view key, int value) noexcept; /** * Get a property as a list of strings. The strings must be separated by whitespace or comma. If the property is @@ -71,7 +93,7 @@ class ICE_API Properties * @return The property value interpreted as a list of strings. * @see #setProperty */ - virtual StringSeq getPropertyAsList(std::string_view key) noexcept = 0; + StringSeq getPropertyAsList(std::string_view key) noexcept; /** * Get a property as a list of strings. The strings must be separated by whitespace or comma. If the property is @@ -84,7 +106,7 @@ class ICE_API Properties * @return The property value interpreted as list of strings, or the default value. * @see #setProperty */ - virtual StringSeq getPropertyAsListWithDefault(std::string_view key, const StringSeq& value) noexcept = 0; + StringSeq getPropertyAsListWithDefault(std::string_view key, const StringSeq& value) noexcept; /** * Get all properties whose keys begins with prefix. If prefix is an empty string, then all @@ -92,7 +114,7 @@ class ICE_API Properties * @param prefix The prefix to search for (empty string if none). * @return The matching property set. */ - virtual PropertyDict getPropertiesForPrefix(std::string_view prefix) noexcept = 0; + PropertyDict getPropertiesForPrefix(std::string_view prefix) noexcept; /** * Set a property. To unset a property, set it to the empty string. @@ -100,14 +122,14 @@ class ICE_API Properties * @param value The property value. * @see #getProperty */ - virtual void setProperty(std::string_view key, std::string_view value) = 0; + void setProperty(std::string_view key, std::string_view value); /** * Get a sequence of command-line options that is equivalent to this property set. Each element of the returned * sequence is a command-line option of the form --key=value. * @return The command line options for this property set. */ - virtual StringSeq getCommandLineOptions() noexcept = 0; + StringSeq getCommandLineOptions() noexcept; /** * Convert a sequence of command-line options into properties. All options that begin with @@ -117,7 +139,7 @@ class ICE_API Properties * @param options The command-line options. * @return The command-line options that do not start with the specified prefix, in their original order. */ - virtual StringSeq parseCommandLineOptions(std::string_view prefix, const StringSeq& options) = 0; + StringSeq parseCommandLineOptions(std::string_view prefix, const StringSeq& options); /** * Convert a sequence of command-line options into properties. All options that begin with one of the following @@ -126,19 +148,50 @@ class ICE_API Properties * @param options The command-line options. * @return The command-line options that do not start with one of the listed prefixes, in their original order. */ - virtual StringSeq parseIceCommandLineOptions(const StringSeq& options) = 0; + StringSeq parseIceCommandLineOptions(const StringSeq& options); /** * Load properties from a file. * @param file The property file. */ - virtual void load(std::string_view file) = 0; + void load(std::string_view file); /** * Create a copy of this property set. * @return A copy of this property set. */ - virtual std::shared_ptr clone() noexcept = 0; + std::shared_ptr clone() { return std::make_shared(*this); } + + /** + * Get the properties that were never read. + * @return A list of unused properties. + */ + std::set getUnusedProperties(); + +private: + + void parseLine(std::string_view, const StringConverterPtr&); + + void loadConfig(); + + struct PropertyValue + { + PropertyValue() : + used(false) + { + } + + PropertyValue(std::string_view v, bool u) : + value(std::string{v}), + used(u) + { + } + + std::string value; + bool used; + }; + std::map> _properties; + std::mutex _mutex; }; using PropertiesPtr = std::shared_ptr; diff --git a/cpp/src/Ice/IPEndpointI.cpp b/cpp/src/Ice/IPEndpointI.cpp index 8684702daa5..93a67040e24 100644 --- a/cpp/src/Ice/IPEndpointI.cpp +++ b/cpp/src/Ice/IPEndpointI.cpp @@ -6,7 +6,7 @@ #include #include #include -#include +#include #include #include #include diff --git a/cpp/src/Ice/Initialize.cpp b/cpp/src/Ice/Initialize.cpp index b51210ee3d1..23504b9becc 100644 --- a/cpp/src/Ice/Initialize.cpp +++ b/cpp/src/Ice/Initialize.cpp @@ -4,7 +4,7 @@ #include #include "Ice/Communicator.h" -#include +#include #include #include #include @@ -144,13 +144,13 @@ Ice::stringSeqToArgs(const StringSeq& args, int& argc, const wchar_t* argv[]) PropertiesPtr Ice::createProperties() { - return make_shared(); + return make_shared(); } PropertiesPtr Ice::createProperties(StringSeq& args, const PropertiesPtr& defaults) { - return make_shared(args, defaults); + return make_shared(args, defaults); } PropertiesPtr diff --git a/cpp/src/Ice/Instance.cpp b/cpp/src/Ice/Instance.cpp index 7ba33e069c7..49c078ead64 100644 --- a/cpp/src/Ice/Instance.cpp +++ b/cpp/src/Ice/Instance.cpp @@ -18,7 +18,7 @@ #include #include #include -#include +#include #include #include #include @@ -29,7 +29,6 @@ #include #include #include -#include #include #include #include @@ -1691,7 +1690,7 @@ IceInternal::Instance::destroy() if(_initData.properties->getPropertyAsInt("Ice.Warn.UnusedProperties") > 0) { - set unusedProperties = static_cast(_initData.properties.get())->getUnusedProperties(); + set unusedProperties = _initData.properties.get()->getUnusedProperties(); if(unusedProperties.size() != 0) { Warning out(_initData.logger); diff --git a/cpp/src/Ice/Properties.cpp b/cpp/src/Ice/Properties.cpp index 074354a0dbe..2059193a00e 100644 --- a/cpp/src/Ice/Properties.cpp +++ b/cpp/src/Ice/Properties.cpp @@ -2,6 +2,730 @@ // Copyright (c) ZeroC, Inc. All rights reserved. // -#include +#include "Ice/Properties.h" +#include +#include +#include +#include +#include +#include +#include +#include -// empty for now +#include + +using namespace std; +using namespace Ice; +using namespace IceInternal; + +Ice::Properties::Properties(const Properties& p) +{ + lock_guard lock(const_cast(p)._mutex); + _properties = p._properties; +} + +Ice::Properties::Properties(StringSeq& args, const PropertiesPtr& defaults) +{ + if (defaults) + { + lock_guard lock(defaults->_mutex); + _properties = defaults->_properties; + } + + StringSeq::iterator q = args.begin(); + + map::iterator p = _properties.find("Ice.ProgramName"); + if(p == _properties.end()) + { + if(q != args.end()) + { + // + // Use the first argument as the value for Ice.ProgramName. Replace + // any backslashes in this value with forward slashes, in case this + // value is used by the event logger. + // + string name = *q; + replace(name.begin(), name.end(), '\\', '/'); + + PropertyValue pv(name, true); + _properties["Ice.ProgramName"] = pv; + } + } + else + { + p->second.used = true; + } + + StringSeq tmp; + + bool loadConfigFiles = false; + while(q != args.end()) + { + string s = *q; + if(s.find("--Ice.Config") == 0) + { + if(s.find('=') == string::npos) + { + s += "=1"; + } + parseLine(s.substr(2), 0); + loadConfigFiles = true; + } + else + { + tmp.push_back(s); + } + ++q; + } + args = tmp; + + if(!loadConfigFiles) + { + // + // If Ice.Config is not set, load from ICE_CONFIG (if set) + // + loadConfigFiles = (_properties.find("Ice.Config") == _properties.end()); + } + + if(loadConfigFiles) + { + loadConfig(); + } + + args = parseIceCommandLineOptions(args); +} + +string +Ice::Properties::getProperty(string_view key) noexcept +{ + lock_guard lock(_mutex); + + map::iterator p = _properties.find(key); + if(p != _properties.end()) + { + p->second.used = true; + return p->second.value; + } + else + { + return string{}; + } +} + +string +Ice::Properties::getPropertyWithDefault(string_view key, string_view value) noexcept +{ + lock_guard lock(_mutex); + + map::iterator p = _properties.find(key); + if(p != _properties.end()) + { + p->second.used = true; + return p->second.value; + } + else + { + return string{value}; + } +} + +int32_t +Ice::Properties::getPropertyAsInt(string_view key) noexcept +{ + return getPropertyAsIntWithDefault(key, 0); +} + +int32_t +Ice::Properties::getPropertyAsIntWithDefault(string_view key, int32_t value) noexcept +{ + lock_guard lock(_mutex); + + map::iterator p = _properties.find(key); + if(p != _properties.end()) + { + int32_t val = value; + p->second.used = true; + istringstream v(p->second.value); + if(!(v >> value) || !v.eof()) + { + Warning out(getProcessLogger()); + out << "numeric property " << key << " set to non-numeric value, defaulting to " << val; + return val; + } + } + + return value; +} + +Ice::StringSeq +Ice::Properties::getPropertyAsList(string_view key) noexcept +{ + return getPropertyAsListWithDefault(key, StringSeq()); +} + +Ice::StringSeq +Ice::Properties::getPropertyAsListWithDefault(string_view key, const StringSeq& value) noexcept +{ + lock_guard lock(_mutex); + + map::iterator p = _properties.find(key); + if(p != _properties.end()) + { + p->second.used = true; + + StringSeq result; + if(!IceUtilInternal::splitString(p->second.value, ", \t\r\n", result)) + { + Warning out(getProcessLogger()); + out << "mismatched quotes in property " << key << "'s value, returning default value"; + } + if(result.size() == 0) + { + result = value; + } + return result; + } + else + { + return value; + } +} + +PropertyDict +Ice::Properties::getPropertiesForPrefix(string_view prefix) noexcept +{ + lock_guard lock(_mutex); + + PropertyDict result; + for(map::iterator p = _properties.begin(); p != _properties.end(); ++p) + { + if(prefix.empty() || p->first.compare(0, prefix.size(), prefix) == 0) + { + p->second.used = true; + result[p->first] = p->second.value; + } + } + + return result; +} + +void +Ice::Properties::setProperty(string_view key, string_view value) +{ + // + // Trim whitespace + // + string currentKey = IceUtilInternal::trim(string{key}); + if(currentKey.empty()) + { + throw InitializationException(__FILE__, __LINE__, "Attempt to set property with empty key"); + } + + // + // Check if the property is legal. + // + LoggerPtr logger = getProcessLogger(); + string::size_type dotPos = currentKey.find('.'); + if(dotPos != string::npos) + { + string prefix = currentKey.substr(0, dotPos); + for(int i = 0 ; IceInternal::PropertyNames::validProps[i].properties != 0; ++i) + { + string pattern(IceInternal::PropertyNames::validProps[i].properties[0].pattern); + + dotPos = pattern.find('.'); + + // + // Each top level prefix describes a non-empty + // namespace. Having a string without a prefix followed by a + // dot is an error. + // + assert(dotPos != string::npos); + + bool mismatchCase = false; + string otherKey; + string propPrefix = pattern.substr(0, dotPos); + if(IceUtilInternal::toUpper(propPrefix) != IceUtilInternal::toUpper(prefix)) + { + continue; + } + + bool found = false; + + for(int j = 0; j < IceInternal::PropertyNames::validProps[i].length && !found; ++j) + { + const IceInternal::Property& prop = IceInternal::PropertyNames::validProps[i].properties[j]; + found = IceUtilInternal::match(currentKey, prop.pattern); + + if(found && prop.deprecated) + { + logger->warning("deprecated property: " + currentKey); + if(prop.deprecatedBy != 0) + { + currentKey = prop.deprecatedBy; + } + } + + if(!found && IceUtilInternal::match(IceUtilInternal::toUpper(currentKey), + IceUtilInternal::toUpper(prop.pattern))) + { + found = true; + mismatchCase = true; + otherKey = prop.pattern; + break; + } + } + if(!found) + { + logger->warning("unknown property: `" + currentKey + "'"); + } + else if(mismatchCase) + { + logger->warning("unknown property: `" + currentKey + "'; did you mean `" + otherKey + "'"); + } + } + } + + lock_guard lock(_mutex); + + // + // Set or clear the property. + // + if(!value.empty()) + { + PropertyValue pv(value, false); + map::const_iterator p = _properties.find(currentKey); + if(p != _properties.end()) + { + pv.used = p->second.used; + } + _properties[currentKey] = pv; + } + else + { + _properties.erase(currentKey); + } +} + +StringSeq +Ice::Properties::getCommandLineOptions() noexcept +{ + lock_guard lock(_mutex); + + StringSeq result; + result.reserve(_properties.size()); + for(map::const_iterator p = _properties.begin(); p != _properties.end(); ++p) + { + result.push_back("--" + p->first + "=" + p->second.value); + } + return result; +} + +StringSeq +Ice::Properties::parseCommandLineOptions(string_view prefix, const StringSeq& options) +{ + string pfx = string{prefix}; + if(!pfx.empty() && pfx[pfx.size() - 1] != '.') + { + pfx += '.'; + } + pfx = "--" + pfx; + + StringSeq result; + for(StringSeq::size_type i = 0; i < options.size(); i++) + { + string opt = options[i]; + + if(opt.find(pfx) == 0) + { + if(opt.find('=') == string::npos) + { + opt += "=1"; + } + + parseLine(opt.substr(2), 0); + } + else + { + result.push_back(opt); + } + } + return result; +} + +StringSeq +Ice::Properties::parseIceCommandLineOptions(const StringSeq& options) +{ + StringSeq args = options; + for(const char** i = IceInternal::PropertyNames::clPropNames; *i != 0; ++i) + { + args = parseCommandLineOptions(*i, args); + } + return args; + +} + +void +Ice::Properties::load(string_view file) +{ + StringConverterPtr stringConverter = getProcessStringConverter(); + +#if defined (_WIN32) + if(file.find("HKCU\\") == 0 || file.find("HKLM\\") == 0) + { + HKEY key = file.find("HKCU\\") == 0 ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; + HKEY iceKey; + const wstring keyName = stringToWstring(file, stringConverter).substr(file.find("\\") + 1).c_str(); + LONG err; + if((err = RegOpenKeyExW(key, keyName.c_str(), 0, KEY_QUERY_VALUE, &iceKey)) != ERROR_SUCCESS) + { + throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + file + "':\n" + + IceUtilInternal::errorToString(err)); + } + + DWORD maxNameSize; // Size in characters not including terminating null character. + DWORD maxDataSize; // Size in bytes + DWORD numValues; + try + { + err = RegQueryInfoKey(iceKey, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, + &numValues, &maxNameSize, &maxDataSize, nullptr, nullptr); + if(err != ERROR_SUCCESS) + { + throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + file + + "':\n" + IceUtilInternal::errorToString(err)); + } + + for(DWORD i = 0; i < numValues; ++i) + { + vector nameBuf(maxNameSize + 1); + vector dataBuf(maxDataSize); + DWORD keyType; + DWORD nameBufSize = static_cast(nameBuf.size()); + DWORD dataBufSize = static_cast(dataBuf.size()); + err = RegEnumValueW(iceKey, i, &nameBuf[0], &nameBufSize, nullptr, &keyType, &dataBuf[0], &dataBufSize); + if(err != ERROR_SUCCESS || nameBufSize == 0) + { + ostringstream os; + os << "could not read Windows registry property name, key: `" + file + "', index: " << i << ":\n"; + if(nameBufSize == 0) + { + os << "property name can't be the empty string"; + } + else + { + os << IceUtilInternal::errorToString(err); + } + getProcessLogger()->warning(os.str()); + continue; + } + string name = wstringToString( + wstring(reinterpret_cast(&nameBuf[0]), nameBufSize), stringConverter); + if(keyType != REG_SZ && keyType != REG_EXPAND_SZ) + { + ostringstream os; + os << "unsupported type for Windows registry property `" + name + "' key: `" + file + "'"; + getProcessLogger()->warning(os.str()); + continue; + } + + string value; + wstring valueW = wstring(reinterpret_cast(&dataBuf[0]), (dataBufSize / sizeof(wchar_t)) - 1); + if(keyType == REG_SZ) + { + value = wstringToString(valueW, stringConverter); + } + else // keyType == REG_EXPAND_SZ + { + vector expandedValue(1024); + DWORD sz = ExpandEnvironmentStringsW(valueW.c_str(), &expandedValue[0], + static_cast(expandedValue.size())); + if(sz >= expandedValue.size()) + { + expandedValue.resize(sz + 1); + if(ExpandEnvironmentStringsW(valueW.c_str(), &expandedValue[0], + static_cast(expandedValue.size())) == 0) + { + ostringstream os; + os << "could not expand variable in property `" << name << "', key: `" + string{file} + "':\n"; + os << IceUtilInternal::lastErrorToString(); + getProcessLogger()->warning(os.str()); + continue; + } + } + value = wstringToString(wstring(&expandedValue[0], sz -1), stringConverter); + } + setProperty(name, value); + } + } + catch(...) + { + RegCloseKey(iceKey); + throw; + } + RegCloseKey(iceKey); + } + else +#endif + { + ifstream in(IceUtilInternal::streamFilename(string{file}).c_str()); + if(!in) + { + throw FileException(__FILE__, __LINE__, string{file}); + } + + string line; + bool firstLine = true; + while(getline(in, line)) + { + // + // Skip UTF8 BOM if present. + // + if(firstLine) + { + const unsigned char UTF8_BOM[3] = {0xEF, 0xBB, 0xBF}; + if(line.size() >= 3 && + static_cast(line[0]) == UTF8_BOM[0] && + static_cast(line[1]) == UTF8_BOM[1] && + static_cast(line[2]) == UTF8_BOM[2]) + { + line = line.substr(3); + } + firstLine = false; + } + parseLine(line, stringConverter); + } + } +} + +set +Ice::Properties::getUnusedProperties() +{ + lock_guard lock(_mutex); + set unusedProperties; + for(map::const_iterator p = _properties.begin(); p != _properties.end(); ++p) + { + if(!p->second.used) + { + unusedProperties.insert(p->first); + } + } + return unusedProperties; +} + +void +Ice::Properties::parseLine(string_view line, const StringConverterPtr& converter) +{ + string key; + string value; + + enum ParseState { Key , Value }; + ParseState state = Key; + + string whitespace; + string escapedspace; + bool finished = false; + for(string::size_type i = 0; i < line.size(); ++i) + { + char c = line[i]; + switch(state) + { + case Key: + { + switch(c) + { + case '\\': + if(i < line.length() - 1) + { + c = line[++i]; + switch(c) + { + case '\\': + case '#': + case '=': + key += whitespace; + whitespace.clear(); + key += c; + break; + + case ' ': + if(key.length() != 0) + { + whitespace += c; + } + break; + + default: + key += whitespace; + whitespace.clear(); + key += '\\'; + key += c; + break; + } + } + else + { + key += whitespace; + key += c; + } + break; + + case ' ': + case '\t': + case '\r': + case '\n': + if(key.length() != 0) + { + whitespace += c; + } + break; + + case '=': + whitespace.clear(); + state = Value; + break; + + case '#': + finished = true; + break; + + default: + key += whitespace; + whitespace.clear(); + key += c; + break; + } + break; + } + + case Value: + { + switch(c) + { + case '\\': + if(i < line.length() - 1) + { + c = line[++i]; + switch(c) + { + case '\\': + case '#': + case '=': + value += value.length() == 0 ? escapedspace : whitespace; + whitespace.clear(); + escapedspace.clear(); + value += c; + break; + + case ' ': + whitespace += c; + escapedspace += c; + break; + + default: + value += value.length() == 0 ? escapedspace : whitespace; + whitespace.clear(); + escapedspace.clear(); + value += '\\'; + value += c; + break; + } + } + else + { + value += value.length() == 0 ? escapedspace : whitespace; + value += c; + } + break; + + case ' ': + case '\t': + case '\r': + case '\n': + if(value.length() != 0) + { + whitespace += c; + } + break; + + case '#': + finished = true; + break; + + default: + value += value.length() == 0 ? escapedspace : whitespace; + whitespace.clear(); + escapedspace.clear(); + value += c; + break; + } + break; + } + } + if(finished) + { + break; + } + } + value += escapedspace; + + if((state == Key && key.length() != 0) || (state == Value && key.length() == 0)) + { + getProcessLogger()->warning("invalid config file entry: \"" + string{line} + "\""); + return; + } + else if(key.length() == 0) + { + return; + } + + key = UTF8ToNative(key, converter); + value = UTF8ToNative(value, converter); + + setProperty(key, value); +} + +void +Ice::Properties::loadConfig() +{ + string value = getProperty("Ice.Config"); + if(value.empty() || value == "1") + { +#ifdef _WIN32 + vector v(256); + DWORD ret = GetEnvironmentVariableW(L"ICE_CONFIG", &v[0], static_cast(v.size())); + if(ret >= v.size()) + { + v.resize(ret + 1); + ret = GetEnvironmentVariableW(L"ICE_CONFIG", &v[0], static_cast(v.size())); + } + if(ret > 0) + { + value = wstringToString(wstring(&v[0], ret), getProcessStringConverter()); + } + else + { + value = ""; + } +#else + const char* s = getenv("ICE_CONFIG"); + if(s && *s != '\0') + { + value = s; + } +#endif + } + + if(!value.empty()) + { + vector files; + IceUtilInternal::splitString(value, ",", files); + for(vector::const_iterator i = files.begin(); i != files.end(); ++i) + { + load(IceUtilInternal::trim(string{*i})); + } + + PropertyValue pv(value, true); + _properties["Ice.Config"] = pv; + } +} diff --git a/cpp/src/Ice/PropertiesI.cpp b/cpp/src/Ice/PropertiesI.cpp deleted file mode 100644 index 7e2db682f4b..00000000000 --- a/cpp/src/Ice/PropertiesI.cpp +++ /dev/null @@ -1,739 +0,0 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -using namespace std; -using namespace Ice; -using namespace IceInternal; - -string -Ice::PropertiesI::getProperty(string_view key) noexcept -{ - lock_guard lock(_mutex); - - map::iterator p = _properties.find(key); - if(p != _properties.end()) - { - p->second.used = true; - return p->second.value; - } - else - { - return string{}; - } -} - -string -Ice::PropertiesI::getPropertyWithDefault(string_view key, string_view value) noexcept -{ - lock_guard lock(_mutex); - - map::iterator p = _properties.find(key); - if(p != _properties.end()) - { - p->second.used = true; - return p->second.value; - } - else - { - return string{value}; - } -} - -int32_t -Ice::PropertiesI::getPropertyAsInt(string_view key) noexcept -{ - return getPropertyAsIntWithDefault(key, 0); -} - -int32_t -Ice::PropertiesI::getPropertyAsIntWithDefault(string_view key, int32_t value) noexcept -{ - lock_guard lock(_mutex); - - map::iterator p = _properties.find(key); - if(p != _properties.end()) - { - int32_t val = value; - p->second.used = true; - istringstream v(p->second.value); - if(!(v >> value) || !v.eof()) - { - Warning out(getProcessLogger()); - out << "numeric property " << key << " set to non-numeric value, defaulting to " << val; - return val; - } - } - - return value; -} - -Ice::StringSeq -Ice::PropertiesI::getPropertyAsList(string_view key) noexcept -{ - return getPropertyAsListWithDefault(key, StringSeq()); -} - -Ice::StringSeq -Ice::PropertiesI::getPropertyAsListWithDefault(string_view key, const StringSeq& value) noexcept -{ - lock_guard lock(_mutex); - - map::iterator p = _properties.find(key); - if(p != _properties.end()) - { - p->second.used = true; - - StringSeq result; - if(!IceUtilInternal::splitString(p->second.value, ", \t\r\n", result)) - { - Warning out(getProcessLogger()); - out << "mismatched quotes in property " << key << "'s value, returning default value"; - } - if(result.size() == 0) - { - result = value; - } - return result; - } - else - { - return value; - } -} - -PropertyDict -Ice::PropertiesI::getPropertiesForPrefix(string_view prefix) noexcept -{ - lock_guard lock(_mutex); - - PropertyDict result; - for(map::iterator p = _properties.begin(); p != _properties.end(); ++p) - { - if(prefix.empty() || p->first.compare(0, prefix.size(), prefix) == 0) - { - p->second.used = true; - result[p->first] = p->second.value; - } - } - - return result; -} - -void -Ice::PropertiesI::setProperty(string_view key, string_view value) -{ - // - // Trim whitespace - // - string currentKey = IceUtilInternal::trim(string{key}); - if(currentKey.empty()) - { - throw InitializationException(__FILE__, __LINE__, "Attempt to set property with empty key"); - } - - // - // Check if the property is legal. - // - LoggerPtr logger = getProcessLogger(); - string::size_type dotPos = currentKey.find('.'); - if(dotPos != string::npos) - { - string prefix = currentKey.substr(0, dotPos); - for(int i = 0 ; IceInternal::PropertyNames::validProps[i].properties != 0; ++i) - { - string pattern(IceInternal::PropertyNames::validProps[i].properties[0].pattern); - - dotPos = pattern.find('.'); - - // - // Each top level prefix describes a non-empty - // namespace. Having a string without a prefix followed by a - // dot is an error. - // - assert(dotPos != string::npos); - - bool mismatchCase = false; - string otherKey; - string propPrefix = pattern.substr(0, dotPos); - if(IceUtilInternal::toUpper(propPrefix) != IceUtilInternal::toUpper(prefix)) - { - continue; - } - - bool found = false; - - for(int j = 0; j < IceInternal::PropertyNames::validProps[i].length && !found; ++j) - { - const IceInternal::Property& prop = IceInternal::PropertyNames::validProps[i].properties[j]; - found = IceUtilInternal::match(currentKey, prop.pattern); - - if(found && prop.deprecated) - { - logger->warning("deprecated property: " + currentKey); - if(prop.deprecatedBy != 0) - { - currentKey = prop.deprecatedBy; - } - } - - if(!found && IceUtilInternal::match(IceUtilInternal::toUpper(currentKey), - IceUtilInternal::toUpper(prop.pattern))) - { - found = true; - mismatchCase = true; - otherKey = prop.pattern; - break; - } - } - if(!found) - { - logger->warning("unknown property: `" + currentKey + "'"); - } - else if(mismatchCase) - { - logger->warning("unknown property: `" + currentKey + "'; did you mean `" + otherKey + "'"); - } - } - } - - lock_guard lock(_mutex); - - // - // Set or clear the property. - // - if(!value.empty()) - { - PropertyValue pv(value, false); - map::const_iterator p = _properties.find(currentKey); - if(p != _properties.end()) - { - pv.used = p->second.used; - } - _properties[currentKey] = pv; - } - else - { - _properties.erase(currentKey); - } -} - -StringSeq -Ice::PropertiesI::getCommandLineOptions() noexcept -{ - lock_guard lock(_mutex); - - StringSeq result; - result.reserve(_properties.size()); - for(map::const_iterator p = _properties.begin(); p != _properties.end(); ++p) - { - result.push_back("--" + p->first + "=" + p->second.value); - } - return result; -} - -StringSeq -Ice::PropertiesI::parseCommandLineOptions(string_view prefix, const StringSeq& options) -{ - string pfx = string{prefix}; - if(!pfx.empty() && pfx[pfx.size() - 1] != '.') - { - pfx += '.'; - } - pfx = "--" + pfx; - - StringSeq result; - for(StringSeq::size_type i = 0; i < options.size(); i++) - { - string opt = options[i]; - - if(opt.find(pfx) == 0) - { - if(opt.find('=') == string::npos) - { - opt += "=1"; - } - - parseLine(opt.substr(2), 0); - } - else - { - result.push_back(opt); - } - } - return result; -} - -StringSeq -Ice::PropertiesI::parseIceCommandLineOptions(const StringSeq& options) -{ - StringSeq args = options; - for(const char** i = IceInternal::PropertyNames::clPropNames; *i != 0; ++i) - { - args = parseCommandLineOptions(*i, args); - } - return args; - -} - -void -Ice::PropertiesI::load(string_view file) -{ - StringConverterPtr stringConverter = getProcessStringConverter(); - -#if defined (_WIN32) - if(file.find("HKCU\\") == 0 || file.find("HKLM\\") == 0) - { - HKEY key = file.find("HKCU\\") == 0 ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; - HKEY iceKey; - const wstring keyName = stringToWstring(file, stringConverter).substr(file.find("\\") + 1).c_str(); - LONG err; - if((err = RegOpenKeyExW(key, keyName.c_str(), 0, KEY_QUERY_VALUE, &iceKey)) != ERROR_SUCCESS) - { - throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + file + "':\n" + - IceUtilInternal::errorToString(err)); - } - - DWORD maxNameSize; // Size in characters not including terminating null character. - DWORD maxDataSize; // Size in bytes - DWORD numValues; - try - { - err = RegQueryInfoKey(iceKey, nullptr, nullptr, nullptr, nullptr, nullptr, nullptr, - &numValues, &maxNameSize, &maxDataSize, nullptr, nullptr); - if(err != ERROR_SUCCESS) - { - throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + file + - "':\n" + IceUtilInternal::errorToString(err)); - } - - for(DWORD i = 0; i < numValues; ++i) - { - vector nameBuf(maxNameSize + 1); - vector dataBuf(maxDataSize); - DWORD keyType; - DWORD nameBufSize = static_cast(nameBuf.size()); - DWORD dataBufSize = static_cast(dataBuf.size()); - err = RegEnumValueW(iceKey, i, &nameBuf[0], &nameBufSize, nullptr, &keyType, &dataBuf[0], &dataBufSize); - if(err != ERROR_SUCCESS || nameBufSize == 0) - { - ostringstream os; - os << "could not read Windows registry property name, key: `" + file + "', index: " << i << ":\n"; - if(nameBufSize == 0) - { - os << "property name can't be the empty string"; - } - else - { - os << IceUtilInternal::errorToString(err); - } - getProcessLogger()->warning(os.str()); - continue; - } - string name = wstringToString( - wstring(reinterpret_cast(&nameBuf[0]), nameBufSize), stringConverter); - if(keyType != REG_SZ && keyType != REG_EXPAND_SZ) - { - ostringstream os; - os << "unsupported type for Windows registry property `" + name + "' key: `" + file + "'"; - getProcessLogger()->warning(os.str()); - continue; - } - - string value; - wstring valueW = wstring(reinterpret_cast(&dataBuf[0]), (dataBufSize / sizeof(wchar_t)) - 1); - if(keyType == REG_SZ) - { - value = wstringToString(valueW, stringConverter); - } - else // keyType == REG_EXPAND_SZ - { - vector expandedValue(1024); - DWORD sz = ExpandEnvironmentStringsW(valueW.c_str(), &expandedValue[0], - static_cast(expandedValue.size())); - if(sz >= expandedValue.size()) - { - expandedValue.resize(sz + 1); - if(ExpandEnvironmentStringsW(valueW.c_str(), &expandedValue[0], - static_cast(expandedValue.size())) == 0) - { - ostringstream os; - os << "could not expand variable in property `" << name << "', key: `" + string{file} + "':\n"; - os << IceUtilInternal::lastErrorToString(); - getProcessLogger()->warning(os.str()); - continue; - } - } - value = wstringToString(wstring(&expandedValue[0], sz -1), stringConverter); - } - setProperty(name, value); - } - } - catch(...) - { - RegCloseKey(iceKey); - throw; - } - RegCloseKey(iceKey); - } - else -#endif - { - ifstream in(IceUtilInternal::streamFilename(string{file}).c_str()); - if(!in) - { - throw FileException(__FILE__, __LINE__, string{file}); - } - - string line; - bool firstLine = true; - while(getline(in, line)) - { - // - // Skip UTF8 BOM if present. - // - if(firstLine) - { - const unsigned char UTF8_BOM[3] = {0xEF, 0xBB, 0xBF}; - if(line.size() >= 3 && - static_cast(line[0]) == UTF8_BOM[0] && - static_cast(line[1]) == UTF8_BOM[1] && - static_cast(line[2]) == UTF8_BOM[2]) - { - line = line.substr(3); - } - firstLine = false; - } - parseLine(line, stringConverter); - } - } -} - -PropertiesPtr -Ice::PropertiesI::clone() noexcept -{ - lock_guard lock(_mutex); - return make_shared(this); -} - -set -Ice::PropertiesI::getUnusedProperties() -{ - lock_guard lock(_mutex); - set unusedProperties; - for(map::const_iterator p = _properties.begin(); p != _properties.end(); ++p) - { - if(!p->second.used) - { - unusedProperties.insert(p->first); - } - } - return unusedProperties; -} - -Ice::PropertiesI::PropertiesI(const PropertiesI* p) : - _properties(p->_properties) -{ -} - -Ice::PropertiesI::PropertiesI() -{ -} - -Ice::PropertiesI::PropertiesI(StringSeq& args, const PropertiesPtr& defaults) -{ - if(defaults != 0) - { - _properties = static_cast(defaults.get())->_properties; - } - - StringSeq::iterator q = args.begin(); - - map::iterator p = _properties.find("Ice.ProgramName"); - if(p == _properties.end()) - { - if(q != args.end()) - { - // - // Use the first argument as the value for Ice.ProgramName. Replace - // any backslashes in this value with forward slashes, in case this - // value is used by the event logger. - // - string name = *q; - replace(name.begin(), name.end(), '\\', '/'); - - PropertyValue pv(name, true); - _properties["Ice.ProgramName"] = pv; - } - } - else - { - p->second.used = true; - } - - StringSeq tmp; - - bool loadConfigFiles = false; - while(q != args.end()) - { - string s = *q; - if(s.find("--Ice.Config") == 0) - { - if(s.find('=') == string::npos) - { - s += "=1"; - } - parseLine(s.substr(2), 0); - loadConfigFiles = true; - } - else - { - tmp.push_back(s); - } - ++q; - } - args = tmp; - - if(!loadConfigFiles) - { - // - // If Ice.Config is not set, load from ICE_CONFIG (if set) - // - loadConfigFiles = (_properties.find("Ice.Config") == _properties.end()); - } - - if(loadConfigFiles) - { - loadConfig(); - } - - args = parseIceCommandLineOptions(args); -} - -void -Ice::PropertiesI::parseLine(string_view line, const StringConverterPtr& converter) -{ - string key; - string value; - - enum ParseState { Key , Value }; - ParseState state = Key; - - string whitespace; - string escapedspace; - bool finished = false; - for(string::size_type i = 0; i < line.size(); ++i) - { - char c = line[i]; - switch(state) - { - case Key: - { - switch(c) - { - case '\\': - if(i < line.length() - 1) - { - c = line[++i]; - switch(c) - { - case '\\': - case '#': - case '=': - key += whitespace; - whitespace.clear(); - key += c; - break; - - case ' ': - if(key.length() != 0) - { - whitespace += c; - } - break; - - default: - key += whitespace; - whitespace.clear(); - key += '\\'; - key += c; - break; - } - } - else - { - key += whitespace; - key += c; - } - break; - - case ' ': - case '\t': - case '\r': - case '\n': - if(key.length() != 0) - { - whitespace += c; - } - break; - - case '=': - whitespace.clear(); - state = Value; - break; - - case '#': - finished = true; - break; - - default: - key += whitespace; - whitespace.clear(); - key += c; - break; - } - break; - } - - case Value: - { - switch(c) - { - case '\\': - if(i < line.length() - 1) - { - c = line[++i]; - switch(c) - { - case '\\': - case '#': - case '=': - value += value.length() == 0 ? escapedspace : whitespace; - whitespace.clear(); - escapedspace.clear(); - value += c; - break; - - case ' ': - whitespace += c; - escapedspace += c; - break; - - default: - value += value.length() == 0 ? escapedspace : whitespace; - whitespace.clear(); - escapedspace.clear(); - value += '\\'; - value += c; - break; - } - } - else - { - value += value.length() == 0 ? escapedspace : whitespace; - value += c; - } - break; - - case ' ': - case '\t': - case '\r': - case '\n': - if(value.length() != 0) - { - whitespace += c; - } - break; - - case '#': - finished = true; - break; - - default: - value += value.length() == 0 ? escapedspace : whitespace; - whitespace.clear(); - escapedspace.clear(); - value += c; - break; - } - break; - } - } - if(finished) - { - break; - } - } - value += escapedspace; - - if((state == Key && key.length() != 0) || (state == Value && key.length() == 0)) - { - getProcessLogger()->warning("invalid config file entry: \"" + string{line} + "\""); - return; - } - else if(key.length() == 0) - { - return; - } - - key = UTF8ToNative(key, converter); - value = UTF8ToNative(value, converter); - - setProperty(key, value); -} - -void -Ice::PropertiesI::loadConfig() -{ - string value = getProperty("Ice.Config"); - if(value.empty() || value == "1") - { -#ifdef _WIN32 - vector v(256); - DWORD ret = GetEnvironmentVariableW(L"ICE_CONFIG", &v[0], static_cast(v.size())); - if(ret >= v.size()) - { - v.resize(ret + 1); - ret = GetEnvironmentVariableW(L"ICE_CONFIG", &v[0], static_cast(v.size())); - } - if(ret > 0) - { - value = wstringToString(wstring(&v[0], ret), getProcessStringConverter()); - } - else - { - value = ""; - } -#else - const char* s = getenv("ICE_CONFIG"); - if(s && *s != '\0') - { - value = s; - } -#endif - } - - if(!value.empty()) - { - vector files; - IceUtilInternal::splitString(value, ",", files); - for(vector::const_iterator i = files.begin(); i != files.end(); ++i) - { - load(IceUtilInternal::trim(string{*i})); - } - - PropertyValue pv(value, true); - _properties["Ice.Config"] = pv; - } -} diff --git a/cpp/src/Ice/PropertiesI.h b/cpp/src/Ice/PropertiesI.h deleted file mode 100644 index c4d65474c27..00000000000 --- a/cpp/src/Ice/PropertiesI.h +++ /dev/null @@ -1,71 +0,0 @@ -// -// Copyright (c) ZeroC, Inc. All rights reserved. -// - -#ifndef ICE_PROPERTIES_I_H -#define ICE_PROPERTIES_I_H - -#include "Ice/Properties.h" -#include "Ice/StringConverter.h" - -#include -#include - -namespace Ice -{ - -class PropertiesI final : public Properties -{ -public: - - std::string getProperty(std::string_view) noexcept final; - std::string getPropertyWithDefault(std::string_view, std::string_view) noexcept final; - std::int32_t getPropertyAsInt(std::string_view) noexcept final; - std::int32_t getPropertyAsIntWithDefault(std::string_view, std::int32_t) noexcept final; - Ice::StringSeq getPropertyAsList(std::string_view) noexcept final; - Ice::StringSeq getPropertyAsListWithDefault(std::string_view, const Ice::StringSeq&) noexcept final; - - PropertyDict getPropertiesForPrefix(std::string_view) noexcept final; - void setProperty(std::string_view, std::string_view) final; - StringSeq getCommandLineOptions() noexcept final; - StringSeq parseCommandLineOptions(std::string_view, const StringSeq&) final; - StringSeq parseIceCommandLineOptions(const StringSeq&) final; - void load(std::string_view) final; - PropertiesPtr clone() noexcept final; - - std::set getUnusedProperties(); - - PropertiesI(const PropertiesI*); - - PropertiesI(); - PropertiesI(StringSeq&, const PropertiesPtr&); - -private: - - void parseLine(std::string_view, const StringConverterPtr&); - - void loadConfig(); - - struct PropertyValue - { - PropertyValue() : - used(false) - { - } - - PropertyValue(std::string_view v, bool u) : - value(std::string{v}), - used(u) - { - } - - std::string value; - bool used; - }; - std::map> _properties; - std::mutex _mutex; -}; - -} - -#endif diff --git a/cpp/src/Ice/msbuild/ice/ice.vcxproj b/cpp/src/Ice/msbuild/ice/ice.vcxproj index da461cec5bd..51da089657f 100644 --- a/cpp/src/Ice/msbuild/ice/ice.vcxproj +++ b/cpp/src/Ice/msbuild/ice/ice.vcxproj @@ -551,7 +551,6 @@ - diff --git a/cpp/src/Ice/msbuild/ice/ice.vcxproj.filters b/cpp/src/Ice/msbuild/ice/ice.vcxproj.filters index 45fa4daef31..6e0ed6529c1 100644 --- a/cpp/src/Ice/msbuild/ice/ice.vcxproj.filters +++ b/cpp/src/Ice/msbuild/ice/ice.vcxproj.filters @@ -387,9 +387,6 @@ Source Files - - Source Files - Source Files From 5a8c9fb8d4d5852538a2a03f737917c31246d3c8 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Thu, 7 Mar 2024 14:48:43 -0500 Subject: [PATCH 3/5] Cleanup --- cpp/include/Ice/Initialize.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cpp/include/Ice/Initialize.h b/cpp/include/Ice/Initialize.h index 30de3d824e6..e44db471039 100644 --- a/cpp/include/Ice/Initialize.h +++ b/cpp/include/Ice/Initialize.h @@ -117,7 +117,7 @@ ICE_API PropertiesPtr createProperties(); * @return A new property set initialized with the property settings * that were removed from the argument vector. */ -ICE_API PropertiesPtr createProperties(StringSeq& seq, const PropertiesPtr& defaults = 0); +ICE_API PropertiesPtr createProperties(StringSeq& seq, const PropertiesPtr& defaults = nullptr); /** * Creates a property set initialized from command-line arguments @@ -138,7 +138,7 @@ ICE_API PropertiesPtr createProperties(StringSeq& seq, const PropertiesPtr& defa * @return A new property set initialized with the property settings * that were removed from the argument vector. */ -ICE_API PropertiesPtr createProperties(int& argc, const char* argv[], const PropertiesPtr& defaults = 0); +ICE_API PropertiesPtr createProperties(int& argc, const char* argv[], const PropertiesPtr& defaults = nullptr); /** * Creates a property set initialized from command-line arguments @@ -159,7 +159,7 @@ ICE_API PropertiesPtr createProperties(int& argc, const char* argv[], const Prop * @return A new property set initialized with the property settings * that were removed from the argument vector. */ -inline PropertiesPtr createProperties(int& argc, char* argv[], const PropertiesPtr& defaults = 0) +inline PropertiesPtr createProperties(int& argc, char* argv[], const PropertiesPtr& defaults = nullptr) { return createProperties(argc, const_cast(argv), defaults); } @@ -184,7 +184,7 @@ inline PropertiesPtr createProperties(int& argc, char* argv[], const PropertiesP * @return A new property set initialized with the property settings * that were removed from the argument vector. */ -ICE_API PropertiesPtr createProperties(int& argc, const wchar_t* argv[], const PropertiesPtr& defaults = 0); +ICE_API PropertiesPtr createProperties(int& argc, const wchar_t* argv[], const PropertiesPtr& defaults = nullptr); /** * Creates a property set initialized from command-line arguments @@ -205,7 +205,7 @@ ICE_API PropertiesPtr createProperties(int& argc, const wchar_t* argv[], const P * @return A new property set initialized with the property settings * that were removed from the argument vector. */ -inline PropertiesPtr createProperties(int& argc, wchar_t* argv[], const PropertiesPtr& defaults = 0) +inline PropertiesPtr createProperties(int& argc, wchar_t* argv[], const PropertiesPtr& defaults = nullptr) { return createProperties(argc, const_cast(argv), defaults); } From b7cc193fb7c27a1423e424148cbd227dfc21bd91 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Thu, 7 Mar 2024 15:08:34 -0500 Subject: [PATCH 4/5] Windows fixes --- .vscode/settings.json | 3 ++- cpp/include/Ice/Properties.h | 7 ++----- cpp/src/Ice/Properties.cpp | 31 +++++++++++++++---------------- 3 files changed, 19 insertions(+), 22 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 27418f94f90..6088ca3140d 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -72,7 +72,8 @@ "typeinfo": "cpp", "unordered_map": "cpp", "variant": "cpp", - "algorithm": "cpp" + "algorithm": "cpp", + "xtree": "cpp" }, "C_Cpp.default.cppStandard": "c++20" } diff --git a/cpp/include/Ice/Properties.h b/cpp/include/Ice/Properties.h index 5515ecded71..a9a0fc2e49e 100644 --- a/cpp/include/Ice/Properties.h +++ b/cpp/include/Ice/Properties.h @@ -176,14 +176,11 @@ class ICE_API Properties final struct PropertyValue { - PropertyValue() : - used(false) + PropertyValue() : used(false) { } - PropertyValue(std::string_view v, bool u) : - value(std::string{v}), - used(u) + PropertyValue(std::string v, bool u) : value(std::move(v)), used(u) { } diff --git a/cpp/src/Ice/Properties.cpp b/cpp/src/Ice/Properties.cpp index 2059193a00e..36289c5462d 100644 --- a/cpp/src/Ice/Properties.cpp +++ b/cpp/src/Ice/Properties.cpp @@ -3,14 +3,13 @@ // #include "Ice/Properties.h" -#include -#include -#include -#include -#include -#include -#include -#include +#include "IceUtil/StringUtil.h" +#include "IceUtil/FileUtil.h" +#include "Ice/Initialize.h" +#include "Ice/LocalException.h" +#include "Ice/PropertyNames.h" +#include "Ice/Logger.h" +#include "Ice/LoggerUtil.h" #include @@ -47,7 +46,7 @@ Ice::Properties::Properties(StringSeq& args, const PropertiesPtr& defaults) string name = *q; replace(name.begin(), name.end(), '\\', '/'); - PropertyValue pv(name, true); + PropertyValue pv{std::move(name), true}; _properties["Ice.ProgramName"] = pv; } } @@ -293,7 +292,7 @@ Ice::Properties::setProperty(string_view key, string_view value) // if(!value.empty()) { - PropertyValue pv(value, false); + PropertyValue pv{string{value}, false}; map::const_iterator p = _properties.find(currentKey); if(p != _properties.end()) { @@ -375,11 +374,11 @@ Ice::Properties::load(string_view file) { HKEY key = file.find("HKCU\\") == 0 ? HKEY_CURRENT_USER : HKEY_LOCAL_MACHINE; HKEY iceKey; - const wstring keyName = stringToWstring(file, stringConverter).substr(file.find("\\") + 1).c_str(); + const wstring keyName = stringToWstring(string{file}, stringConverter).substr(file.find("\\") + 1).c_str(); LONG err; if((err = RegOpenKeyExW(key, keyName.c_str(), 0, KEY_QUERY_VALUE, &iceKey)) != ERROR_SUCCESS) { - throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + file + "':\n" + + throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + string{file} + "':\n" + IceUtilInternal::errorToString(err)); } @@ -392,7 +391,7 @@ Ice::Properties::load(string_view file) &numValues, &maxNameSize, &maxDataSize, nullptr, nullptr); if(err != ERROR_SUCCESS) { - throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + file + + throw InitializationException(__FILE__, __LINE__, "could not open Windows registry key `" + string{file} + "':\n" + IceUtilInternal::errorToString(err)); } @@ -407,7 +406,7 @@ Ice::Properties::load(string_view file) if(err != ERROR_SUCCESS || nameBufSize == 0) { ostringstream os; - os << "could not read Windows registry property name, key: `" + file + "', index: " << i << ":\n"; + os << "could not read Windows registry property name, key: `" + string{file} + "', index: " << i << ":\n"; if(nameBufSize == 0) { os << "property name can't be the empty string"; @@ -424,7 +423,7 @@ Ice::Properties::load(string_view file) if(keyType != REG_SZ && keyType != REG_EXPAND_SZ) { ostringstream os; - os << "unsupported type for Windows registry property `" + name + "' key: `" + file + "'"; + os << "unsupported type for Windows registry property `" + name + "' key: `" + string{file} + "'"; getProcessLogger()->warning(os.str()); continue; } @@ -725,7 +724,7 @@ Ice::Properties::loadConfig() load(IceUtilInternal::trim(string{*i})); } - PropertyValue pv(value, true); + PropertyValue pv{std::move(value), true}; _properties["Ice.Config"] = pv; } } From 017dd2dcd58eefa849bef346b997eab83d64fec4 Mon Sep 17 00:00:00 2001 From: Bernard Normier Date: Thu, 7 Mar 2024 15:37:47 -0500 Subject: [PATCH 5/5] Fix review comment --- cpp/include/Ice/Properties.h | 2 +- cpp/src/Ice/Properties.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/cpp/include/Ice/Properties.h b/cpp/include/Ice/Properties.h index a9a0fc2e49e..4fdbac68817 100644 --- a/cpp/include/Ice/Properties.h +++ b/cpp/include/Ice/Properties.h @@ -188,7 +188,7 @@ class ICE_API Properties final bool used; }; std::map> _properties; - std::mutex _mutex; + mutable std::mutex _mutex; }; using PropertiesPtr = std::shared_ptr; diff --git a/cpp/src/Ice/Properties.cpp b/cpp/src/Ice/Properties.cpp index 36289c5462d..39026c0cc5b 100644 --- a/cpp/src/Ice/Properties.cpp +++ b/cpp/src/Ice/Properties.cpp @@ -19,7 +19,7 @@ using namespace IceInternal; Ice::Properties::Properties(const Properties& p) { - lock_guard lock(const_cast(p)._mutex); + lock_guard lock(p._mutex); _properties = p._properties; }