1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include <config_features.h>
22 #include <tools/errcode.hxx>
23 #include <basic/sbx.hxx>
24 #include "sbxconv.hxx"
26 #include <unotools/syslocale.hxx>
30 #include <vcl/svapp.hxx>
31 #include <vcl/settings.hxx>
38 #include "sbxbase.hxx"
39 #include <basic/sbxfac.hxx>
40 #include <basic/sbxform.hxx>
41 #include <svtools/svtools.hrc>
45 #include "runtime.hxx"
47 #include <rtl/strbuf.hxx>
48 #include <svl/zforlist.hxx>
49 #include <comphelper/processfactory.hxx>
52 void ImpGetIntntlSep( sal_Unicode
& rcDecimalSep
, sal_Unicode
& rcThousandSep
)
54 SvtSysLocale aSysLocale
;
55 const LocaleDataWrapper
& rData
= aSysLocale
.GetLocaleData();
56 rcDecimalSep
= rData
.getNumDecimalSep()[0];
57 rcThousandSep
= rData
.getNumThousandSep()[0];
60 inline bool ImpIsDigit( sal_Unicode c
)
62 return '0' <= c
&& c
<= '9';
65 /** NOTE: slightly differs from strchr() in that it does not consider the
66 terminating NULL character to be part of the string and returns bool
67 instead of pointer, if character is 0 returns false.
69 bool ImpStrChr( const sal_Unicode
* p
, sal_Unicode c
)
81 bool ImpIsAlNum( sal_Unicode c
)
83 return c
< 128 && isalnum( static_cast<char>(c
) );
86 // scanning a string according to BASIC-conventions
87 // but exponent may also be a D, so data type is SbxDOUBLE
88 // conversion error if data type is fixed and it doesn't fit
90 SbxError
ImpScan( const OUString
& rWSrc
, double& nVal
, SbxDataType
& rType
,
91 sal_uInt16
* pLen
, bool bAllowIntntl
, bool bOnlyIntntl
)
93 sal_Unicode cIntntlDecSep
, cIntntlGrpSep
;
94 sal_Unicode cNonIntntlDecSep
= '.';
95 if( bAllowIntntl
|| bOnlyIntntl
)
97 ImpGetIntntlSep( cIntntlDecSep
, cIntntlGrpSep
);
99 cNonIntntlDecSep
= cIntntlDecSep
;
103 cIntntlDecSep
= cNonIntntlDecSep
;
104 cIntntlGrpSep
= 0; // no group separator accepted in non-i18n
107 const sal_Unicode
* const pStart
= rWSrc
.getStr();
108 const sal_Unicode
* p
= pStart
;
109 OUStringBuffer
aBuf( rWSrc
.getLength());
113 SbxDataType eScanType
= SbxSINGLE
;
114 while( *p
== ' ' || *p
== '\t' )
121 if( ImpIsDigit( *p
) || ((*p
== cNonIntntlDecSep
|| *p
== cIntntlDecSep
||
122 (cIntntlDecSep
&& *p
== cIntntlGrpSep
)) && ImpIsDigit( *(p
+1) )))
127 short ncdig
= 0; // number of digits after decimal point
128 OUStringBuffer
aSearchStr("0123456789DEde");
129 aSearchStr
.append(cNonIntntlDecSep
);
130 if( cIntntlDecSep
!= cNonIntntlDecSep
)
131 aSearchStr
.append(cIntntlDecSep
);
133 aSearchStr
.append(cIntntlGrpSep
);
134 const sal_Unicode
* const pSearchStr
= aSearchStr
.getStr();
135 const sal_Unicode pDdEe
[] = { 'D', 'd', 'E', 'e', 0 };
136 while( ImpStrChr( pSearchStr
, *p
) )
139 if( bOnlyIntntl
&& *p
== cIntntlGrpSep
)
144 if( *p
== cNonIntntlDecSep
|| *p
== cIntntlDecSep
)
146 // Use the separator that is passed to stringToDouble()
147 aBuf
[ p
- pStart
] = cIntntlDecSep
;
152 else if( ImpStrChr( pDdEe
, *p
) )
159 if( *p
== 'D' || *p
== 'd' )
160 eScanType
= SbxDOUBLE
;
161 aBuf
[ p
- pStart
] = 'E';
174 if( decsep
> 1 || exp
> 1 )
177 OUString
aBufStr( aBuf
.makeStringAndClear());
178 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
179 sal_Int32 nParseEnd
= 0;
180 nVal
= rtl::math::stringToDouble( aBufStr
, cIntntlDecSep
, cIntntlGrpSep
, &eStatus
, &nParseEnd
);
181 if( eStatus
!= rtl_math_ConversionStatus_Ok
|| nParseEnd
!= aBufStr
.getLength() )
184 if( !decsep
&& !exp
)
186 if( nVal
>= SbxMININT
&& nVal
<= SbxMAXINT
)
187 eScanType
= SbxINTEGER
;
188 else if( nVal
>= SbxMINLNG
&& nVal
<= SbxMAXLNG
)
192 ndig
= ndig
- decsep
;
193 // too many numbers for SINGLE?
194 if( ndig
> 15 || ncdig
> 6 )
195 eScanType
= SbxDOUBLE
;
198 const sal_Unicode pTypes
[] = { '%', '!', '&', '#', 0 };
199 if( ImpStrChr( pTypes
, *p
) )
202 // hex/octal number? read in and convert:
207 OUString
aCmp( "0123456789ABCDEFabcdef" );
224 const sal_Unicode
* const pCmp
= aCmp
.getStr();
225 while( ImpIsAlNum( *p
) ) /* XXX: really munge all alnum also when error? */
228 if( ImpStrChr( pCmp
, ch
) )
231 ch
-= 0x20; // convert ASCII lower to upper case
238 OUString
aBufStr( aBuf
.makeStringAndClear());
240 for( const sal_Unicode
* q
= aBufStr
.getStr(); bRes
&& *q
; q
++ )
244 i
-= 7; // 'A'-'0' = 17 => 10, ...
245 l
= ( l
* base
) + i
;
252 if( l
>= SbxMININT
&& l
<= SbxMAXINT
)
253 eScanType
= SbxINTEGER
;
255 #if HAVE_FEATURE_SCRIPTING
256 else if ( SbiRuntime::isVBAEnabled() )
258 OSL_TRACE("Reporting error converting");
259 return SbxERR_CONVERSION
;
263 *pLen
= (sal_uInt16
) ( p
- pStart
);
265 return SbxERR_CONVERSION
;
272 // port for CDbl in the Basic
273 SbxError
SbxValue::ScanNumIntnl( const OUString
& rSrc
, double& nVal
, bool bSingle
)
277 SbxError nRetError
= ImpScan( rSrc
, nVal
, t
, &nLen
,
278 /*bAllowIntntl*/false, /*bOnlyIntntl*/true );
280 if( nRetError
== SbxERR_OK
&& nLen
!= rSrc
.getLength() )
282 nRetError
= SbxERR_CONVERSION
;
286 SbxValues
aValues( nVal
);
287 nVal
= (double)ImpGetSingle( &aValues
); // here error at overflow
293 static const double roundArray
[] = {
294 5.0e+0, 0.5e+0, 0.5e-1, 0.5e-2, 0.5e-3, 0.5e-4, 0.5e-5, 0.5e-6, 0.5e-7,
295 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,0.5e-15 };
297 /***************************************************************************
299 |* void myftoa( double, char *, short, short, bool, bool )
301 |* description: conversion double --> ASCII
302 |* parameters: double the number
303 |* char * target buffer
304 |* short number of positions after decimal point
305 |* short range of the exponent ( 0=no E )
306 |* bool true: with 1000-separators
307 |* bool true: output without formatting
309 ***************************************************************************/
311 static void myftoa( double nNum
, char * pBuf
, short nPrec
, short nExpWidth
,
312 bool bPt
, bool bFix
, sal_Unicode cForceThousandSep
= 0 )
316 short nDig
= nPrec
+ 1;
317 short nDec
; // number of positions before decimal point
320 sal_Unicode cDecimalSep
, cThousandSep
;
321 ImpGetIntntlSep( cDecimalSep
, cThousandSep
);
322 if( cForceThousandSep
)
323 cThousandSep
= cForceThousandSep
;
329 while( nNum
< 1.0 ) nNum
*= 10.0, nExp
--;
330 while( nNum
>= 10.0 ) nNum
/= 10.0, nExp
++;
332 if( !bFix
&& !nExpWidth
)
334 else if( bFix
&& !nPrec
)
338 if( (nNum
+= roundArray
[( nDig
> 16 ) ? 16 : nDig
] ) >= 10.0 )
342 if( !nExpWidth
) ++nDig
;
345 // determine positions before decimal point
350 // #41691: also a 0 at bFix
352 if( nPrec
) *pBuf
++ = (char)cDecimalSep
;
354 if( nDig
<= 0 ) i
= nPrec
;
355 while( i
-- ) *pBuf
++ = '0';
373 *pBuf
++ = sal::static_int_cast
< char >(digit
+ '0');
374 nNum
=( nNum
- digit
) * 10.0;
377 if( --nDig
== 0 ) break;
382 *pBuf
++ = (char)cDecimalSep
;
383 else if( !(nDec
% 3 ) && bPt
)
384 *pBuf
++ = (char)cThousandSep
;
392 if( nExpWidth
< 3 ) nExpWidth
= 3;
395 *pBuf
++ =( nExp
< 0 ) ?( (nExp
= -nExp
), '-' ) : '+';
396 while( nExpWidth
> 3 ) *pBuf
++ = '0', nExpWidth
--;
397 if( nExp
>= 100 || nExpWidth
== 3 )
399 *pBuf
++ = sal::static_int_cast
< char >(nExp
/100 + '0');
402 if( nExp
/10 || nExpWidth
>= 2 )
403 *pBuf
++ = sal::static_int_cast
< char >(nExp
/10 + '0');
404 *pBuf
++ = sal::static_int_cast
< char >(nExp
%10 + '0');
409 // The number is prepared unformattedly with the given number of
410 // NK-positions. A leading minus is added if applicable.
411 // This routine is public because it's also used by the Put-functions
412 // in the class SbxImpSTRING.
414 void ImpCvtNum( double nNum
, short nPrec
, OUString
& rRes
, bool bCoreString
)
417 char cBuf
[ 40 ], *p
= cBuf
;
419 sal_Unicode cDecimalSep
, cThousandSep
;
420 ImpGetIntntlSep( cDecimalSep
, cThousandSep
);
428 double dMaxNumWithoutExp
= (nPrec
== 6) ? 1E6
: 1E14
;
429 myftoa( nNum
, p
, nPrec
,( nNum
&&( nNum
< 1E-1 || nNum
>= dMaxNumWithoutExp
) ) ? 4:0,
430 false, true, cDecimalSep
);
431 // remove trailing zeros
432 for( p
= cBuf
; *p
&&( *p
!= 'E' ); p
++ ) {}
434 while( nPrec
&& *p
== '0' ) nPrec
--, p
--;
435 if( *p
== cDecimalSep
) p
--;
436 while( *q
) *++p
= *q
++;
438 rRes
= OUString::createFromAscii( cBuf
);
441 bool ImpConvStringExt( OUString
& rSrc
, SbxDataType eTargetType
)
443 bool bChanged
= false;
446 // only special cases are handled, nothing on default
447 switch( eTargetType
)
449 // consider international for floating point
454 sal_Unicode cDecimalSep
, cThousandSep
;
455 ImpGetIntntlSep( cDecimalSep
, cThousandSep
);
458 if( cDecimalSep
!= (sal_Unicode
)'.' )
460 sal_Int32 nPos
= aNewString
.indexOf( cDecimalSep
);
463 sal_Unicode
* pStr
= const_cast<sal_Unicode
*>(aNewString
.getStr());
464 pStr
[nPos
] = (sal_Unicode
)'.';
471 // check as string in case of sal_Bool sal_True and sal_False
474 if( rSrc
.equalsIgnoreAsciiCase("true") )
476 aNewString
= OUString::number( SbxTRUE
);
479 else if( rSrc
.equalsIgnoreAsciiCase("false") )
481 aNewString
= OUString::number( SbxFALSE
);
495 // formatted number output
496 // the return value is the number of characters used
499 static sal_uInt16
printfmtstr( const OUString
& rStr
, OUString
& rRes
, const OUString
& rFmt
)
501 OUStringBuffer aTemp
;
502 const sal_Unicode
* pStr
= rStr
.getStr();
503 const sal_Unicode
* pFmtStart
= rFmt
.getStr();
504 const sal_Unicode
* pFmt
= pFmtStart
;
509 aTemp
.append(*pStr
++);
515 aTemp
.append( *pStr
? *pStr
++ : static_cast< sal_Unicode
>(' '));
518 while( *pFmt
!= '\\' );
519 aTemp
.append(*pStr
? *pStr
++ : static_cast< sal_Unicode
>(' '));
528 rRes
= aTemp
.makeStringAndClear();
529 return (sal_uInt16
) ( pFmt
- pFmtStart
);
533 bool SbxValue::Scan( const OUString
& rSrc
, sal_uInt16
* pLen
)
535 SbxError eRes
= SbxERR_OK
;
538 eRes
= SbxERR_PROP_READONLY
;
544 eRes
= ImpScan( rSrc
, n
, t
, pLen
);
545 if( eRes
== SbxERR_OK
)
566 ResMgr
* implGetResMgr()
568 static ResMgr
* pResMgr
= NULL
;
571 pResMgr
= ResMgr::CreateResMgr("sb", Application::GetSettings().GetUILanguageTag() );
576 class SbxValueFormatResId
: public ResId
579 SbxValueFormatResId( sal_uInt16 nId
)
580 : ResId( nId
, *implGetResMgr() )
587 VBA_FORMAT_TYPE_OFFSET
, // standard number format
588 VBA_FORMAT_TYPE_USERDEFINED
, // user defined number format
594 VbaFormatType meType
;
595 OUString mpVbaFormat
; // Format string in vba
596 NfIndexTableOffset meOffset
; // SvNumberFormatter format index, if meType = VBA_FORMAT_TYPE_OFFSET
597 const char* mpOOoFormat
; // if meType = VBA_FORMAT_TYPE_USERDEFINED
600 #define VBA_FORMAT_OFFSET( pcUtf8, eOffset ) \
601 { VBA_FORMAT_TYPE_OFFSET, OUString(pcUtf8), eOffset, 0 }
603 #define VBA_FORMAT_USERDEFINED( pcUtf8, pcDefinedUtf8 ) \
604 { VBA_FORMAT_TYPE_USERDEFINED, OUString(pcUtf8), NF_NUMBER_STANDARD, pcDefinedUtf8 }
606 static VbaFormatInfo pFormatInfoTable
[] =
608 VBA_FORMAT_OFFSET( "Long Date", NF_DATE_SYSTEM_LONG
),
609 VBA_FORMAT_USERDEFINED( "Medium Date", "DD-MMM-YY" ),
610 VBA_FORMAT_OFFSET( "Short Date", NF_DATE_SYSTEM_SHORT
),
611 VBA_FORMAT_USERDEFINED( "Long Time", "H:MM:SS AM/PM" ),
612 VBA_FORMAT_OFFSET( "Medium Time", NF_TIME_HHMMAMPM
),
613 VBA_FORMAT_OFFSET( "Short Time", NF_TIME_HHMM
),
614 VBA_FORMAT_OFFSET( "ddddd", NF_DATE_SYSTEM_SHORT
),
615 VBA_FORMAT_OFFSET( "dddddd", NF_DATE_SYSTEM_LONG
),
616 VBA_FORMAT_USERDEFINED( "ttttt", "H:MM:SS AM/PM" ),
617 VBA_FORMAT_OFFSET( "ww", NF_DATE_WW
),
618 { VBA_FORMAT_TYPE_NULL
, OUString(""), NF_INDEX_TABLE_ENTRIES
, 0 }
621 VbaFormatInfo
* getFormatInfo( const OUString
& rFmt
)
623 VbaFormatInfo
* pInfo
= NULL
;
625 while( (pInfo
= pFormatInfoTable
+ i
)->meType
!= VBA_FORMAT_TYPE_NULL
)
627 if( rFmt
.equalsIgnoreAsciiCase( pInfo
->mpVbaFormat
) )
634 #define VBAFORMAT_GENERALDATE "General Date"
635 #define VBAFORMAT_C "c"
636 #define VBAFORMAT_N "n"
637 #define VBAFORMAT_NN "nn"
638 #define VBAFORMAT_W "w"
639 #define VBAFORMAT_Y "y"
640 #define VBAFORMAT_LOWERCASE "<"
641 #define VBAFORMAT_UPPERCASE ">"
643 void SbxValue::Format( OUString
& rRes
, const OUString
* pFmt
) const
648 // pflin, It is better to use SvNumberFormatter to handle the date/time/number format.
649 // the SvNumberFormatter output is mostly compatible with
650 // VBA output besides the OOo-basic output
651 if( pFmt
&& !SbxBasicFormater::isBasicFormat( *pFmt
) )
653 OUString aStr
= GetOUString();
655 SvtSysLocale aSysLocale
;
656 const CharClass
& rCharClass
= aSysLocale
.GetCharClass();
658 if( pFmt
->equalsIgnoreAsciiCase( VBAFORMAT_LOWERCASE
) )
660 rRes
= rCharClass
.lowercase( aStr
);
663 if( pFmt
->equalsIgnoreAsciiCase( VBAFORMAT_UPPERCASE
) )
665 rRes
= rCharClass
.uppercase( aStr
);
669 LanguageType eLangType
= Application::GetSettings().GetLanguageTag().getLanguageType();
670 SvNumberFormatter
aFormatter( comphelper::getProcessComponentContext(), eLangType
);
672 sal_uInt32 nIndex
= 0;
676 bool bSuccess
= aFormatter
.IsNumberFormat( aStr
, nIndex
, nNumber
);
678 // number format, use SvNumberFormatter to handle it.
681 sal_Int32 nCheckPos
= 0;
683 OUString aFmtStr
= *pFmt
;
684 VbaFormatInfo
* pInfo
= getFormatInfo( aFmtStr
);
685 if( pInfo
&& pInfo
->meType
!= VBA_FORMAT_TYPE_NULL
)
687 if( pInfo
->meType
== VBA_FORMAT_TYPE_OFFSET
)
689 nIndex
= aFormatter
.GetFormatIndex( pInfo
->meOffset
, eLangType
);
693 aFmtStr
= OUString::createFromAscii(pInfo
->mpOOoFormat
);
694 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
696 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
698 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_GENERALDATE
)
699 || aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_C
))
701 if( nNumber
<=-1.0 || nNumber
>= 1.0 )
704 nIndex
= aFormatter
.GetFormatIndex( NF_DATE_SYSTEM_SHORT
, eLangType
);
705 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
708 if( floor( nNumber
) != nNumber
)
710 aFmtStr
= "H:MM:SS AM/PM";
711 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
713 aFormatter
.GetOutputString( nNumber
, nIndex
, aTime
, &pCol
);
720 aFmtStr
= "H:MM:SS AM/PM";
721 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
722 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
725 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_N
) ||
726 aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_NN
))
728 sal_Int32 nMin
= implGetMinute( nNumber
);
729 if( nMin
< 10 && aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_NN
))
731 // Minute in two digits
734 aBuf
[1] = '0' + nMin
;
735 rRes
= OUString(aBuf
, SAL_N_ELEMENTS(aBuf
));
739 rRes
= OUString::number(nMin
);
742 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_W
))
744 sal_Int32 nWeekDay
= implGetWeekDay( nNumber
);
745 rRes
= OUString::number(nWeekDay
);
747 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_Y
))
749 sal_Int16 nYear
= implGetDateYear( nNumber
);
751 implDateSerial( nYear
, 1, 1, dBaseDate
);
752 sal_Int32 nYear32
= 1 + sal_Int32( nNumber
- dBaseDate
);
753 rRes
= OUString::number(nYear32
);
757 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
758 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
765 SbxDataType eType
= GetType();
776 case SbxNULL
: // #45929 NULL with a little cheating
777 nComma
= 0; goto cvt
;
779 nComma
= 6; goto cvt
;
784 if( eType
!= SbxNULL
)
788 // #45355 another point to jump in for isnumeric-String
792 SbxAppData
& rAppData
= GetSbxData_Impl();
794 LanguageType eLangType
= Application::GetSettings().GetLanguageTag().getLanguageType();
795 if( rAppData
.pBasicFormater
)
797 if( rAppData
.eBasicFormaterLangType
!= eLangType
)
799 delete rAppData
.pBasicFormater
;
800 rAppData
.pBasicFormater
= NULL
;
803 rAppData
.eBasicFormaterLangType
= eLangType
;
806 if( !rAppData
.pBasicFormater
)
808 SvtSysLocale aSysLocale
;
809 const LocaleDataWrapper
& rData
= aSysLocale
.GetLocaleData();
810 sal_Unicode cComma
= rData
.getNumDecimalSep()[0];
811 sal_Unicode c1000
= rData
.getNumThousandSep()[0];
812 OUString aCurrencyStrg
= rData
.getCurrSymbol();
814 // initialize the Basic-formater help object:
815 // get resources for predefined output
816 // of the Format()-command, e. g. for "On/Off"
817 OUString aOnStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_ON
).toString();
818 OUString aOffStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_OFF
).toString();
819 OUString aYesStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_YES
).toString();
820 OUString aNoStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_NO
).toString();
821 OUString aTrueStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_TRUE
).toString();
822 OUString aFalseStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_FALSE
).toString();
823 OUString aCurrencyFormatStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_CURRENCY
).toString();
825 rAppData
.pBasicFormater
= new SbxBasicFormater( cComma
,c1000
,aOnStrg
,aOffStrg
,
826 aYesStrg
,aNoStrg
,aTrueStrg
,aFalseStrg
,
827 aCurrencyStrg
,aCurrencyFormatStrg
);
829 // Remark: For performance reasons there's only ONE BasicFormater-
830 // object created and 'stored', so that the expensive resource-
831 // loading is saved (for country-specific predefined outputs,
832 // e. g. "On/Off") and the continuous string-creation
834 // BUT: therefore this code is NOT multithreading capable!
836 // here are problems with ;;;Null because this method is only
837 // called, if SbxValue is a number!!!
838 // in addition rAppData.pBasicFormater->BasicFormatNull( *pFmt ); could be called!
839 if( eType
!= SbxNULL
)
841 rRes
= rAppData
.pBasicFormater
->BasicFormat( d
,*pFmt
);
845 rRes
= rAppData
.pBasicFormater
->BasicFormatNull( *pFmt
);
851 OUString
aTmpString( rRes
);
852 ImpCvtNum( GetDouble(), nComma
, aTmpString
);
859 // #45355 converting if numeric
862 ScanNumIntnl( GetOUString(), d
, /*bSingle*/false );
867 printfmtstr( GetOUString(), rRes
, *pFmt
);
872 rRes
= GetOUString();
876 rRes
= GetOUString();
881 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */