LibreOffice Module basic (master) 1
sbxform.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
21#include <stdlib.h>
22
23#include <sbxform.hxx>
24#include <rtl/ustrbuf.hxx>
25
26#include <rtl/character.hxx>
27#include <o3tl/sprintf.hxx>
28#include <o3tl/string_view.hxx>
29#include <string_view>
30#include <utility>
31
32/*
33TODO: are there any Star-Basic characteristics unconsidered?
34
35 what means: * as placeholder
36
37COMMENT: Visual-Basic treats the following (invalid) format-strings
38 as shown:
39
40 ##0##.##0## --> ##000.000##
41
42 (this class behaves the same way)
43*/
44
45#include <stdio.h>
46#include <float.h>
47#include <math.h>
48
49#define NO_DIGIT_ -1
50
51#define MAX_NO_OF_DIGITS DBL_DIG
52#define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9
53 // +1 for leading sign
54 // +1 for digit before the decimal point
55 // +1 for decimal point
56 // +2 for exponent E and exp. leading sign
57 // +3 for the exponent's value
58 // +1 for closing 0
59
60#define CREATE_1000SEP_CHAR '@'
61
62#define FORMAT_SEPARATOR ';'
63
64// predefined formats for the Format$()-command:
65constexpr OUStringLiteral BASICFORMAT_GENERALNUMBER = u"General Number";
66constexpr OUStringLiteral BASICFORMAT_CURRENCY = u"Currency";
67constexpr OUStringLiteral BASICFORMAT_FIXED = u"Fixed";
68constexpr OUStringLiteral BASICFORMAT_STANDARD = u"Standard";
69constexpr OUStringLiteral BASICFORMAT_PERCENT = u"Percent";
70constexpr OUStringLiteral BASICFORMAT_SCIENTIFIC = u"Scientific";
71constexpr OUStringLiteral BASICFORMAT_YESNO = u"Yes/No";
72constexpr OUStringLiteral BASICFORMAT_TRUEFALSE = u"True/False";
73constexpr OUStringLiteral BASICFORMAT_ONOFF = u"On/Off";
74
75// Comment: Visual-Basic has a maximum of 12 positions after the
76// decimal point for floating-point-numbers.
77// all format-strings are compatible to Visual-Basic:
78constexpr OUStringLiteral GENERALNUMBER_FORMAT = u"0.############";
79constexpr OUStringLiteral FIXED_FORMAT = u"0.00";
80constexpr OUStringLiteral STANDARD_FORMAT = u"@0.00";
81constexpr OUStringLiteral PERCENT_FORMAT = u"0.00%";
82constexpr OUStringLiteral SCIENTIFIC_FORMAT = u"#.00E+00";
83// Comment: the character @ means that thousand-separators shall
84// be generated. That's a StarBasic 'extension'.
85
86
87static double get_number_of_digits( double dNumber )
88//double floor_log10_fabs( double dNumber )
89{
90 if( dNumber==0.0 )
91 return 0.0; // used to be 1.0, now 0.0 because of #40025;
92 else
93 return floor( log10( fabs( dNumber ) ) );
94}
95
96
98 OUString _sOnStrg,
99 OUString _sOffStrg,
100 OUString _sYesStrg,
101 OUString _sNoStrg,
102 OUString _sTrueStrg,
103 OUString _sFalseStrg,
104 OUString _sCurrencyStrg,
105 OUString _sCurrencyFormatStrg )
106 : cDecPoint(_cDecPoint)
107 , cThousandSep(_cThousandSep)
108 , sOnStrg(std::move(_sOnStrg))
109 , sOffStrg(std::move(_sOffStrg))
110 , sYesStrg(std::move(_sYesStrg))
111 , sNoStrg(std::move(_sNoStrg))
112 , sTrueStrg(std::move(_sTrueStrg))
113 , sFalseStrg(std::move(_sFalseStrg))
114 , sCurrencyStrg(std::move(_sCurrencyStrg))
115 , sCurrencyFormatStrg(std::move(_sCurrencyFormatStrg))
116 , dNum(0.0)
117 , nNumExp(0)
118 , nExpExp(0)
119{
120}
121
122// function to output an error-text (for debugging)
123// displaces all characters of the string, starting from nStartPos
124// for one position to larger indexes, i. e. place for a new
125// character (which is to be inserted) is created.
126// ATTENTION: the string MUST be long enough!
127inline void SbxBasicFormater::ShiftString( OUStringBuffer& sStrg, sal_uInt16 nStartPos )
128{
129 sStrg.remove(nStartPos,1);
130}
131
132void SbxBasicFormater::AppendDigit( OUStringBuffer& sStrg, short nDigit )
133{
134 if( nDigit>=0 && nDigit<=9 )
135 {
136 sStrg.append(static_cast<sal_Unicode>(nDigit+'0'));
137 }
138}
139
140void SbxBasicFormater::LeftShiftDecimalPoint( OUStringBuffer& sStrg )
141{
142 sal_Int32 nPos = -1;
143
144 for(sal_Int32 i = 0; i < sStrg.getLength(); i++)
145 {
146 if(sStrg[i] == cDecPoint)
147 {
148 nPos = i;
149 break;
150 }
151 }
152 if( nPos >= 0 )
153 {
154 sStrg[nPos] = sStrg[nPos - 1];
155 sStrg[nPos - 1] = cDecPoint;
156 }
157}
158
159// returns a flag if rounding a 9
160void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos, bool& bOverflow )
161{
162 if( nPos<0 )
163 {
164 return;
165 }
166 bOverflow = false;
167 sal_Unicode c = sStrg[nPos];
168 if( nPos > 0 && (c == cDecPoint || c == cThousandSep) )
169 {
170 StrRoundDigit( sStrg, nPos - 1, bOverflow );
171 // CHANGE from 9.3.1997: end the method immediately after recursive call!
172 return;
173 }
174 // skip non-digits:
175 // COMMENT:
176 // in a valid format-string the number's output should be done
177 // in one piece, i. e. special characters should ONLY be in
178 // front OR behind the number and not right in the middle of
179 // the format information for the number
180 while( nPos >= 0 && ! rtl::isAsciiDigit(sStrg[nPos]))
181 {
182 nPos--;
183 }
184 if( nPos==-1 )
185 {
186 ShiftString( sStrg, 0 );
187 sStrg[0] = '1';
188 bOverflow = true;
189 }
190 else
191 {
192 sal_Unicode c2 = sStrg[nPos];
193 if( rtl::isAsciiDigit(c2) )
194 {
195 if( c2 == '9' )
196 {
197 sStrg[nPos] = '0';
198 StrRoundDigit( sStrg, nPos - 1, bOverflow );
199 }
200 else
201 {
202 sStrg[nPos] = c2 + 1;
203 }
204 }
205 else
206 {
207 ShiftString( sStrg,nPos+1 );
208 sStrg[nPos + 1] = '1';
209 bOverflow = true;
210 }
211 }
212}
213
214void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos )
215{
216 bool bOverflow;
217
218 StrRoundDigit( sStrg, nPos, bOverflow );
219}
220
221void SbxBasicFormater::ParseBack( OUStringBuffer& sStrg, std::u16string_view sFormatStrg,
222 short nFormatPos )
223{
224 for( sal_Int32 i = nFormatPos;
225 i>0 && sFormatStrg[ i ] == '#' && sStrg[sStrg.getLength() - 1] == '0';
226 i-- )
227 {
228 sStrg.setLength(sStrg.getLength() - 1 );
229 }
230}
231
232void SbxBasicFormater::InitScan( double _dNum )
233{
234 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
235
236 dNum = _dNum;
238 // maximum of 15 positions behind the decimal point, example: -1.234000000000000E-001
239 /*int nCount =*/ o3tl::sprintf( sBuffer,"%+22.15lE",dNum );
240 sSciNumStrg = OUString::createFromAscii( sBuffer );
241}
242
243
244void SbxBasicFormater::InitExp( double _dNewExp )
245{
246 nNumExp = static_cast<short>(_dNewExp);
247 sNumExpStrg = (nNumExp >= 0 ? std::u16string_view(u"+") : std::u16string_view(u""))
248 + OUString::number(nNumExp);
249 nExpExp = static_cast<short>(get_number_of_digits( static_cast<double>(nNumExp) ));
250}
251
252
253short SbxBasicFormater::GetDigitAtPosScan( short nPos, bool& bFoundFirstDigit )
254{
255 // trying to read a higher digit,
256 // e. g. position 4 in 1.234,
257 // or to read a digit outside of the
258 // number's dissolution (double)
260 {
261 return NO_DIGIT_;
262 }
263 // determine the index of the position in the number-string:
264 // skip the leading sign
265 sal_uInt16 no = 1;
266 // skip the decimal point if necessary
267 if( nPos<nNumExp )
268 no++;
269 no += nNumExp-nPos;
270 // query of the number's first valid digit --> set flag
271 if( nPos==nNumExp )
272 bFoundFirstDigit = true;
273 return static_cast<short>(sSciNumStrg[ no ] - '0');
274}
275
276short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, bool& bFoundFirstDigit )
277{
278 if( nPos>nExpExp )
279 return -1;
280
281 sal_uInt16 no = 1;
282 no += nExpExp-nPos;
283
284 if( nPos==nExpExp )
285 bFoundFirstDigit = true;
286 return static_cast<short>(sNumExpStrg[ no ] - '0');
287}
288
289// a value for the exponent can be given because the number maybe shall
290// not be displayed in a normed way (e. g. 1.2345e-03) but maybe 123.345e-3 !
291short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos,
292 bool& bFoundFirstDigit )
293{
294 InitExp( dNewExponent );
295
296 return GetDigitAtPosExpScan( nPos,bFoundFirstDigit );
297}
298
299// Copies the respective part of the format-string, if existing, and returns it.
300// So a new string is created, which has to be freed by the caller later.
301OUString SbxBasicFormater::GetPosFormatString( std::u16string_view sFormatStrg, bool & bFound )
302{
303 bFound = false; // default...
304 size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR );
305
306 if( nPos != std::u16string_view::npos )
307 {
308 bFound = true;
309 // the format-string for positive numbers is
310 // everything before the first ';'
311 return OUString(sFormatStrg.substr( 0,nPos ));
312 }
313
314 return OUString();
315}
316
317// see also GetPosFormatString()
318OUString SbxBasicFormater::GetNegFormatString( std::u16string_view sFormatStrg, bool & bFound )
319{
320 bFound = false; // default...
321 size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR );
322
323 if( nPos != std::u16string_view::npos)
324 {
325 // the format-string for negative numbers is
326 // everything between the first and the second ';'
327 std::u16string_view sTempStrg = sFormatStrg.substr( nPos+1 );
328 nPos = sTempStrg.find( FORMAT_SEPARATOR );
329 bFound = true;
330 if( nPos == std::u16string_view::npos )
331 {
332 return OUString(sTempStrg);
333 }
334 else
335 {
336 return OUString(sTempStrg.substr( 0,nPos ));
337 }
338 }
339 return OUString();
340}
341
342// see also GetPosFormatString()
343OUString SbxBasicFormater::Get0FormatString( std::u16string_view sFormatStrg, bool & bFound )
344{
345 bFound = false; // default...
346 size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR );
347
348 if( nPos != std::u16string_view::npos )
349 {
350 // the format string for the zero is
351 // everything after the second ';'
352 std::u16string_view sTempStrg = sFormatStrg.substr( nPos+1 );
353 nPos = sTempStrg.find( FORMAT_SEPARATOR );
354 if( nPos != std::u16string_view::npos )
355 {
356 bFound = true;
357 sTempStrg = sTempStrg.substr( nPos+1 );
358 nPos = sTempStrg.find( FORMAT_SEPARATOR );
359 if( nPos == std::u16string_view::npos )
360 {
361 return OUString(sTempStrg);
362 }
363 else
364 {
365 return OUString(sTempStrg.substr( 0,nPos ));
366 }
367 }
368 }
369
370 return OUString();
371}
372
373// see also GetPosFormatString()
374OUString SbxBasicFormater::GetNullFormatString( std::u16string_view sFormatStrg, bool & bFound )
375{
376 bFound = false; // default...
377 size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR );
378
379 if( nPos != std::u16string_view::npos )
380 {
381 // the format-string for the Null is
382 // everything after the third ';'
383 std::u16string_view sTempStrg = sFormatStrg.substr( nPos+1 );
384 nPos = sTempStrg.find( FORMAT_SEPARATOR );
385 if( nPos != std::u16string_view::npos )
386 {
387 sTempStrg = sTempStrg.substr( nPos+1 );
388 nPos = sTempStrg.find( FORMAT_SEPARATOR );
389 if( nPos != std::u16string_view::npos )
390 {
391 bFound = true;
392 return OUString(sTempStrg.substr( nPos+1 ));
393 }
394 }
395 }
396
397 return OUString();
398}
399
400// returns value <> 0 in case of an error
401void SbxBasicFormater::AnalyseFormatString( std::u16string_view sFormatStrg,
402 short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
403 short& nNoOfOptionalDigitsLeft,
404 short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits,
405 bool& bPercent, bool& bCurrency, bool& bScientific,
406 bool& bGenerateThousandSeparator,
407 short& nMultipleThousandSeparators )
408{
409 sal_Int32 nLen;
410 short nState = 0;
411
412 nLen = sFormatStrg.size();
413 nNoOfDigitsLeft = 0;
414 nNoOfDigitsRight = 0;
415 nNoOfOptionalDigitsLeft = 0;
416 nNoOfExponentDigits = 0;
417 nNoOfOptionalExponentDigits = 0;
418 bPercent = false;
419 bCurrency = false;
420 bScientific = false;
421 // from 11.7.97: as soon as a comma (point?) is found in the format string,
422 // all three decimal powers are marked (i. e. thousand, million, ...)
423 bGenerateThousandSeparator = sFormatStrg.find( ',' ) != std::u16string_view::npos;
424 nMultipleThousandSeparators = 0;
425
426 for( sal_Int32 i = 0; i < nLen; i++ )
427 {
428 sal_Unicode c = sFormatStrg[ i ];
429 switch( c )
430 {
431 case '#':
432 case '0':
433 if( nState==0 )
434 {
435 nNoOfDigitsLeft++;
436// TODO here maybe better error inspection of the mantissa for valid syntax (see grammar)h
437 // ATTENTION: 'undefined' behaviour if # and 0 are combined!
438 // REMARK: #-placeholders are actually useless for
439 // scientific display before the decimal point!
440 if( c=='#' )
441 {
442 nNoOfOptionalDigitsLeft++;
443 }
444 }
445 else if( nState==1 )
446 {
447 nNoOfDigitsRight++;
448 }
449 else if( nState==-1 ) // search 0 in the exponent
450 {
451 if( c=='#' ) // # switches on the condition
452 {
453 nNoOfOptionalExponentDigits++;
454 nState = -2;
455 }
456 nNoOfExponentDigits++;
457 }
458 else if( nState==-2 ) // search # in the exponent
459 {
460 if( c=='0' )
461 {
462 // ERROR: 0 after # in the exponent is NOT allowed!!
463 return;
464 }
465 nNoOfOptionalExponentDigits++;
466 nNoOfExponentDigits++;
467 }
468 break;
469 case '.':
470 nState++;
471 if( nState>1 )
472 {
473 return; // ERROR: too many decimal points
474 }
475 break;
476 case '%':
477 bPercent = true;
478 break;
479 case '(':
480 bCurrency = true;
481 break;
482 case ',':
483 {
484 sal_Unicode ch = sFormatStrg[ i+1 ];
485
486 if( ch!=0 && (ch==',' || ch=='.') )
487 {
488 nMultipleThousandSeparators++;
489 }
490 }
491 break;
492 case 'e':
493 case 'E':
494 // #i13821 not when no digits before
495 if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 )
496 {
497 nState = -1; // abort counting digits
498 bScientific = true;
499 }
500 break;
501 // OWN command-character which turns on
502 // the creation of thousand-separators
503 case '\\':
504 // Ignore next char
505 i++;
506 break;
508 bGenerateThousandSeparator = true;
509 break;
510 }
511 }
512}
513
514// the flag bCreateSign says that at the mantissa a leading sign
515// shall be created
517 std::u16string_view sFormatStrg, OUString& sReturnStrgFinal,
518 bool bCreateSign )
519{
520 short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft,
521 nNoOfExponentDigits,nNoOfOptionalExponentDigits,
522 nMultipleThousandSeparators;
523 bool bPercent,bCurrency,bScientific,bGenerateThousandSeparator;
524
525 OUStringBuffer sReturnStrg(32);
526
527 // analyse the format-string, i. e. determine the following values:
528 /*
529 - number of digits before decimal point
530 - number of digits after decimal point
531 - optional digits before decimal point
532 - number of digits in the exponent
533 - optional digits in the exponent
534 - percent-character found?
535 - () for negative leading sign?
536 - exponential-notation?
537 - shall thousand-separators be generated?
538 - is a percent-character being found? --> dNumber *= 100.0;
539 - are there thousand-separators in a row?
540 ,, or ,. --> dNumber /= 1000.0;
541 - other errors? multiple decimal points, E's, etc.
542 --> errors are simply ignored at the moment
543 */
544 AnalyseFormatString( sFormatStrg, nNoOfDigitsLeft, nNoOfDigitsRight,
545 nNoOfOptionalDigitsLeft, nNoOfExponentDigits,
546 nNoOfOptionalExponentDigits,
547 bPercent, bCurrency, bScientific,
548 bGenerateThousandSeparator, nMultipleThousandSeparators );
549 // special handling for special characters
550 if( bPercent )
551 {
552 dNumber *= 100.0;
553 }
554// TODO: this condition (,, or ,.) is NOT Visual-Basic compatible!
555 // Question: shall this stay here (requirements)?
556 if( nMultipleThousandSeparators )
557 {
558 dNumber /= 1000.0;
559 }
560 double dExponent;
561 short i,nLen;
562 short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit;
563 bool bFirstDigit,bFirstExponentDigit,bFoundFirstDigit,
564 bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative;
565
566 bSignHappend = false;
567 bFoundFirstDigit = false;
568 bIsNegative = dNumber < 0.0;
569 nLen = sFormatStrg.size();
570 dExponent = get_number_of_digits( dNumber );
571 nExponentPos = 0;
572 nMaxExponentDigit = 0;
573 nMaxDigit = static_cast<short>(dExponent);
574 bDigitPosNegative = false;
575 if( bScientific )
576 {
577 dExponent = dExponent - static_cast<double>(nNoOfDigitsLeft-1);
578 nDigitPos = nMaxDigit;
579 nMaxExponentDigit = static_cast<short>(get_number_of_digits( dExponent ));
580 nExponentPos = nNoOfExponentDigits - 1 - nNoOfOptionalExponentDigits;
581 }
582 else
583 {
584 nDigitPos = nNoOfDigitsLeft - 1; // counting starts at 0, 10^0
585 // no exponent-data is needed here!
586 bDigitPosNegative = (nDigitPos < 0);
587 }
588 bFirstDigit = true;
589 bFirstExponentDigit = true;
590 nState = 0; // 0 --> mantissa; 1 --> exponent
591 bZeroSpaceOn = false;
592
593
594 InitScan( dNumber );
595 // scanning the format-string:
596 sal_Unicode cForce = 0;
597 for( i = 0; i < nLen; i++ )
598 {
599 sal_Unicode c;
600 if( cForce )
601 {
602 c = cForce;
603 cForce = 0;
604 }
605 else
606 {
607 c = sFormatStrg[ i ];
608 }
609 switch( c )
610 {
611 case '0':
612 case '#':
613 if( nState==0 )
614 {
615 // handling of the mantissa
616 if( bFirstDigit )
617 {
618 // remark: at bCurrency the negative
619 // leading sign shall be shown with ()
620 if( bIsNegative && !bCreateSign && !bSignHappend )
621 {
622 bSignHappend = true;
623 sReturnStrg.append('-');
624 }
625 // output redundant positions, i. e. those which
626 // are undocumented by the format-string
627 if( nMaxDigit > nDigitPos )
628 {
629 for( short j = nMaxDigit; j > nDigitPos; j-- )
630 {
631 short nTempDigit = GetDigitAtPosScan( j, bFoundFirstDigit );
632 AppendDigit( sReturnStrg, nTempDigit );
633 if( nTempDigit != NO_DIGIT_ )
634 {
635 bFirstDigit = false;
636 }
637 if( bGenerateThousandSeparator && c=='0' && j > 0 && (j % 3 == 0) )
638 {
639 sReturnStrg.append(cThousandSep );
640 }
641 }
642 }
643 }
644
645 if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) )
646 {
647 AppendDigit( sReturnStrg, 0 );
648 bFirstDigit = false;
649 bZeroSpaceOn = true;
650 // Remark: in Visual-Basic the first 0 turns on the 0 for
651 // all the following # (up to the decimal point),
652 // this behaviour is simulated here with the flag.
653 if (bGenerateThousandSeparator && c == '0' && nDigitPos > 0 && (nDigitPos % 3 == 0))
654 {
655 sReturnStrg.append(cThousandSep);
656 }
657 }
658 else
659 {
660 short nTempDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ) ;
661 AppendDigit( sReturnStrg, nTempDigit );
662
663 if( nTempDigit != NO_DIGIT_ )
664 {
665 bFirstDigit = false;
666 }
667 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) )
668 {
669 sReturnStrg.append(cThousandSep);
670 }
671 }
672 nDigitPos--;
673 }
674 else
675 {
676 // handling the exponent
677 if( bFirstExponentDigit )
678 {
679 // leading sign has been given out at e/E already
680 bFirstExponentDigit = false;
681 if( nMaxExponentDigit > nExponentPos )
682 // output redundant positions, i. e. those which
683 // are undocumented by the format-string
684 {
685 for( short j = nMaxExponentDigit; j > nExponentPos; j-- )
686 {
687 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, j, bFoundFirstDigit ) );
688 }
689 }
690 }
691
692 if( nMaxExponentDigit < nExponentPos && c=='0' )
693 {
694 AppendDigit( sReturnStrg, 0 );
695 }
696 else
697 {
698 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, nExponentPos, bFoundFirstDigit ) );
699 }
700 nExponentPos--;
701 }
702 break;
703 case '.':
704 if( bDigitPosNegative ) // #i13821: If no digits before .
705 {
706 bDigitPosNegative = false;
707 nDigitPos = 0;
708 cForce = '#';
709 i-=2;
710 break;
711 }
712 sReturnStrg.append(cDecPoint);
713 break;
714 case '%':
715 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
716 ParseBack( sReturnStrg, sFormatStrg, i-1 );
717 sReturnStrg.append('%');
718 break;
719 case 'e':
720 case 'E':
721 // does mantissa have to be rounded, before the exponent is displayed?
722 {
723 // is there a mantissa at all?
724 if( bFirstDigit )
725 {
726 // apparently not, i. e. invalid format string, e. g. E000.00
727 // so ignore these e and E characters
728 // maybe output an error (like in Visual Basic)?
729
730 // #i13821: VB 6 behaviour
731 sReturnStrg.append(c);
732 break;
733 }
734
735 bool bOverflow = false;
736 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
737 if( nNextDigit>=5 )
738 {
739 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1, bOverflow );
740 }
741 if( bOverflow )
742 {
743 // a leading 9 has been rounded
744 LeftShiftDecimalPoint( sReturnStrg );
745 sReturnStrg[sReturnStrg.getLength() - 1] = 0;
746 dExponent += 1.0;
747 }
748 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
749 ParseBack( sReturnStrg, sFormatStrg, i-1 );
750 }
751 // change the scanner's condition
752 nState++;
753 // output exponent character
754 sReturnStrg.append(c);
755 // i++; // MANIPULATION of the loop-variable!
756 c = sFormatStrg[ ++i ];
757 // output leading sign / exponent
758 if( c != 0 )
759 {
760 if( c == '-' )
761 {
762 if( dExponent < 0.0 )
763 {
764 sReturnStrg.append('-');
765 }
766 }
767 else if( c == '+' )
768 {
769 if( dExponent < 0.0 )
770 {
771 sReturnStrg.append('-');
772 }
773 else
774 {
775 sReturnStrg.append('+');
776 }
777 }
778 }
779 break;
780 case ',':
781 break;
782 case ';':
783 break;
784 case '(':
785 case ')':
786 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
787 ParseBack( sReturnStrg, sFormatStrg, i-1 );
788 if( bIsNegative )
789 {
790 sReturnStrg.append(c);
791 }
792 break;
793 case '$':
794 // append the string for the currency:
795 sReturnStrg.append(sCurrencyStrg);
796 break;
797 case ' ':
798 case '-':
799 case '+':
800 ParseBack( sReturnStrg, sFormatStrg, i-1 );
801 sReturnStrg.append(c);
802 break;
803 case '\\':
804 ParseBack( sReturnStrg, sFormatStrg, i-1 );
805 // special character found, output next
806 // character directly (if existing)
807 c = sFormatStrg[ ++i ];
808 if( c!=0 )
809 {
810 sReturnStrg.append(c);
811 }
812 break;
814 // ignore here, action has already been
815 // executed in AnalyseFormatString
816 break;
817 default:
818 // output characters and digits, too (like in Visual-Basic)
819 if( ( c>='a' && c<='z' ) ||
820 ( c>='A' && c<='Z' ) ||
821 ( c>='1' && c<='9' ) )
822 {
823 sReturnStrg.append(c);
824 }
825 }
826 }
827
828 // scan completed - rounding necessary?
829 if( !bScientific )
830 {
831 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
832 if( nNextDigit>=5 )
833 {
834 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1 );
835 }
836 }
837
838 if( nNoOfDigitsRight>0 )
839 {
840 ParseBack( sReturnStrg, sFormatStrg, sFormatStrg.size()-1 );
841 }
842 sReturnStrgFinal = sReturnStrg.makeStringAndClear();
843}
844
845OUString SbxBasicFormater::BasicFormatNull( std::u16string_view sFormatStrg )
846{
847 bool bNullFormatFound;
848 OUString sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound );
849
850 if( bNullFormatFound )
851 {
852 return sNullFormatStrg;
853 }
854 return "null";
855}
856
857OUString SbxBasicFormater::BasicFormat( double dNumber, const OUString& _sFormatStrg )
858{
859 bool bPosFormatFound,bNegFormatFound,b0FormatFound;
860 OUString sFormatStrg = _sFormatStrg;
861
862 // analyse format-string concerning predefined formats:
863 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
864 {
865 sFormatStrg = GENERALNUMBER_FORMAT;
866 }
867 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
868 {
869 sFormatStrg = sCurrencyFormatStrg;
870 }
871 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
872 {
873 sFormatStrg = FIXED_FORMAT;
874 }
875 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
876 {
877 sFormatStrg = STANDARD_FORMAT;
878 }
879 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
880 {
881 sFormatStrg = PERCENT_FORMAT;
882 }
883 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
884 {
885 sFormatStrg = SCIENTIFIC_FORMAT;
886 }
887 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
888 {
889 return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ;
890 }
891 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
892 {
893 return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ;
894 }
895 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
896 {
897 return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ;
898 }
899
900 // analyse format-string concerning ';', i. e. format-strings for
901 // positive-, negative- and 0-values
902 OUString sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound );
903 OUString sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound );
904 OUString s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound );
905
906 OUString sReturnStrg;
907 OUString sTempStrg;
908
909 if( dNumber==0.0 )
910 {
911 sTempStrg = sFormatStrg;
912 if( b0FormatFound )
913 {
914 if( s0FormatStrg.isEmpty() && bPosFormatFound )
915 {
916 sTempStrg = sPosFormatStrg;
917 }
918 else
919 {
920 sTempStrg = s0FormatStrg;
921 }
922 }
923 else if( bPosFormatFound )
924 {
925 sTempStrg = sPosFormatStrg;
926 }
927 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/false );
928 }
929 else
930 {
931 if( dNumber<0.0 )
932 {
933 if( bNegFormatFound )
934 {
935 if( sNegFormatStrg.isEmpty() && bPosFormatFound )
936 {
937 sTempStrg = "-" + sPosFormatStrg;
938 }
939 else
940 {
941 sTempStrg = sNegFormatStrg;
942 }
943 }
944 else
945 {
946 sTempStrg = sFormatStrg;
947 }
948 // if NO format-string especially for negative
949 // values is given, output the leading sign
950 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ );
951 }
952 else // if( dNumber>0.0 )
953 {
954 ScanFormatString( dNumber,
955 (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg),
956 sReturnStrg,/*bCreateSign=*/false );
957 }
958 }
959 return sReturnStrg;
960}
961
962bool SbxBasicFormater::isBasicFormat( std::u16string_view sFormatStrg )
963{
965 {
966 return true;
967 }
969 {
970 return true;
971 }
973 {
974 return true;
975 }
977 {
978 return true;
979 }
981 {
982 return true;
983 }
985 {
986 return true;
987 }
989 {
990 return true;
991 }
993 {
994 return true;
995 }
997 {
998 return true;
999 }
1000 return false;
1001}
1002
1003/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
static OUString GetNegFormatString(std::u16string_view sFormatStrg, bool &bFound)
Definition: sbxform.cxx:318
OUString sCurrencyFormatStrg
Definition: sbxform.hxx:141
static void ParseBack(OUStringBuffer &sStrg, std::u16string_view sFormatStrg, short nFormatPos)
Definition: sbxform.cxx:221
static OUString GetPosFormatString(std::u16string_view sFormatStrg, bool &bFound)
Definition: sbxform.cxx:301
OUString sYesStrg
Definition: sbxform.hxx:136
void InitExp(double _dNewExp)
Definition: sbxform.cxx:244
OUString sOffStrg
Definition: sbxform.hxx:135
static void AppendDigit(OUStringBuffer &sStrg, short nDigit)
Definition: sbxform.cxx:132
OUString sFalseStrg
Definition: sbxform.hxx:139
OUString sNumExpStrg
Definition: sbxform.hxx:148
OUString BasicFormat(double dNumber, const OUString &sFormatStrg)
Definition: sbxform.cxx:857
static OUString BasicFormatNull(std::u16string_view sFormatStrg)
Definition: sbxform.cxx:845
void ScanFormatString(double dNumber, std::u16string_view sFormatStrg, OUString &sReturnStrg, bool bCreateSign)
Definition: sbxform.cxx:516
OUString sTrueStrg
Definition: sbxform.hxx:138
void LeftShiftDecimalPoint(OUStringBuffer &sStrg)
Definition: sbxform.cxx:140
void StrRoundDigit(OUStringBuffer &sStrg, short nPos, bool &bOverflow)
Definition: sbxform.cxx:160
SbxBasicFormater(sal_Unicode _cDecPoint, sal_Unicode _cThousandSep, OUString _sOnStrg, OUString _sOffStrg, OUString _sYesStrg, OUString _sNoStrg, OUString _sTrueStrg, OUString _sFalseStrg, OUString _sCurrencyStrg, OUString _sCurrencyFormatStrg)
Definition: sbxform.cxx:97
sal_Unicode cThousandSep
Definition: sbxform.hxx:132
static OUString GetNullFormatString(std::u16string_view sFormatStrg, bool &bFound)
Definition: sbxform.cxx:374
static bool isBasicFormat(std::u16string_view sFormatStrg)
Definition: sbxform.cxx:962
OUString sSciNumStrg
Definition: sbxform.hxx:146
static OUString Get0FormatString(std::u16string_view sFormatStrg, bool &bFound)
Definition: sbxform.cxx:343
static void AnalyseFormatString(std::u16string_view sFormatStrg, short &nNoOfDigitsLeft, short &nNoOfDigitsRight, short &nNoOfOptionalDigitsLeft, short &nNoOfExponentDigits, short &nNoOfOptionalExponentDigits, bool &bPercent, bool &bCurrency, bool &bScientific, bool &bGenerateThousandSeparator, short &nMultipleThousandSeparators)
Definition: sbxform.cxx:401
static void ShiftString(OUStringBuffer &sStrg, sal_uInt16 nStartPos)
Definition: sbxform.cxx:127
void InitScan(double _dNum)
Definition: sbxform.cxx:232
sal_Unicode cDecPoint
Definition: sbxform.hxx:131
OUString sNoStrg
Definition: sbxform.hxx:137
OUString sOnStrg
Definition: sbxform.hxx:134
OUString sCurrencyStrg
Definition: sbxform.hxx:140
short GetDigitAtPosExpScan(double dNewExponent, short nPos, bool &bFoundFirstDigit)
Definition: sbxform.cxx:291
short GetDigitAtPosScan(short nPos, bool &bFoundFirstDigit)
Definition: sbxform.cxx:253
float u
sal_Int32 nState
sal_uInt16 nPos
int i
bool equalsIgnoreAsciiCase(std::u16string_view s1, std::u16string_view s2)
int sprintf(char(&s)[N], char const *format, T &&... arguments)
SwNodeOffset abs(const SwNodeOffset &a)
#define CREATE_1000SEP_CHAR
Definition: sbxform.cxx:60
static double get_number_of_digits(double dNumber)
Definition: sbxform.cxx:87
#define FORMAT_SEPARATOR
Definition: sbxform.cxx:62
constexpr OUStringLiteral BASICFORMAT_SCIENTIFIC
Definition: sbxform.cxx:70
constexpr OUStringLiteral GENERALNUMBER_FORMAT
Definition: sbxform.cxx:78
constexpr OUStringLiteral BASICFORMAT_FIXED
Definition: sbxform.cxx:67
constexpr OUStringLiteral STANDARD_FORMAT
Definition: sbxform.cxx:80
#define MAX_DOUBLE_BUFFER_LENGTH
Definition: sbxform.cxx:52
constexpr OUStringLiteral SCIENTIFIC_FORMAT
Definition: sbxform.cxx:82
#define NO_DIGIT_
Definition: sbxform.cxx:49
constexpr OUStringLiteral PERCENT_FORMAT
Definition: sbxform.cxx:81
constexpr OUStringLiteral FIXED_FORMAT
Definition: sbxform.cxx:79
constexpr OUStringLiteral BASICFORMAT_YESNO
Definition: sbxform.cxx:71
constexpr OUStringLiteral BASICFORMAT_STANDARD
Definition: sbxform.cxx:68
constexpr OUStringLiteral BASICFORMAT_TRUEFALSE
Definition: sbxform.cxx:72
constexpr OUStringLiteral BASICFORMAT_ONOFF
Definition: sbxform.cxx:73
constexpr OUStringLiteral BASICFORMAT_GENERALNUMBER
Definition: sbxform.cxx:65
#define MAX_NO_OF_DIGITS
Definition: sbxform.cxx:51
constexpr OUStringLiteral BASICFORMAT_PERCENT
Definition: sbxform.cxx:69
constexpr OUStringLiteral BASICFORMAT_CURRENCY
Definition: sbxform.cxx:66
sal_uInt16 sal_Unicode