LibreOffice Module basic (master) 1
sbxscan.cxx
Go to the documentation of this file.
1/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2/*
3 * This file is part of the LibreOffice project.
4 *
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/.
8 *
9 * This file incorporates work covered by the following license notice:
10 *
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 .
18 */
19
20#include <sal/config.h>
21
22#include <string_view>
23
24#include <config_features.h>
25
27#include <unotools/resmgr.hxx>
28#include "sbxconv.hxx"
29#include <rtlproto.hxx>
30
33
34#include <vcl/svapp.hxx>
35#include <vcl/settings.hxx>
36
37#include <math.h>
38
39#include <sbxbase.hxx>
40#include <sbintern.hxx>
41#include <sbxform.hxx>
42
43#include <date.hxx>
44#include <runtime.hxx>
45#include <strings.hrc>
46
47#include <rtl/character.hxx>
48#include <rtl/math.hxx>
49#include <svl/numformat.hxx>
50#include <svl/zforlist.hxx>
51#include <o3tl/string_view.hxx>
52
53
54void ImpGetIntntlSep( sal_Unicode& rcDecimalSep, sal_Unicode& rcThousandSep, sal_Unicode& rcDecimalSepAlt )
55{
56 SvtSysLocale aSysLocale;
57 const LocaleDataWrapper& rData = aSysLocale.GetLocaleData();
58 rcDecimalSep = rData.getNumDecimalSep()[0];
59 rcThousandSep = rData.getNumThousandSep()[0];
60 rcDecimalSepAlt = rData.getNumDecimalSepAlt().toChar();
61}
62
63
64static bool ImpStrChr( std::u16string_view str, sal_Unicode c ) { return str.find(c) != std::u16string_view::npos; }
65
66
67// scanning a string according to BASIC-conventions
68// but exponent may also be a D, so data type is SbxDOUBLE
69// conversion error if data type is fixed and it doesn't fit
70
71ErrCode ImpScan( const OUString& rWSrc, double& nVal, SbxDataType& rType,
72 sal_uInt16* pLen, bool bOnlyIntntl )
73{
74 sal_Unicode cIntntlDecSep, cIntntlGrpSep, cIntntlDecSepAlt;
75 sal_Unicode cNonIntntlDecSep = '.';
76 if( bOnlyIntntl )
77 {
78 ImpGetIntntlSep( cIntntlDecSep, cIntntlGrpSep, cIntntlDecSepAlt );
79 cNonIntntlDecSep = cIntntlDecSep;
80 // Ensure that the decimal separator alternative is really one.
81 if (cIntntlDecSepAlt && cIntntlDecSepAlt == cNonIntntlDecSep)
82 cIntntlDecSepAlt = 0;
83 }
84 else
85 {
86 cIntntlDecSep = cNonIntntlDecSep;
87 cIntntlGrpSep = 0; // no group separator accepted in non-i18n
88 cIntntlDecSepAlt = 0;
89 }
90
91 const sal_Unicode* const pStart = rWSrc.getStr();
92 const sal_Unicode* p = pStart;
93 OUStringBuffer aBuf( rWSrc.getLength());
94 bool bRes = true;
95 bool bMinus = false;
96 nVal = 0;
97 SbxDataType eScanType = SbxSINGLE;
98 while( *p == ' ' || *p == '\t' )
99 p++;
100 if (*p == '+')
101 p++;
102 else if( *p == '-' )
103 {
104 p++;
105 bMinus = true;
106 }
107 if( rtl::isAsciiDigit( *p ) || ((*p == cNonIntntlDecSep || *p == cIntntlDecSep ||
108 (cIntntlDecSep && *p == cIntntlGrpSep) || (cIntntlDecSepAlt && *p == cIntntlDecSepAlt)) &&
109 rtl::isAsciiDigit( *(p+1) )))
110 {
111 // tdf#118442: Whitespace and minus are skipped; store the position to calculate index
112 const sal_Unicode* const pDigitsStart = p;
113 short exp = 0;
114 short decsep = 0;
115 short ndig = 0;
116 short ncdig = 0; // number of digits after decimal point
117 OUStringBuffer aSearchStr(OUString::Concat("0123456789DEde") + OUStringChar(cNonIntntlDecSep));
118 if( cIntntlDecSep != cNonIntntlDecSep )
119 aSearchStr.append(cIntntlDecSep);
120 if( cIntntlDecSepAlt && cIntntlDecSepAlt != cNonIntntlDecSep )
121 aSearchStr.append(cIntntlDecSepAlt);
122 if( bOnlyIntntl )
123 aSearchStr.append(cIntntlGrpSep);
124 const OUString pSearchStr = aSearchStr.makeStringAndClear();
125 static constexpr OUStringLiteral pDdEe = u"DdEe";
126 while( ImpStrChr( pSearchStr, *p ) )
127 {
128 aBuf.append( *p );
129 if( bOnlyIntntl && *p == cIntntlGrpSep )
130 {
131 p++;
132 continue;
133 }
134 if( *p == cNonIntntlDecSep || *p == cIntntlDecSep || (cIntntlDecSepAlt && *p == cIntntlDecSepAlt) )
135 {
136 // Use the separator that is passed to stringToDouble()
137 aBuf[p - pDigitsStart] = cIntntlDecSep;
138 p++;
139 if( ++decsep > 1 )
140 continue;
141 }
142 else if( ImpStrChr( pDdEe, *p ) )
143 {
144 if( ++exp > 1 )
145 {
146 p++;
147 continue;
148 }
149 if( *p == 'D' || *p == 'd' )
150 eScanType = SbxDOUBLE;
151 aBuf[p - pDigitsStart] = 'E';
152 p++;
153 if (*p == '+')
154 ++p;
155 else if (*p == '-')
156 {
157 aBuf.append('-');
158 ++p;
159 }
160 }
161 else
162 {
163 p++;
164 if( decsep && !exp )
165 ncdig++;
166 }
167 if( !exp )
168 ndig++;
169 }
170
171 if( decsep > 1 || exp > 1 )
172 bRes = false;
173
174 rtl_math_ConversionStatus eStatus = rtl_math_ConversionStatus_Ok;
175 sal_Int32 nParseEnd = 0;
176 nVal = rtl::math::stringToDouble( aBuf, cIntntlDecSep, cIntntlGrpSep, &eStatus, &nParseEnd );
177 if( eStatus != rtl_math_ConversionStatus_Ok || nParseEnd != aBuf.getLength() )
178 bRes = false;
179
180 if( !decsep && !exp )
181 {
182 if( nVal >= SbxMININT && nVal <= SbxMAXINT )
183 eScanType = SbxINTEGER;
184 else if( nVal >= SbxMINLNG && nVal <= SbxMAXLNG )
185 eScanType = SbxLONG;
186 }
187
188 ndig = ndig - decsep;
189 // too many numbers for SINGLE?
190 if( ndig > 15 || ncdig > 6 )
191 eScanType = SbxDOUBLE;
192
193 // type detection?
194 static constexpr OUStringLiteral pTypes = u"%!&#";
195 if( ImpStrChr( pTypes, *p ) )
196 p++;
197 }
198 // hex/octal number? read in and convert:
199 else if( *p == '&' )
200 {
201 p++;
202 eScanType = SbxLONG;
203 OUString aCmp( "0123456789ABCDEF" );
204 char base = 16;
205 char ndig = 8;
206 switch( *p++ )
207 {
208 case 'O':
209 case 'o':
210 aCmp = "01234567";
211 base = 8;
212 ndig = 11;
213 break;
214 case 'H':
215 case 'h':
216 break;
217 default :
218 bRes = false;
219 }
220 while( rtl::isAsciiAlphanumeric( *p ) ) /* XXX: really munge all alnum also when error? */
221 {
222 sal_Unicode ch = rtl::toAsciiUpperCase(*p);
223 if( ImpStrChr( aCmp, ch ) )
224 aBuf.append( ch );
225 else
226 bRes = false;
227 p++;
228 }
229 OUString aBufStr( aBuf.makeStringAndClear());
230 sal_Int32 l = 0;
231 for( const sal_Unicode* q = aBufStr.getStr(); bRes && *q; q++ )
232 {
233 int i = *q - '0';
234 if( i > 9 )
235 i -= 7; // 'A'-'0' = 17 => 10, ...
236 l = ( l * base ) + i;
237 if( !ndig-- )
238 bRes = false;
239 }
240 if( *p == '&' )
241 p++;
242 nVal = static_cast<double>(l);
243 if( l >= SbxMININT && l <= SbxMAXINT )
244 eScanType = SbxINTEGER;
245 }
246#if HAVE_FEATURE_SCRIPTING
247 else if ( SbiRuntime::isVBAEnabled() )
248 {
250 }
251#endif
252 // tdf#146672 - skip whitespaces and tabs at the end of the scanned string
253 while (*p == ' ' || *p == '\t')
254 p++;
255 if( pLen )
256 *pLen = static_cast<sal_uInt16>( p - pStart );
257 if( !bRes )
259 if( bMinus )
260 nVal = -nVal;
261 rType = eScanType;
262 return ERRCODE_NONE;
263}
264
265// port for CDbl in the Basic
266ErrCode SbxValue::ScanNumIntnl( const OUString& rSrc, double& nVal, bool bSingle )
267{
269 sal_uInt16 nLen = 0;
270 ErrCode nRetError = ImpScan( rSrc, nVal, t, &nLen,
271 /*bOnlyIntntl*/true );
272 // read completely?
273 if( nRetError == ERRCODE_NONE && nLen != rSrc.getLength() )
274 {
275 nRetError = ERRCODE_BASIC_CONVERSION;
276 }
277 if( bSingle )
278 {
279 SbxValues aValues( nVal );
280 nVal = static_cast<double>(ImpGetSingle( &aValues )); // here error at overflow
281 }
282 return nRetError;
283}
284
285// The number is prepared unformattedly with the given number of
286// NK-positions. A leading minus is added if applicable.
287// This routine is public because it's also used by the Put-functions
288// in the class SbxImpSTRING.
289
290void ImpCvtNum( double nNum, short nPrec, OUString& rRes, bool bCoreString )
291{
292 sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt;
293 ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt );
294 if( bCoreString )
295 cDecimalSep = '.';
296
297 // tdf#143575 - use rtl::math::doubleToUString to convert numbers to strings in basic
298 rRes = rtl::math::doubleToUString(nNum, rtl_math_StringFormat_Automatic, nPrec, cDecimalSep, true);
299}
300
301bool ImpConvStringExt( OUString& rSrc, SbxDataType eTargetType )
302{
303 bool bChanged = false;
304 OUString aNewString;
305
306 // only special cases are handled, nothing on default
307 switch( eTargetType )
308 {
309 // consider international for floating point
310 case SbxSINGLE:
311 case SbxDOUBLE:
312 case SbxCURRENCY:
313 {
314 sal_Unicode cDecimalSep, cThousandSep, cDecimalSepAlt;
315 ImpGetIntntlSep( cDecimalSep, cThousandSep, cDecimalSepAlt );
316 aNewString = rSrc;
317
318 if( cDecimalSep != '.' || (cDecimalSepAlt && cDecimalSepAlt != '.') )
319 {
320 sal_Int32 nPos = aNewString.indexOf( cDecimalSep );
321 if( nPos == -1 && cDecimalSepAlt )
322 nPos = aNewString.indexOf( cDecimalSepAlt );
323 if( nPos != -1 )
324 {
325 sal_Unicode* pStr = const_cast<sal_Unicode*>(aNewString.getStr());
326 pStr[nPos] = '.';
327 bChanged = true;
328 }
329 }
330 break;
331 }
332
333 // check as string in case of sal_Bool sal_True and sal_False
334 case SbxBOOL:
335 {
336 if( rSrc.equalsIgnoreAsciiCase("true") )
337 {
338 aNewString = OUString::number( SbxTRUE );
339 bChanged = true;
340 }
341 else if( rSrc.equalsIgnoreAsciiCase("false") )
342 {
343 aNewString = OUString::number( SbxFALSE );
344 bChanged = true;
345 }
346 break;
347 }
348 default: break;
349 }
350
351 if( bChanged )
352 rSrc = aNewString;
353 return bChanged;
354}
355
356
357// formatted number output
358// the return value is the number of characters used
359// from the format
360
361static sal_uInt16 printfmtstr( const OUString& rStr, OUString& rRes, const OUString& rFmt )
362{
363 OUStringBuffer aTemp;
364 const sal_Unicode* pStr = rStr.getStr();
365 const sal_Unicode* pFmtStart = rFmt.getStr();
366 const sal_Unicode* pFmt = pFmtStart;
367
368 switch( *pFmt )
369 {
370 case '!':
371 aTemp.append(*pStr++);
372 pFmt++;
373 break;
374 case '\\':
375 do
376 {
377 aTemp.append( *pStr ? *pStr++ : u' ');
378 pFmt++;
379 }
380 while( *pFmt && *pFmt != '\\' );
381 aTemp.append(*pStr ? *pStr++ : u' ');
382 pFmt++; break;
383 case '&':
384 aTemp = rStr;
385 pFmt++; break;
386 default:
387 aTemp = rStr;
388 break;
389 }
390 rRes = aTemp.makeStringAndClear();
391 return static_cast<sal_uInt16>( pFmt - pFmtStart );
392}
393
394
395bool SbxValue::Scan( const OUString& rSrc, sal_uInt16* pLen )
396{
397 ErrCode eRes = ERRCODE_NONE;
398 if( !CanWrite() )
399 {
401 }
402 else
403 {
404 double n;
406 eRes = ImpScan( rSrc, n, t, pLen, !LibreOffice6FloatingPointMode() );
407 if( eRes == ERRCODE_NONE )
408 {
409 if( !IsFixed() )
410 {
411 SetType( t );
412 }
413 PutDouble( n );
414 }
415 }
416 if( eRes )
417 {
418 SetError( eRes );
419 return false;
420 }
421 else
422 {
423 return true;
424 }
425}
426
427std::locale BasResLocale()
428{
429 return Translate::Create("sb");
430}
431
433{
434 return Translate::get(aId, BasResLocale());
435}
436
437namespace
438{
439
440enum class VbaFormatType
441{
442 Offset, // standard number format
443 UserDefined, // user defined number format
444 Null
445};
446
447#if HAVE_FEATURE_SCRIPTING
448
449struct VbaFormatInfo
450{
451 VbaFormatType meType;
452 std::u16string_view mpVbaFormat; // Format string in vba
453 NfIndexTableOffset meOffset; // SvNumberFormatter format index, if meType = VbaFormatType::Offset
454 const char* mpOOoFormat; // if meType = VbaFormatType::UserDefined
455};
456
457const VbaFormatInfo pFormatInfoTable[] =
458{
459 { VbaFormatType::Offset, std::u16string_view(u"Long Date"), NF_DATE_SYSTEM_LONG, nullptr },
460 { VbaFormatType::UserDefined, std::u16string_view(u"Medium Date"), NF_NUMBER_STANDARD, "DD-MMM-YY" },
461 { VbaFormatType::Offset, std::u16string_view(u"Short Date"), NF_DATE_SYSTEM_SHORT, nullptr },
462 { VbaFormatType::UserDefined, std::u16string_view(u"Long Time"), NF_NUMBER_STANDARD, "H:MM:SS AM/PM" },
463 { VbaFormatType::Offset, std::u16string_view(u"Medium Time"), NF_TIME_HHMMAMPM, nullptr },
464 { VbaFormatType::Offset, std::u16string_view(u"Short Time"), NF_TIME_HHMM, nullptr },
465 { VbaFormatType::Offset, std::u16string_view(u"ddddd"), NF_DATE_SYSTEM_SHORT, nullptr },
466 { VbaFormatType::Offset, std::u16string_view(u"dddddd"), NF_DATE_SYSTEM_LONG, nullptr },
467 { VbaFormatType::UserDefined, std::u16string_view(u"ttttt"), NF_NUMBER_STANDARD, "H:MM:SS AM/PM" },
468 { VbaFormatType::Offset, std::u16string_view(u"ww"), NF_DATE_WW, nullptr },
469 { VbaFormatType::Null, std::u16string_view(u""), NF_INDEX_TABLE_ENTRIES, nullptr }
470};
471
472const VbaFormatInfo* getFormatInfo( std::u16string_view rFmt )
473{
474 const VbaFormatInfo* pInfo = pFormatInfoTable;
475 while( pInfo->meType != VbaFormatType::Null )
476 {
477 if( o3tl::equalsIgnoreAsciiCase( rFmt, pInfo->mpVbaFormat ) )
478 break;
479 ++pInfo;
480 }
481 return pInfo;
482}
483#endif
484
485} // namespace
486
487#if HAVE_FEATURE_SCRIPTING
488constexpr OUStringLiteral VBAFORMAT_GENERALDATE = u"General Date";
489constexpr OUStringLiteral VBAFORMAT_C = u"c";
490constexpr OUStringLiteral VBAFORMAT_N = u"n";
491constexpr OUStringLiteral VBAFORMAT_NN = u"nn";
492constexpr OUStringLiteral VBAFORMAT_W = u"w";
493constexpr OUStringLiteral VBAFORMAT_Y = u"y";
494constexpr OUStringLiteral VBAFORMAT_LOWERCASE = u"<";
495constexpr OUStringLiteral VBAFORMAT_UPPERCASE = u">";
496#endif
497
498void SbxValue::Format( OUString& rRes, const OUString* pFmt ) const
499{
500 short nComma = 0;
501 double d = 0;
502
503 // pflin, It is better to use SvNumberFormatter to handle the date/time/number format.
504 // the SvNumberFormatter output is mostly compatible with
505 // VBA output besides the OOo-basic output
506#if HAVE_FEATURE_SCRIPTING
507 if( pFmt && !SbxBasicFormater::isBasicFormat( *pFmt ) )
508 {
509 OUString aStr = GetOUString();
510
511 SvtSysLocale aSysLocale;
512 const CharClass& rCharClass = aSysLocale.GetCharClass();
513
514 if( pFmt->equalsIgnoreAsciiCase( VBAFORMAT_LOWERCASE ) )
515 {
516 rRes = rCharClass.lowercase( aStr );
517 return;
518 }
519 if( pFmt->equalsIgnoreAsciiCase( VBAFORMAT_UPPERCASE ) )
520 {
521 rRes = rCharClass.uppercase( aStr );
522 return;
523 }
524
526 std::shared_ptr<SvNumberFormatter> pFormatter;
527 if (GetSbData()->pInst)
528 {
529 pFormatter = GetSbData()->pInst->GetNumberFormatter();
530 }
531 else
532 {
533 sal_uInt32 n; // Dummy
534 pFormatter = SbiInstance::PrepareNumberFormatter( n, n, n );
535 }
536
537 // Passing an index of a locale switches IsNumberFormat() to use that
538 // locale in case the formatter wasn't default created with it.
539 sal_uInt32 nIndex = pFormatter->GetStandardIndex( eLangType);
540 double nNumber;
541 const Color* pCol;
542
543 bool bSuccess = pFormatter->IsNumberFormat( aStr, nIndex, nNumber );
544
545 // number format, use SvNumberFormatter to handle it.
546 if( bSuccess )
547 {
548 sal_Int32 nCheckPos = 0;
550 OUString aFmtStr = *pFmt;
551 const VbaFormatInfo* pInfo = getFormatInfo( aFmtStr );
552 if( pInfo->meType != VbaFormatType::Null )
553 {
554 if( pInfo->meType == VbaFormatType::Offset )
555 {
556 nIndex = pFormatter->GetFormatIndex( pInfo->meOffset, eLangType );
557 }
558 else
559 {
560 aFmtStr = OUString::createFromAscii(pInfo->mpOOoFormat);
561 pFormatter->PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH_US, eLangType, true);
562 }
563 pFormatter->GetOutputString( nNumber, nIndex, rRes, &pCol );
564 }
565 else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_GENERALDATE )
566 || aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_C ))
567 {
568 if( nNumber <=-1.0 || nNumber >= 1.0 )
569 {
570 // short date
571 nIndex = pFormatter->GetFormatIndex( NF_DATE_SYSTEM_SHORT, eLangType );
572 pFormatter->GetOutputString( nNumber, nIndex, rRes, &pCol );
573
574 // long time
575 if( floor( nNumber ) != nNumber )
576 {
577 aFmtStr = "H:MM:SS AM/PM";
578 pFormatter->PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH_US, eLangType, true);
579 OUString aTime;
580 pFormatter->GetOutputString( nNumber, nIndex, aTime, &pCol );
581 rRes += " " + aTime;
582 }
583 }
584 else
585 {
586 // long time only
587 aFmtStr = "H:MM:SS AM/PM";
588 pFormatter->PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH_US, eLangType, true);
589 pFormatter->GetOutputString( nNumber, nIndex, rRes, &pCol );
590 }
591 }
592 else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_N ) ||
593 aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_NN ))
594 {
595 sal_Int32 nMin = implGetMinute( nNumber );
596 if( nMin < 10 && aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_NN ))
597 {
598 // Minute in two digits
599 sal_Unicode aBuf[2];
600 aBuf[0] = '0';
601 aBuf[1] = '0' + nMin;
602 rRes = OUString(aBuf, std::size(aBuf));
603 }
604 else
605 {
606 rRes = OUString::number(nMin);
607 }
608 }
609 else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_W ))
610 {
611 sal_Int32 nWeekDay = implGetWeekDay( nNumber );
612 rRes = OUString::number(nWeekDay);
613 }
614 else if( aFmtStr.equalsIgnoreAsciiCase( VBAFORMAT_Y ))
615 {
616 sal_Int16 nYear = implGetDateYear( nNumber );
617 double dBaseDate;
618 implDateSerial( nYear, 1, 1, true, SbDateCorrection::None, dBaseDate );
619 sal_Int32 nYear32 = 1 + sal_Int32( nNumber - dBaseDate );
620 rRes = OUString::number(nYear32);
621 }
622 else
623 {
624 pFormatter->PutandConvertEntry( aFmtStr, nCheckPos, nType, nIndex, LANGUAGE_ENGLISH_US, eLangType, true);
625 pFormatter->GetOutputString( nNumber, nIndex, rRes, &pCol );
626 }
627
628 return;
629 }
630 }
631#endif
632
634 switch( eType )
635 {
636 case SbxCHAR:
637 case SbxBYTE:
638 case SbxINTEGER:
639 case SbxUSHORT:
640 case SbxLONG:
641 case SbxULONG:
642 case SbxINT:
643 case SbxUINT:
644 case SbxNULL: // #45929 NULL with a little cheating
645 nComma = 0; goto cvt;
646 case SbxSINGLE:
647 nComma = 6; goto cvt;
648 case SbxDOUBLE:
649 nComma = 14;
650
651 cvt:
652 if( eType != SbxNULL )
653 {
654 d = GetDouble();
655 }
656 // #45355 another point to jump in for isnumeric-String
657 cvt2:
658 if( pFmt )
659 {
660 SbxAppData& rAppData = GetSbxData_Impl();
661
663 if( rAppData.pBasicFormater )
664 {
665 if( rAppData.eBasicFormaterLangType != eLangType )
666 {
667 rAppData.pBasicFormater.reset();
668 }
669 }
670 rAppData.eBasicFormaterLangType = eLangType;
671
672
673 if( !rAppData.pBasicFormater )
674 {
675 SvtSysLocale aSysLocale;
676 const LocaleDataWrapper& rData = aSysLocale.GetLocaleData();
677 sal_Unicode cComma = rData.getNumDecimalSep()[0];
678 sal_Unicode c1000 = rData.getNumThousandSep()[0];
679 const OUString& aCurrencyStrg = rData.getCurrSymbol();
680
681 // initialize the Basic-formater help object:
682 // get resources for predefined output
683 // of the Format()-command, e. g. for "On/Off"
684 OUString aOnStrg = BasResId(STR_BASICKEY_FORMAT_ON);
685 OUString aOffStrg = BasResId(STR_BASICKEY_FORMAT_OFF);
686 OUString aYesStrg = BasResId(STR_BASICKEY_FORMAT_YES);
687 OUString aNoStrg = BasResId(STR_BASICKEY_FORMAT_NO);
688 OUString aTrueStrg = BasResId(STR_BASICKEY_FORMAT_TRUE);
689 OUString aFalseStrg = BasResId(STR_BASICKEY_FORMAT_FALSE);
690 OUString aCurrencyFormatStrg = BasResId(STR_BASICKEY_FORMAT_CURRENCY);
691
692 rAppData.pBasicFormater = std::make_unique<SbxBasicFormater>(
693 cComma,c1000,aOnStrg,aOffStrg,
694 aYesStrg,aNoStrg,aTrueStrg,aFalseStrg,
695 aCurrencyStrg,aCurrencyFormatStrg );
696 }
697 // Remark: For performance reasons there's only ONE BasicFormater-
698 // object created and 'stored', so that the expensive resource-
699 // loading is saved (for country-specific predefined outputs,
700 // e. g. "On/Off") and the continuous string-creation
701 // operations, too.
702 // BUT: therefore this code is NOT multithreading capable!
703
704 // here are problems with ;;;Null because this method is only
705 // called, if SbxValue is a number!!!
706 // in addition rAppData.pBasicFormater->BasicFormatNull( *pFmt ); could be called!
707 if( eType != SbxNULL )
708 {
709 rRes = rAppData.pBasicFormater->BasicFormat( d ,*pFmt );
710 }
711 else
712 {
713 rRes = SbxBasicFormater::BasicFormatNull( *pFmt );
714 }
715
716 }
717 else
718 ImpCvtNum( GetDouble(), nComma, rRes );
719 break;
720 case SbxSTRING:
721 if( pFmt )
722 {
723 // #45355 converting if numeric
724 if( IsNumericRTL() )
725 {
727 goto cvt2;
728 }
729 else
730 {
731 printfmtstr( GetOUString(), rRes, *pFmt );
732 }
733 }
734 else
735 {
736 rRes = GetOUString();
737 }
738 break;
739 default:
740 rRes = GetOUString();
741 }
742}
743
744
745/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
XPropertyListType t
double d
SbxAppData & GetSbxData_Impl()
Definition: basrdll.cxx:123
const LanguageTag & GetLanguageTag() const
static const AllSettings & GetSettings()
OUString uppercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
OUString lowercase(const OUString &rStr, sal_Int32 nPos, sal_Int32 nCount) const
LanguageType getLanguageType(bool bResolveSystem=true) const
const OUString & getNumThousandSep() const
const OUString & getCurrSymbol() const
const OUString & getNumDecimalSepAlt() const
const OUString & getNumDecimalSep() const
static std::shared_ptr< SvNumberFormatter > PrepareNumberFormatter(sal_uInt32 &rnStdDateIdx, sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx, LanguageType const *peFormatterLangType=nullptr, DateOrder const *peFormatterDateOrder=nullptr)
Definition: runtime.cxx:404
std::shared_ptr< SvNumberFormatter > const & GetNumberFormatter()
Definition: runtime.cxx:380
static bool isVBAEnabled()
Definition: runtime.cxx:115
bool CanWrite() const
Definition: sbxcore.hxx:123
static void SetError(ErrCode)
Definition: sbxbase.cxx:116
static OUString BasicFormatNull(std::u16string_view sFormatStrg)
Definition: sbxform.cxx:845
static bool isBasicFormat(std::u16string_view sFormatStrg)
Definition: sbxform.cxx:962
OUString GetOUString() const
Definition: sbxvalue.cxx:380
bool PutDouble(double)
virtual bool IsFixed() const override
Definition: sbxvalue.cxx:618
static ErrCode ScanNumIntnl(const OUString &rSrc, double &nVal, bool bSingle=false)
Definition: sbxscan.cxx:266
bool SetType(SbxDataType)
Definition: sbxvalue.cxx:674
double GetDouble() const
Definition: sbxvar.hxx:150
bool IsNumericRTL() const
Definition: sbxvalue.cxx:632
bool Scan(const OUString &, sal_uInt16 *)
Definition: sbxscan.cxx:395
void Format(OUString &, const OUString *=nullptr) const
Definition: sbxscan.cxx:498
virtual SbxDataType GetType() const override
Definition: sbxvalue.cxx:668
const LocaleDataWrapper & GetLocaleData() const
const CharClass & GetCharClass() const
bool implDateSerial(sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bUseTwoDigitYear, SbDateCorrection eCorr, double &rdRet)
Definition: methods.cxx:4630
sal_Int16 implGetWeekDay(double aDate, bool bFirstDayParam=false, sal_Int16 nFirstDay=0)
Definition: methods1.cxx:2953
sal_Int16 implGetDateYear(double aDate)
Definition: methods.cxx:4621
sal_Int16 implGetMinute(double dDate)
Definition: methods.cxx:4761
float u
#define ERRCODE_NONE
DocumentType eType
void const * base
sal_Int32 nIndex
void * p
sal_Int64 n
#define LANGUAGE_ENGLISH_US
sal_uInt16 nPos
aStr
aBuf
std::locale Create(std::string_view aPrefixName, const LanguageTag &rLocale)
OUString get(TranslateId sContextAndId, const std::locale &loc)
int i
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
QPRO_FUNC_TYPE nType
bool LibreOffice6FloatingPointMode()
Definition: methods1.cxx:2946
#define ERRCODE_BASIC_PROP_READONLY
Definition: sberrors.hxx:39
#define ERRCODE_BASIC_CONVERSION
Definition: sberrors.hxx:30
SbiGlobals * GetSbData()
Definition: sbintern.cxx:26
float ImpGetSingle(const SbxValues *)
Definition: sbxsng.cxx:27
constexpr auto SbxMAXLNG
Definition: sbxdef.hxx:190
constexpr sal_Int32 SbxMINLNG
Definition: sbxdef.hxx:191
SbxBOOL
Definition: sbxdef.hxx:215
@ SbxFALSE
Definition: sbxdef.hxx:215
@ SbxTRUE
Definition: sbxdef.hxx:215
constexpr auto SbxMAXINT
Definition: sbxdef.hxx:187
SbxDataType
Definition: sbxdef.hxx:37
@ SbxLONG
Definition: sbxdef.hxx:41
@ SbxNULL
Definition: sbxdef.hxx:39
@ SbxBYTE
Definition: sbxdef.hxx:55
@ SbxUINT
Definition: sbxdef.hxx:60
@ SbxULONG
Definition: sbxdef.hxx:57
@ SbxUSHORT
Definition: sbxdef.hxx:56
@ SbxCURRENCY
Definition: sbxdef.hxx:44
@ SbxINT
Definition: sbxdef.hxx:59
@ SbxSINGLE
Definition: sbxdef.hxx:42
@ SbxCHAR
Definition: sbxdef.hxx:54
@ SbxSTRING
Definition: sbxdef.hxx:46
@ SbxINTEGER
Definition: sbxdef.hxx:40
@ SbxDOUBLE
Definition: sbxdef.hxx:43
constexpr auto SbxMININT
Definition: sbxdef.hxx:188
OUString BasResId(TranslateId aId)
Definition: sbxscan.cxx:432
ErrCode ImpScan(const OUString &rWSrc, double &nVal, SbxDataType &rType, sal_uInt16 *pLen, bool bOnlyIntntl)
Definition: sbxscan.cxx:71
static bool ImpStrChr(std::u16string_view str, sal_Unicode c)
Definition: sbxscan.cxx:64
bool ImpConvStringExt(OUString &rSrc, SbxDataType eTargetType)
Definition: sbxscan.cxx:301
void ImpCvtNum(double nNum, short nPrec, OUString &rRes, bool bCoreString)
Definition: sbxscan.cxx:290
static sal_uInt16 printfmtstr(const OUString &rStr, OUString &rRes, const OUString &rFmt)
Definition: sbxscan.cxx:361
void ImpGetIntntlSep(sal_Unicode &rcDecimalSep, sal_Unicode &rcThousandSep, sal_Unicode &rcDecimalSepAlt)
Definition: sbxscan.cxx:54
std::locale BasResLocale()
Definition: sbxscan.cxx:427
SbiInstance * pInst
Definition: sbintern.hxx:108
std::unique_ptr< SbxBasicFormater > pBasicFormater
Definition: sbxbase.hxx:45
LanguageType eBasicFormaterLangType
Definition: sbxbase.hxx:47
sal_uInt16 sal_Unicode
RedlineType meType
SvNumFormatType
NfIndexTableOffset
NF_DATE_SYSTEM_SHORT
NF_TIME_HHMMAMPM
NF_DATE_WW
NF_INDEX_TABLE_ENTRIES
NF_NUMBER_STANDARD
NF_TIME_HHMM
NF_DATE_SYSTEM_LONG