Version 6.4.0.3, tag libreoffice-6.4.0.3
[LibreOffice.git] / basic / source / sbx / sbxform.cxx
blobc291f3e23af3bab1be2e1f01be97f978ce75bce8
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 .
21 #include <stdlib.h>
23 #include <basic/sbxform.hxx>
24 #include <rtl/ustrbuf.hxx>
26 #include <rtl/character.hxx>
29 TODO: are there any Star-Basic characteristics unconsidered?
31 what means: * as placeholder
33 COMMENT: Visual-Basic treats the following (invalid) format-strings
34 as shown:
36 ##0##.##0## --> ##000.000##
38 (this class behaves the same way)
41 #include <stdio.h>
42 #include <float.h>
43 #include <math.h>
45 #define NO_DIGIT_ -1
47 #define MAX_NO_OF_DIGITS DBL_DIG
48 #define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9
49 // +1 for leading sign
50 // +1 for digit before the decimal point
51 // +1 for decimal point
52 // +2 for exponent E and exp. leading sign
53 // +3 for the exponent's value
54 // +1 for closing 0
56 #define CREATE_1000SEP_CHAR '@'
58 #define FORMAT_SEPARATOR ';'
60 // predefined formats for the Format$()-command:
61 #define BASICFORMAT_GENERALNUMBER "General Number"
62 #define BASICFORMAT_CURRENCY "Currency"
63 #define BASICFORMAT_FIXED "Fixed"
64 #define BASICFORMAT_STANDARD "Standard"
65 #define BASICFORMAT_PERCENT "Percent"
66 #define BASICFORMAT_SCIENTIFIC "Scientific"
67 #define BASICFORMAT_YESNO "Yes/No"
68 #define BASICFORMAT_TRUEFALSE "True/False"
69 #define BASICFORMAT_ONOFF "On/Off"
71 // Comment: Visual-Basic has a maximum of 12 positions after the
72 // decimal point for floating-point-numbers.
73 // all format-strings are compatible to Visual-Basic:
74 #define GENERALNUMBER_FORMAT "0.############"
75 #define FIXED_FORMAT "0.00"
76 #define STANDARD_FORMAT "@0.00"
77 #define PERCENT_FORMAT "0.00%"
78 #define SCIENTIFIC_FORMAT "#.00E+00"
79 // Comment: the character @ means that thousand-separators shall
80 // be generated. That's a StarBasic 'extension'.
83 static double get_number_of_digits( double dNumber )
84 //double floor_log10_fabs( double dNumber )
86 if( dNumber==0.0 )
87 return 0.0; // used to be 1.0, now 0.0 because of #40025;
88 else
89 return floor( log10( fabs( dNumber ) ) );
93 SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep,
94 const OUString& _sOnStrg,
95 const OUString& _sOffStrg,
96 const OUString& _sYesStrg,
97 const OUString& _sNoStrg,
98 const OUString& _sTrueStrg,
99 const OUString& _sFalseStrg,
100 const OUString& _sCurrencyStrg,
101 const OUString& _sCurrencyFormatStrg )
102 : cDecPoint(_cDecPoint)
103 , cThousandSep(_cThousandSep)
104 , sOnStrg(_sOnStrg)
105 , sOffStrg(_sOffStrg)
106 , sYesStrg(_sYesStrg)
107 , sNoStrg(_sNoStrg)
108 , sTrueStrg(_sTrueStrg)
109 , sFalseStrg(_sFalseStrg)
110 , sCurrencyStrg(_sCurrencyStrg)
111 , sCurrencyFormatStrg(_sCurrencyFormatStrg)
112 , dNum(0.0)
113 , nNumExp(0)
114 , nExpExp(0)
118 // function to output an error-text (for debugging)
119 // displaces all characters of the string, starting from nStartPos
120 // for one position to larger indexes, i. e. place for a new
121 // character (which is to be inserted) is created.
122 // ATTENTION: the string MUST be long enough!
123 inline void SbxBasicFormater::ShiftString( OUStringBuffer& sStrg, sal_uInt16 nStartPos )
125 sStrg.remove(nStartPos,1);
128 void SbxBasicFormater::AppendDigit( OUStringBuffer& sStrg, short nDigit )
130 if( nDigit>=0 && nDigit<=9 )
132 sStrg.append(static_cast<sal_Unicode>(nDigit+'0'));
136 void SbxBasicFormater::LeftShiftDecimalPoint( OUStringBuffer& sStrg )
138 sal_Int32 nPos = -1;
140 for(sal_Int32 i = 0; i < sStrg.getLength(); i++)
142 if(sStrg[i] == cDecPoint)
144 nPos = i;
145 break;
148 if( nPos >= 0 )
150 sStrg[nPos] = sStrg[nPos - 1];
151 sStrg[nPos - 1] = cDecPoint;
155 // returns a flag if rounding a 9
156 void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos, bool& bOverflow )
158 if( nPos<0 )
160 return;
162 bOverflow = false;
163 sal_Unicode c = sStrg[nPos];
164 if( nPos > 0 && (c == cDecPoint || c == cThousandSep) )
166 StrRoundDigit( sStrg, nPos - 1, bOverflow );
167 // CHANGE from 9.3.1997: end the method immediately after recursive call!
168 return;
170 // skip non-digits:
171 // COMMENT:
172 // in a valid format-string the number's output should be done
173 // in one piece, i. e. special characters should ONLY be in
174 // front OR behind the number and not right in the middle of
175 // the format information for the number
176 while( nPos >= 0 && ! rtl::isAsciiDigit(sStrg[nPos]))
178 nPos--;
180 if( nPos==-1 )
182 ShiftString( sStrg, 0 );
183 sStrg[0] = '1';
184 bOverflow = true;
186 else
188 sal_Unicode c2 = sStrg[nPos];
189 if( rtl::isAsciiDigit(c2) )
191 if( c2 == '9' )
193 sStrg[nPos] = '0';
194 StrRoundDigit( sStrg, nPos - 1, bOverflow );
196 else
198 sStrg[nPos] = c2 + 1;
201 else
203 ShiftString( sStrg,nPos+1 );
204 sStrg[nPos + 1] = '1';
205 bOverflow = true;
210 void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos )
212 bool bOverflow;
214 StrRoundDigit( sStrg, nPos, bOverflow );
217 void SbxBasicFormater::ParseBack( OUStringBuffer& sStrg, const OUString& sFormatStrg,
218 short nFormatPos )
220 for( sal_Int32 i = nFormatPos;
221 i>0 && sFormatStrg[ i ] == '#' && sStrg[sStrg.getLength() - 1] == '0';
222 i-- )
224 sStrg.setLength(sStrg.getLength() - 1 );
228 void SbxBasicFormater::InitScan( double _dNum )
230 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
232 dNum = _dNum;
233 InitExp( get_number_of_digits( dNum ) );
234 // maximum of 15 positions behind the decimal point, example: -1.234000000000000E-001
235 /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum );
236 sSciNumStrg = OUString::createFromAscii( sBuffer );
240 void SbxBasicFormater::InitExp( double _dNewExp )
242 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
243 nNumExp = static_cast<short>(_dNewExp);
244 /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp );
245 sNumExpStrg = OUString::createFromAscii( sBuffer );
246 nExpExp = static_cast<short>(get_number_of_digits( static_cast<double>(nNumExp) ));
250 short SbxBasicFormater::GetDigitAtPosScan( short nPos, bool& bFoundFirstDigit )
252 // trying to read a higher digit,
253 // e. g. position 4 in 1.234,
254 // or to read a digit outside of the
255 // number's dissolution (double)
256 if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS )
258 return NO_DIGIT_;
260 // determine the index of the position in the number-string:
261 // skip the leading sign
262 sal_uInt16 no = 1;
263 // skip the decimal point if necessary
264 if( nPos<nNumExp )
265 no++;
266 no += nNumExp-nPos;
267 // query of the number's first valid digit --> set flag
268 if( nPos==nNumExp )
269 bFoundFirstDigit = true;
270 return static_cast<short>(sSciNumStrg[ no ] - '0');
273 short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, bool& bFoundFirstDigit )
275 if( nPos>nExpExp )
276 return -1;
278 sal_uInt16 no = 1;
279 no += nExpExp-nPos;
281 if( nPos==nExpExp )
282 bFoundFirstDigit = true;
283 return static_cast<short>(sNumExpStrg[ no ] - '0');
286 // a value for the exponent can be given because the number maybe shall
287 // not be displayed in a normed way (e. g. 1.2345e-03) but maybe 123.345e-3 !
288 short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos,
289 bool& bFoundFirstDigit )
291 InitExp( dNewExponent );
293 return GetDigitAtPosExpScan( nPos,bFoundFirstDigit );
296 // Copies the respective part of the format-string, if existing, and returns it.
297 // So a new string is created, which has to be freed by the caller later.
298 OUString SbxBasicFormater::GetPosFormatString( const OUString& sFormatStrg, bool & bFound )
300 bFound = false; // default...
301 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
303 if( nPos >= 0 )
305 bFound = true;
306 // the format-string for positive numbers is
307 // everything before the first ';'
308 return sFormatStrg.copy( 0,nPos );
311 return OUString();
314 // see also GetPosFormatString()
315 OUString SbxBasicFormater::GetNegFormatString( const OUString& sFormatStrg, bool & bFound )
317 bFound = false; // default...
318 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
320 if( nPos >= 0)
322 // the format-string for negative numbers is
323 // everything between the first and the second ';'
324 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
325 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
326 bFound = true;
327 if( nPos < 0 )
329 return sTempStrg;
331 else
333 return sTempStrg.copy( 0,nPos );
336 return OUString();
339 // see also GetPosFormatString()
340 OUString SbxBasicFormater::Get0FormatString( const OUString& sFormatStrg, bool & bFound )
342 bFound = false; // default...
343 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
345 if( nPos >= 0 )
347 // the format string for the zero is
348 // everything after the second ';'
349 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
350 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
351 if( nPos >= 0 )
353 bFound = true;
354 sTempStrg = sTempStrg.copy( nPos+1 );
355 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
356 if( nPos < 0 )
358 return sTempStrg;
360 else
362 return sTempStrg.copy( 0,nPos );
367 return OUString();
370 // see also GetPosFormatString()
371 OUString SbxBasicFormater::GetNullFormatString( const OUString& sFormatStrg, bool & bFound )
373 bFound = false; // default...
374 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
376 if( nPos >= 0 )
378 // the format-string for the Null is
379 // everything after the third ';'
380 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
381 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
382 if( nPos >= 0 )
384 sTempStrg = sTempStrg.copy( nPos+1 );
385 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
386 if( nPos >= 0 )
388 bFound = true;
389 return sTempStrg.copy( nPos+1 );
394 return OUString();
397 // returns value <> 0 in case of an error
398 void SbxBasicFormater::AnalyseFormatString( const OUString& sFormatStrg,
399 short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
400 short& nNoOfOptionalDigitsLeft,
401 short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits,
402 bool& bPercent, bool& bCurrency, bool& bScientific,
403 bool& bGenerateThousandSeparator,
404 short& nMultipleThousandSeparators )
406 sal_Int32 nLen;
407 short nState = 0;
409 nLen = sFormatStrg.getLength();
410 nNoOfDigitsLeft = 0;
411 nNoOfDigitsRight = 0;
412 nNoOfOptionalDigitsLeft = 0;
413 nNoOfExponentDigits = 0;
414 nNoOfOptionalExponentDigits = 0;
415 bPercent = false;
416 bCurrency = false;
417 bScientific = false;
418 // from 11.7.97: as soon as a comma (point?) is found in the format string,
419 // all three decimal powers are marked (i. e. thousand, million, ...)
420 bGenerateThousandSeparator = sFormatStrg.indexOf( ',' ) >= 0;
421 nMultipleThousandSeparators = 0;
423 for( sal_Int32 i = 0; i < nLen; i++ )
425 sal_Unicode c = sFormatStrg[ i ];
426 switch( c )
428 case '#':
429 case '0':
430 if( nState==0 )
432 nNoOfDigitsLeft++;
433 // TODO here maybe better error inspection of the mantissa for valid syntax (see grammar)h
434 // ATTENTION: 'undefined' behaviour if # and 0 are combined!
435 // REMARK: #-placeholders are actually useless for
436 // scientific display before the decimal point!
437 if( c=='#' )
439 nNoOfOptionalDigitsLeft++;
442 else if( nState==1 )
444 nNoOfDigitsRight++;
446 else if( nState==-1 ) // search 0 in the exponent
448 if( c=='#' ) // # switches on the condition
450 nNoOfOptionalExponentDigits++;
451 nState = -2;
453 nNoOfExponentDigits++;
455 else if( nState==-2 ) // search # in the exponent
457 if( c=='0' )
459 // ERROR: 0 after # in the exponent is NOT allowed!!
460 return;
462 nNoOfOptionalExponentDigits++;
463 nNoOfExponentDigits++;
465 break;
466 case '.':
467 nState++;
468 if( nState>1 )
470 return; // ERROR: too many decimal points
472 break;
473 case '%':
474 bPercent = true;
475 break;
476 case '(':
477 bCurrency = true;
478 break;
479 case ',':
481 sal_Unicode ch = sFormatStrg[ i+1 ];
483 if( ch!=0 && (ch==',' || ch=='.') )
485 nMultipleThousandSeparators++;
488 break;
489 case 'e':
490 case 'E':
491 // #i13821 not when no digits before
492 if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 )
494 nState = -1; // abort counting digits
495 bScientific = true;
497 break;
498 // OWN command-character which turns on
499 // the creation of thousand-separators
500 case '\\':
501 // Ignore next char
502 i++;
503 break;
504 case CREATE_1000SEP_CHAR:
505 bGenerateThousandSeparator = true;
506 break;
511 // the flag bCreateSign says that at the mantissa a leading sign
512 // shall be created
513 void SbxBasicFormater::ScanFormatString( double dNumber,
514 const OUString& sFormatStrg, OUString& sReturnStrgFinal,
515 bool bCreateSign )
517 short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft,
518 nNoOfExponentDigits,nNoOfOptionalExponentDigits,
519 nMultipleThousandSeparators;
520 bool bPercent,bCurrency,bScientific,bGenerateThousandSeparator;
522 OUStringBuffer sReturnStrg(32);
524 // analyse the format-string, i. e. determine the following values:
526 - number of digits before decimal point
527 - number of digits after decimal point
528 - optional digits before decimal point
529 - number of digits in the exponent
530 - optional digits in the exponent
531 - percent-character found?
532 - () for negative leading sign?
533 - exponential-notation?
534 - shall thousand-separators be generated?
535 - is a percent-character being found? --> dNumber *= 100.0;
536 - are there thousand-separators in a row?
537 ,, or ,. --> dNumber /= 1000.0;
538 - other errors? multiple decimal points, E's, etc.
539 --> errors are simply ignored at the moment
541 AnalyseFormatString( sFormatStrg, nNoOfDigitsLeft, nNoOfDigitsRight,
542 nNoOfOptionalDigitsLeft, nNoOfExponentDigits,
543 nNoOfOptionalExponentDigits,
544 bPercent, bCurrency, bScientific,
545 bGenerateThousandSeparator, nMultipleThousandSeparators );
546 // special handling for special characters
547 if( bPercent )
549 dNumber *= 100.0;
551 // TODO: this condition (,, or ,.) is NOT Visual-Basic compatible!
552 // Question: shall this stay here (requirements)?
553 if( nMultipleThousandSeparators )
555 dNumber /= 1000.0;
557 double dExponent;
558 short i,nLen;
559 short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit;
560 bool bFirstDigit,bFirstExponentDigit,bFoundFirstDigit,
561 bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative;
563 bSignHappend = false;
564 bFoundFirstDigit = false;
565 bIsNegative = dNumber < 0.0;
566 nLen = sFormatStrg.getLength();
567 dExponent = get_number_of_digits( dNumber );
568 nExponentPos = 0;
569 nMaxExponentDigit = 0;
570 nMaxDigit = static_cast<short>(dExponent);
571 bDigitPosNegative = false;
572 if( bScientific )
574 dExponent = dExponent - static_cast<double>(nNoOfDigitsLeft-1);
575 nDigitPos = nMaxDigit;
576 nMaxExponentDigit = static_cast<short>(get_number_of_digits( dExponent ));
577 nExponentPos = nNoOfExponentDigits - 1 - nNoOfOptionalExponentDigits;
579 else
581 nDigitPos = nNoOfDigitsLeft - 1; // counting starts at 0, 10^0
582 // no exponent-data is needed here!
583 bDigitPosNegative = (nDigitPos < 0);
585 bFirstDigit = true;
586 bFirstExponentDigit = true;
587 nState = 0; // 0 --> mantissa; 1 --> exponent
588 bZeroSpaceOn = false;
591 InitScan( dNumber );
592 // scanning the format-string:
593 sal_Unicode cForce = 0;
594 for( i = 0; i < nLen; i++ )
596 sal_Unicode c;
597 if( cForce )
599 c = cForce;
600 cForce = 0;
602 else
604 c = sFormatStrg[ i ];
606 switch( c )
608 case '0':
609 case '#':
610 if( nState==0 )
612 // handling of the mantissa
613 if( bFirstDigit )
615 // remark: at bCurrency the negative
616 // leading sign shall be shown with ()
617 if( bIsNegative && !bCreateSign && !bSignHappend )
619 bSignHappend = true;
620 sReturnStrg.append('-');
622 // output redundant positions, i. e. those which
623 // are undocumented by the format-string
624 if( nMaxDigit > nDigitPos )
626 for( short j = nMaxDigit; j > nDigitPos; j-- )
628 short nTempDigit = GetDigitAtPosScan( j, bFoundFirstDigit );
629 AppendDigit( sReturnStrg, nTempDigit );
630 if( nTempDigit != NO_DIGIT_ )
632 bFirstDigit = false;
634 // coverity[copy_paste_error : FALSE] - this is correct and nDigitPos should not be j
635 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit >= nDigitPos ) && j > 0 && (j % 3 == 0) )
637 sReturnStrg.append(cThousandSep );
643 if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) )
645 AppendDigit( sReturnStrg, 0 );
646 bFirstDigit = false;
647 bZeroSpaceOn = true;
648 // Remark: in Visual-Basic the first 0 turns on the 0 for
649 // all the following # (up to the decimal point),
650 // this behaviour is simulated here with the flag.
651 if (bGenerateThousandSeparator && c == '0' && nDigitPos > 0 && (nDigitPos % 3 == 0))
653 sReturnStrg.append(cThousandSep);
656 else
658 short nTempDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ) ;
659 AppendDigit( sReturnStrg, nTempDigit );
661 if( nTempDigit != NO_DIGIT_ )
663 bFirstDigit = false;
665 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) )
667 sReturnStrg.append(cThousandSep);
670 nDigitPos--;
672 else
674 // handling the exponent
675 if( bFirstExponentDigit )
677 // leading sign has been given out at e/E already
678 bFirstExponentDigit = false;
679 if( nMaxExponentDigit > nExponentPos )
680 // output redundant positions, i. e. those which
681 // are undocumented by the format-string
683 for( short j = nMaxExponentDigit; j > nExponentPos; j-- )
685 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, j, bFoundFirstDigit ) );
690 if( nMaxExponentDigit < nExponentPos && c=='0' )
692 AppendDigit( sReturnStrg, 0 );
694 else
696 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, nExponentPos, bFoundFirstDigit ) );
698 nExponentPos--;
700 break;
701 case '.':
702 if( bDigitPosNegative ) // #i13821: If no digits before .
704 bDigitPosNegative = false;
705 nDigitPos = 0;
706 cForce = '#';
707 i-=2;
708 break;
710 sReturnStrg.append(cDecPoint);
711 break;
712 case '%':
713 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
714 ParseBack( sReturnStrg, sFormatStrg, i-1 );
715 sReturnStrg.append('%');
716 break;
717 case 'e':
718 case 'E':
719 // does mantissa have to be rounded, before the exponent is displayed?
721 // is there a mantissa at all?
722 if( bFirstDigit )
724 // apparently not, i. e. invalid format string, e. g. E000.00
725 // so ignore these e and E characters
726 // maybe output an error (like in Visual Basic)?
728 // #i13821: VB 6 behaviour
729 sReturnStrg.append(c);
730 break;
733 bool bOverflow = false;
734 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
735 if( nNextDigit>=5 )
737 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1, bOverflow );
739 if( bOverflow )
741 // a leading 9 has been rounded
742 LeftShiftDecimalPoint( sReturnStrg );
743 sReturnStrg[sReturnStrg.getLength() - 1] = 0;
744 dExponent += 1.0;
746 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
747 ParseBack( sReturnStrg, sFormatStrg, i-1 );
749 // change the scanner's condition
750 nState++;
751 // output exponent character
752 sReturnStrg.append(c);
753 // i++; // MANIPULATION of the loop-variable!
754 c = sFormatStrg[ ++i ];
755 // output leading sign / exponent
756 if( c != 0 )
758 if( c == '-' )
760 if( dExponent < 0.0 )
762 sReturnStrg.append('-');
765 else if( c == '+' )
767 if( dExponent < 0.0 )
769 sReturnStrg.append('-');
771 else
773 sReturnStrg.append('+');
777 break;
778 case ',':
779 break;
780 case ';':
781 break;
782 case '(':
783 case ')':
784 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
785 ParseBack( sReturnStrg, sFormatStrg, i-1 );
786 if( bIsNegative )
788 sReturnStrg.append(c);
790 break;
791 case '$':
792 // append the string for the currency:
793 sReturnStrg.append(sCurrencyStrg);
794 break;
795 case ' ':
796 case '-':
797 case '+':
798 ParseBack( sReturnStrg, sFormatStrg, i-1 );
799 sReturnStrg.append(c);
800 break;
801 case '\\':
802 ParseBack( sReturnStrg, sFormatStrg, i-1 );
803 // special character found, output next
804 // character directly (if existing)
805 c = sFormatStrg[ ++i ];
806 if( c!=0 )
808 sReturnStrg.append(c);
810 break;
811 case CREATE_1000SEP_CHAR:
812 // ignore here, action has already been
813 // executed in AnalyseFormatString
814 break;
815 default:
816 // output characters and digits, too (like in Visual-Basic)
817 if( ( c>='a' && c<='z' ) ||
818 ( c>='A' && c<='Z' ) ||
819 ( c>='1' && c<='9' ) )
821 sReturnStrg.append(c);
826 // scan completed - rounding necessary?
827 if( !bScientific )
829 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
830 if( nNextDigit>=5 )
832 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1 );
836 if( nNoOfDigitsRight>0 )
838 ParseBack( sReturnStrg, sFormatStrg, sFormatStrg.getLength()-1 );
840 sReturnStrgFinal = sReturnStrg.makeStringAndClear();
843 OUString SbxBasicFormater::BasicFormatNull( const OUString& sFormatStrg )
845 bool bNullFormatFound;
846 OUString sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound );
848 if( bNullFormatFound )
850 return sNullFormatStrg;
852 return "null";
855 OUString SbxBasicFormater::BasicFormat( double dNumber, const OUString& _sFormatStrg )
857 bool bPosFormatFound,bNegFormatFound,b0FormatFound;
858 OUString sFormatStrg = _sFormatStrg;
860 // analyse format-string concerning predefined formats:
861 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
863 sFormatStrg = GENERALNUMBER_FORMAT;
865 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
867 sFormatStrg = sCurrencyFormatStrg;
869 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
871 sFormatStrg = FIXED_FORMAT;
873 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
875 sFormatStrg = STANDARD_FORMAT;
877 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
879 sFormatStrg = PERCENT_FORMAT;
881 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
883 sFormatStrg = SCIENTIFIC_FORMAT;
885 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
887 return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ;
889 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
891 return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ;
893 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
895 return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ;
898 // analyse format-string concerning ';', i. e. format-strings for
899 // positive-, negative- and 0-values
900 OUString sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound );
901 OUString sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound );
902 OUString s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound );
904 OUString sReturnStrg;
905 OUString sTempStrg;
907 if( dNumber==0.0 )
909 sTempStrg = sFormatStrg;
910 if( b0FormatFound )
912 if( s0FormatStrg.isEmpty() && bPosFormatFound )
914 sTempStrg = sPosFormatStrg;
916 else
918 sTempStrg = s0FormatStrg;
921 else if( bPosFormatFound )
923 sTempStrg = sPosFormatStrg;
925 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/false );
927 else
929 if( dNumber<0.0 )
931 if( bNegFormatFound )
933 if( sNegFormatStrg.isEmpty() && bPosFormatFound )
935 sTempStrg = "-" + sPosFormatStrg;
937 else
939 sTempStrg = sNegFormatStrg;
942 else
944 sTempStrg = sFormatStrg;
946 // if NO format-string especially for negative
947 // values is given, output the leading sign
948 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ );
950 else // if( dNumber>0.0 )
952 ScanFormatString( dNumber,
953 (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg),
954 sReturnStrg,/*bCreateSign=*/false );
957 return sReturnStrg;
960 bool SbxBasicFormater::isBasicFormat( const OUString& sFormatStrg )
962 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
964 return true;
966 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
968 return true;
970 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
972 return true;
974 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
976 return true;
978 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
980 return true;
982 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
984 return true;
986 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
988 return true;
990 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
992 return true;
994 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
996 return true;
998 return false;
1001 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */