fdo#74697 Add Bluez 5 support for impress remote.
[LibreOffice.git] / basic / source / sbx / sbxform.cxx
blob3a3d5bfe73db4a43beb00152f0dd993655c7b995
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> // for: sprintf()
40 #include <float.h> // for: DBL_DIG, DBL_EPSILON
41 #include <math.h> // for: floor(), fabs(), log10(), pow()
43 //=================================================================
44 //=========================== DEFINES =============================
45 //=================================================================
47 #define _NO_DIGIT -1
49 #define MAX_NO_OF_DIGITS DBL_DIG
50 #define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9
51 // +1 for leading sign
52 // +1 for digit before the decimal point
53 // +1 for decimal point
54 // +2 for exponent E and exp. leading sign
55 // +3 for the exponent's value
56 // +1 for closing 0
58 // Defines for the digits:
59 #define ASCII_0 '0' // 48
60 #define ASCII_9 '9' // 57
62 #define CREATE_1000SEP_CHAR '@'
64 #define FORMAT_SEPARATOR ';'
66 // predefined formats for the Format$()-command:
67 #define BASICFORMAT_GENERALNUMBER "General Number"
68 #define BASICFORMAT_CURRENCY "Currency"
69 #define BASICFORMAT_FIXED "Fixed"
70 #define BASICFORMAT_STANDARD "Standard"
71 #define BASICFORMAT_PERCENT "Percent"
72 #define BASICFORMAT_SCIENTIFIC "Scientific"
73 #define BASICFORMAT_YESNO "Yes/No"
74 #define BASICFORMAT_TRUEFALSE "True/False"
75 #define BASICFORMAT_ONOFF "On/Off"
77 #define EMPTYFORMATSTRING ""
79 // Comment: Visual-Basic has a maximum of 12 positions after the
80 // decimal point for floating-point-numbers.
81 // all format-strings are compatible to Visual-Basic:
82 #define GENERALNUMBER_FORMAT "0.############"
83 #define FIXED_FORMAT "0.00"
84 #define STANDARD_FORMAT "@0.00"
85 #define PERCENT_FORMAT "0.00%"
86 #define SCIENTIFIC_FORMAT "#.00E+00"
87 // Comment: the character @ means that thousand-separators shall
88 // be generated. That's a StarBasic 'extension'.
90 //=================================================================
93 double get_number_of_digits( double dNumber )
94 //double floor_log10_fabs( double dNumber )
96 if( dNumber==0.0 )
97 return 0.0; // used to be 1.0, now 0.0 because of #40025;
98 else
99 return floor( log10( fabs( dNumber ) ) );
102 //=================================================================
103 //======================= IMPLEMENTATION ==========================
104 //=================================================================
106 SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep,
107 OUString _sOnStrg,
108 OUString _sOffStrg,
109 OUString _sYesStrg,
110 OUString _sNoStrg,
111 OUString _sTrueStrg,
112 OUString _sFalseStrg,
113 OUString _sCurrencyStrg,
114 OUString _sCurrencyFormatStrg )
116 cDecPoint = _cDecPoint;
117 cThousandSep = _cThousandSep;
118 sOnStrg = _sOnStrg;
119 sOffStrg = _sOffStrg;
120 sYesStrg = _sYesStrg;
121 sNoStrg = _sNoStrg;
122 sTrueStrg = _sTrueStrg;
123 sFalseStrg = _sFalseStrg;
124 sCurrencyStrg = _sCurrencyStrg;
125 sCurrencyFormatStrg = _sCurrencyFormatStrg;
128 // function for ouput of a error-text (for debugging)
129 // displaces all characters of the string, starting from nStartPos
130 // for one position to larger indexes, i. e. place for a new
131 // character (which is to be inserted) is created.
132 // ATTENTION: the string MUST be long enough!
133 inline void SbxBasicFormater::ShiftString( OUStringBuffer& sStrg, sal_uInt16 nStartPos )
135 sStrg.remove(nStartPos,1);
138 void SbxBasicFormater::AppendDigit( OUStringBuffer& sStrg, short nDigit )
140 if( nDigit>=0 && nDigit<=9 )
142 sStrg.append((sal_Unicode)(nDigit+ASCII_0));
146 void SbxBasicFormater::LeftShiftDecimalPoint( OUStringBuffer& sStrg )
148 sal_Int32 nPos = -1;
150 for(sal_Int32 i = 0; i < sStrg.getLength(); i++)
152 if(sStrg[i] == cDecPoint)
154 nPos = i;
155 break;
158 if( nPos >= 0 )
160 sStrg[nPos] = sStrg[nPos - 1];
161 sStrg[nPos - 1] = cDecPoint;
165 // returns a flag if rounding a 9
166 void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos, sal_Bool& bOverflow )
168 if( nPos<0 )
170 return;
172 bOverflow = sal_False;
173 sal_Unicode c = sStrg[nPos];
174 if( nPos > 0 && (c == cDecPoint || c == cThousandSep) )
176 StrRoundDigit( sStrg, nPos - 1, bOverflow );
177 // CHANGE from 9.3.1997: end the method immediately after recursive call!
178 return;
180 // skip non-digits:
181 // COMMENT:
182 // in a valid format-string the number's output should be done
183 // in one piece, i. e. special characters should ONLY be in
184 // front OR behind the number and not right in the middle of
185 // the format information for the number
186 while( nPos >= 0 && ( sStrg[nPos] < ASCII_0 || sStrg[nPos] > ASCII_9 ))
188 nPos--;
190 if( nPos==-1 )
192 ShiftString( sStrg, 0 );
193 sStrg[0] = (sal_Unicode)'1';
194 bOverflow = sal_True;
196 else
198 sal_Unicode c2 = sStrg[nPos];
199 if( c2 >= ASCII_0 && c2 <= ASCII_9 )
201 if( c2 == ASCII_9 )
203 sStrg[nPos] = (sal_Unicode)'0';
204 StrRoundDigit( sStrg, nPos - 1, bOverflow );
206 else
208 sStrg[nPos] = c2 + 1;
211 else
213 ShiftString( sStrg,nPos+1 );
214 sStrg[nPos + 1] = (sal_Unicode)'1';
215 bOverflow = sal_True;
220 void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos )
222 sal_Bool bOverflow;
224 StrRoundDigit( sStrg, nPos, bOverflow );
227 void SbxBasicFormater::ParseBack( OUStringBuffer& sStrg, const OUString& sFormatStrg,
228 short nFormatPos )
230 for( sal_Int32 i = nFormatPos;
231 i>0 && sFormatStrg[ i ] == (sal_Unicode)'#' && sStrg[sStrg.getLength() - 1] == (sal_Unicode)'0';
232 i-- )
234 sStrg.setLength(sStrg.getLength() - 1 );
238 #ifdef _with_sprintf
241 void SbxBasicFormater::InitScan( double _dNum )
243 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
245 dNum = _dNum;
246 InitExp( get_number_of_digits( dNum ) );
247 // maximum of 15 positions behind the decimal point, example: -1.234000000000000E-001
248 /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum );
249 sSciNumStrg = OUString::createFromAscii( sBuffer );
253 void SbxBasicFormater::InitExp( double _dNewExp )
255 char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ];
256 nNumExp = (short)_dNewExp;
257 /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp );
258 sNumExpStrg = OUString::createFromAscii( sBuffer );
259 nExpExp = (short)get_number_of_digits( (double)nNumExp );
263 short SbxBasicFormater::GetDigitAtPosScan( short nPos, sal_Bool& bFoundFirstDigit )
265 // trying to read a higher digit,
266 // e. g. position 4 in 1.234,
267 // or to read a digit outside of the
268 // number's dissolution (double)
269 if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS )
271 return _NO_DIGIT;
273 // determine the index of the position in the number-string:
274 // skip the leading sign
275 sal_uInt16 no = 1;
276 // skip the decimal point if necessary
277 if( nPos<nNumExp )
278 no++;
279 no += nNumExp-nPos;
280 // query of the number's first valid digit --> set flag
281 if( nPos==nNumExp )
282 bFoundFirstDigit = sal_True;
283 return (short)(sSciNumStrg[ no ] - ASCII_0);
286 short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, sal_Bool& bFoundFirstDigit )
288 if( nPos>nExpExp )
289 return -1;
291 sal_uInt16 no = 1;
292 no += nExpExp-nPos;
294 if( nPos==nExpExp )
295 bFoundFirstDigit = sal_True;
296 return (short)(sNumExpStrg[ no ] - ASCII_0);
299 // a value for the exponent can be given because the number maybe shall
300 // not be displayed in a normed way (e. g. 1.2345e-03) but maybe 123.345e-3 !
301 short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos,
302 sal_Bool& bFoundFirstDigit )
304 InitExp( dNewExponent );
306 return GetDigitAtPosExpScan( nPos,bFoundFirstDigit );
309 #else
311 /* Problems with the following method:
313 TODO: an 'intelligent' peek-parser might be needed to detect rounding
314 mistakes at double-numbers - e. g. for 0.00115 #.#e-000
316 problem with: format( 0.3345 , "0.000" )
317 problem with: format( 0.00115 , "0.0000" )
320 // returns the digit at the given '10 system'-position,
321 // i. e. positive nPos for positions before the decimal
322 // point and negative for positions after.
323 // nPos==0 means first position after the decimalpoint, so 10^0.
324 // returns 0..9 for valid digits and -1 for not existing,
325 // i. e. if the passed number is too small
326 // (e. g. position 5 of dNumber=123).
327 // Furthermore in dNextNumber the number shorted by leading
328 // positions (till nPos) is returned, e. g.
329 // GetDigitAtPos( 3434.565 , 2 , dNewNumber ) --> dNewNumber = 434.565
330 // In bFoundFirstDigit a flag is set if a digit has been found,
331 // this is used to prevent 'errors' on parsing 202
332 // ATTENTION: apparently there are sometimes still problems with rounding mistakes!
333 short SbxBasicFormater::GetDigitAtPos( double dNumber, short nPos,
334 double& dNextNumber, sal_Bool& bFoundFirstDigit )
336 double dDigit;
337 short nMaxDigit;
339 dNumber = fabs( dNumber );
341 nMaxDigit = (short)get_number_of_digits( dNumber );
342 // error only at numbers > 0, i. e. for digits before
343 // the decimal point
344 if( nMaxDigit<nPos && !bFoundFirstDigit && nPos>=0 )
345 return _NO_DIGIT;
347 bFoundFirstDigit = sal_True;
348 for( short i=nMaxDigit; i>=nPos; i-- )
350 double dI = (double)i;
351 double dTemp1 = pow( 10.0,dI );
353 dDigit = floor( pow( 10.0,log10( fabs( dNumber ) )-dI ) );
354 dNumber -= dTemp1 * dDigit;
356 // for optimized loop run
357 dNextNumber = dNumber;
359 return RoundDigit( dDigit );
363 short SbxBasicFormater::RoundDigit( double dNumber )
365 if( dNumber<0.0 || dNumber>10.0 )
366 return -1;
367 short nTempHigh = (short)(dNumber+0.5); // maybe floor( )
368 return nTempHigh;
371 #endif
373 // Copies the respective part of the format-string, if existing, and returns it.
374 // So a new string is created, which has to be freed by the caller later.
375 OUString SbxBasicFormater::GetPosFormatString( const OUString& sFormatStrg, sal_Bool & bFound )
377 bFound = sal_False; // default...
378 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
380 if( nPos >= 0 )
382 bFound = sal_True;
383 // the format-string for positive numbers is
384 // everything before the first ';'
385 return sFormatStrg.copy( 0,nPos );
388 OUString aRetStr;
389 aRetStr = OUString::createFromAscii( EMPTYFORMATSTRING );
390 return aRetStr;
393 // see also GetPosFormatString()
394 OUString SbxBasicFormater::GetNegFormatString( const OUString& sFormatStrg, sal_Bool & bFound )
396 bFound = sal_False; // default...
397 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
399 if( nPos >= 0)
401 // the format-string for negative numbers is
402 // everything between the first and the second ';'
403 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
404 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
405 bFound = sal_True;
406 if( nPos < 0 )
408 return sTempStrg;
410 else
412 return sTempStrg.copy( 0,nPos );
415 OUString aRetStr;
416 aRetStr = OUString::createFromAscii( EMPTYFORMATSTRING );
417 return aRetStr;
420 // see also GetPosFormatString()
421 OUString SbxBasicFormater::Get0FormatString( const OUString& sFormatStrg, sal_Bool & bFound )
423 bFound = sal_False; // default...
424 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
426 if( nPos >= 0 )
428 // the format string for the zero is
429 // everything after the second ';'
430 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
431 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
432 if( nPos >= 0 )
434 bFound = sal_True;
435 sTempStrg = sTempStrg.copy( nPos+1 );
436 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
437 if( nPos < 0 )
439 return sTempStrg;
441 else
443 return sTempStrg.copy( 0,nPos );
448 OUString aRetStr;
449 aRetStr = OUString::createFromAscii( EMPTYFORMATSTRING );
450 return aRetStr;
453 // see also GetPosFormatString()
454 OUString SbxBasicFormater::GetNullFormatString( const OUString& sFormatStrg, sal_Bool & bFound )
456 bFound = sal_False; // default...
457 sal_Int32 nPos = sFormatStrg.indexOf( FORMAT_SEPARATOR );
459 if( nPos >= 0 )
461 // the format-string for the Null is
462 // everything after the third ';'
463 OUString sTempStrg = sFormatStrg.copy( nPos+1 );
464 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
465 if( nPos >= 0 )
467 sTempStrg = sTempStrg.copy( nPos+1 );
468 nPos = sTempStrg.indexOf( FORMAT_SEPARATOR );
469 if( nPos >= 0 )
471 bFound = sal_True;
472 return sTempStrg.copy( nPos+1 );
477 OUString aRetStr;
478 aRetStr = OUString::createFromAscii( EMPTYFORMATSTRING );
479 return aRetStr;
482 // returns value <> 0 in case of an error
483 short SbxBasicFormater::AnalyseFormatString( const OUString& sFormatStrg,
484 short& nNoOfDigitsLeft, short& nNoOfDigitsRight,
485 short& nNoOfOptionalDigitsLeft,
486 short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits,
487 sal_Bool& bPercent, sal_Bool& bCurrency, sal_Bool& bScientific,
488 sal_Bool& bGenerateThousandSeparator,
489 short& nMultipleThousandSeparators )
491 sal_Int32 nLen;
492 short nState = 0;
494 nLen = sFormatStrg.getLength();
495 nNoOfDigitsLeft = 0;
496 nNoOfDigitsRight = 0;
497 nNoOfOptionalDigitsLeft = 0;
498 nNoOfExponentDigits = 0;
499 nNoOfOptionalExponentDigits = 0;
500 bPercent = sal_False;
501 bCurrency = sal_False;
502 bScientific = sal_False;
503 // from 11.7.97: as soon as a comma (point?) is found in the format string,
504 // all three decimal powers are marked (i. e. thousand, million, ...)
505 bGenerateThousandSeparator = sFormatStrg.indexOf( ',' ) >= 0;
506 nMultipleThousandSeparators = 0;
508 for( sal_Int32 i = 0; i < nLen; i++ )
510 sal_Unicode c = sFormatStrg[ i ];
511 switch( c )
513 case '#':
514 case '0':
515 if( nState==0 )
517 nNoOfDigitsLeft++;
518 // TODO here maybe better error inspection of the mantissa for valid syntax (see grammar)h
519 // ATTENTION: 'undefined' behaviour if # and 0 are combined!
520 // REMARK: #-placeholders are actually useless for
521 // scientific display before the decimal point!
522 if( c=='#' )
524 nNoOfOptionalDigitsLeft++;
527 else if( nState==1 )
529 nNoOfDigitsRight++;
531 else if( nState==-1 ) // search 0 in the exponent
533 if( c=='#' ) // # switches on the condition
535 nNoOfOptionalExponentDigits++;
536 nState = -2;
538 nNoOfExponentDigits++;
540 else if( nState==-2 ) // search # in the exponent
542 if( c=='0' )
544 // ERROR: 0 after # in the exponent is NOT allowed!!
545 return -4;
547 nNoOfOptionalExponentDigits++;
548 nNoOfExponentDigits++;
550 break;
551 case '.':
552 nState++;
553 if( nState>1 )
555 return -1; // ERROR: too many decimal points
557 break;
558 case '%':
559 bPercent = sal_True;
560 break;
561 case '(':
562 bCurrency = sal_True;
563 break;
564 case ',':
566 sal_Unicode ch = sFormatStrg[ i+1 ];
568 if( ch!=0 && (ch==',' || ch=='.') )
570 nMultipleThousandSeparators++;
573 break;
574 case 'e':
575 case 'E':
576 // #i13821 not when no digits before
577 if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 )
579 nState = -1; // abort counting digits
580 bScientific = sal_True;
582 break;
583 // OWN command-character which turns on
584 // the creation of thousand-separators
585 case '\\':
586 // Ignore next char
587 i++;
588 break;
589 case CREATE_1000SEP_CHAR:
590 bGenerateThousandSeparator = sal_True;
591 break;
594 return 0;
597 // the flag bCreateSign says that at the mantissa a leading sign
598 // shall be created
599 void SbxBasicFormater::ScanFormatString( double dNumber,
600 const OUString& sFormatStrg, OUString& sReturnStrgFinal,
601 sal_Bool bCreateSign )
603 short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft,
604 nNoOfExponentDigits,nNoOfOptionalExponentDigits,
605 nMultipleThousandSeparators;
606 sal_Bool bPercent,bCurrency,bScientific,bGenerateThousandSeparator;
608 OUStringBuffer sReturnStrg = OUStringBuffer();
610 // analyse the format-string, i. e. determine the following values:
612 - number of digits before decimal point
613 - number of digits after decimal point
614 - optional digits before decimal point
615 - number of digits in the exponent
616 - optional digits in the exponent
617 - percent-character found?
618 - () for negative leading sign?
619 - exponetial-notation?
620 - shall thousand-separators be generated?
621 - is a percent-character being found? --> dNumber *= 100.0;
622 - are there thousand-separators in a row?
623 ,, or ,. --> dNumber /= 1000.0;
624 - other errors? multiple decimal points, E's, etc.
625 --> errors are simply ignored at the moment
627 AnalyseFormatString( sFormatStrg, nNoOfDigitsLeft, nNoOfDigitsRight,
628 nNoOfOptionalDigitsLeft, nNoOfExponentDigits,
629 nNoOfOptionalExponentDigits,
630 bPercent, bCurrency, bScientific,
631 bGenerateThousandSeparator, nMultipleThousandSeparators );
632 // special handling for special characters
633 if( bPercent )
635 dNumber *= 100.0;
637 // TODO: this condition (,, or ,.) is NOT Visual-Basic compatible!
638 // Question: shall this stay here (requirements)?
639 if( nMultipleThousandSeparators )
641 dNumber /= 1000.0;
643 double dExponent;
644 short i,nLen;
645 short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit;
646 sal_Bool bFirstDigit,bFirstExponentDigit,bFoundFirstDigit,
647 bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative;
649 bSignHappend = sal_False;
650 bFoundFirstDigit = sal_False;
651 bIsNegative = dNumber < 0.0;
652 nLen = sFormatStrg.getLength();
653 dExponent = get_number_of_digits( dNumber );
654 nExponentPos = 0;
655 nMaxExponentDigit = 0;
656 nMaxDigit = (short)dExponent;
657 bDigitPosNegative = false;
658 if( bScientific )
660 dExponent = dExponent - (double)(nNoOfDigitsLeft-1);
661 nDigitPos = nMaxDigit;
662 nMaxExponentDigit = (short)get_number_of_digits( dExponent );
663 nExponentPos = nNoOfExponentDigits - 1 - nNoOfOptionalExponentDigits;
665 else
667 nDigitPos = nNoOfDigitsLeft - 1; // counting starts at 0, 10^0
668 // no exponent-data is needed here!
669 bDigitPosNegative = (nDigitPos < 0);
671 bFirstDigit = sal_True;
672 bFirstExponentDigit = sal_True;
673 nState = 0; // 0 --> mantissa; 1 --> exponent
674 bZeroSpaceOn = 0;
677 #ifdef _with_sprintf
678 InitScan( dNumber );
679 #endif
680 // scanning the format-string:
681 sal_Unicode cForce = 0;
682 for( i = 0; i < nLen; i++ )
684 sal_Unicode c;
685 if( cForce )
687 c = cForce;
688 cForce = 0;
690 else
692 c = sFormatStrg[ i ];
694 switch( c )
696 case '0':
697 case '#':
698 if( nState==0 )
700 // handling of the mantissa
701 if( bFirstDigit )
703 // remark: at bCurrency the negative
704 // leading sign shall be shown with ()
705 if( bIsNegative && !bCreateSign && !bSignHappend )
707 bSignHappend = sal_True;
708 sReturnStrg.append('-');
710 // output redundant positions, i. e. those which
711 // are undocumented by the format-string
712 if( nMaxDigit > nDigitPos )
714 for( short j = nMaxDigit; j > nDigitPos; j-- )
716 short nTempDigit;
717 #ifdef _with_sprintf
718 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPosScan( j, bFoundFirstDigit ) );
719 #else
720 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPos( dNumber, j, dNumber, bFoundFirstDigit ) );
721 #endif
722 if( nTempDigit!=_NO_DIGIT )
724 bFirstDigit = sal_False;
726 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit >= nDigitPos ) && j > 0 && (j % 3 == 0) )
728 sReturnStrg.append(cThousandSep );
734 if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) )
736 AppendDigit( sReturnStrg, 0 );
737 bFirstDigit = sal_False;
738 bZeroSpaceOn = 1;
739 // Remark: in Visual-Basic the first 0 turns on the 0 for
740 // all the following # (up to the decimal point),
741 // this behaviour is simulated here with the flag.
742 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit >= nDigitPos ) && nDigitPos > 0 && (nDigitPos % 3 == 0) )
744 sReturnStrg.append(cThousandSep);
747 else
749 short nTempDigit;
750 #ifdef _with_sprintf
751 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ) );
752 #else
753 AppendDigit( sReturnStrg, nTempDigit = GetDigitAtPos( dNumber, nDigitPos, dNumber, bFoundFirstDigit ) );
754 #endif
756 if( nTempDigit != _NO_DIGIT )
758 bFirstDigit = sal_False;
760 if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) )
762 sReturnStrg.append(cThousandSep);
765 nDigitPos--;
767 else
769 // handling the exponent
770 if( bFirstExponentDigit )
772 // leading sign has been given out at e/E already
773 bFirstExponentDigit = sal_False;
774 if( nMaxExponentDigit > nExponentPos )
775 // output redundant positions, i. e. those which
776 // are undocumented by the format-string
778 for( short j = nMaxExponentDigit; j > nExponentPos; j-- )
780 #ifdef _with_sprintf
781 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, j, bFoundFirstDigit ) );
782 #else
783 AppendDigit( sReturnStrg,GetDigitAtPos( dExponent, j, dExponent, bFoundFirstDigit ) );
784 #endif
789 if( nMaxExponentDigit < nExponentPos && c=='0' )
791 AppendDigit( sReturnStrg, 0 );
793 else
795 #ifdef _with_sprintf
796 AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, nExponentPos, bFoundFirstDigit ) );
797 #else
798 AppendDigit( sReturnStrg, GetDigitAtPos( dExponent, nExponentPos, dExponent, bFoundFirstDigit ) );
799 #endif
801 nExponentPos--;
803 break;
804 case '.':
805 if( bDigitPosNegative ) // #i13821: If no digits before .
807 bDigitPosNegative = false;
808 nDigitPos = 0;
809 cForce = '#';
810 i-=2;
811 break;
813 sReturnStrg.append(cDecPoint);
814 break;
815 case '%':
816 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
817 ParseBack( sReturnStrg, sFormatStrg, i-1 );
818 sReturnStrg.append('%');
819 break;
820 case 'e':
821 case 'E':
822 // does mantissa have to be rounded, before the exponent is displayed?
824 // is there a mantissa at all?
825 if( bFirstDigit )
827 // apparently not, i. e. invalid format string, e. g. E000.00
828 // so ignore these e and E characters
829 // maybe output an error (like in Visual Basic)?
831 // #i13821: VB 6 behaviour
832 sReturnStrg.append(c);
833 break;
836 sal_Bool bOverflow = sal_False;
837 #ifdef _with_sprintf
838 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
839 #else
840 short nNextDigit = GetDigitAtPos( dNumber, nDigitPos, dNumber, bFoundFirstDigit );
841 #endif
842 if( nNextDigit>=5 )
844 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1, bOverflow );
846 if( bOverflow )
848 // a leading 9 has been rounded
849 LeftShiftDecimalPoint( sReturnStrg );
850 sReturnStrg[sReturnStrg.getLength() - 1] = 0;
851 dExponent += 1.0;
853 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
854 ParseBack( sReturnStrg, sFormatStrg, i-1 );
856 // change the scanner's condition
857 nState++;
858 // output exponent character
859 sReturnStrg.append(c);
860 // i++; // MANIPULATION of the loop-variable!
861 c = sFormatStrg[ ++i ];
862 // output leading sign / exponent
863 if( c != 0 )
865 if( c == '-' )
867 if( dExponent < 0.0 )
869 sReturnStrg.append('-');
872 else if( c == '+' )
874 if( dExponent < 0.0 )
876 sReturnStrg.append('-');
878 else
880 sReturnStrg.append('+');
884 break;
885 case ',':
886 break;
887 case ';':
888 break;
889 case '(':
890 case ')':
891 // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00
892 ParseBack( sReturnStrg, sFormatStrg, i-1 );
893 if( bIsNegative )
895 sReturnStrg.append(c);
897 break;
898 case '$':
899 // append the string for the currency:
900 sReturnStrg.append(sCurrencyStrg);
901 break;
902 case ' ':
903 case '-':
904 case '+':
905 ParseBack( sReturnStrg, sFormatStrg, i-1 );
906 sReturnStrg.append(c);
907 break;
908 case '\\':
909 ParseBack( sReturnStrg, sFormatStrg, i-1 );
910 // special character found, output next
911 // character directly (if existing)
912 c = sFormatStrg[ ++i ];
913 if( c!=0 )
915 sReturnStrg.append(c);
917 break;
918 case CREATE_1000SEP_CHAR:
919 // ignore here, action has already been
920 // executed in AnalyseFormatString
921 break;
922 default:
923 // output characters and digits, too (like in Visual-Basic)
924 if( ( c>='a' && c<='z' ) ||
925 ( c>='A' && c<='Z' ) ||
926 ( c>='1' && c<='9' ) )
928 sReturnStrg.append(c);
933 // scan completed - rounding necessary?
934 if( !bScientific )
936 #ifdef _with_sprintf
937 short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit );
938 #else
939 short nNextDigit = GetDigitAtPos( dNumber, nDigitPos, dNumber, bFoundFirstDigit );
940 #endif
941 if( nNextDigit>=5 )
943 StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1 );
947 if( nNoOfDigitsRight>0 )
949 ParseBack( sReturnStrg, sFormatStrg, sFormatStrg.getLength()-1 );
951 sReturnStrgFinal = sReturnStrg.makeStringAndClear();
954 OUString SbxBasicFormater::BasicFormatNull( OUString sFormatStrg )
956 sal_Bool bNullFormatFound;
957 OUString sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound );
959 if( bNullFormatFound )
961 return sNullFormatStrg;
963 OUString aRetStr;
964 aRetStr = OUString::createFromAscii( "null" );
965 return aRetStr;
968 OUString SbxBasicFormater::BasicFormat( double dNumber, OUString sFormatStrg )
970 sal_Bool bPosFormatFound,bNegFormatFound,b0FormatFound;
972 // analyse format-string concerning predefined formats:
973 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
975 sFormatStrg = OUString::createFromAscii( GENERALNUMBER_FORMAT );
977 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
979 sFormatStrg = sCurrencyFormatStrg;
981 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
983 sFormatStrg = OUString::createFromAscii( FIXED_FORMAT );
985 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
987 sFormatStrg = OUString::createFromAscii( STANDARD_FORMAT );
989 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
991 sFormatStrg = OUString::createFromAscii( PERCENT_FORMAT );
993 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
995 sFormatStrg = OUString::createFromAscii( SCIENTIFIC_FORMAT );
997 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
999 return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ;
1001 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
1003 return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ;
1005 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
1007 return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ;
1010 // analyse format-string concerning ';', i. e. format-strings for
1011 // positive-, negative- and 0-values
1012 OUString sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound );
1013 OUString sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound );
1014 OUString s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound );
1016 OUString sReturnStrg;
1017 OUString sTempStrg;
1019 if( dNumber==0.0 )
1021 sTempStrg = sFormatStrg;
1022 if( b0FormatFound )
1024 if( s0FormatStrg.isEmpty() && bPosFormatFound )
1026 sTempStrg = sPosFormatStrg;
1028 else
1030 sTempStrg = s0FormatStrg;
1033 else if( bPosFormatFound )
1035 sTempStrg = sPosFormatStrg;
1037 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/sal_False );
1039 else
1041 if( dNumber<0.0 )
1043 if( bNegFormatFound )
1045 if( sNegFormatStrg.isEmpty() && bPosFormatFound )
1047 sTempStrg = "-";
1048 sTempStrg += sPosFormatStrg;
1050 else
1052 sTempStrg = sNegFormatStrg;
1055 else
1057 sTempStrg = sFormatStrg;
1059 // if NO format-string especially for negative
1060 // values is given, output the leading sign
1061 ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ );
1063 else // if( dNumber>0.0 )
1065 ScanFormatString( dNumber,
1066 (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg),
1067 sReturnStrg,/*bCreateSign=*/sal_False );
1070 return sReturnStrg;
1073 sal_Bool SbxBasicFormater::isBasicFormat( OUString sFormatStrg )
1075 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) )
1077 return sal_True;
1079 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) )
1081 return sal_True;
1083 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) )
1085 return sal_True;
1087 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) )
1089 return sal_True;
1091 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) )
1093 return sal_True;
1095 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) )
1097 return sal_True;
1099 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) )
1101 return sal_True;
1103 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) )
1105 return sal_True;
1107 if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) )
1109 return sal_True;
1111 return sal_False;
1114 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */