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

Reply via email to