bump product version to 5.0.4.1
[LibreOffice.git] / basic / source / sbx / sbxform.cxx
blob26e9aa58dddeb48b9cfbb41c4fcb67e5ea3082ff
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>
27 TODO: are there any Star-Basic characteristics unconsidered?
29 what means: * as placeholder
31 COMMENT: Visual-Basic treats the following (invalid) format-strings
32 as shown:
34 ##0##.##0## --> ##000.000##
36 (this class behaves the same way)
39 #include <stdio.h>
40 #include <float.h>
41 #include <math.h>
43 #define _NO_DIGIT -1
45 #define MAX_NO_OF_DIGITS DBL_DIG
46 #define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9
47 // +1 for leading sign
48 // +1 for digit before the decimal point
49 // +1 for decimal point
50 // +2 for exponent E and exp. leading sign
51 // +3 for the exponent's value
52 // +1 for closing 0
54 // Defines for the digits:
55 #define ASCII_0 '0' // 48
56 #define ASCII_9 '9' // 57
58 #define CREATE_1000SEP_CHAR '@'
60 #define FORMAT_SEPARATOR ';'
62 // predefined formats for the Format$()-command:
63 #define BASICFORMAT_GENERALNUMBER "General Number"
64 #define BASICFORMAT_CURRENCY "Currency"
65 #define BASICFORMAT_FIXED "Fixed"
66 #define BASICFORMAT_STANDARD "Standard"
67 #define BASICFORMAT_PERCENT "Percent"
68 #define BASICFORMAT_SCIENTIFIC "Scientific"
69 #define BASICFORMAT_YESNO "Yes/No"
70 #define BASICFORMAT_TRUEFALSE "True/False"
71 #define BASICFORMAT_ONOFF "On/Off"
73 // Comment: Visual-Basic has a maximum of 12 positions after the
74 // decimal point for floating-point-numbers.
75 // all format-strings are compatible to Visual-Basic:
76 #define GENERALNUMBER_FORMAT "0.############"
77 #define FIXED_FORMAT "0.00"
78 #define STANDARD_FORMAT "@0.00"
79 #define PERCENT_FORMAT "0.00%"
80 #define SCIENTIFIC_FORMAT "#.00E+00"
81 // Comment: the character @ means that thousand-separators shall
82 // be generated. That's a StarBasic 'extension'.
87 double get_number_of_digits( double dNumber )
88 //double floor_log10_fabs( double dNumber )
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 ) ) );
97 SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep,
98 const OUString& _sOnStrg,
99 const OUString& _sOffStrg,
100 const OUString& _sYesStrg,
101 const OUString& _sNoStrg,
102 const OUString& _sTrueStrg,
103 const OUString& _sFalseStrg,
104 const OUString& _sCurrencyStrg,
105 const OUString& _sCurrencyFormatStrg )
106 : cDecPoint(_cDecPoint)
107 , cThousandSep(_cThousandSep)
108 , sOnStrg(_sOnStrg)
109 , sOffStrg(_sOffStrg)
110 , sYesStrg(_sYesStrg)
111 , sNoStrg(_sNoStrg)
112 , sTrueStrg(_sTrueStrg)
113 , sFalseStrg(_sFalseStrg)
114 , sCurrencyStrg(_sCurrencyStrg)
115 , sCurrencyFormatStrg(_sCurrencyFormatStrg)
116 , dNum(0.0)
117 , nNumExp(0)
118 , nExpExp(0)
122 // function for ouput of a 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!
127 inline void SbxBasicFormater::ShiftString( OUStringBuffer& sStrg, sal_uInt16 nStartPos )
129 sStrg.remove(nStartPos,1);
132 void SbxBasicFormater::AppendDigit( OUStringBuffer& sStrg, short nDigit )
134 if( nDigit>=0 && nDigit<=9 )
136 sStrg.append((sal_Unicode)(nDigit+ASCII_0));
140 void SbxBasicFormater::LeftShiftDecimalPoint( OUStringBuffer& sStrg )
142 sal_Int32 nPos = -1;
144 for(sal_Int32 i = 0; i < sStrg.getLength(); i++)
146 if(sStrg[i] == cDecPoint)
148 nPos = i;
149 break;
152 if( nPos >= 0 )
154 sStrg[nPos] = sStrg[nPos - 1];
155 sStrg[nPos - 1] = cDecPoint;
159 // returns a flag if rounding a 9
160 void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos, bool& bOverflow )
162 if( nPos<0 )
164 return;
166 bOverflow = false;
167 sal_Unicode c = sStrg[nPos];
168 if( nPos > 0 && (c == cDecPoint || c == cThousandSep) )
170 StrRoundDigit( sStrg, nPos - 1, bOverflow );
171 // CHANGE from 9.3.1997: end the method immediately after recursive call!
172 return;
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 && ( sStrg[nPos] < ASCII_0 || sStrg[nPos] > ASCII_9 ))
182 nPos--;
184 if( nPos==-1 )
186 ShiftString( sStrg, 0 );
187 sStrg[0] = (sal_Unicode)'1';
188 bOverflow = true;
190 else
192 sal_Unicode c2 = sStrg[nPos];
193 if( c2 >= ASCII_0 && c2 <= ASCII_9 )
195 if( c2 == ASCII_9 )
197 sStrg[nPos] = (sal_Unicode)'0';
198 StrRoundDigit( sStrg, nPos - 1, bOverflow );
200 else
202 sStrg[nPos] = c2 + 1;
205 else
207 ShiftString( sStrg,nPos+1 );
208 sStrg[nPos + 1] = (sal_Unicode)'1';
209 bOverflow = true;
214 void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos )
216 bool bOverflow;
218 StrRoundDigit( sStrg, nPos, bOverflow );
221 void SbxBasicFormater::ParseBack( OUStringBuffer& sStrg, const OUString& sFormatStrg,
222 short nFormatPos )
224 for( sal_Int32 i = nFormatPos;
225 i>0 && sFormatStrg[ i ] == (sal_Unicode)'#' && sStrg[sStrg.getLength() - 1] == (sal_Unicode)'0';
226 i-- )
228 sStrg.setLength(sStrg.getLength() - 1 );
232 #ifdef _with_sprintf
235 void SbxBasicFormater::InitScan( double _dNum )
237 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
239 dNum = _dNum;
240 InitExp( get_number_of_digits( dNum ) );
241 // maximum of 15 positions behind the decimal point, example: -1.234000000000000E-001
242 /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum );
243 sSciNumStrg = OUString::createFromAscii( sBuffer );
247 void SbxBasicFormater::InitExp( double _dNewExp )
249 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
250 nNumExp = (short)_dNewExp;
251 /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp );
252 sNumExpStrg = OUString::createFromAscii( sBuffer );
253 nExpExp = (short)get_number_of_digits( (double)nNumExp );
257 short SbxBasicFormater::GetDigitAtPosScan( short nPos, bool& bFoundFirstDigit )
259 // trying to read a higher digit,
260 // e. g. position 4 in 1.234,
261 // or to read a digit outside of the
262 // number's dissolution (double)
263 if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS )
265 return _NO_DIGIT;
267 // determine the index of the position in the number-string:
268 // skip the leading sign
269 sal_uInt16 no = 1;
270 // skip the decimal point if necessary
271 if( nPos<nNumExp )
272 no++;
273 no += nNumExp-nPos;
274 // query of the number's first valid digit --> set flag
275 if( nPos==nNumExp )
276 bFoundFirstDigit = true;
277 return (short)(sSciNumStrg[ no ] - ASCII_0);
280 short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, bool& bFoundFirstDigit )
282 if( nPos>nExpExp )
283 return -1;
285 sal_uInt16 no = 1;
286 no += nExpExp-nPos;
288 if( nPos==nExpExp )
289 bFoundFirstDigit = true;
290 return (short)(sNumExpStrg[ no ] - ASCII_0);
293 // a value for the exponent can be given because the number maybe shall
294 // not be displayed in a normed way (e. g. 1.2345e-03) but maybe 123.345e-3 !
295 short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos,
296 bool& bFoundFirstDigit )
298 InitExp( dNewExponent );
300 return GetDigitAtPosExpScan( nPos,bFoundFirstDigit );
303 #else
305 /* Problems with the following method:
307 TODO: an 'intelligent' peek-parser might be needed to detect rounding
308 mistakes at double-numbers - e. g. for 0.00115 #.#e-000
310 problem with: format( 0.3345 , "0.000" )
311 problem with: format( 0.00115 , "0.0000" )
314 // returns the digit at the given '10 system'-position,
315 // i. e. positive nPos for positions before the decimal
316 // point and negative for positions after.
317 // nPos==0 means first position after the decimalpoint, so 10^0.
318 // returns 0..9 for valid digits and -1 for not existing,
319 // i. e. if the passed number is too small
320 // (e. g. position 5 of dNumber=123).
321 // Furthermore in dNextNumber the number shorted by leading
322 // positions (till nPos) is returned, e. g.
323 // GetDigitAtPos( 3434.565 , 2 , dNewNumber ) --> dNewNumber = 434.565
324 // In bFoundFirstDigit a flag is set if a digit has been found,
325 // this is used to prevent 'errors' on parsing 202
326 // ATTENTION: apparently there are sometimes still problems with rounding mistakes!
327 short SbxBasicFormater::GetDigitAtPos( double dNumber, short nPos,
328 double& dNextNumber, bool& bFoundFirstDigit )
330 double dDigit;
331 short nMaxDigit;
333 dNumber = fabs( dNumber );
335 nMaxDigit = (short)get_number_of_digits( dNumber );
336 // error only at numbers > 0, i. e. for digits before
337 // the decimal point
338 if( nMaxDigit<nPos && !bFoundFirstDigit && nPos>=0 )
339 return _NO_DIGIT;
341 bFoundFirstDigit = true;
342 for( short i=nMaxDigit; i>=nPos; i-- )
344 double dI = (double)i;
345 double dTemp1 = pow( 10.0,dI );
347 dDigit = floor( pow( 10.0,log10( fabs( dNumber ) )-dI ) );
348 dNumber -= dTemp1 * dDigit;
350 // for optimized loop run
351 dNextNumber = dNumber;
353 return RoundDigit( dDigit );
357 short SbxBasicFormater::RoundDigit( double dNumber )
359 if( dNumber<0.0 || dNumber>10.0 )
360 return -1;
361 short nTempHigh = (short)(dNumber+0.5); // maybe floor( )
362 return nTempHigh;
365 #endif
367 // Copies the respective part of the format-string, if existing, and returns it.
368 // So a new string is created, which has to be freed by the caller later.
369 OUString SbxBasicFormater::GetPosFormatString( const OUString& sFormatStrg, bool & bFound )
371 bFound = false; // default...
372 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
374 if( nPos >= 0 )
376 bFound = true;
377 // the format-string for positive numbers is
378 // everything before the first ';'
379 return sFormatStrg.copy( 0,nPos );
382 return OUString();
385 // see also GetPosFormatString()
386 OUString SbxBasicFormater::GetNegFormatString( const OUString& sFormatStrg, bool & bFound )
388 bFound = false; // default...
389 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
391 if( nPos >= 0)
393 // the format-string for negative numbers is
394 // everything between the first and the second ';'
395 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
396 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
397 bFound = true;
398 if( nPos < 0 )
400 return sTempStrg;
402 else
404 return sTempStrg.copy( 0,nPos );
407 return OUString();
410 // see also GetPosFormatString()
411 OUString SbxBasicFormater::Get0FormatString( const OUString& sFormatStrg, bool & bFound )
413 bFound = false; // default...
414 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
416 if( nPos >= 0 )
418 // the format string for the zero is
419 // everything after the second ';'
420 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
421 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
422 if( nPos >= 0 )
424 bFound = true;
425 sTempStrg = sTempStrg.copy( nPos+1 );
426 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
427 if( nPos < 0 )
429 return sTempStrg;
431 else
433 return sTempStrg.copy( 0,nPos );
438 return OUString();
441 // see also GetPosFormatString()
442 OUString SbxBasicFormater::GetNullFormatString( const OUString& sFormatStrg, bool & bFound )
444 bFound = false; // default...
445 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
447 if( nPos >= 0 )
449 // the format-string for the Null is
450 // everything after the third ';'
451 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
452 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
453 if( nPos >= 0 )
455 sTempStrg = sTempStrg.copy( nPos+1 );
456 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
457 if( nPos >= 0 )
459 bFound = true;
460 return sTempStrg.copy( nPos+1 );
465 return OUString();
468 // returns value <> 0 in case of an error
469 short SbxBasicFormater::AnalyseFormatString( const OUString& sFormatStrg,
470 short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
471 short& nNoOfOptionalDigitsLeft,
472 short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits,
473 bool& bPercent, bool& bCurrency, bool& bScientific,
474 bool& bGenerateThousandSeparator,
475 short& nMultipleThousandSeparators )
477 sal_Int32 nLen;
478 short nState = 0;
480 nLen = sFormatStrg.getLength();
481 nNoOfDigitsLeft = 0;
482 nNoOfDigitsRight = 0;
483 nNoOfOptionalDigitsLeft = 0;
484 nNoOfExponentDigits = 0;
485 nNoOfOptionalExponentDigits = 0;
486 bPercent = false;
487 bCurrency = false;
488 bScientific = false;
489 // from 11.7.97: as soon as a comma (point?) is found in the format string,
490 // all three decimal powers are marked (i. e. thousand, million, ...)
491 bGenerateThousandSeparator = sFormatStrg.indexOf( ',' ) >= 0;
492 nMultipleThousandSeparators = 0;
494 for( sal_Int32 i = 0; i < nLen; i++ )
496 sal_Unicode c = sFormatStrg[ i ];
497 switch( c )
499 case '#':
500 case '0':
501 if( nState==0 )
503 nNoOfDigitsLeft++;
504 // TODO here maybe better error inspection of the mantissa for valid syntax (see grammar)h
505 // ATTENTION: 'undefined' behaviour if # and 0 are combined!
506 // REMARK: #-placeholders are actually useless for
507 // scientific display before the decimal point!
508 if( c=='#' )
510 nNoOfOptionalDigitsLeft++;
513 else if( nState==1 )
515 nNoOfDigitsRight++;
517 else if( nState==-1 ) // search 0 in the exponent
519 if( c=='#' ) // # switches on the condition
521 nNoOfOptionalExponentDigits++;
522 nState = -2;
524 nNoOfExponentDigits++;
526 else if( nState==-2 ) // search # in the exponent
528 if( c=='0' )
530 // ERROR: 0 after # in the exponent is NOT allowed!!
531 return -4;
533 nNoOfOptionalExponentDigits++;
534 nNoOfExponentDigits++;
536 break;
537 case '.':
538 nState++;
539 if( nState>1 )
541 return -1; // ERROR: too many decimal points
543 break;
544 case '%':
545 bPercent = true;
546 break;
547 case '(':
548 bCurrency = true;
549 break;
550 case ',':
552 sal_Unicode ch = sFormatStrg[ i+1 ];
554 if( ch!=0 && (ch==',' || ch=='.') )
556 nMultipleThousandSeparators++;
559 break;
560 case 'e':
561 case 'E':
562 // #i13821 not when no digits before
563 if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 )
565 nState = -1; // abort counting digits
566 bScientific = true;
568 break;
569 // OWN command-character which turns on
570 // the creation of thousand-separators
571 case '\\':
572 // Ignore next char
573 i++;
574 break;
575 case CREATE_1000SEP_CHAR:
576 bGenerateThousandSeparator = true;
577 break;
580 return 0;
583 // the flag bCreateSign says that at the mantissa a leading sign
584 // shall be created
585 void SbxBasicFormater::ScanFormatString( double dNumber,
586 const OUString& sFormatStrg, OUString& sReturnStrgFinal,
587 bool bCreateSign )
589 short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft,
590 nNoOfExponentDigits,nNoOfOptionalExponentDigits,
591 nMultipleThousandSeparators;
592 bool bPercent,bCurrency,bScientific,bGenerateThousandSeparator;
594 OUStringBuffer sReturnStrg = OUStringBuffer();
596 // analyse the format-string, i. e. determine the following values:
598 - number of digits before decimal point
599 - number of digits after decimal point
600 - optional digits before decimal point
601 - number of digits in the exponent
602 - optional digits in the exponent
603 - percent-character found?
604 - () for negative leading sign?
605 - exponetial-notation?
606 - shall thousand-separators be generated?
607 - is a percent-character being found? --> dNumber *= 100.0;
608 - are there thousand-separators in a row?
609 ,, or ,. --> dNumber /= 1000.0;
610 - other errors? multiple decimal points, E's, etc.
611 --> errors are simply ignored at the moment
613 AnalyseFormatString( sFormatStrg, nNoOfDigitsLeft, nNoOfDigitsRight,
614 nNoOfOptionalDigitsLeft, nNoOfExponentDigits,
615 nNoOfOptionalExponentDigits,
616 bPercent, bCurrency, bScientific,
617 bGenerateThousandSeparator, nMultipleThousandSeparators );
618 // special handling for special characters
619 if( bPercent )
621 dNumber *= 100.0;
623 // TODO: this condition (,, or ,.) is NOT Visual-Basic compatible!
624 // Question: shall this stay here (requirements)?
625 if( nMultipleThousandSeparators )
627 dNumber /= 1000.0;
629 double dExponent;
630 short i,nLen;
631 short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit;
632 bool bFirstDigit,bFirstExponentDigit,bFoundFirstDigit,
633 bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative;
635 bSignHappend = false;
636 bFoundFirstDigit = false;
637 bIsNegative = dNumber < 0.0;
638 nLen = sFormatStrg.getLength();
639 dExponent = get_number_of_digits( dNumber );
640 nExponentPos = 0;
641 nMaxExponentDigit = 0;
642 nMaxDigit = (short)dExponent;
643 bDigitPosNegative = false;
644 if( bScientific )
646 dExponent = dExponent - (double)(nNoOfDigitsLeft-1);
647 nDigitPos = nMaxDigit;
648 nMaxExponentDigit = (short)get_number_of_digits( dExponent );
649 nExponentPos = nNoOfExponentDigits - 1 - nNoOfOptionalExponentDigits;
651 else
653 nDigitPos = nNoOfDigitsLeft - 1; // counting starts at 0, 10^0
654 // no exponent-data is needed here!
655 bDigitPosNegative = (nDigitPos < 0);
657 bFirstDigit = true;
658 bFirstExponentDigit = true;
659 nState = 0; // 0 --> mantissa; 1 --> exponent
660 bZeroSpaceOn = false;
663 #ifdef _with_sprintf
664 InitScan( dNumber );
665 #endif
666 // scanning the format-string:
667 sal_Unicode cForce = 0;
668 for( i = 0; i < nLen; i++ )
670 sal_Unicode c;
671 if( cForce )
673 c = cForce;
674 cForce = 0;
676 else
678 c = sFormatStrg[ i ];
680 switch( c )
682 case '0':
683 case '#':
684 if( nState==0 )
686 // handling of the mantissa
687 if( bFirstDigit )
689 // remark: at bCurrency the negative
690 // leading sign shall be shown with ()
691 if( bIsNegative && !bCreateSign && !bSignHappend )
693 bSignHappend = true;
694 sReturnStrg.append('-');
696 // output redundant positions, i. e. those which
697 // are undocumented by the format-string
698 if( nMaxDigit > nDigitPos )
700 for( short j = nMaxDigit; j > nDigitPos; j-- )
702 short nTempDigit;
703 #ifdef _with_sprintf
704 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPosScan( j, bFoundFirstDigit ) );
705 #else
706 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPos( dNumber, j, dNumber, bFoundFirstDigit ) );
707 #endif
708 if( nTempDigit!=_NO_DIGIT )
710 bFirstDigit = false;
712 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit >= nDigitPos ) && j > 0 && (j % 3 == 0) )
714 sReturnStrg.append(cThousandSep );
720 if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) )
722 AppendDigit( sReturnStrg, 0 );
723 bFirstDigit = false;
724 bZeroSpaceOn = true;
725 // Remark: in Visual-Basic the first 0 turns on the 0 for
726 // all the following # (up to the decimal point),
727 // this behaviour is simulated here with the flag.
728 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit >= nDigitPos ) && nDigitPos > 0 && (nDigitPos % 3 == 0) )
730 sReturnStrg.append(cThousandSep);
733 else
735 short nTempDigit;
736 #ifdef _with_sprintf
737 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ) );
738 #else
739 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPos( dNumber, nDigitPos, dNumber, bFoundFirstDigit ) );
740 #endif
742 if( nTempDigit != _NO_DIGIT )
744 bFirstDigit = false;
746 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) )
748 sReturnStrg.append(cThousandSep);
751 nDigitPos--;
753 else
755 // handling the exponent
756 if( bFirstExponentDigit )
758 // leading sign has been given out at e/E already
759 bFirstExponentDigit = false;
760 if( nMaxExponentDigit > nExponentPos )
761 // output redundant positions, i. e. those which
762 // are undocumented by the format-string
764 for( short j = nMaxExponentDigit; j > nExponentPos; j-- )
766 #ifdef _with_sprintf
767 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, j, bFoundFirstDigit ) );
768 #else
769 AppendDigit( sReturnStrg,GetDigitAtPos( dExponent, j, dExponent, bFoundFirstDigit ) );
770 #endif
775 if( nMaxExponentDigit < nExponentPos && c=='0' )
777 AppendDigit( sReturnStrg, 0 );
779 else
781 #ifdef _with_sprintf
782 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, nExponentPos, bFoundFirstDigit ) );
783 #else
784 AppendDigit( sReturnStrg, GetDigitAtPos( dExponent, nExponentPos, dExponent, bFoundFirstDigit ) );
785 #endif
787 nExponentPos--;
789 break;
790 case '.':
791 if( bDigitPosNegative ) // #i13821: If no digits before .
793 bDigitPosNegative = false;
794 nDigitPos = 0;
795 cForce = '#';
796 i-=2;
797 break;
799 sReturnStrg.append(cDecPoint);
800 break;
801 case '%':
802 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
803 ParseBack( sReturnStrg, sFormatStrg, i-1 );
804 sReturnStrg.append('%');
805 break;
806 case 'e':
807 case 'E':
808 // does mantissa have to be rounded, before the exponent is displayed?
810 // is there a mantissa at all?
811 if( bFirstDigit )
813 // apparently not, i. e. invalid format string, e. g. E000.00
814 // so ignore these e and E characters
815 // maybe output an error (like in Visual Basic)?
817 // #i13821: VB 6 behaviour
818 sReturnStrg.append(c);
819 break;
822 bool bOverflow = false;
823 #ifdef _with_sprintf
824 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
825 #else
826 short nNextDigit = GetDigitAtPos( dNumber, nDigitPos, dNumber, bFoundFirstDigit );
827 #endif
828 if( nNextDigit>=5 )
830 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1, bOverflow );
832 if( bOverflow )
834 // a leading 9 has been rounded
835 LeftShiftDecimalPoint( sReturnStrg );
836 sReturnStrg[sReturnStrg.getLength() - 1] = 0;
837 dExponent += 1.0;
839 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
840 ParseBack( sReturnStrg, sFormatStrg, i-1 );
842 // change the scanner's condition
843 nState++;
844 // output exponent character
845 sReturnStrg.append(c);
846 // i++; // MANIPULATION of the loop-variable!
847 c = sFormatStrg[ ++i ];
848 // output leading sign / exponent
849 if( c != 0 )
851 if( c == '-' )
853 if( dExponent < 0.0 )
855 sReturnStrg.append('-');
858 else if( c == '+' )
860 if( dExponent < 0.0 )
862 sReturnStrg.append('-');
864 else
866 sReturnStrg.append('+');
870 break;
871 case ',':
872 break;
873 case ';':
874 break;
875 case '(':
876 case ')':
877 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
878 ParseBack( sReturnStrg, sFormatStrg, i-1 );
879 if( bIsNegative )
881 sReturnStrg.append(c);
883 break;
884 case '$':
885 // append the string for the currency:
886 sReturnStrg.append(sCurrencyStrg);
887 break;
888 case ' ':
889 case '-':
890 case '+':
891 ParseBack( sReturnStrg, sFormatStrg, i-1 );
892 sReturnStrg.append(c);
893 break;
894 case '\\':
895 ParseBack( sReturnStrg, sFormatStrg, i-1 );
896 // special character found, output next
897 // character directly (if existing)
898 c = sFormatStrg[ ++i ];
899 if( c!=0 )
901 sReturnStrg.append(c);
903 break;
904 case CREATE_1000SEP_CHAR:
905 // ignore here, action has already been
906 // executed in AnalyseFormatString
907 break;
908 default:
909 // output characters and digits, too (like in Visual-Basic)
910 if( ( c>='a' && c<='z' ) ||
911 ( c>='A' && c<='Z' ) ||
912 ( c>='1' && c<='9' ) )
914 sReturnStrg.append(c);
919 // scan completed - rounding necessary?
920 if( !bScientific )
922 #ifdef _with_sprintf
923 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
924 #else
925 short nNextDigit = GetDigitAtPos( dNumber, nDigitPos, dNumber, bFoundFirstDigit );
926 #endif
927 if( nNextDigit>=5 )
929 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1 );
933 if( nNoOfDigitsRight>0 )
935 ParseBack( sReturnStrg, sFormatStrg, sFormatStrg.getLength()-1 );
937 sReturnStrgFinal = sReturnStrg.makeStringAndClear();
940 OUString SbxBasicFormater::BasicFormatNull( const OUString& sFormatStrg )
942 bool bNullFormatFound;
943 OUString sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound );
945 if( bNullFormatFound )
947 return sNullFormatStrg;
949 return OUString("null");
952 OUString SbxBasicFormater::BasicFormat( double dNumber, const OUString& _sFormatStrg )
954 bool bPosFormatFound,bNegFormatFound,b0FormatFound;
955 OUString sFormatStrg = _sFormatStrg;
957 // analyse format-string concerning predefined formats:
958 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
960 sFormatStrg = GENERALNUMBER_FORMAT;
962 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
964 sFormatStrg = sCurrencyFormatStrg;
966 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
968 sFormatStrg = FIXED_FORMAT;
970 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
972 sFormatStrg = STANDARD_FORMAT;
974 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
976 sFormatStrg = PERCENT_FORMAT;
978 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
980 sFormatStrg = SCIENTIFIC_FORMAT;
982 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
984 return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ;
986 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
988 return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ;
990 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
992 return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ;
995 // analyse format-string concerning ';', i. e. format-strings for
996 // positive-, negative- and 0-values
997 OUString sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound );
998 OUString sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound );
999 OUString s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound );
1001 OUString sReturnStrg;
1002 OUString sTempStrg;
1004 if( dNumber==0.0 )
1006 sTempStrg = sFormatStrg;
1007 if( b0FormatFound )
1009 if( s0FormatStrg.isEmpty() && bPosFormatFound )
1011 sTempStrg = sPosFormatStrg;
1013 else
1015 sTempStrg = s0FormatStrg;
1018 else if( bPosFormatFound )
1020 sTempStrg = sPosFormatStrg;
1022 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/false );
1024 else
1026 if( dNumber<0.0 )
1028 if( bNegFormatFound )
1030 if( sNegFormatStrg.isEmpty() && bPosFormatFound )
1032 sTempStrg = "-";
1033 sTempStrg += sPosFormatStrg;
1035 else
1037 sTempStrg = sNegFormatStrg;
1040 else
1042 sTempStrg = sFormatStrg;
1044 // if NO format-string especially for negative
1045 // values is given, output the leading sign
1046 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ );
1048 else // if( dNumber>0.0 )
1050 ScanFormatString( dNumber,
1051 (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg),
1052 sReturnStrg,/*bCreateSign=*/false );
1055 return sReturnStrg;
1058 bool SbxBasicFormater::isBasicFormat( const OUString& sFormatStrg )
1060 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
1062 return true;
1064 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
1066 return true;
1068 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
1070 return true;
1072 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
1074 return true;
1076 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
1078 return true;
1080 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
1082 return true;
1084 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
1086 return true;
1088 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
1090 return true;
1092 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
1094 return true;
1096 return false;
1099 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */