basic/source/sbx/sbxconv.hxx | 3 - basic/source/sbx/sbxscan.cxx | 61 ---------------------------------------- basic/source/sbx/sbxvalue.cxx | 64 +++++++++++++++++++++++++++++++++--------- 3 files changed, 52 insertions(+), 76 deletions(-)
New commits: commit b01e697b53607fef0ac3ab222b5b25a6eb0257a5 Author: Mike Kaganski <mike.kagan...@collabora.com> AuthorDate: Tue Dec 24 12:21:51 2024 +0500 Commit: Mike Kaganski <mike.kagan...@collabora.com> CommitDate: Tue Dec 24 12:03:02 2024 +0100 tdf#164446: fix internationalized FP input in Basic IDE Watch Now that tdf#97983 fix made the default conversion internationalized, the special handling of the Watch window input needs to do it in the other direction. Additionally, move ImpConvStringExt to the single place that uses it. Change-Id: I18a4043511f4a1b32f79410447e96c7679329886 Reviewed-on: https://gerrit.libreoffice.org/c/core/+/179302 Tested-by: Jenkins Reviewed-by: Mike Kaganski <mike.kagan...@collabora.com> diff --git a/basic/source/sbx/sbxconv.hxx b/basic/source/sbx/sbxconv.hxx index 1ddc6f73c847..82652e5dbff6 100644 --- a/basic/source/sbx/sbxconv.hxx +++ b/basic/source/sbx/sbxconv.hxx @@ -69,9 +69,6 @@ extern ErrCode ImpScan extern ErrCode ImpScan ( std::u16string_view rSrc, double& nVal, SbxDataType& rType, sal_uInt16* pLen ); -// with advanced evaluation (International, "TRUE"/"FALSE") -extern bool ImpConvStringExt( OUString& rSrc, SbxDataType eTargetType ); - void ImpGetIntntlSep( sal_Unicode& rcDecimalSep, sal_Unicode& rcThousandSep, sal_Unicode& rcDecimalSepAlt ); // SBXINT.CXX diff --git a/basic/source/sbx/sbxscan.cxx b/basic/source/sbx/sbxscan.cxx index 5619a59d548f..1084d6cf2810 100644 --- a/basic/source/sbx/sbxscan.cxx +++ b/basic/source/sbx/sbxscan.cxx @@ -254,9 +254,8 @@ 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 ) { - SbxDataType t; sal_uInt16 nLen = 0; - ErrCode nRetError = ImpScan( rSrc, nVal, t, &nLen, + ErrCode nRetError = ImpScan( rSrc, nVal, o3tl::temporary(SbxDataType()), &nLen, /*bOnlyIntntl*/true ); // read completely? if( nRetError == ERRCODE_NONE && nLen != rSrc.getLength() ) @@ -288,65 +287,7 @@ void ImpCvtNum( double nNum, short nPrec, OUString& rRes, bool bCoreString ) rRes = rtl::math::doubleToUString(nNum, rtl_math_StringFormat_Automatic, nPrec, cDecimalSep, true); } -bool ImpConvStringExt( OUString& rSrc, SbxDataType eTargetType ) -{ - bool bChanged = false; - OUString aNewString; - - // only special cases are handled, nothing on default - switch( eTargetType ) - { - // consider international for floating point - case SbxSINGLE: - case SbxDOUBLE: - case SbxCURRENCY: - { - sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt; - ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt ); - aNewString = rSrc; - - if( cDecimalSep != '.' || (cDecimalSepAlt && cDecimalSepAlt != '.') ) - { - sal_Int32 nPos = aNewString.indexOf( cDecimalSep ); - if( nPos == -1 && cDecimalSepAlt ) - nPos = aNewString.indexOf( cDecimalSepAlt ); - if( nPos != -1 ) - { - sal_Unicode* pStr = const_cast<sal_Unicode*>(aNewString.getStr()); - pStr[nPos] = '.'; - bChanged = true; - } - } - break; - } - - // check as string in case of sal_Bool sal_True and sal_False - case SbxBOOL: - { - if( rSrc.equalsIgnoreAsciiCase("true") ) - { - aNewString = OUString::number( SbxTRUE ); - bChanged = true; - } - else if( rSrc.equalsIgnoreAsciiCase("false") ) - { - aNewString = OUString::number( SbxFALSE ); - bChanged = true; - } - break; - } - default: break; - } - - if( bChanged ) - rSrc = aNewString; - return bChanged; -} - - // formatted number output -// the return value is the number of characters used -// from the format static void printfmtstr(std::u16string_view rStr, OUString& rRes, std::u16string_view rFmt) { diff --git a/basic/source/sbx/sbxvalue.cxx b/basic/source/sbx/sbxvalue.cxx index f3122fe71904..da1efcf688ce 100644 --- a/basic/source/sbx/sbxvalue.cxx +++ b/basic/source/sbx/sbxvalue.cxx @@ -492,31 +492,69 @@ bool SbxValue::Put( const SbxValues& rVal ) return bRes; } +// with advanced evaluation (International, "TRUE"/"FALSE") +static OUString ImpConvStringExt(const OUString& rSrc, SbxDataType eTargetType) +{ + // only special cases are handled, nothing on default + switch (eTargetType) + { + // Consider international for floating point. Following default conversion (SbxValue::Put) + // assumes internationalized strings, but the input may use standard decimal dot. + case SbxSINGLE: + case SbxDOUBLE: + case SbxCURRENCY: + { + sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt; + ImpGetIntntlSep(cDecimalSep, cThousandSep, cDecimalSepAlt); + + // 1. If any of the returned decimal separators is dot, do nothing + if (cDecimalSep == '.' || cDecimalSepAlt == '.') + break; + + // 2. If there are internationalized separators already, do nothing + if (rSrc.indexOf(cDecimalSep) >= 0 || rSrc.indexOf(cDecimalSepAlt) >= 0) + break; + + // 3. Replace all dots with the primary separator. This resolves possible ambiguity with + // dot as thousand separator, in favor of decimal dot; unlike "only change one dot" + // approach, this prevents inconsistency like converting "234.567" to a number with + // floating point 234.567, while "1.234.567" to a whole number 1234567. The latter will + // be rejected now. + return rSrc.replaceAll(".", OUStringChar(cDecimalSep)); + } + + // check as string in case of sal_Bool sal_True and sal_False + case SbxBOOL: + if (rSrc.equalsIgnoreAsciiCase("true")) + return OUString::number(SbxTRUE); + if (rSrc.equalsIgnoreAsciiCase("false")) + return OUString::number(SbxFALSE); + break; + + default: + break; + } + + return rSrc; +} + // From 1996-03-28: // Method to execute a pretreatment of the strings at special types. // In particular necessary for BASIC-IDE, so that // the output in the Watch-Window can be written back with PutStringExt, -// if Float were declared with ',' as the decimal separator or BOOl -// explicit with "TRUE" or "FALSE". -// Implementation in ImpConvStringExt (SBXSCAN.CXX) +// if Float were declared with either '.' or locale-specific decimal +// separator, or BOOl explicit with "TRUE" or "FALSE". +// Implementation in ImpConvStringExt void SbxValue::PutStringExt( const OUString& r ) { - // Copy; if it is Unicode convert it immediately - OUString aStr( r ); - // Identify the own type (not as in Put() with TheRealValue(), // Objects are not handled anyway) SbxDataType eTargetType = SbxDataType( aData.eType & 0x0FFF ); + OUString aStr(ImpConvStringExt(r, eTargetType)); // tinker a Source-Value SbxValues aRes(SbxSTRING); - - // Only if really something was converted, take the copy, - // otherwise take the original (Unicode remains) - if( ImpConvStringExt( aStr, eTargetType ) ) - aRes.pOUString = &aStr; - else - aRes.pOUString = const_cast<OUString*>(&r); + aRes.pOUString = &aStr; // #34939: For Strings which contain a number, and if this has a Num-Type, // set a Fixed flag so that the type will not be changed