#4173: AbstractConfiguration: when expanding property references, allow specifying a default value; #4174: AbstractConfiguration: support Int16/UInt16 and Int32/UInt32

This commit is contained in:
Günter Obiltschnig 2023-09-30 14:18:10 +02:00
parent c209148ba7
commit 22213f1111
5 changed files with 335 additions and 33 deletions

View File

@ -125,14 +125,14 @@ public:
std::string getString(const std::string& key) const;
/// Returns the string value of the property with the given name.
/// Throws a NotFoundException if the key does not exist.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
std::string getString(const std::string& key, const std::string& defaultValue) const;
/// If a property with the given key exists, returns the property's string value,
/// otherwise returns the given default value.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
std::string getRawString(const std::string& key) const;
/// Returns the raw string value of the property with the given name.
@ -150,8 +150,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an int.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
unsigned int getUInt(const std::string& key) const;
/// Returns the unsigned int value of the property with the given name.
@ -159,8 +159,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an unsigned int.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
int getInt(const std::string& key, int defaultValue) const;
/// If a property with the given key exists, returns the property's int value,
@ -168,8 +168,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an int.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
unsigned int getUInt(const std::string& key, unsigned int defaultValue) const;
/// If a property with the given key exists, returns the property's unsigned int
@ -177,8 +177,80 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an unsigned int.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::Int32 getInt32(const std::string& key) const;
/// Returns the 32-bit int value of the property with the given name.
/// Throws a NotFoundException if the key does not exist.
/// Throws a SyntaxException if the property can not be converted
/// to an Int32.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::UInt32 getUInt32(const std::string& key) const;
/// Returns the 32-bit unsigned int value of the property with the given name.
/// Throws a NotFoundException if the key does not exist.
/// Throws a SyntaxException if the property can not be converted
/// to an UInt32.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::Int32 getInt32(const std::string& key, Poco::Int32 defaultValue) const;
/// If a property with the given key exists, returns the property's 32-bit int value,
/// otherwise returns the given default value.
/// Throws a SyntaxException if the property can not be converted
/// to an Int32.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::UInt32 getUInt32(const std::string& key, Poco::UInt32 defaultValue) const;
/// If a property with the given key exists, returns the property's 32-bit unsigned int
/// value, otherwise returns the given default value.
/// Throws a SyntaxException if the property can not be converted
/// to an UInt32.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::Int16 getInt16(const std::string& key) const;
/// Returns the 16-bit int value of the property with the given name.
/// Throws a NotFoundException if the key does not exist.
/// Throws a SyntaxException or a RangeException if the property can not be converted
/// to an Int16.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::UInt16 getUInt16(const std::string& key) const;
/// Returns the unsigned 16-bit int value of the property with the given name.
/// Throws a NotFoundException if the key does not exist.
/// Throws a SyntaxException or a RangeException if the property can not be converted
/// to an UInt16.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::Int16 getInt16(const std::string& key, Poco::Int16 defaultValue) const;
/// If a property with the given key exists, returns the property's 16-bit int value,
/// otherwise returns the given default value.
/// Throws a SyntaxException or a RangeException if the property can not be converted
/// to an Int16.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Poco::UInt16 getUInt16(const std::string& key, Poco::UInt16 defaultValue) const;
/// If a property with the given key exists, returns the property's unsigned 16-bit int
/// value, otherwise returns the given default value.
/// Throws a SyntaxException or a RangeException if the property can not be converted
/// to an UInt16.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
#if defined(POCO_HAVE_INT64)
@ -188,8 +260,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an Int64.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
UInt64 getUInt64(const std::string& key) const;
/// Returns the UInt64 value of the property with the given name.
@ -197,8 +269,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an UInt64.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
Int64 getInt64(const std::string& key, Int64 defaultValue) const;
/// If a property with the given key exists, returns the property's Int64 value,
@ -206,8 +278,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an Int64.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
UInt64 getUInt64(const std::string& key, UInt64 defaultValue) const;
/// If a property with the given key exists, returns the property's UInt64
@ -215,8 +287,8 @@ public:
/// Throws a SyntaxException if the property can not be converted
/// to an UInt64.
/// Numbers starting with 0x are treated as hexadecimal.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
#endif // defined(POCO_HAVE_INT64)
@ -225,24 +297,24 @@ public:
/// Throws a NotFoundException if the key does not exist.
/// Throws a SyntaxException if the property can not be converted
/// to a double.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
double getDouble(const std::string& key, double defaultValue) const;
/// If a property with the given key exists, returns the property's double value,
/// otherwise returns the given default value.
/// Throws a SyntaxException if the property can not be converted
/// to an double.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
bool getBool(const std::string& key) const;
/// Returns the boolean value of the property with the given name.
/// Throws a NotFoundException if the key does not exist.
/// Throws a SyntaxException if the property can not be converted
/// to a boolean.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
bool getBool(const std::string& key, bool defaultValue) const;
/// If a property with the given key exists, returns the property's boolean value,
@ -253,8 +325,8 @@ public:
/// - numerical values: non zero becomes true, zero becomes false
/// - strings: true, yes, on become true, false, no, off become false
/// Case does not matter.
/// If the value contains references to other properties (${<property>}), these
/// are expanded.
/// If the value contains references to other properties (${<property>}, or
/// ${<property>:-<default>}), these are expanded (see expand()).
virtual void setString(const std::string& key, const std::string& value);
/// Sets the property with the given key to the given value.
@ -268,6 +340,22 @@ public:
/// Sets the property with the given key to the given value.
/// An already existing value for the key is overwritten.
virtual void setInt16(const std::string& key, Poco::Int16 value);
/// Sets the property with the given key to the given value.
/// An already existing value for the key is overwritten.
virtual void setUInt16(const std::string& key, Poco::UInt16 value);
/// Sets the property with the given key to the given value.
/// An already existing value for the key is overwritten.
virtual void setInt32(const std::string& key, Poco::Int32 value);
/// Sets the property with the given key to the given value.
/// An already existing value for the key is overwritten.
virtual void setUInt32(const std::string& key, Poco::UInt32 value);
/// Sets the property with the given key to the given value.
/// An already existing value for the key is overwritten.
#if defined(POCO_HAVE_INT64)
virtual void setInt64(const std::string& key, Int64 value);
@ -312,6 +400,12 @@ public:
/// value of the <property>. If <property> does not exist,
/// nothing is changed.
///
/// It is also possible to specify a default value for a referenced
/// property that does not exist, using ${<property>:-<default>}.
/// Note that currently a default value cannot contain a closing
/// curly bracket ("}"). The default value also cannot reference
/// another variable.
///
/// If a circular property reference is detected, a
/// CircularReferenceException will be thrown.
@ -359,6 +453,14 @@ protected:
/// Returns string as unsigned integer.
/// Decimal and hexadecimal notation is supported.
static Poco::Int16 parseInt16(const std::string& value);
/// Returns string as signed 16-bit integer.
/// Decimal and hexadecimal notation is supported.
static Poco::UInt16 parseUInt16(const std::string& value);
/// Returns string as unsigned 16-bit integer.
/// Decimal and hexadecimal notation is supported.
#if defined(POCO_HAVE_INT64)
static Int64 parseInt64(const std::string& value);
@ -394,6 +496,35 @@ private:
};
//
// inlines
//
inline Poco::Int32 AbstractConfiguration::getInt32(const std::string& key) const
{
return getInt(key);
}
inline Poco::Int32 AbstractConfiguration::getInt32(const std::string& key, Poco::Int32 defaultValue) const
{
return getInt(key, defaultValue);
}
inline Poco::UInt32 AbstractConfiguration::getUInt32(const std::string& key) const
{
return getUInt(key);
}
inline Poco::UInt32 AbstractConfiguration::getUInt32(const std::string& key, Poco::UInt32 defaultValue) const
{
return getUInt(key, defaultValue);
}
} } // namespace Poco::Util

View File

@ -164,6 +164,54 @@ unsigned AbstractConfiguration::getUInt(const std::string& key, unsigned default
}
Poco::Int16 AbstractConfiguration::getInt16(const std::string& key) const
{
Mutex::ScopedLock lock(_mutex);
std::string value;
if (getRaw(key, value))
return parseInt16(internalExpand(value));
else
throw NotFoundException(key);
}
Poco::Int16 AbstractConfiguration::getInt16(const std::string& key, Poco::Int16 defaultValue) const
{
Mutex::ScopedLock lock(_mutex);
std::string value;
if (getRaw(key, value))
return parseInt16(internalExpand(value));
else
return defaultValue;
}
Poco::UInt16 AbstractConfiguration::getUInt16(const std::string& key) const
{
Mutex::ScopedLock lock(_mutex);
std::string value;
if (getRaw(key, value))
return parseUInt16(internalExpand(value));
else
throw NotFoundException(key);
}
Poco::UInt16 AbstractConfiguration::getUInt16(const std::string& key, Poco::UInt16 defaultValue) const
{
Mutex::ScopedLock lock(_mutex);
std::string value;
if (getRaw(key, value))
return parseUInt16(internalExpand(value));
else
return defaultValue;
}
#if defined(POCO_HAVE_INT64)
@ -284,6 +332,30 @@ void AbstractConfiguration::setUInt(const std::string& key, unsigned int value)
}
void AbstractConfiguration::setInt16(const std::string& key, Poco::Int16 value)
{
setRawWithEvent(key, NumberFormatter::format(value));
}
void AbstractConfiguration::setUInt16(const std::string& key, Poco::UInt16 value)
{
setRawWithEvent(key, NumberFormatter::format(value));
}
void AbstractConfiguration::setInt32(const std::string& key, Poco::Int32 value)
{
setRawWithEvent(key, NumberFormatter::format(value));
}
void AbstractConfiguration::setUInt32(const std::string& key, Poco::UInt32 value)
{
setRawWithEvent(key, NumberFormatter::format(value));
}
#if defined(POCO_HAVE_INT64)
@ -448,13 +520,33 @@ std::string AbstractConfiguration::uncheckedExpand(const std::string& value) con
{
++it;
std::string prop;
while (it != end && *it != '}') prop += *it++;
std::string deflt;
bool haveDefault = false;
while (it != end && *it != '}')
{
if (*it == ':')
{
++it;
if (it != end && *it == '-')
{
haveDefault = true;
++it;
while (it != end && *it != '}') deflt += *it++;
}
else prop += ':';
}
else prop += *it++;
}
if (it != end) ++it;
std::string value;
if (getRaw(prop, value))
{
result.append(internalExpand(value));
}
else if (haveDefault)
{
result.append(deflt);
}
else
{
result.append("${");
@ -488,6 +580,34 @@ unsigned AbstractConfiguration::parseUInt(const std::string& value)
}
Poco::Int16 AbstractConfiguration::parseInt16(const std::string& value)
{
int intValue = 0;
if ((value.compare(0, 2, "0x") == 0) || (value.compare(0, 2, "0X") == 0))
intValue = static_cast<int>(NumberParser::parseHex(value));
else
intValue = NumberParser::parse(value);
if (intValue >= -32768 && intValue <= 32767)
return static_cast<Poco::Int16>(intValue);
else
throw Poco::RangeException("Not a valid 16-bit integer value", value);
}
Poco::UInt16 AbstractConfiguration::parseUInt16(const std::string& value)
{
unsigned uintValue;
if ((value.compare(0, 2, "0x") == 0) || (value.compare(0, 2, "0X") == 0))
uintValue = NumberParser::parseHex(value);
else
uintValue = NumberParser::parseUnsigned(value);
if (uintValue <= 65535)
return static_cast<Poco::UInt16>(uintValue);
else
throw Poco::RangeException("Not a valid unsigned 16-bit integer value", value);
}
Int64 AbstractConfiguration::parseInt64(const std::string& value)
{
if ((value.compare(0, 2, "0x") == 0) || (value.compare(0, 2, "0X") == 0))

View File

@ -105,6 +105,49 @@ void AbstractConfigurationTest::testGetInt()
}
void AbstractConfigurationTest::testGetInt16()
{
AutoPtr<AbstractConfiguration> pConf = createConfiguration();
assertTrue (pConf->getInt16("prop4.int1") == 42);
assertTrue (pConf->getInt16("prop4.int2") == -42);
assertTrue (pConf->getInt16("prop4.hex") == 0x1f);
assertTrue (pConf->getUInt16("prop4.hex") == 0x1f);
assertTrue (pConf->getInt16("ref2") == 42);
try
{
pConf->getInt16("prop1");
fail("not a number - must throw");
}
catch (Poco::SyntaxException&)
{
}
try
{
pConf->getInt16("prop4.notint16");
fail("too big for UInt16 - must throw");
}
catch (Poco::RangeException&)
{
}
try
{
pConf->getUInt16("prop4.notuint16");
fail("too big for UInt16 - must throw");
}
catch (Poco::RangeException&)
{
}
assertTrue (pConf->getInt16("prop4.int1", 100) == 42);
assertTrue (pConf->getInt16("prop4.int2", 100) == -42);
assertTrue (pConf->getInt16("prop4.int3", 100) == 100);
}
void AbstractConfigurationTest::testGetInt64()
{
#if defined(POCO_HAVE_INT64)
@ -212,6 +255,11 @@ void AbstractConfigurationTest::testExpand()
assertTrue (pConf->getString("dollar.atend") == "foo$");
assertTrue (pConf->getString("dollar.middle") == "foo$bar");
assertTrue (pConf->expand("default=${undefined:-default value}") == "default=default value");
assertTrue (pConf->expand("default=${undefined:-}") == "default=");
assertTrue (pConf->expand("default=${undefined:value}") == "default=${undefined:value}");
assertTrue (pConf->expand("default:${undefined::value}") == "default:${undefined::value}");
}
@ -368,7 +416,7 @@ void AbstractConfigurationTest::testRemove()
pConf->keys(keys);
assertTrue (keys.size() == 13);
pConf->keys("prop4", keys);
assertTrue (keys.size() == 17);
assertTrue (keys.size() == 19);
pConf->remove("prop4.bool1");
assertTrue (!pConf->hasProperty("prop4.bool1"));
@ -377,7 +425,7 @@ void AbstractConfigurationTest::testRemove()
pConf->keys(keys);
assertTrue (keys.size() == 13);
pConf->keys("prop4", keys);
assertTrue (keys.size() == 16);
assertTrue (keys.size() == 18);
pConf->remove("prop4");
assertTrue (!pConf->hasProperty("prop4.bool1"));
@ -406,6 +454,8 @@ AbstractConfiguration::Ptr AbstractConfigurationTest::createConfiguration() cons
pConfig->setString("prop4.int1", "42");
pConfig->setString("prop4.int2", "-42");
pConfig->setString("prop4.uint", NumberFormatter::format(std::numeric_limits<unsigned>::max()));
pConfig->setString("prop4.notint16", "32768");
pConfig->setString("prop4.notuint16", "65536");
#if defined(POCO_HAVE_INT64)
pConfig->setString("prop4.bigint1", NumberFormatter::format(std::numeric_limits<Int64>::max()));
pConfig->setString("prop4.bigint2", NumberFormatter::format(std::numeric_limits<Int64>::min()));

View File

@ -29,6 +29,7 @@ public:
void testHasProperty();
void testGetString();
void testGetInt();
void testGetInt16();
void testGetInt64();
void testGetDouble();
void testGetBool();

View File

@ -102,7 +102,7 @@ void IniFileConfigurationTest::testCaseInsensitiveRemove()
pConf->keys(keys);
assertTrue (keys.size() == 13);
pConf->keys("prop4", keys);
assertTrue (keys.size() == 17);
assertTrue (keys.size() == 19);
pConf->remove("PROP4.Bool1");
assertTrue (pConf->hasProperty("Prop1"));
@ -112,7 +112,7 @@ void IniFileConfigurationTest::testCaseInsensitiveRemove()
pConf->keys(keys);
assertTrue (keys.size() == 13);
pConf->keys("PROP4", keys);
assertTrue (keys.size() == 16);
assertTrue (keys.size() == 18);
pConf->remove("Prop4");
assertTrue (pConf->hasProperty("Prop1"));