basic/qa/basic_coverage/test_isnumeric_method.bas | 35 ++++++++++++++++------ basic/qa/vba_tests/isnumeric.vb | 8 +++++ basic/source/runtime/runtime.cxx | 2 - basic/source/sbx/sbxbool.cxx | 2 - basic/source/sbx/sbxconv.hxx | 6 +-- basic/source/sbx/sbxexec.cxx | 2 - basic/source/sbx/sbxscan.cxx | 25 +++++++++++---- basic/source/sbx/sbxvalue.cxx | 7 ++-- include/basic/sbxvar.hxx | 2 - 9 files changed, 64 insertions(+), 25 deletions(-)
New commits: commit f8ac9d3311a623fdca64583b08780ea8ebed157c Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Jan 6 15:16:40 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Jan 8 06:02:43 2025 +0100 tdf#164599: Allow space between sign and number in VBASupport mode Change-Id: Ib9e8c8770f8c2d1b348ff032502467915829c4f3 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179865 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/basic/qa/basic_coverage/test_isnumeric_method.bas b/basic/qa/basic_coverage/test_isnumeric_method.bas index 21e4a91a8b45..eb476e8a6b35 100644 --- a/basic/qa/basic_coverage/test_isnumeric_method.bas +++ b/basic/qa/basic_coverage/test_isnumeric_method.bas @@ -28,7 +28,7 @@ Sub verify_IsNumeric TestUtil.Assert(Not IsNumeric(" "), "Not IsNumeric("" "")") TestUtil.Assert(Not IsNumeric(" + "), "Not IsNumeric("" + "")") TestUtil.Assert(Not IsNumeric(" - "), "Not IsNumeric("" - "")") - ' Note: the two following tests should behave different in VBA (TODO/FIXME); + ' Note: the two following tests behave different in VBA; ' should it be unified maybe in non-VBA, too (a breaking change)? TestUtil.Assert(Not IsNumeric(" + 0 "), "Not IsNumeric("" + 0 "")") TestUtil.Assert(Not IsNumeric(" - 0 "), "Not IsNumeric("" - 0 "")") diff --git a/basic/qa/vba_tests/isnumeric.vb b/basic/qa/vba_tests/isnumeric.vb index ead7e83e1494..721a2fb7f4b6 100644 --- a/basic/qa/vba_tests/isnumeric.vb +++ b/basic/qa/vba_tests/isnumeric.vb @@ -26,6 +26,14 @@ rem TestUtil.Assert(IsNumeric(True), "IsNumeric(True)") TestUtil.Assert(IsNumeric("123"), "IsNumeric(""123"")") TestUtil.Assert(IsNumeric("+123"), "IsNumeric(""+123"")") + TestUtil.Assert(Not IsNumeric(""), "Not IsNumeric("""")") + TestUtil.Assert(Not IsNumeric(" "), "Not IsNumeric("" "")") + TestUtil.Assert(Not IsNumeric(" + "), "Not IsNumeric("" + "")") + TestUtil.Assert(Not IsNumeric(" - "), "Not IsNumeric("" - "")") + + TestUtil.Assert(IsNumeric(" + 0 "), "IsNumeric("" + 0 "")") + TestUtil.Assert(IsNumeric(" - 0 "), "IsNumeric("" - 0 "")") + Exit Sub errorHandler: TestUtil.ReportErrorHandler("verify_testIsNumeric", Err, Error$, Erl) diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx index 84e2e78dc99e..f843d6b44e13 100644 --- a/basic/source/sbx/sbxscan.cxx +++ b/basic/source/sbx/sbxscan.cxx @@ -102,6 +102,13 @@ ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, p++; bMinus = true; } +#if HAVE_FEATURE_SCRIPTING + if (SbiRuntime::isVBAEnabled()) + { + while (p != rWSrc.end() && (*p == ' ' || *p == ' ')) + p++; + } +#endif const auto pNumberStart = p; if (p != rWSrc.end() && (rtl::isAsciiDigit(*p) commit 20db60030eaa9a2bc099894d89a63808e12c7635 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Jan 6 14:49:40 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Jan 8 06:02:37 2025 +0100 Use sal_Int32 for string length Change-Id: Ie069c20b7d91631cb3b5d39e1a52f09cc13e8a22 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179864 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins diff --git a/basic/source/runtime/runtime.cxx b/basic/source/runtime/runtime.cxx index 2fcbfb7372cb..3a715a9278db 100644 --- a/basic/source/runtime/runtime.cxx +++ b/basic/source/runtime/runtime.cxx @@ -2521,7 +2521,7 @@ void SbiRuntime::StepINPUT() // then with a string value if( !pVar->IsFixed() || pVar->IsNumeric() ) { - sal_uInt16 nLen = 0; + sal_Int32 nLen = 0; if( !pVar->Scan( s, &nLen ) ) { err = SbxBase::GetError(); diff --git a/basic/source/sbx/sbxbool.cxx b/basic/source/sbx/sbxbool.cxx index fd9002b4eff3..c6d9c2fbd166 100644 --- a/basic/source/sbx/sbxbool.cxx +++ b/basic/source/sbx/sbxbool.cxx @@ -79,7 +79,7 @@ enum SbxBOOL ImpGetBool( const SbxValues* p ) bool bError = true; double n; SbxDataType t; - sal_uInt16 nLen = 0; + sal_Int32 nLen = 0; if( ImpScan( *p->pOUString, n, t, &nLen ) == ERRCODE_NONE ) { if( nLen == p->pOUString->getLength() ) diff --git a/basic/source/sbx/sbxconv.hxx b/basic/source/sbx/sbxconv.hxx index 11725dec5b29..edb0e8cd973c 100644 --- a/basic/source/sbx/sbxconv.hxx +++ b/basic/source/sbx/sbxconv.hxx @@ -63,11 +63,11 @@ inline auto ImpDoubleToSalInt64(double d) // SBXSCAN.CXX extern void ImpCvtNum( double nNum, short nPrec, OUString& rRes, bool bCoreString=false ); extern ErrCode ImpScan - ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_uInt16* pLen, + ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_Int32* pLen, bool* pHasNumber, bool bOnlyIntntl ); // A version that uses defaults / compatibility settings for bOnlyIntntl extern ErrCode ImpScan - ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_uInt16* pLen ); + ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_Int32* pLen ); void ImpGetIntntlSep( sal_Unicode& rcDecimalSep, sal_Unicode& rcThousandSep, sal_Unicode& rcDecimalSepAlt ); diff --git a/basic/source/sbx/sbxexec.cxx b/basic/source/sbx/sbxexec.cxx index 8c88099efbee..9d9b339ef715 100644 --- a/basic/source/sbx/sbxexec.cxx +++ b/basic/source/sbx/sbxexec.cxx @@ -129,7 +129,7 @@ static SbxVariableRef Operand || *p == '&' ) ) { // A number could be scanned in directly! - sal_uInt16 nLen; + sal_Int32 nLen; if (!refVar->Scan(p, &nLen)) { refVar.clear(); diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx index 008b5aeb0a4e..84e2e78dc99e 100644 --- a/basic/source/sbx/sbxscan.cxx +++ b/basic/source/sbx/sbxscan.cxx @@ -71,7 +71,7 @@ static bool ImpStrChr( std::u16string_view str, sal_Unicode c ) { return str.fin // conversion error if data type is fixed and it doesn't fit ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, - sal_uInt16* pLen, bool* pHasNumber, bool bOnlyIntntl ) + sal_Int32* pLen, bool* pHasNumber, bool bOnlyIntntl ) { sal_Unicode cDecSep, cGrpSep, cDecSepAlt; if( bOnlyIntntl ) @@ -237,7 +237,7 @@ ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, while (p != rWSrc.end() && (*p == ' ' || *p == ' ')) p++; if( pLen ) - *pLen = static_cast<sal_uInt16>( p - pStart ); + *pLen = p - pStart; if (pHasNumber) *pHasNumber = pNumberEnd > pNumberStart; if( bMinus ) @@ -246,7 +246,7 @@ ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, return ERRCODE_NONE; } -ErrCode ImpScan(std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_uInt16* pLen) +ErrCode ImpScan(std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_Int32* pLen) { using namespace officecfg::Office::Scripting; static const bool bEnv = std::getenv("LIBREOFFICE6FLOATINGPOINTMODE") != nullptr; @@ -258,7 +258,7 @@ ErrCode ImpScan(std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_ // port for CDbl in the Basic ErrCode SbxValue::ScanNumIntnl( const OUString& rSrc, double& nVal, bool bSingle ) { - sal_uInt16 nLen = 0; + sal_Int32 nLen = 0; ErrCode nRetError = ImpScan( rSrc, nVal, o3tl::temporary(SbxDataType()), &nLen, nullptr, /*bOnlyIntntl*/true ); // read completely? @@ -324,7 +324,7 @@ static void printfmtstr(std::u16string_view rStr, OUString& rRes, std::u16string } -bool SbxValue::Scan(std::u16string_view rSrc, sal_uInt16* pLen) +bool SbxValue::Scan(std::u16string_view rSrc, sal_Int32* pLen) { ErrCode eRes = ERRCODE_NONE; if( !CanWrite() ) diff --git a/basic/source/sbx/sbxvalue.cxx b/basic/source/sbx/sbxvalue.cxx index 6b70fe31131a..146c4f50faf1 100644 --- a/basic/source/sbx/sbxvalue.cxx +++ b/basic/source/sbx/sbxvalue.cxx @@ -692,7 +692,7 @@ bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const OUString s( *aData.pOUString ); double n; SbxDataType t2; - sal_uInt16 nLen = 0; + sal_Int32 nLen = 0; bool bHasNumber = false; if( ImpScan( s, n, t2, &nLen, &bHasNumber, bOnlyIntntl ) == ERRCODE_NONE ) return nLen == s.getLength() && bHasNumber; diff --git a/include/basic/sbxvar.hxx b/include/basic/sbxvar.hxx index 29976d1fe7f6..daa961be1a19 100644 --- a/include/basic/sbxvar.hxx +++ b/include/basic/sbxvar.hxx @@ -189,7 +189,7 @@ public: SAL_DLLPRIVATE bool Convert( SbxDataType ); bool Compute( SbxOperator, const SbxValue& ); bool Compare( SbxOperator, const SbxValue& ) const; - SAL_DLLPRIVATE bool Scan( std::u16string_view, sal_uInt16* ); + SAL_DLLPRIVATE bool Scan( std::u16string_view, sal_Int32* ); SAL_DLLPRIVATE void Format( OUString&, const OUString* = nullptr ) const; // The following operators are defined for easier handling. commit bb86627216f5532b6d776fafafd9e796060b57b8 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Mon Jan 6 14:45:44 2025 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Wed Jan 8 06:02:30 2025 +0100 tdf#154284: check if ImpScan found a number at all Change-Id: Iddc87bd0d04f9b0212b03d63f3177b17bb07d278 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179863 Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> Tested-by: Jenkins diff --git a/basic/qa/basic_coverage/test_isnumeric_method.bas b/basic/qa/basic_coverage/test_isnumeric_method.bas index 1b454aa8d5ec..21e4a91a8b45 100644 --- a/basic/qa/basic_coverage/test_isnumeric_method.bas +++ b/basic/qa/basic_coverage/test_isnumeric_method.bas @@ -8,13 +8,32 @@ Option Explicit -Function doUnitTest as String +Function doUnitTest() As String + TestUtil.TestInit + verify_IsNumeric + doUnitTest = TestUtil.GetResult() +End Function + +Sub verify_IsNumeric + On Error GoTo errorHandler + dim aVariant as Variant aVariant = 3 - ' ISNUMERIC - If ( IsNumeric( aVariant ) = False ) Then - doUnitTest = "FAIL" - Else - doUnitTest = "OK" - End If -End Function + TestUtil.Assert(IsNumeric(aVariant), "IsNumeric(aVariant)") + + TestUtil.Assert(IsNumeric(" 0 "), "IsNumeric("" 0 "")") + TestUtil.Assert(IsNumeric(" +0 "), "IsNumeric("" +0 "")") + TestUtil.Assert(IsNumeric(" -0 "), "IsNumeric("" -0 "")") + TestUtil.Assert(Not IsNumeric(""), "Not IsNumeric("""")") + TestUtil.Assert(Not IsNumeric(" "), "Not IsNumeric("" "")") + TestUtil.Assert(Not IsNumeric(" + "), "Not IsNumeric("" + "")") + TestUtil.Assert(Not IsNumeric(" - "), "Not IsNumeric("" - "")") + ' Note: the two following tests should behave different in VBA (TODO/FIXME); + ' should it be unified maybe in non-VBA, too (a breaking change)? + TestUtil.Assert(Not IsNumeric(" + 0 "), "Not IsNumeric("" + 0 "")") + TestUtil.Assert(Not IsNumeric(" - 0 "), "Not IsNumeric("" - 0 "")") + + Exit Sub +errorHandler: + TestUtil.ReportErrorHandler("verify_IsNumeric", Err, Error$, Erl) +End Sub diff --git a/basic/source/sbx/sbxconv.hxx b/basic/source/sbx/sbxconv.hxx index 82652e5dbff6..11725dec5b29 100644 --- a/basic/source/sbx/sbxconv.hxx +++ b/basic/source/sbx/sbxconv.hxx @@ -64,7 +64,7 @@ inline auto ImpDoubleToSalInt64(double d) extern void ImpCvtNum( double nNum, short nPrec, OUString& rRes, bool bCoreString=false ); extern ErrCode ImpScan ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_uInt16* pLen, - bool bOnlyIntntl ); + bool* pHasNumber, bool bOnlyIntntl ); // A version that uses defaults / compatibility settings for bOnlyIntntl extern ErrCode ImpScan ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_uInt16* pLen ); diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx index 1084d6cf2810..008b5aeb0a4e 100644 --- a/basic/source/sbx/sbxscan.cxx +++ b/basic/source/sbx/sbxscan.cxx @@ -71,7 +71,7 @@ static bool ImpStrChr( std::u16string_view str, sal_Unicode c ) { return str.fin // conversion error if data type is fixed and it doesn't fit ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, - sal_uInt16* pLen, bool bOnlyIntntl ) + sal_uInt16* pLen, bool* pHasNumber, bool bOnlyIntntl ) { sal_Unicode cDecSep, cGrpSep, cDecSepAlt; if( bOnlyIntntl ) @@ -102,6 +102,7 @@ ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, p++; bMinus = true; } + const auto pNumberStart = p; if (p != rWSrc.end() && (rtl::isAsciiDigit(*p) || ((*p == cDecSep || (cGrpSep && *p == cGrpSep) || (cDecSepAlt && *p == cDecSepAlt)) @@ -231,11 +232,14 @@ ErrCode ImpScan( std::u16string_view rWSrc, double& nVal, SbxDataType& rType, return ERRCODE_BASIC_CONVERSION; } #endif + const auto pNumberEnd = p; // tdf#146672 - skip whitespaces and tabs at the end of the scanned string while (p != rWSrc.end() && (*p == ' ' || *p == ' ')) p++; if( pLen ) *pLen = static_cast<sal_uInt16>( p - pStart ); + if (pHasNumber) + *pHasNumber = pNumberEnd > pNumberStart; if( bMinus ) nVal = -nVal; rType = eScanType; @@ -248,14 +252,14 @@ ErrCode ImpScan(std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_ static const bool bEnv = std::getenv("LIBREOFFICE6FLOATINGPOINTMODE") != nullptr; bool bMode = bEnv || Basic::Compatibility::UseLibreOffice6FloatingPointConversion::get(); - return ImpScan(rSrc, nVal, rType, pLen, !bMode); + return ImpScan(rSrc, nVal, rType, pLen, nullptr, !bMode); } // port for CDbl in the Basic ErrCode SbxValue::ScanNumIntnl( const OUString& rSrc, double& nVal, bool bSingle ) { sal_uInt16 nLen = 0; - ErrCode nRetError = ImpScan( rSrc, nVal, o3tl::temporary(SbxDataType()), &nLen, + ErrCode nRetError = ImpScan( rSrc, nVal, o3tl::temporary(SbxDataType()), &nLen, nullptr, /*bOnlyIntntl*/true ); // read completely? if( nRetError == ERRCODE_NONE && nLen != rSrc.getLength() ) diff --git a/basic/source/sbx/sbxvalue.cxx b/basic/source/sbx/sbxvalue.cxx index da1efcf688ce..6b70fe31131a 100644 --- a/basic/source/sbx/sbxvalue.cxx +++ b/basic/source/sbx/sbxvalue.cxx @@ -693,8 +693,9 @@ bool SbxValue::ImpIsNumeric( bool bOnlyIntntl ) const double n; SbxDataType t2; sal_uInt16 nLen = 0; - if( ImpScan( s, n, t2, &nLen, bOnlyIntntl ) == ERRCODE_NONE ) - return nLen == s.getLength(); + bool bHasNumber = false; + if( ImpScan( s, n, t2, &nLen, &bHasNumber, bOnlyIntntl ) == ERRCODE_NONE ) + return nLen == s.getLength() && bHasNumber; } return false; }