diff --git a/tools/inc/tools/string.hxx b/tools/inc/tools/string.hxx index 25cb2d4..e6dc3f7 100644 --- a/tools/inc/tools/string.hxx +++ b/tools/inc/tools/string.hxx @@ -301,6 +301,7 @@ public: xub_StrLen nLen = STRING_LEN ) const; StringCompare CompareTo( const sal_Char* pCharStr, xub_StrLen nLen = STRING_LEN ) const; + StringCompare CompareToNumeric( const ByteString& rStr ) const; StringCompare CompareIgnoreCaseToAscii( const ByteString& rStr, xub_StrLen nLen = STRING_LEN ) const; StringCompare CompareIgnoreCaseToAscii( const sal_Char* pCharStr, @@ -597,6 +598,7 @@ public: xub_StrLen nLen = STRING_LEN ) const; StringCompare CompareToAscii( const sal_Char* pAsciiStr, xub_StrLen nLen = STRING_LEN ) const; + StringCompare CompareToNumeric( const UniString& rStr ) const; StringCompare CompareIgnoreCaseToAscii( const UniString& rStr, xub_StrLen nLen = STRING_LEN ) const; StringCompare CompareIgnoreCaseToAscii( const sal_Unicode* pCharStr, diff --git a/tools/qa/makefile.mk b/tools/qa/makefile.mk index f8cca03..ac550df 100644 --- a/tools/qa/makefile.mk +++ b/tools/qa/makefile.mk @@ -46,7 +46,8 @@ SHL1TARGET=test_tools SHL1OBJS=\ $(SLO)$/pathutils.obj \ $(SLO)$/test_pathutils.obj \ - $(SLO)$/test_reversemap.obj + $(SLO)$/test_reversemap.obj \ + $(SLO)$/test_strings.obj SHL1STDLIBS = $(TOOLSLIB) $(CPPUNITLIB) $(SALLIB) SHL1VERSIONMAP = version.map SHL1IMPLIB = i$(SHL1TARGET) diff --git a/tools/qa/test_strings.cxx b/tools/qa/test_strings.cxx new file mode 100644 index 0000000..b7060f3 --- /dev/null +++ b/tools/qa/test_strings.cxx @@ -0,0 +1,88 @@ +#include +#include +#include + +#include + +namespace test { + namespace unistring { + /** + * test::unistring::Compare Perform comparison functions + * tests on UniString. + */ + class Compare: public CppUnit::TestFixture + { + private: + /** + * Performs tests on natural comparison function + */ + void testCompareToNumeric(); + + CPPUNIT_TEST_SUITE(Compare); + CPPUNIT_TEST(testCompareToNumeric); + CPPUNIT_TEST_SUITE_END(); + + }; + } +} + +#define US_FROM_STRING(STRING) UniString((STRING), RTL_TEXTENCODING_UTF8) + +void test::unistring::Compare::testCompareToNumeric() +{ +// --- Some generic tests to ensure we do not alter original behavior +// outside what we want + CPPUNIT_ASSERT( + US_FROM_STRING("ABC").CompareToNumeric(US_FROM_STRING("ABC")) == COMPARE_EQUAL + ); + // Case sensitivity + CPPUNIT_ASSERT( + US_FROM_STRING("ABC").CompareToNumeric(US_FROM_STRING("abc")) == COMPARE_LESS + ); + // Reverse + CPPUNIT_ASSERT( + US_FROM_STRING("abc").CompareToNumeric(US_FROM_STRING("ABC")) == COMPARE_GREATER + ); + // First shorter + CPPUNIT_ASSERT( + US_FROM_STRING("alongstring").CompareToNumeric(US_FROM_STRING("alongerstring")) == COMPARE_GREATER + ); + // Second shorter + CPPUNIT_ASSERT( + US_FROM_STRING("alongerstring").CompareToNumeric(US_FROM_STRING("alongstring")) == COMPARE_LESS + ); +// -- Here we go on natural order, each one is followed by classic compare and the reverse comparison + // That's why we originally made the patch + CPPUNIT_ASSERT( + US_FROM_STRING("Heading 9").CompareToNumeric(US_FROM_STRING("Heading 10")) == COMPARE_LESS + ); + // Original behavior + CPPUNIT_ASSERT( + US_FROM_STRING("Heading 9").CompareTo(US_FROM_STRING("Heading 10")) == COMPARE_GREATER + ); + CPPUNIT_ASSERT( + US_FROM_STRING("Heading 10").CompareToNumeric(US_FROM_STRING("Heading 9")) == COMPARE_GREATER + ); + // Harder + CPPUNIT_ASSERT( + US_FROM_STRING("July, the 4th").CompareToNumeric(US_FROM_STRING("July, the 10th")) == COMPARE_LESS + ); + CPPUNIT_ASSERT( + US_FROM_STRING("July, the 4th").CompareTo(US_FROM_STRING("July, the 10th")) == COMPARE_GREATER + ); + CPPUNIT_ASSERT( + US_FROM_STRING("July, the 10th").CompareToNumeric(US_FROM_STRING("July, the 4th")) == COMPARE_GREATER + ); + // Hardest + CPPUNIT_ASSERT( + US_FROM_STRING("abc08").CompareToNumeric(US_FROM_STRING("abc010")) == COMPARE_LESS + ); + CPPUNIT_ASSERT( + US_FROM_STRING("abc08").CompareTo(US_FROM_STRING("abc010")) == COMPARE_GREATER + ); + CPPUNIT_ASSERT( + US_FROM_STRING("abc010").CompareToNumeric(US_FROM_STRING("abc08")) == COMPARE_GREATER + ); +} + +CPPUNIT_TEST_SUITE_REGISTRATION(test::unistring::Compare); diff --git a/tools/source/string/strimp.cxx b/tools/source/string/strimp.cxx index e77a4ac..01f2955 100644 --- a/tools/source/string/strimp.cxx +++ b/tools/source/string/strimp.cxx @@ -30,6 +30,8 @@ // ======================================================================= +#define IS_DIGIT(CHAR) (((CHAR) >= 48) && ((CHAR <= 57))) + static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2 ) { sal_Int32 nRet; @@ -61,6 +63,55 @@ static sal_Int32 ImplStringCompare( const STRCODE* pStr1, const STRCODE* pStr2, return nRet; } +static sal_Int32 ImplStringCompareToNumeric( const STRCODE* pStr1, const STRCODE* pStr2 ) +{ + sal_Int32 nRet = 0; + do + { + while ( ((nRet = ((sal_Int32)((STRCODEU)*pStr1))- + ((sal_Int32)((STRCODEU)*pStr2))) == 0) && + *pStr2 ) + { + pStr1++; + pStr2++; + } + + if(*pStr1 && *pStr2) + { + STRCODE c1 = ( *pStr1 ); + STRCODE c2 = ( *pStr2 ); + sal_Int64 number1 = 0; + sal_Int64 number2 = 0; + if(IS_DIGIT(c1) && IS_DIGIT(c2)) + { + do + { + number1 = number1 * 10 + (c1 - '0'); + pStr1++; + c1 = ( *pStr1 ); + } + while(c1 && IS_DIGIT(c1)); + + do + { + number2 = number2 * 10 + (c2 - '0'); + pStr2++; + c2 = ( *pStr2 ); + } + while(c2 && IS_DIGIT(c2)); + + if(number1 != number2) + { + nRet = number1 - number2; + } + } + } + } + while(nRet == 0 && *pStr1 && *pStr2); + + return nRet; +} + // ----------------------------------------------------------------------- static sal_Int32 ImplStringCompareWithoutZero( const STRCODE* pStr1, const STRCODE* pStr2, @@ -1277,6 +1328,24 @@ StringCompare STRING::CompareTo( const STRCODE* pCharStr, xub_StrLen nLen ) cons return COMPARE_GREATER; } +StringCompare STRING::CompareToNumeric( const STRING& rStr) const +{ + // ensure arguments' types + DBG_CHKTHIS( STRING, DBGCHECKSTRING ); + DBG_CHKOBJ( &rStr, STRING, DBGCHECKSTRING ); + + if ( mpData == rStr.mpData ) + return COMPARE_EQUAL; + + sal_Int32 nCompare = ImplStringCompareToNumeric( mpData->maStr, rStr.mpData->maStr ); + + if( nCompare == 0) + return COMPARE_EQUAL; + else if(nCompare < 0 ) + return COMPARE_LESS; + else + return COMPARE_GREATER; +} // ----------------------------------------------------------------------- StringCompare STRING::CompareIgnoreCaseToAscii( const STRING& rStr,