diff --git a/include/wx/string.h b/include/wx/string.h index 73fc59fb20..4259c5c8b9 100644 --- a/include/wx/string.h +++ b/include/wx/string.h @@ -2310,9 +2310,14 @@ public: // provided, the base is the numeric base in which the conversion should be // done and must be comprised between 2 and 36 or be 0 in which case the // standard C rules apply (leading '0' => octal, "0x" => hex) - // convert to a signed integer + + // convert to a signed integer + bool ToInt(int *val, int base = 10) const; + // convert to an unsigned integer + bool ToUInt(unsigned int *val, int base = 10) const; + // convert to a signed long bool ToLong(long *val, int base = 10) const; - // convert to an unsigned integer + // convert to an unsigned long bool ToULong(unsigned long *val, int base = 10) const; // convert to wxLongLong #if defined(wxLongLong_t) diff --git a/interface/wx/string.h b/interface/wx/string.h index 3519b8442a..adb448159d 100644 --- a/interface/wx/string.h +++ b/interface/wx/string.h @@ -1266,6 +1266,24 @@ public: */ bool ToCDouble(double* val) const; + /** + Works like ToLong() but for signed integers. + + @see ToLong(), ToUInt(), ToDouble() + + @since 3.1.6 + */ + bool ToInt(int *val, int base = 10) const; + + /** + Works like ToULong() but for unsigned integers. + + @see ToInt(), ToULong(), ToDouble() + + @since 3.1.6 + */ + bool ToUInt(unsigned int *val, int base = 10) const; + /** Attempts to convert the string to a signed integer in base @a base. @@ -1294,7 +1312,7 @@ public: Please refer to the documentation of the standard function @c strtol() for more details about the supported syntax. - @see ToCDouble(), ToDouble(), ToULong() + @see ToCDouble(), ToDouble(), ToULong(), ToInt() */ bool ToLong(long* val, int base = 10) const; diff --git a/src/common/string.cpp b/src/common/string.cpp index 9fcd5a672b..0dd78e0ddd 100644 --- a/src/common/string.cpp +++ b/src/common/string.cpp @@ -1677,6 +1677,32 @@ int wxString::Find(wxUniChar ch, bool bFromEnd) const *pVal = val; \ return !*end; +bool wxString::ToInt(int *pVal, int base) const +{ + wxASSERT_MSG(!base || (base > 1 && base <= 36), wxT("invalid base")); + + WX_STRING_TO_X_TYPE_START + wxLongLong_t lval = wxStrtoll(start, &end, base); + + if (lval < INT_MIN || lval > INT_MAX) + return false; + int val = (int)lval; + + WX_STRING_TO_X_TYPE_END +} + +bool wxString::ToUInt(unsigned int *pVal, int base) const +{ + wxASSERT_MSG(!base || (base > 1 && base <= 36), wxT("invalid base")); + + WX_STRING_TO_X_TYPE_START + wxULongLong_t lval = wxStrtoull(start, &end, base); + if (lval > UINT_MAX) + return false; + unsigned int val = (unsigned int)lval; + WX_STRING_TO_X_TYPE_END +} + bool wxString::ToLong(long *pVal, int base) const { wxASSERT_MSG( !base || (base > 1 && base <= 36), wxT("invalid base") ); diff --git a/tests/strings/strings.cpp b/tests/strings/strings.cpp index 8bbe9d69ad..5b48f37bbc 100644 --- a/tests/strings/strings.cpp +++ b/tests/strings/strings.cpp @@ -43,6 +43,8 @@ private: CPPUNIT_TEST( Compare ); CPPUNIT_TEST( CompareNoCase ); CPPUNIT_TEST( Contains ); + CPPUNIT_TEST( ToInt ); + CPPUNIT_TEST( ToUInt ); CPPUNIT_TEST( ToLong ); CPPUNIT_TEST( ToULong ); #ifdef wxLongLong_t @@ -78,6 +80,8 @@ private: void Compare(); void CompareNoCase(); void Contains(); + void ToInt(); + void ToUInt(); void ToLong(); void ToULong(); #ifdef wxLongLong_t @@ -602,7 +606,8 @@ enum Number_Unsigned = 2, // if not specified, works for signed conversion Number_Signed = 4, // if not specified, works for unsigned Number_LongLong = 8, // only for long long tests - Number_Long = 16 // only for long tests + Number_Long = 16, // only for long tests + Number_Int = 32 // only for int tests }; #ifdef wxLongLong_t @@ -613,6 +618,38 @@ typedef long TestValue_t; wxGCC_WARNING_SUPPRESS(missing-field-initializers) +static const struct ToIntData +{ + const wxChar *str; + TestValue_t value; + int flags; + int base; + + int IValue() const { return value; } + unsigned int UIValue() const { return value; } + + bool IsOk() const { return !(flags & Number_Invalid); } +} intData[] = +{ + { wxT("1"), 1, Number_Ok }, + { wxT("0"), 0, Number_Ok }, + { wxT("a"), 0, Number_Invalid }, + { wxT("12345"), 12345, Number_Ok }, + { wxT("--1"), 0, Number_Invalid }, + + { wxT("-1"), -1, Number_Signed | Number_Int }, + { wxT("-1"), (TestValue_t)UINT_MAX, Number_Unsigned | Number_Int | Number_Invalid }, + + { wxT("2147483647"), (TestValue_t)INT_MAX, Number_Int | Number_Signed }, + { wxT("2147483648"), (TestValue_t)INT_MAX, Number_Int | Number_Signed | Number_Invalid }, + + { wxT("-2147483648"), (TestValue_t)INT_MIN, Number_Int | Number_Signed }, + { wxT("-2147483649"), (TestValue_t)INT_MIN, Number_Int | Number_Signed | Number_Invalid }, + + { wxT("4294967295"), (TestValue_t)UINT_MAX, Number_Int | Number_Unsigned }, + { wxT("4294967296"), (TestValue_t)UINT_MAX, Number_Int | Number_Unsigned | Number_Invalid }, +}; + static const struct ToLongData { const wxChar *str; @@ -670,6 +707,64 @@ static const struct ToLongData wxGCC_WARNING_RESTORE(missing-field-initializers) +void StringTestCase::ToInt() +{ + int i; + for (size_t n = 0; n < WXSIZEOF(intData); n++) + { + const ToIntData &id = intData[n]; + + if (id.flags & (Number_Unsigned)) + continue; + + CPPUNIT_ASSERT_EQUAL(id.IsOk(), + wxString(id.str).ToInt(&i, id.base)); + + if (id.IsOk()) + CPPUNIT_ASSERT_EQUAL(id.IValue(), i); + } + + // special case: check that the output is not modified if the parsing + // failed completely + i = 17; + CPPUNIT_ASSERT(!wxString("foo").ToInt(&i)); + CPPUNIT_ASSERT_EQUAL(17, i); + + // also check that it is modified if we did parse something successfully in + // the beginning of the string + CPPUNIT_ASSERT(!wxString("9 cats").ToInt(&i)); + CPPUNIT_ASSERT_EQUAL(9, i); +} + +void StringTestCase::ToUInt() +{ + unsigned int i; + for (size_t n = 0; n < WXSIZEOF(intData); n++) + { + const ToIntData &id = intData[n]; + + if (id.flags & (Number_Signed)) + continue; + + CPPUNIT_ASSERT_EQUAL(id.IsOk(), + wxString(id.str).ToUInt(&i, id.base)); + + if (id.IsOk()) + CPPUNIT_ASSERT_EQUAL(id.UIValue(), i); + } + + // special case: check that the output is not modified if the parsing + // failed completely + i = 17; + CPPUNIT_ASSERT(!wxString("foo").ToUInt(&i)); + CPPUNIT_ASSERT_EQUAL(17, i); + + // also check that it is modified if we did parse something successfully in + // the beginning of the string + CPPUNIT_ASSERT(!wxString("9 cats").ToUInt(&i)); + CPPUNIT_ASSERT_EQUAL(9, i); +} + void StringTestCase::ToLong() { long l;