Fix more compatibility problems in C++17 wxString::ToLong()

Unlike the traditional C functions, std::from_chars() doesn't skip
leading whitespace and doesn't accept the leading "+" sign, so we need
to skip them explicitly to preserve the behaviour of ToLong() in the
previous wxWidgets versions.
This commit is contained in:
Vadim Zeitlin 2023-10-31 00:04:27 +01:00
parent 8d6a722ed8
commit ae2b05be5c
2 changed files with 20 additions and 7 deletions

View file

@ -1580,15 +1580,25 @@ bool wxString::ToDouble(double *pVal) const
namespace
{
// Helper of ToCLong() and ToCULong() taking care of base-related stuff:
// because from_chars() doesn't recognize base==0 and doesn't recognize "0x"
// prefix even if base 16 is explicitly specified, we need to skip the prefix
// indicating the base to use if it's present and adjust "base" itself instead.
// Helper of ToCLong() and ToCULong() taking care of prefix and base-related
// stuff: because from_chars() doesn't skip leading whitespace and doesn't
// recognize base==0 nor "0x" prefix even if base 16 is explicitly specified,
// we need to skip the leading space and prefix indicating the base to use if
// it's present and adjust "base" itself instead.
//
// Return false if base is already specified but is incompatible with the
// prefix used.
bool SetBaseAndSkipPrefix(int& base, const char*& start, const char* end)
bool SkipOptPrefixAndSetBase(int& base, const char*& start, const char* end)
{
// Start by skipping whitespace.
while ( wxSafeIsspace(*start) )
++start;
// Also skip optional "+" which std::from_chars() doesn't accept neither.
if ( *start == '+' )
++start;
// Then check for the base prefix.
if ( end - start > 1 && *start == '0' )
{
++start;
@ -1623,7 +1633,7 @@ bool wxString::ToCLong(long *pVal, int base) const
auto start = buf.data();
const auto end = start + buf.length();
if ( !SetBaseAndSkipPrefix(base, start, end) )
if ( !SkipOptPrefixAndSetBase(base, start, end) )
return false;
const auto res = std::from_chars(start, end, *pVal, base);
@ -1639,7 +1649,7 @@ bool wxString::ToCULong(unsigned long *pVal, int base) const
auto start = buf.data();
const auto end = start + buf.length();
if ( !SetBaseAndSkipPrefix(base, start, end) )
if ( !SkipOptPrefixAndSetBase(base, start, end) )
return false;
// Extra complication: for compatibility reasons, this function does accept

View file

@ -580,6 +580,9 @@ static const struct ToLongData
{ wxT("-1"), -1, Number_Signed | Number_Long },
// this is surprising but consistent with strtoul() behaviour
{ wxT("-1"), (TestValue_t)ULONG_MAX, Number_Unsigned | Number_Long },
// a couple of edge cases
{ wxT(" +1"), 1, Number_Ok },
{ wxT(" -1"), (TestValue_t)ULONG_MAX, Number_Unsigned | Number_Long },
// this must overflow, even with 64 bit long
{ wxT("922337203685477580711"), 0, Number_Invalid },