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 <tools/errcode.hxx>
21 #include <basic/sbx.hxx>
22 #include "sbxconv.hxx"
24 #include "unotools/syslocale.hxx"
30 #include <vcl/svapp.hxx>
36 #include <basic/sbxbase.hxx>
37 #include <basic/sbxfac.hxx>
38 #include <basic/sbxform.hxx>
39 #include <svtools/svtools.hrc>
43 #include "runtime.hxx"
45 #include <rtl/strbuf.hxx>
46 #include <svl/zforlist.hxx>
47 #include <comphelper/processfactory.hxx>
50 void ImpGetIntntlSep( sal_Unicode
& rcDecimalSep
, sal_Unicode
& rcThousandSep
)
52 SvtSysLocale aSysLocale
;
53 const LocaleDataWrapper
& rData
= aSysLocale
.GetLocaleData();
54 rcDecimalSep
= rData
.getNumDecimalSep()[0];
55 rcThousandSep
= rData
.getNumThousandSep()[0];
58 inline bool ImpIsDigit( sal_Unicode c
)
60 return '0' <= c
&& c
<= '9';
63 /** NOTE: slightly differs from strchr() in that it does not consider the
64 terminating NULL character to be part of the string and returns bool
65 instead of pointer, if character is 0 returns false.
67 bool ImpStrChr( const sal_Unicode
* p
, sal_Unicode c
)
79 bool ImpIsAlNum( sal_Unicode c
)
81 return (c
< 128) ? isalnum( static_cast<char>(c
) ) : false;
84 // scanning a string according to BASIC-conventions
85 // but exponent may also be a D, so data type is SbxDOUBLE
86 // conversion error if data type is fixed and it doesn't fit
88 SbxError
ImpScan( const OUString
& rWSrc
, double& nVal
, SbxDataType
& rType
,
89 sal_uInt16
* pLen
, bool bAllowIntntl
, bool bOnlyIntntl
)
91 sal_Unicode cIntntlDecSep
, cIntntlGrpSep
;
92 sal_Unicode cNonIntntlDecSep
= '.';
93 if( bAllowIntntl
|| bOnlyIntntl
)
95 ImpGetIntntlSep( cIntntlDecSep
, cIntntlGrpSep
);
97 cNonIntntlDecSep
= cIntntlDecSep
;
101 cIntntlDecSep
= cNonIntntlDecSep
;
102 cIntntlGrpSep
= 0; // no group separator accepted in non-i18n
105 const sal_Unicode
* const pStart
= rWSrc
.getStr();
106 const sal_Unicode
* p
= pStart
;
107 OUStringBuffer
aBuf( rWSrc
.getLength());
111 SbxDataType eScanType
= SbxSINGLE
;
112 while( *p
== ' ' || *p
== '\t' )
119 if( ImpIsDigit( *p
) || ((*p
== cNonIntntlDecSep
|| *p
== cIntntlDecSep
||
120 (cIntntlDecSep
&& *p
== cIntntlGrpSep
)) && ImpIsDigit( *(p
+1) )))
125 short ncdig
= 0; // number of digits after decimal point
126 OUStringBuffer
aSearchStr("0123456789DEde");
127 aSearchStr
.append(cNonIntntlDecSep
);
128 if( cIntntlDecSep
!= cNonIntntlDecSep
)
129 aSearchStr
.append(cIntntlDecSep
);
131 aSearchStr
.append(cIntntlGrpSep
);
132 const sal_Unicode
* const pSearchStr
= aSearchStr
.getStr();
133 const sal_Unicode pDdEe
[] = { 'D', 'd', 'E', 'e', 0 };
134 while( ImpStrChr( pSearchStr
, *p
) )
137 if( bOnlyIntntl
&& *p
== cIntntlGrpSep
)
142 if( *p
== cNonIntntlDecSep
|| *p
== cIntntlDecSep
)
144 // Use the separator that is passed to stringToDouble()
145 aBuf
[ p
- pStart
] = cIntntlDecSep
;
150 else if( ImpStrChr( pDdEe
, *p
) )
157 if( *p
== 'D' || *p
== 'd' )
158 eScanType
= SbxDOUBLE
;
159 aBuf
[ p
- pStart
] = 'E';
172 if( decsep
> 1 || exp
> 1 )
175 OUString
aBufStr( aBuf
.makeStringAndClear());
176 rtl_math_ConversionStatus eStatus
= rtl_math_ConversionStatus_Ok
;
177 sal_Int32 nParseEnd
= 0;
178 nVal
= rtl::math::stringToDouble( aBufStr
, cIntntlDecSep
, cIntntlGrpSep
, &eStatus
, &nParseEnd
);
179 if( eStatus
!= rtl_math_ConversionStatus_Ok
|| nParseEnd
!= aBufStr
.getLength() )
182 if( !decsep
&& !exp
)
184 if( nVal
>= SbxMININT
&& nVal
<= SbxMAXINT
)
185 eScanType
= SbxINTEGER
;
186 else if( nVal
>= SbxMINLNG
&& nVal
<= SbxMAXLNG
)
190 ndig
= ndig
- decsep
;
191 // too many numbers for SINGLE?
192 if( ndig
> 15 || ncdig
> 6 )
193 eScanType
= SbxDOUBLE
;
196 const sal_Unicode pTypes
[] = { '%', '!', '&', '#', 0 };
197 if( ImpStrChr( pTypes
, *p
) )
200 // hex/octal number? read in and convert:
205 OUString
aCmp( "0123456789ABCDEFabcdef" );
222 const sal_Unicode
* const pCmp
= aCmp
.getStr();
223 while( ImpIsAlNum( *p
) ) /* XXX: really munge all alnum also when error? */
226 if( ImpStrChr( pCmp
, ch
) )
229 ch
-= 0x20; // convert ASCII lower to upper case
236 OUString
aBufStr( aBuf
.makeStringAndClear());
238 for( const sal_Unicode
* q
= aBufStr
.getStr(); bRes
&& *q
; q
++ )
242 i
-= 7; // 'A'-'0' = 17 => 10, ...
243 l
= ( l
* base
) + i
;
250 if( l
>= SbxMININT
&& l
<= SbxMAXINT
)
251 eScanType
= SbxINTEGER
;
253 #ifndef DISABLE_SCRIPTING
254 else if ( SbiRuntime::isVBAEnabled() )
256 OSL_TRACE("Reporting error converting");
257 return SbxERR_CONVERSION
;
261 *pLen
= (sal_uInt16
) ( p
- pStart
);
263 return SbxERR_CONVERSION
;
270 // port for CDbl in the Basic
271 SbxError
SbxValue::ScanNumIntnl( const OUString
& rSrc
, double& nVal
, bool bSingle
)
275 SbxError nRetError
= ImpScan( rSrc
, nVal
, t
, &nLen
,
276 /*bAllowIntntl*/false, /*bOnlyIntntl*/true );
278 if( nRetError
== SbxERR_OK
&& nLen
!= rSrc
.getLength() )
280 nRetError
= SbxERR_CONVERSION
;
284 SbxValues
aValues( nVal
);
285 nVal
= (double)ImpGetSingle( &aValues
); // here error at overflow
291 static double roundArray
[] = {
292 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,
293 0.5e-8, 0.5e-9, 0.5e-10,0.5e-11,0.5e-12,0.5e-13,0.5e-14,0.5e-15 };
295 /***************************************************************************
297 |* void myftoa( double, char *, short, short, bool, bool )
299 |* description: conversion double --> ASCII
300 |* parameters: double the number
301 |* char * target buffer
302 |* short number of positions after decimal point
303 |* short range of the exponent ( 0=no E )
304 |* bool true: with 1000-separators
305 |* bool true: output without formatting
307 ***************************************************************************/
309 static void myftoa( double nNum
, char * pBuf
, short nPrec
, short nExpWidth
,
310 bool bPt
, bool bFix
, sal_Unicode cForceThousandSep
= 0 )
314 short nDig
= nPrec
+ 1;
315 short nDec
; // number of positions before decimal point
318 sal_Unicode cDecimalSep
, cThousandSep
;
319 ImpGetIntntlSep( cDecimalSep
, cThousandSep
);
320 if( cForceThousandSep
)
321 cThousandSep
= cForceThousandSep
;
327 while( nNum
< 1.0 ) nNum
*= 10.0, nExp
--;
328 while( nNum
>= 10.0 ) nNum
/= 10.0, nExp
++;
330 if( !bFix
&& !nExpWidth
)
332 else if( bFix
&& !nPrec
)
336 if( (nNum
+= roundArray
[( nDig
> 16 ) ? 16 : nDig
] ) >= 10.0 )
340 if( !nExpWidth
) ++nDig
;
343 // determine positions before decimal point
348 // #41691: also a 0 at bFix
350 if( nPrec
) *pBuf
++ = (char)cDecimalSep
;
352 if( nDig
<= 0 ) i
= nPrec
;
353 while( i
-- ) *pBuf
++ = '0';
371 *pBuf
++ = sal::static_int_cast
< char >(digit
+ '0');
372 nNum
=( nNum
- digit
) * 10.0;
375 if( --nDig
== 0 ) break;
380 *pBuf
++ = (char)cDecimalSep
;
381 else if( !(nDec
% 3 ) && bPt
)
382 *pBuf
++ = (char)cThousandSep
;
390 if( nExpWidth
< 3 ) nExpWidth
= 3;
393 *pBuf
++ =( nExp
< 0 ) ?( (nExp
= -nExp
), '-' ) : '+';
394 while( nExpWidth
> 3 ) *pBuf
++ = '0', nExpWidth
--;
395 if( nExp
>= 100 || nExpWidth
== 3 )
397 *pBuf
++ = sal::static_int_cast
< char >(nExp
/100 + '0');
400 if( nExp
/10 || nExpWidth
>= 2 )
401 *pBuf
++ = sal::static_int_cast
< char >(nExp
/10 + '0');
402 *pBuf
++ = sal::static_int_cast
< char >(nExp
%10 + '0');
407 // The number is prepared unformattedly with the given number of
408 // NK-positions. A leading minus is added if applicable.
409 // This routine is public because it's also used by the Put-functions
410 // in the class SbxImpSTRING.
412 void ImpCvtNum( double nNum
, short nPrec
, OUString
& rRes
, bool bCoreString
)
415 char cBuf
[ 40 ], *p
= cBuf
;
417 sal_Unicode cDecimalSep
, cThousandSep
;
418 ImpGetIntntlSep( cDecimalSep
, cThousandSep
);
426 double dMaxNumWithoutExp
= (nPrec
== 6) ? 1E6
: 1E14
;
427 myftoa( nNum
, p
, nPrec
,( nNum
&&( nNum
< 1E-1 || nNum
>= dMaxNumWithoutExp
) ) ? 4:0,
428 false, true, cDecimalSep
);
429 // remove trailing zeros
430 for( p
= cBuf
; *p
&&( *p
!= 'E' ); p
++ ) {}
432 while( nPrec
&& *p
== '0' ) nPrec
--, p
--;
433 if( *p
== cDecimalSep
) p
--;
434 while( *q
) *++p
= *q
++;
436 rRes
= OUString::createFromAscii( cBuf
);
439 bool ImpConvStringExt( OUString
& rSrc
, SbxDataType eTargetType
)
441 bool bChanged
= false;
444 // only special cases are handled, nothing on default
445 switch( eTargetType
)
447 // consider international for floating point
452 sal_Unicode cDecimalSep
, cThousandSep
;
453 ImpGetIntntlSep( cDecimalSep
, cThousandSep
);
456 if( cDecimalSep
!= (sal_Unicode
)'.' )
458 sal_Int32 nPos
= aNewString
.indexOf( cDecimalSep
);
461 sal_Unicode
* pStr
= (sal_Unicode
*)aNewString
.getStr();
462 pStr
[nPos
] = (sal_Unicode
)'.';
469 // check as string in case of sal_Bool sal_True and sal_False
472 if( rSrc
.equalsIgnoreAsciiCase("true") )
474 aNewString
= OUString::valueOf( (sal_Int32
)SbxTRUE
);
477 else if( rSrc
.equalsIgnoreAsciiCase("false") )
479 aNewString
= OUString::valueOf( (sal_Int32
)SbxFALSE
);
493 // formatted number output
494 // the return value is the number of characters used
497 #ifdef _old_format_code_
498 // leave the code provisionally to copy the previous implementation
500 static sal_uInt16
printfmtnum( double nNum
, OUString
& rRes
, const OUString
& rWFmt
)
502 const String
& rFmt
= rWFmt
;
503 char cFill
= ' '; // filling characters
504 char cPre
= 0; // start character ( maybe "$" )
505 short nExpDig
= 0; // number of exponent positions
506 short nPrec
= 0; // number of positions after decimal point
507 short nWidth
= 0; // number range completely
508 short nLen
; // length of converted number
509 bool bPoint
= false; // true: with 1000 separators
510 bool bTrail
= false; // true, if following minus
511 bool bSign
= false; // true: always with leading sign
512 bool bNeg
= false; // true: number is negative
513 char cBuf
[1024]; // number buffer
515 const char* pFmt
= rFmt
;
517 // catch $$ and **, is simply output as character
519 if( *++pFmt
!= '$' ) rRes
+= '$';
521 if( *++pFmt
!= '*' ) rRes
+= '*';
528 bSign
= true; nWidth
++; break;
530 nWidth
++; cFill
= '*';
531 if( *pFmt
== '$' ) nWidth
++, pFmt
++, cPre
= '$';
534 nWidth
++; cPre
= '$'; break;
543 while( *pFmt
== '#' ) pFmt
++, nWidth
++;
547 nWidth
++; pFmt
++; bPoint
= true;
553 while( *++pFmt
== '#' ) nPrec
++;
557 while( *pFmt
== '^' )
558 pFmt
++, nExpDig
++, nWidth
++;
560 if( !bSign
&& *pFmt
== '-' )
561 pFmt
++, bTrail
= true;
564 if( nPrec
> 15 ) nPrec
= 15;
565 if( nNum
< 0.0 ) nNum
= -nNum
, bNeg
= true;
567 if( bSign
) *p
++ = bNeg
? '-' : '+';
568 myftoa( nNum
, p
, nPrec
, nExpDig
, bPoint
, false );
569 nLen
= strlen( cBuf
);
573 if( nLen
> nWidth
) rRes
+= '%';
576 while( nWidth
-- ) rRes
+= (sal_Unicode
)cFill
;
577 if( cPre
) rRes
+= (sal_Unicode
)cPre
;
579 rRes
+= (sal_Unicode
*)&(cBuf
[0]);
581 rRes
+= bNeg
? '-' : ' ';
583 return (sal_uInt16
) ( pFmt
- (const char*) rFmt
);
586 #endif //_old_format_code_
588 static sal_uInt16
printfmtstr( const OUString
& rStr
, OUString
& rRes
, const OUString
& rFmt
)
590 OUStringBuffer aTemp
;
591 const sal_Unicode
* pStr
= rStr
.getStr();
592 const sal_Unicode
* pFmtStart
= rFmt
.getStr();
593 const sal_Unicode
* pFmt
= pFmtStart
;
598 aTemp
.append(*pStr
++);
604 aTemp
.append( *pStr
? *pStr
++ : static_cast< sal_Unicode
>(' '));
607 while( *pFmt
!= '\\' );
608 aTemp
.append(*pStr
? *pStr
++ : static_cast< sal_Unicode
>(' '));
617 rRes
= aTemp
.makeStringAndClear();
618 return (sal_uInt16
) ( pFmt
- pFmtStart
);
622 sal_Bool
SbxValue::Scan( const OUString
& rSrc
, sal_uInt16
* pLen
)
624 SbxError eRes
= SbxERR_OK
;
627 eRes
= SbxERR_PROP_READONLY
;
633 eRes
= ImpScan( rSrc
, n
, t
, pLen
);
634 if( eRes
== SbxERR_OK
)
645 SetError( eRes
); return sal_False
;
654 ResMgr
* implGetResMgr( void )
656 static ResMgr
* pResMgr
= NULL
;
659 pResMgr
= ResMgr::CreateResMgr("sb", Application::GetSettings().GetUILanguageTag() );
664 class SbxValueFormatResId
: public ResId
667 SbxValueFormatResId( sal_uInt16 nId
)
668 : ResId( nId
, *implGetResMgr() )
675 VBA_FORMAT_TYPE_OFFSET
, // standard number format
676 VBA_FORMAT_TYPE_USERDEFINED
, // user defined number format
682 VbaFormatType meType
;
683 const char* mpVbaFormat
; // Format string in vba
684 NfIndexTableOffset meOffset
; // SvNumberFormatter format index, if meType = VBA_FORMAT_TYPE_OFFSET
685 const char* mpOOoFormat
; // if meType = VBA_FORMAT_TYPE_USERDEFINED
688 #define VBA_FORMAT_OFFSET( pcUtf8, eOffset ) \
689 { VBA_FORMAT_TYPE_OFFSET, pcUtf8, eOffset, 0 }
691 #define VBA_FORMAT_USERDEFINED( pcUtf8, pcDefinedUtf8 ) \
692 { VBA_FORMAT_TYPE_USERDEFINED, pcUtf8, NF_NUMBER_STANDARD, pcDefinedUtf8 }
694 static VbaFormatInfo pFormatInfoTable
[] =
696 VBA_FORMAT_OFFSET( "Long Date", NF_DATE_SYSTEM_LONG
),
697 VBA_FORMAT_USERDEFINED( "Medium Date", "DD-MMM-YY" ),
698 VBA_FORMAT_OFFSET( "Short Date", NF_DATE_SYSTEM_SHORT
),
699 VBA_FORMAT_USERDEFINED( "Long Time", "H:MM:SS AM/PM" ),
700 VBA_FORMAT_OFFSET( "Medium Time", NF_TIME_HHMMAMPM
),
701 VBA_FORMAT_OFFSET( "Short Time", NF_TIME_HHMM
),
702 VBA_FORMAT_OFFSET( "ddddd", NF_DATE_SYSTEM_SHORT
),
703 VBA_FORMAT_OFFSET( "dddddd", NF_DATE_SYSTEM_LONG
),
704 VBA_FORMAT_USERDEFINED( "ttttt", "H:MM:SS AM/PM" ),
705 VBA_FORMAT_OFFSET( "ww", NF_DATE_WW
),
706 { VBA_FORMAT_TYPE_NULL
, 0, NF_INDEX_TABLE_ENTRIES
, 0 }
709 VbaFormatInfo
* getFormatInfo( const String
& rFmt
)
711 VbaFormatInfo
* pInfo
= NULL
;
713 while( (pInfo
= pFormatInfoTable
+ i
)->mpVbaFormat
!= NULL
)
715 if( rFmt
.EqualsIgnoreCaseAscii( pInfo
->mpVbaFormat
) )
722 #define VBAFORMAT_GENERALDATE "General Date"
723 #define VBAFORMAT_C "c"
724 #define VBAFORMAT_N "n"
725 #define VBAFORMAT_NN "nn"
726 #define VBAFORMAT_W "w"
727 #define VBAFORMAT_Y "y"
728 #define VBAFORMAT_LOWERCASE "<"
729 #define VBAFORMAT_UPPERCASE ">"
731 void SbxValue::Format( OUString
& rRes
, const OUString
* pFmt
) const
736 // pflin, It is better to use SvNumberFormatter to handle the date/time/number format.
737 // the SvNumberFormatter output is mostly compatible with
738 // VBA output besides the OOo-basic output
739 if( pFmt
&& !SbxBasicFormater::isBasicFormat( *pFmt
) )
741 OUString aStr
= GetOUString();
743 SvtSysLocale aSysLocale
;
744 const CharClass
& rCharClass
= aSysLocale
.GetCharClass();
746 if( pFmt
->equalsIgnoreAsciiCase( VBAFORMAT_LOWERCASE
) )
748 rRes
= rCharClass
.lowercase( aStr
);
751 if( pFmt
->equalsIgnoreAsciiCase( VBAFORMAT_UPPERCASE
) )
753 rRes
= rCharClass
.uppercase( aStr
);
757 LanguageType eLangType
= GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
758 SvNumberFormatter
aFormatter( comphelper::getProcessComponentContext(), eLangType
);
760 sal_uInt32 nIndex
= 0;
764 sal_Bool bSuccess
= aFormatter
.IsNumberFormat( aStr
, nIndex
, nNumber
);
766 // number format, use SvNumberFormatter to handle it.
769 sal_Int32 nCheckPos
= 0;
771 OUString aFmtStr
= *pFmt
;
772 VbaFormatInfo
* pInfo
= getFormatInfo( aFmtStr
);
773 if( pInfo
&& pInfo
->meType
!= VBA_FORMAT_TYPE_NULL
)
775 if( pInfo
->meType
== VBA_FORMAT_TYPE_OFFSET
)
777 nIndex
= aFormatter
.GetFormatIndex( pInfo
->meOffset
, eLangType
);
781 aFmtStr
= OUString::createFromAscii(pInfo
->mpOOoFormat
);
782 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
784 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
786 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_GENERALDATE
)
787 || aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_C
))
789 if( nNumber
<=-1.0 || nNumber
>= 1.0 )
792 nIndex
= aFormatter
.GetFormatIndex( NF_DATE_SYSTEM_SHORT
, eLangType
);
793 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
796 if( floor( nNumber
) != nNumber
)
798 aFmtStr
= "H:MM:SS AM/PM";
799 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
801 aFormatter
.GetOutputString( nNumber
, nIndex
, aTime
, &pCol
);
809 aFmtStr
= "H:MM:SS AM/PM";
810 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
811 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
814 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_N
) ||
815 aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_NN
))
817 sal_Int32 nMin
= implGetMinute( nNumber
);
818 if( nMin
< 10 && aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_NN
))
820 // Minute in two digits
823 aBuf
[1] = '0' + nMin
;
824 rRes
= OUString(aBuf
, SAL_N_ELEMENTS(aBuf
));
828 rRes
= OUString::valueOf(nMin
);
831 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_W
))
833 sal_Int32 nWeekDay
= implGetWeekDay( nNumber
);
834 rRes
= OUString::valueOf(nWeekDay
);
836 else if( aFmtStr
.equalsIgnoreAsciiCase( VBAFORMAT_Y
))
838 sal_Int16 nYear
= implGetDateYear( nNumber
);
840 implDateSerial( nYear
, 1, 1, dBaseDate
);
841 sal_Int32 nYear32
= 1 + sal_Int32( nNumber
- dBaseDate
);
842 rRes
= OUString::valueOf(nYear32
);
846 aFormatter
.PutandConvertEntry( aFmtStr
, nCheckPos
, nType
, nIndex
, LANGUAGE_ENGLISH
, eLangType
);
847 aFormatter
.GetOutputString( nNumber
, nIndex
, rRes
, &pCol
);
854 SbxDataType eType
= GetType();
865 case SbxNULL
: // #45929 NULL with a little cheating
866 nComma
= 0; goto cvt
;
868 nComma
= 6; goto cvt
;
873 if( eType
!= SbxNULL
)
877 // #45355 another point to jump in for isnumeric-String
881 SbxAppData
& rAppData
= GetSbxData_Impl();
883 LanguageType eLangType
= GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
884 if( rAppData
.pBasicFormater
)
886 if( rAppData
.eBasicFormaterLangType
!= eLangType
)
888 delete rAppData
.pBasicFormater
;
889 rAppData
.pBasicFormater
= NULL
;
892 rAppData
.eBasicFormaterLangType
= eLangType
;
895 if( !rAppData
.pBasicFormater
)
897 SvtSysLocale aSysLocale
;
898 const LocaleDataWrapper
& rData
= aSysLocale
.GetLocaleData();
899 sal_Unicode cComma
= rData
.getNumDecimalSep()[0];
900 sal_Unicode c1000
= rData
.getNumThousandSep()[0];
901 OUString aCurrencyStrg
= rData
.getCurrSymbol();
903 // initialize the Basic-formater help object:
904 // get resources for predefined output
905 // of the Format()-command, e. g. for "On/Off"
906 OUString aOnStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_ON
).toString();
907 OUString aOffStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_OFF
).toString();
908 OUString aYesStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_YES
).toString();
909 OUString aNoStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_NO
).toString();
910 OUString aTrueStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_TRUE
).toString();
911 OUString aFalseStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_FALSE
).toString();
912 OUString aCurrencyFormatStrg
= SbxValueFormatResId(STR_BASICKEY_FORMAT_CURRENCY
).toString();
914 rAppData
.pBasicFormater
= new SbxBasicFormater( cComma
,c1000
,aOnStrg
,aOffStrg
,
915 aYesStrg
,aNoStrg
,aTrueStrg
,aFalseStrg
,
916 aCurrencyStrg
,aCurrencyFormatStrg
);
918 // Remark: For performance reasons there's only ONE BasicFormater-
919 // object created and 'stored', so that the expensive resource-
920 // loading is saved (for country-specific predefined outputs,
921 // e. g. "On/Off") and the continous string-creation
923 // BUT: therefore this code is NOT multithreading capable!
925 // here are problems with ;;;Null because this method is only
926 // called, if SbxValue is a number!!!
927 // in addition rAppData.pBasicFormater->BasicFormatNull( *pFmt ); could be called!
928 if( eType
!= SbxNULL
)
930 rRes
= rAppData
.pBasicFormater
->BasicFormat( d
,*pFmt
);
934 rRes
= rAppData
.pBasicFormater
->BasicFormatNull( *pFmt
);
940 OUString
aTmpString( rRes
);
941 ImpCvtNum( GetDouble(), nComma
, aTmpString
);
948 // #45355 converting if numeric
951 ScanNumIntnl( GetOUString(), d
, /*bSingle*/false );
956 printfmtstr( GetOUString(), rRes
, *pFmt
);
961 rRes
= GetOUString();
965 rRes
= GetOUString();
970 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */