fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / basic / source / sbx / sbxscan.cxx
blobc136e95c61b380ad5ab9fa3960588ff8097b0b32
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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"
26 #if defined ( UNX )
27 #include <stdlib.h>
28 #endif
30 #include <vcl/svapp.hxx>
31 #include <math.h>
32 #include <string.h>
33 #include <ctype.h>
35 #include "sbxres.hxx"
36 #include <basic/sbxbase.hxx>
37 #include <basic/sbxfac.hxx>
38 #include <basic/sbxform.hxx>
39 #include <svtools/svtools.hrc>
41 #include "basrid.hxx"
42 #include "date.hxx"
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 )
69 if (!c)
70 return false;
71 while (*p)
73 if (*p++ == c)
74 return true;
76 return false;
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 );
96 if( bOnlyIntntl )
97 cNonIntntlDecSep = cIntntlDecSep;
99 else
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());
108 bool bRes = true;
109 bool bMinus = false;
110 nVal = 0;
111 SbxDataType eScanType = SbxSINGLE;
112 while( *p == ' ' || *p == '\t' )
113 p++;
114 if( *p == '-' )
116 p++;
117 bMinus = true;
119 if( ImpIsDigit( *p ) || ((*p == cNonIntntlDecSep || *p == cIntntlDecSep ||
120 (cIntntlDecSep && *p == cIntntlGrpSep)) && ImpIsDigit( *(p+1) )))
122 short exp = 0;
123 short decsep = 0;
124 short ndig = 0;
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);
130 if( bOnlyIntntl )
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 ) )
136 aBuf.append( *p );
137 if( bOnlyIntntl && *p == cIntntlGrpSep )
139 p++;
140 continue;
142 if( *p == cNonIntntlDecSep || *p == cIntntlDecSep )
144 // Use the separator that is passed to stringToDouble()
145 aBuf[ p - pStart ] = cIntntlDecSep;
146 p++;
147 if( ++decsep > 1 )
148 continue;
150 else if( ImpStrChr( pDdEe, *p ) )
152 if( ++exp > 1 )
154 p++;
155 continue;
157 if( *p == 'D' || *p == 'd' )
158 eScanType = SbxDOUBLE;
159 aBuf[ p - pStart ] = 'E';
160 p++;
162 else
164 p++;
165 if( decsep && !exp )
166 ncdig++;
168 if( !exp )
169 ndig++;
172 if( decsep > 1 || exp > 1 )
173 bRes = false;
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() )
180 bRes = false;
182 if( !decsep && !exp )
184 if( nVal >= SbxMININT && nVal <= SbxMAXINT )
185 eScanType = SbxINTEGER;
186 else if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG )
187 eScanType = SbxLONG;
190 ndig = ndig - decsep;
191 // too many numbers for SINGLE?
192 if( ndig > 15 || ncdig > 6 )
193 eScanType = SbxDOUBLE;
195 // type detection?
196 const sal_Unicode pTypes[] = { '%', '!', '&', '#', 0 };
197 if( ImpStrChr( pTypes, *p ) )
198 p++;
200 // hex/octal number? read in and convert:
201 else if( *p == '&' )
203 p++;
204 eScanType = SbxLONG;
205 OUString aCmp( "0123456789ABCDEFabcdef" );
206 char base = 16;
207 char ndig = 8;
208 switch( *p++ )
210 case 'O':
211 case 'o':
212 aCmp = "01234567";
213 base = 8;
214 ndig = 11;
215 break;
216 case 'H':
217 case 'h':
218 break;
219 default :
220 bRes = false;
222 const sal_Unicode* const pCmp = aCmp.getStr();
223 while( ImpIsAlNum( *p ) ) /* XXX: really munge all alnum also when error? */
225 sal_Unicode ch = *p;
226 if( ImpStrChr( pCmp, ch ) )
228 if (ch > 0x60)
229 ch -= 0x20; // convert ASCII lower to upper case
230 aBuf.append( ch );
232 else
233 bRes = false;
234 p++;
236 OUString aBufStr( aBuf.makeStringAndClear());
237 long l = 0;
238 for( const sal_Unicode* q = aBufStr.getStr(); bRes && *q; q++ )
240 int i = *q - '0';
241 if( i > 9 )
242 i -= 7; // 'A'-'0' = 17 => 10, ...
243 l = ( l * base ) + i;
244 if( !ndig-- )
245 bRes = false;
247 if( *p == '&' )
248 p++;
249 nVal = (double) l;
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;
259 #endif
260 if( pLen )
261 *pLen = (sal_uInt16) ( p - pStart );
262 if( !bRes )
263 return SbxERR_CONVERSION;
264 if( bMinus )
265 nVal = -nVal;
266 rType = eScanType;
267 return SbxERR_OK;
270 // port for CDbl in the Basic
271 SbxError SbxValue::ScanNumIntnl( const OUString& rSrc, double& nVal, bool bSingle )
273 SbxDataType t;
274 sal_uInt16 nLen = 0;
275 SbxError nRetError = ImpScan( rSrc, nVal, t, &nLen,
276 /*bAllowIntntl*/false, /*bOnlyIntntl*/true );
277 // read completely?
278 if( nRetError == SbxERR_OK && nLen != rSrc.getLength() )
280 nRetError = SbxERR_CONVERSION;
282 if( bSingle )
284 SbxValues aValues( nVal );
285 nVal = (double)ImpGetSingle( &aValues ); // here error at overflow
287 return nRetError;
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 )
313 short nExp = 0;
314 short nDig = nPrec + 1;
315 short nDec; // number of positions before decimal point
316 register int i;
318 sal_Unicode cDecimalSep, cThousandSep;
319 ImpGetIntntlSep( cDecimalSep, cThousandSep );
320 if( cForceThousandSep )
321 cThousandSep = cForceThousandSep;
323 // compute exponent
324 nExp = 0;
325 if( nNum > 0.0 )
327 while( nNum < 1.0 ) nNum *= 10.0, nExp--;
328 while( nNum >= 10.0 ) nNum /= 10.0, nExp++;
330 if( !bFix && !nExpWidth )
331 nDig = nDig + nExp;
332 else if( bFix && !nPrec )
333 nDig = nExp + 1;
335 // round number
336 if( (nNum += roundArray [( nDig > 16 ) ? 16 : nDig] ) >= 10.0 )
338 nNum = 1.0;
339 ++nExp;
340 if( !nExpWidth ) ++nDig;
343 // determine positions before decimal point
344 if( !nExpWidth )
346 if( nExp < 0 )
348 // #41691: also a 0 at bFix
349 *pBuf++ = '0';
350 if( nPrec ) *pBuf++ = (char)cDecimalSep;
351 i = -nExp - 1;
352 if( nDig <= 0 ) i = nPrec;
353 while( i-- ) *pBuf++ = '0';
354 nDec = 0;
356 else
357 nDec = nExp+1;
359 else
360 nDec = 1;
362 // output number
363 if( nDig > 0 )
365 register int digit;
366 for( i = 0 ; ; ++i )
368 if( i < 16 )
370 digit = (int) nNum;
371 *pBuf++ = sal::static_int_cast< char >(digit + '0');
372 nNum =( nNum - digit ) * 10.0;
373 } else
374 *pBuf++ = '0';
375 if( --nDig == 0 ) break;
376 if( nDec )
378 nDec--;
379 if( !nDec )
380 *pBuf++ = (char)cDecimalSep;
381 else if( !(nDec % 3 ) && bPt )
382 *pBuf++ = (char)cThousandSep;
387 // output exponent
388 if( nExpWidth )
390 if( nExpWidth < 3 ) nExpWidth = 3;
391 nExpWidth -= 2;
392 *pBuf++ = 'E';
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');
398 nExp %= 100;
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');
404 *pBuf = 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 )
414 char *q;
415 char cBuf[ 40 ], *p = cBuf;
417 sal_Unicode cDecimalSep, cThousandSep;
418 ImpGetIntntlSep( cDecimalSep, cThousandSep );
419 if( bCoreString )
420 cDecimalSep = '.';
422 if( nNum < 0.0 ) {
423 nNum = -nNum;
424 *p++ = '-';
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++ ) {}
431 q = p; p--;
432 while( nPrec && *p == '0' ) nPrec--, p--;
433 if( *p == cDecimalSep ) p--;
434 while( *q ) *++p = *q++;
435 *++p = 0;
436 rRes = OUString::createFromAscii( cBuf );
439 bool ImpConvStringExt( OUString& rSrc, SbxDataType eTargetType )
441 bool bChanged = false;
442 OUString aNewString;
444 // only special cases are handled, nothing on default
445 switch( eTargetType )
447 // consider international for floating point
448 case SbxSINGLE:
449 case SbxDOUBLE:
450 case SbxCURRENCY:
452 sal_Unicode cDecimalSep, cThousandSep;
453 ImpGetIntntlSep( cDecimalSep, cThousandSep );
454 aNewString = rSrc;
456 if( cDecimalSep != (sal_Unicode)'.' )
458 sal_Int32 nPos = aNewString.indexOf( cDecimalSep );
459 if( nPos != -1 )
461 sal_Unicode* pStr = (sal_Unicode*)aNewString.getStr();
462 pStr[nPos] = (sal_Unicode)'.';
463 bChanged = true;
466 break;
469 // check as string in case of sal_Bool sal_True and sal_False
470 case SbxBOOL:
472 if( rSrc.equalsIgnoreAsciiCase("true") )
474 aNewString = OUString::valueOf( (sal_Int32)SbxTRUE );
475 bChanged = true;
477 else if( rSrc.equalsIgnoreAsciiCase("false") )
479 aNewString = OUString::valueOf( (sal_Int32)SbxFALSE );
480 bChanged = true;
482 break;
484 default: break;
487 if( bChanged )
488 rSrc = aNewString;
489 return bChanged;
493 // formatted number output
494 // the return value is the number of characters used
495 // from the format
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
514 char * p;
515 const char* pFmt = rFmt;
516 rRes.Erase();
517 // catch $$ and **, is simply output as character
518 if( *pFmt == '$' )
519 if( *++pFmt != '$' ) rRes += '$';
520 if( *pFmt == '*' )
521 if( *++pFmt != '*' ) rRes += '*';
523 switch( *pFmt++ )
525 case 0:
526 break;
527 case '+':
528 bSign = true; nWidth++; break;
529 case '*':
530 nWidth++; cFill = '*';
531 if( *pFmt == '$' ) nWidth++, pFmt++, cPre = '$';
532 break;
533 case '$':
534 nWidth++; cPre = '$'; break;
535 case '#':
536 case '.':
537 case ',':
538 pFmt--; break;
540 // pre point
541 for( ;; )
543 while( *pFmt == '#' ) pFmt++, nWidth++;
544 // 1000 separators?
545 if( *pFmt == ',' )
547 nWidth++; pFmt++; bPoint = true;
548 } else break;
550 // after point
551 if( *pFmt == '.' )
553 while( *++pFmt == '#' ) nPrec++;
554 nWidth += nPrec + 1;
556 // exponent
557 while( *pFmt == '^' )
558 pFmt++, nExpDig++, nWidth++;
559 // following minus
560 if( !bSign && *pFmt == '-' )
561 pFmt++, bTrail = true;
563 // convert number
564 if( nPrec > 15 ) nPrec = 15;
565 if( nNum < 0.0 ) nNum = -nNum, bNeg = true;
566 p = cBuf;
567 if( bSign ) *p++ = bNeg ? '-' : '+';
568 myftoa( nNum, p, nPrec, nExpDig, bPoint, false );
569 nLen = strlen( cBuf );
571 // overflow?
572 if( cPre ) nLen++;
573 if( nLen > nWidth ) rRes += '%';
574 else {
575 nWidth -= nLen;
576 while( nWidth-- ) rRes += (sal_Unicode)cFill;
577 if( cPre ) rRes += (sal_Unicode)cPre;
579 rRes += (sal_Unicode*)&(cBuf[0]);
580 if( bTrail )
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;
595 switch( *pFmt )
597 case '!':
598 aTemp.append(*pStr++);
599 pFmt++;
600 break;
601 case '\\':
604 aTemp.append( *pStr ? *pStr++ : static_cast< sal_Unicode >(' '));
605 pFmt++;
607 while( *pFmt != '\\' );
608 aTemp.append(*pStr ? *pStr++ : static_cast< sal_Unicode >(' '));
609 pFmt++; break;
610 case '&':
611 aTemp = rStr;
612 pFmt++; break;
613 default:
614 aTemp = rStr;
615 break;
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;
625 if( !CanWrite() )
627 eRes = SbxERR_PROP_READONLY;
629 else
631 double n;
632 SbxDataType t;
633 eRes = ImpScan( rSrc, n, t, pLen );
634 if( eRes == SbxERR_OK )
636 if( !IsFixed() )
638 SetType( t );
640 PutDouble( n );
643 if( eRes )
645 SetError( eRes ); return sal_False;
647 else
649 return sal_True;
654 ResMgr* implGetResMgr( void )
656 static ResMgr* pResMgr = NULL;
657 if( !pResMgr )
659 pResMgr = ResMgr::CreateResMgr("sb", Application::GetSettings().GetUILanguageTag() );
661 return pResMgr;
664 class SbxValueFormatResId : public ResId
666 public:
667 SbxValueFormatResId( sal_uInt16 nId )
668 : ResId( nId, *implGetResMgr() )
673 enum VbaFormatType
675 VBA_FORMAT_TYPE_OFFSET, // standard number format
676 VBA_FORMAT_TYPE_USERDEFINED, // user defined number format
677 VBA_FORMAT_TYPE_NULL
680 struct VbaFormatInfo
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;
712 sal_Int16 i = 0;
713 while( (pInfo = pFormatInfoTable + i )->mpVbaFormat != NULL )
715 if( rFmt.EqualsIgnoreCaseAscii( pInfo->mpVbaFormat ) )
716 break;
717 i++;
719 return pInfo;
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
733 short nComma = 0;
734 double d = 0;
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 );
749 return;
751 if( pFmt->equalsIgnoreAsciiCase( VBAFORMAT_UPPERCASE ) )
753 rRes = rCharClass.uppercase( aStr );
754 return;
757 LanguageType eLangType = GetpApp()->GetSettings().GetLanguageTag().getLanguageType();
758 SvNumberFormatter aFormatter( comphelper::getProcessComponentContext(), eLangType );
760 sal_uInt32 nIndex = 0;
761 double nNumber;
762 Color* pCol;
764 sal_Bool bSuccess = aFormatter.IsNumberFormat( aStr, nIndex, nNumber );
766 // number format, use SvNumberFormatter to handle it.
767 if( bSuccess )
769 sal_Int32 nCheckPos = 0;
770 short nType;
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 );
779 else
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 )
791 // short date
792 nIndex = aFormatter.GetFormatIndex( NF_DATE_SYSTEM_SHORT, eLangType );
793 aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol );
795 // long time
796 if( floor( nNumber ) != nNumber )
798 aFmtStr = "H:MM:SS AM/PM";
799 aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType );
800 OUString aTime;
801 aFormatter.GetOutputString( nNumber, nIndex, aTime, &pCol );
802 rRes += " ";
803 rRes += aTime;
806 else
808 // long time only
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
821 sal_Unicode aBuf[2];
822 aBuf[0] = '0';
823 aBuf[1] = '0' + nMin;
824 rRes = OUString(aBuf, SAL_N_ELEMENTS(aBuf));
826 else
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 );
839 double dBaseDate;
840 implDateSerial( nYear, 1, 1, dBaseDate );
841 sal_Int32 nYear32 = 1 + sal_Int32( nNumber - dBaseDate );
842 rRes = OUString::valueOf(nYear32);
844 else
846 aFormatter.PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH, eLangType );
847 aFormatter.GetOutputString( nNumber, nIndex, rRes, &pCol );
850 return;
854 SbxDataType eType = GetType();
855 switch( eType )
857 case SbxCHAR:
858 case SbxBYTE:
859 case SbxINTEGER:
860 case SbxUSHORT:
861 case SbxLONG:
862 case SbxULONG:
863 case SbxINT:
864 case SbxUINT:
865 case SbxNULL: // #45929 NULL with a little cheating
866 nComma = 0; goto cvt;
867 case SbxSINGLE:
868 nComma = 6; goto cvt;
869 case SbxDOUBLE:
870 nComma = 14;
872 cvt:
873 if( eType != SbxNULL )
875 d = GetDouble();
877 // #45355 another point to jump in for isnumeric-String
878 cvt2:
879 if( pFmt )
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
922 // operations, too.
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 );
932 else
934 rRes = rAppData.pBasicFormater->BasicFormatNull( *pFmt );
938 else
940 OUString aTmpString( rRes );
941 ImpCvtNum( GetDouble(), nComma, aTmpString );
942 rRes = aTmpString;
944 break;
945 case SbxSTRING:
946 if( pFmt )
948 // #45355 converting if numeric
949 if( IsNumericRTL() )
951 ScanNumIntnl( GetOUString(), d, /*bSingle*/false );
952 goto cvt2;
954 else
956 printfmtstr( GetOUString(), rRes, *pFmt );
959 else
961 rRes = GetOUString();
963 break;
964 default:
965 rRes = GetOUString();
970 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */