diff options
Diffstat (limited to '')
-rw-r--r-- | basic/source/sbx/sbxform.cxx | 1003 |
1 files changed, 1003 insertions, 0 deletions
diff --git a/basic/source/sbx/sbxform.cxx b/basic/source/sbx/sbxform.cxx new file mode 100644 index 000000000..bda6da33e --- /dev/null +++ b/basic/source/sbx/sbxform.cxx @@ -0,0 +1,1003 @@ +/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ +/* + * This file is part of the LibreOffice project. + * + * This Source Code Form is subject to the terms of the Mozilla Public + * License, v. 2.0. If a copy of the MPL was not distributed with this + * file, You can obtain one at http://mozilla.org/MPL/2.0/. + * + * This file incorporates work covered by the following license notice: + * + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed + * with this work for additional information regarding copyright + * ownership. The ASF licenses this file to you under the Apache + * License, Version 2.0 (the "License"); you may not use this file + * except in compliance with the License. You may obtain a copy of + * the License at http://www.apache.org/licenses/LICENSE-2.0 . + */ + + +#include <stdlib.h> + +#include <sbxform.hxx> +#include <rtl/ustrbuf.hxx> + +#include <rtl/character.hxx> +#include <o3tl/string_view.hxx> +#include <utility> + +/* +TODO: are there any Star-Basic characteristics unconsidered? + + what means: * as placeholder + +COMMENT: Visual-Basic treats the following (invalid) format-strings + as shown: + + ##0##.##0## --> ##000.000## + + (this class behaves the same way) +*/ + +#include <stdio.h> +#include <float.h> +#include <math.h> + +#define NO_DIGIT_ -1 + +#define MAX_NO_OF_DIGITS DBL_DIG +#define MAX_DOUBLE_BUFFER_LENGTH MAX_NO_OF_DIGITS + 9 + // +1 for leading sign + // +1 for digit before the decimal point + // +1 for decimal point + // +2 for exponent E and exp. leading sign + // +3 for the exponent's value + // +1 for closing 0 + +#define CREATE_1000SEP_CHAR '@' + +#define FORMAT_SEPARATOR ';' + +// predefined formats for the Format$()-command: +constexpr OUStringLiteral BASICFORMAT_GENERALNUMBER = u"General Number"; +constexpr OUStringLiteral BASICFORMAT_CURRENCY = u"Currency"; +constexpr OUStringLiteral BASICFORMAT_FIXED = u"Fixed"; +constexpr OUStringLiteral BASICFORMAT_STANDARD = u"Standard"; +constexpr OUStringLiteral BASICFORMAT_PERCENT = u"Percent"; +constexpr OUStringLiteral BASICFORMAT_SCIENTIFIC = u"Scientific"; +constexpr OUStringLiteral BASICFORMAT_YESNO = u"Yes/No"; +constexpr OUStringLiteral BASICFORMAT_TRUEFALSE = u"True/False"; +constexpr OUStringLiteral BASICFORMAT_ONOFF = u"On/Off"; + +// Comment: Visual-Basic has a maximum of 12 positions after the +// decimal point for floating-point-numbers. +// all format-strings are compatible to Visual-Basic: +constexpr OUStringLiteral GENERALNUMBER_FORMAT = u"0.############"; +constexpr OUStringLiteral FIXED_FORMAT = u"0.00"; +constexpr OUStringLiteral STANDARD_FORMAT = u"@0.00"; +constexpr OUStringLiteral PERCENT_FORMAT = u"0.00%"; +constexpr OUStringLiteral SCIENTIFIC_FORMAT = u"#.00E+00"; +// Comment: the character @ means that thousand-separators shall +// be generated. That's a StarBasic 'extension'. + + +static double get_number_of_digits( double dNumber ) +//double floor_log10_fabs( double dNumber ) +{ + if( dNumber==0.0 ) + return 0.0; // used to be 1.0, now 0.0 because of #40025; + else + return floor( log10( fabs( dNumber ) ) ); +} + + +SbxBasicFormater::SbxBasicFormater( sal_Unicode _cDecPoint, sal_Unicode _cThousandSep, + OUString _sOnStrg, + OUString _sOffStrg, + OUString _sYesStrg, + OUString _sNoStrg, + OUString _sTrueStrg, + OUString _sFalseStrg, + OUString _sCurrencyStrg, + OUString _sCurrencyFormatStrg ) + : cDecPoint(_cDecPoint) + , cThousandSep(_cThousandSep) + , sOnStrg(std::move(_sOnStrg)) + , sOffStrg(std::move(_sOffStrg)) + , sYesStrg(std::move(_sYesStrg)) + , sNoStrg(std::move(_sNoStrg)) + , sTrueStrg(std::move(_sTrueStrg)) + , sFalseStrg(std::move(_sFalseStrg)) + , sCurrencyStrg(std::move(_sCurrencyStrg)) + , sCurrencyFormatStrg(std::move(_sCurrencyFormatStrg)) + , dNum(0.0) + , nNumExp(0) + , nExpExp(0) +{ +} + +// function to output an error-text (for debugging) +// displaces all characters of the string, starting from nStartPos +// for one position to larger indexes, i. e. place for a new +// character (which is to be inserted) is created. +// ATTENTION: the string MUST be long enough! +inline void SbxBasicFormater::ShiftString( OUStringBuffer& sStrg, sal_uInt16 nStartPos ) +{ + sStrg.remove(nStartPos,1); +} + +void SbxBasicFormater::AppendDigit( OUStringBuffer& sStrg, short nDigit ) +{ + if( nDigit>=0 && nDigit<=9 ) + { + sStrg.append(static_cast<sal_Unicode>(nDigit+'0')); + } +} + +void SbxBasicFormater::LeftShiftDecimalPoint( OUStringBuffer& sStrg ) +{ + sal_Int32 nPos = -1; + + for(sal_Int32 i = 0; i < sStrg.getLength(); i++) + { + if(sStrg[i] == cDecPoint) + { + nPos = i; + break; + } + } + if( nPos >= 0 ) + { + sStrg[nPos] = sStrg[nPos - 1]; + sStrg[nPos - 1] = cDecPoint; + } +} + +// returns a flag if rounding a 9 +void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos, bool& bOverflow ) +{ + if( nPos<0 ) + { + return; + } + bOverflow = false; + sal_Unicode c = sStrg[nPos]; + if( nPos > 0 && (c == cDecPoint || c == cThousandSep) ) + { + StrRoundDigit( sStrg, nPos - 1, bOverflow ); + // CHANGE from 9.3.1997: end the method immediately after recursive call! + return; + } + // skip non-digits: + // COMMENT: + // in a valid format-string the number's output should be done + // in one piece, i. e. special characters should ONLY be in + // front OR behind the number and not right in the middle of + // the format information for the number + while( nPos >= 0 && ! rtl::isAsciiDigit(sStrg[nPos])) + { + nPos--; + } + if( nPos==-1 ) + { + ShiftString( sStrg, 0 ); + sStrg[0] = '1'; + bOverflow = true; + } + else + { + sal_Unicode c2 = sStrg[nPos]; + if( rtl::isAsciiDigit(c2) ) + { + if( c2 == '9' ) + { + sStrg[nPos] = '0'; + StrRoundDigit( sStrg, nPos - 1, bOverflow ); + } + else + { + sStrg[nPos] = c2 + 1; + } + } + else + { + ShiftString( sStrg,nPos+1 ); + sStrg[nPos + 1] = '1'; + bOverflow = true; + } + } +} + +void SbxBasicFormater::StrRoundDigit( OUStringBuffer& sStrg, short nPos ) +{ + bool bOverflow; + + StrRoundDigit( sStrg, nPos, bOverflow ); +} + +void SbxBasicFormater::ParseBack( OUStringBuffer& sStrg, std::u16string_view sFormatStrg, + short nFormatPos ) +{ + for( sal_Int32 i = nFormatPos; + i>0 && sFormatStrg[ i ] == '#' && sStrg[sStrg.getLength() - 1] == '0'; + i-- ) + { + sStrg.setLength(sStrg.getLength() - 1 ); + } +} + +void SbxBasicFormater::InitScan( double _dNum ) +{ + char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ]; + + dNum = _dNum; + InitExp( get_number_of_digits( dNum ) ); + // maximum of 15 positions behind the decimal point, example: -1.234000000000000E-001 + /*int nCount =*/ sprintf( sBuffer,"%+22.15lE",dNum ); + sSciNumStrg = OUString::createFromAscii( sBuffer ); +} + + +void SbxBasicFormater::InitExp( double _dNewExp ) +{ + char sBuffer[ MAX_DOUBLE_BUFFER_LENGTH ]; + nNumExp = static_cast<short>(_dNewExp); + /*int nCount =*/ sprintf( sBuffer,"%+i",nNumExp ); + sNumExpStrg = OUString::createFromAscii( sBuffer ); + nExpExp = static_cast<short>(get_number_of_digits( static_cast<double>(nNumExp) )); +} + + +short SbxBasicFormater::GetDigitAtPosScan( short nPos, bool& bFoundFirstDigit ) +{ + // trying to read a higher digit, + // e. g. position 4 in 1.234, + // or to read a digit outside of the + // number's dissolution (double) + if( nPos>nNumExp || abs(nNumExp-nPos)>MAX_NO_OF_DIGITS ) + { + return NO_DIGIT_; + } + // determine the index of the position in the number-string: + // skip the leading sign + sal_uInt16 no = 1; + // skip the decimal point if necessary + if( nPos<nNumExp ) + no++; + no += nNumExp-nPos; + // query of the number's first valid digit --> set flag + if( nPos==nNumExp ) + bFoundFirstDigit = true; + return static_cast<short>(sSciNumStrg[ no ] - '0'); +} + +short SbxBasicFormater::GetDigitAtPosExpScan( short nPos, bool& bFoundFirstDigit ) +{ + if( nPos>nExpExp ) + return -1; + + sal_uInt16 no = 1; + no += nExpExp-nPos; + + if( nPos==nExpExp ) + bFoundFirstDigit = true; + return static_cast<short>(sNumExpStrg[ no ] - '0'); +} + +// a value for the exponent can be given because the number maybe shall +// not be displayed in a normed way (e. g. 1.2345e-03) but maybe 123.345e-3 ! +short SbxBasicFormater::GetDigitAtPosExpScan( double dNewExponent, short nPos, + bool& bFoundFirstDigit ) +{ + InitExp( dNewExponent ); + + return GetDigitAtPosExpScan( nPos,bFoundFirstDigit ); +} + +// Copies the respective part of the format-string, if existing, and returns it. +// So a new string is created, which has to be freed by the caller later. +OUString SbxBasicFormater::GetPosFormatString( std::u16string_view sFormatStrg, bool & bFound ) +{ + bFound = false; // default... + size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR ); + + if( nPos != std::u16string_view::npos ) + { + bFound = true; + // the format-string for positive numbers is + // everything before the first ';' + return OUString(sFormatStrg.substr( 0,nPos )); + } + + return OUString(); +} + +// see also GetPosFormatString() +OUString SbxBasicFormater::GetNegFormatString( std::u16string_view sFormatStrg, bool & bFound ) +{ + bFound = false; // default... + size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR ); + + if( nPos != std::u16string_view::npos) + { + // the format-string for negative numbers is + // everything between the first and the second ';' + std::u16string_view sTempStrg = sFormatStrg.substr( nPos+1 ); + nPos = sTempStrg.find( FORMAT_SEPARATOR ); + bFound = true; + if( nPos == std::u16string_view::npos ) + { + return OUString(sTempStrg); + } + else + { + return OUString(sTempStrg.substr( 0,nPos )); + } + } + return OUString(); +} + +// see also GetPosFormatString() +OUString SbxBasicFormater::Get0FormatString( std::u16string_view sFormatStrg, bool & bFound ) +{ + bFound = false; // default... + size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR ); + + if( nPos != std::u16string_view::npos ) + { + // the format string for the zero is + // everything after the second ';' + std::u16string_view sTempStrg = sFormatStrg.substr( nPos+1 ); + nPos = sTempStrg.find( FORMAT_SEPARATOR ); + if( nPos != std::u16string_view::npos ) + { + bFound = true; + sTempStrg = sTempStrg.substr( nPos+1 ); + nPos = sTempStrg.find( FORMAT_SEPARATOR ); + if( nPos == std::u16string_view::npos ) + { + return OUString(sTempStrg); + } + else + { + return OUString(sTempStrg.substr( 0,nPos )); + } + } + } + + return OUString(); +} + +// see also GetPosFormatString() +OUString SbxBasicFormater::GetNullFormatString( std::u16string_view sFormatStrg, bool & bFound ) +{ + bFound = false; // default... + size_t nPos = sFormatStrg.find( FORMAT_SEPARATOR ); + + if( nPos != std::u16string_view::npos ) + { + // the format-string for the Null is + // everything after the third ';' + std::u16string_view sTempStrg = sFormatStrg.substr( nPos+1 ); + nPos = sTempStrg.find( FORMAT_SEPARATOR ); + if( nPos != std::u16string_view::npos ) + { + sTempStrg = sTempStrg.substr( nPos+1 ); + nPos = sTempStrg.find( FORMAT_SEPARATOR ); + if( nPos != std::u16string_view::npos ) + { + bFound = true; + return OUString(sTempStrg.substr( nPos+1 )); + } + } + } + + return OUString(); +} + +// returns value <> 0 in case of an error +void SbxBasicFormater::AnalyseFormatString( const OUString& sFormatStrg, + short& nNoOfDigitsLeft, short& nNoOfDigitsRight, + short& nNoOfOptionalDigitsLeft, + short& nNoOfExponentDigits, short& nNoOfOptionalExponentDigits, + bool& bPercent, bool& bCurrency, bool& bScientific, + bool& bGenerateThousandSeparator, + short& nMultipleThousandSeparators ) +{ + sal_Int32 nLen; + short nState = 0; + + nLen = sFormatStrg.getLength(); + nNoOfDigitsLeft = 0; + nNoOfDigitsRight = 0; + nNoOfOptionalDigitsLeft = 0; + nNoOfExponentDigits = 0; + nNoOfOptionalExponentDigits = 0; + bPercent = false; + bCurrency = false; + bScientific = false; + // from 11.7.97: as soon as a comma (point?) is found in the format string, + // all three decimal powers are marked (i. e. thousand, million, ...) + bGenerateThousandSeparator = sFormatStrg.indexOf( ',' ) >= 0; + nMultipleThousandSeparators = 0; + + for( sal_Int32 i = 0; i < nLen; i++ ) + { + sal_Unicode c = sFormatStrg[ i ]; + switch( c ) + { + case '#': + case '0': + if( nState==0 ) + { + nNoOfDigitsLeft++; +// TODO here maybe better error inspection of the mantissa for valid syntax (see grammar)h + // ATTENTION: 'undefined' behaviour if # and 0 are combined! + // REMARK: #-placeholders are actually useless for + // scientific display before the decimal point! + if( c=='#' ) + { + nNoOfOptionalDigitsLeft++; + } + } + else if( nState==1 ) + { + nNoOfDigitsRight++; + } + else if( nState==-1 ) // search 0 in the exponent + { + if( c=='#' ) // # switches on the condition + { + nNoOfOptionalExponentDigits++; + nState = -2; + } + nNoOfExponentDigits++; + } + else if( nState==-2 ) // search # in the exponent + { + if( c=='0' ) + { + // ERROR: 0 after # in the exponent is NOT allowed!! + return; + } + nNoOfOptionalExponentDigits++; + nNoOfExponentDigits++; + } + break; + case '.': + nState++; + if( nState>1 ) + { + return; // ERROR: too many decimal points + } + break; + case '%': + bPercent = true; + break; + case '(': + bCurrency = true; + break; + case ',': + { + sal_Unicode ch = sFormatStrg[ i+1 ]; + + if( ch!=0 && (ch==',' || ch=='.') ) + { + nMultipleThousandSeparators++; + } + } + break; + case 'e': + case 'E': + // #i13821 not when no digits before + if( nNoOfDigitsLeft > 0 || nNoOfDigitsRight > 0 ) + { + nState = -1; // abort counting digits + bScientific = true; + } + break; + // OWN command-character which turns on + // the creation of thousand-separators + case '\\': + // Ignore next char + i++; + break; + case CREATE_1000SEP_CHAR: + bGenerateThousandSeparator = true; + break; + } + } +} + +// the flag bCreateSign says that at the mantissa a leading sign +// shall be created +void SbxBasicFormater::ScanFormatString( double dNumber, + const OUString& sFormatStrg, OUString& sReturnStrgFinal, + bool bCreateSign ) +{ + short /*nErr,*/nNoOfDigitsLeft,nNoOfDigitsRight,nNoOfOptionalDigitsLeft, + nNoOfExponentDigits,nNoOfOptionalExponentDigits, + nMultipleThousandSeparators; + bool bPercent,bCurrency,bScientific,bGenerateThousandSeparator; + + OUStringBuffer sReturnStrg(32); + + // analyse the format-string, i. e. determine the following values: + /* + - number of digits before decimal point + - number of digits after decimal point + - optional digits before decimal point + - number of digits in the exponent + - optional digits in the exponent + - percent-character found? + - () for negative leading sign? + - exponential-notation? + - shall thousand-separators be generated? + - is a percent-character being found? --> dNumber *= 100.0; + - are there thousand-separators in a row? + ,, or ,. --> dNumber /= 1000.0; + - other errors? multiple decimal points, E's, etc. + --> errors are simply ignored at the moment + */ + AnalyseFormatString( sFormatStrg, nNoOfDigitsLeft, nNoOfDigitsRight, + nNoOfOptionalDigitsLeft, nNoOfExponentDigits, + nNoOfOptionalExponentDigits, + bPercent, bCurrency, bScientific, + bGenerateThousandSeparator, nMultipleThousandSeparators ); + // special handling for special characters + if( bPercent ) + { + dNumber *= 100.0; + } +// TODO: this condition (,, or ,.) is NOT Visual-Basic compatible! + // Question: shall this stay here (requirements)? + if( nMultipleThousandSeparators ) + { + dNumber /= 1000.0; + } + double dExponent; + short i,nLen; + short nState,nDigitPos,nExponentPos,nMaxDigit,nMaxExponentDigit; + bool bFirstDigit,bFirstExponentDigit,bFoundFirstDigit, + bIsNegative,bZeroSpaceOn, bSignHappend,bDigitPosNegative; + + bSignHappend = false; + bFoundFirstDigit = false; + bIsNegative = dNumber < 0.0; + nLen = sFormatStrg.getLength(); + dExponent = get_number_of_digits( dNumber ); + nExponentPos = 0; + nMaxExponentDigit = 0; + nMaxDigit = static_cast<short>(dExponent); + bDigitPosNegative = false; + if( bScientific ) + { + dExponent = dExponent - static_cast<double>(nNoOfDigitsLeft-1); + nDigitPos = nMaxDigit; + nMaxExponentDigit = static_cast<short>(get_number_of_digits( dExponent )); + nExponentPos = nNoOfExponentDigits - 1 - nNoOfOptionalExponentDigits; + } + else + { + nDigitPos = nNoOfDigitsLeft - 1; // counting starts at 0, 10^0 + // no exponent-data is needed here! + bDigitPosNegative = (nDigitPos < 0); + } + bFirstDigit = true; + bFirstExponentDigit = true; + nState = 0; // 0 --> mantissa; 1 --> exponent + bZeroSpaceOn = false; + + + InitScan( dNumber ); + // scanning the format-string: + sal_Unicode cForce = 0; + for( i = 0; i < nLen; i++ ) + { + sal_Unicode c; + if( cForce ) + { + c = cForce; + cForce = 0; + } + else + { + c = sFormatStrg[ i ]; + } + switch( c ) + { + case '0': + case '#': + if( nState==0 ) + { + // handling of the mantissa + if( bFirstDigit ) + { + // remark: at bCurrency the negative + // leading sign shall be shown with () + if( bIsNegative && !bCreateSign && !bSignHappend ) + { + bSignHappend = true; + sReturnStrg.append('-'); + } + // output redundant positions, i. e. those which + // are undocumented by the format-string + if( nMaxDigit > nDigitPos ) + { + for( short j = nMaxDigit; j > nDigitPos; j-- ) + { + short nTempDigit = GetDigitAtPosScan( j, bFoundFirstDigit ); + AppendDigit( sReturnStrg, nTempDigit ); + if( nTempDigit != NO_DIGIT_ ) + { + bFirstDigit = false; + } + // coverity[copy_paste_error : FALSE] - this is correct and nDigitPos should not be j + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit >= nDigitPos ) && j > 0 && (j % 3 == 0) ) + { + sReturnStrg.append(cThousandSep ); + } + } + } + } + + if( nMaxDigit<nDigitPos && ( c=='0' || bZeroSpaceOn ) ) + { + AppendDigit( sReturnStrg, 0 ); + bFirstDigit = false; + bZeroSpaceOn = true; + // Remark: in Visual-Basic the first 0 turns on the 0 for + // all the following # (up to the decimal point), + // this behaviour is simulated here with the flag. + if (bGenerateThousandSeparator && c == '0' && nDigitPos > 0 && (nDigitPos % 3 == 0)) + { + sReturnStrg.append(cThousandSep); + } + } + else + { + short nTempDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ) ; + AppendDigit( sReturnStrg, nTempDigit ); + + if( nTempDigit != NO_DIGIT_ ) + { + bFirstDigit = false; + } + if( bGenerateThousandSeparator && ( c=='0' || nMaxDigit>=nDigitPos ) && nDigitPos>0 && (nDigitPos % 3 == 0) ) + { + sReturnStrg.append(cThousandSep); + } + } + nDigitPos--; + } + else + { + // handling the exponent + if( bFirstExponentDigit ) + { + // leading sign has been given out at e/E already + bFirstExponentDigit = false; + if( nMaxExponentDigit > nExponentPos ) + // output redundant positions, i. e. those which + // are undocumented by the format-string + { + for( short j = nMaxExponentDigit; j > nExponentPos; j-- ) + { + AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, j, bFoundFirstDigit ) ); + } + } + } + + if( nMaxExponentDigit < nExponentPos && c=='0' ) + { + AppendDigit( sReturnStrg, 0 ); + } + else + { + AppendDigit( sReturnStrg, GetDigitAtPosExpScan( dExponent, nExponentPos, bFoundFirstDigit ) ); + } + nExponentPos--; + } + break; + case '.': + if( bDigitPosNegative ) // #i13821: If no digits before . + { + bDigitPosNegative = false; + nDigitPos = 0; + cForce = '#'; + i-=2; + break; + } + sReturnStrg.append(cDecPoint); + break; + case '%': + // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg, sFormatStrg, i-1 ); + sReturnStrg.append('%'); + break; + case 'e': + case 'E': + // does mantissa have to be rounded, before the exponent is displayed? + { + // is there a mantissa at all? + if( bFirstDigit ) + { + // apparently not, i. e. invalid format string, e. g. E000.00 + // so ignore these e and E characters + // maybe output an error (like in Visual Basic)? + + // #i13821: VB 6 behaviour + sReturnStrg.append(c); + break; + } + + bool bOverflow = false; + short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ); + if( nNextDigit>=5 ) + { + StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1, bOverflow ); + } + if( bOverflow ) + { + // a leading 9 has been rounded + LeftShiftDecimalPoint( sReturnStrg ); + sReturnStrg[sReturnStrg.getLength() - 1] = 0; + dExponent += 1.0; + } + // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg, sFormatStrg, i-1 ); + } + // change the scanner's condition + nState++; + // output exponent character + sReturnStrg.append(c); + // i++; // MANIPULATION of the loop-variable! + c = sFormatStrg[ ++i ]; + // output leading sign / exponent + if( c != 0 ) + { + if( c == '-' ) + { + if( dExponent < 0.0 ) + { + sReturnStrg.append('-'); + } + } + else if( c == '+' ) + { + if( dExponent < 0.0 ) + { + sReturnStrg.append('-'); + } + else + { + sReturnStrg.append('+'); + } + } + } + break; + case ',': + break; + case ';': + break; + case '(': + case ')': + // maybe remove redundant 0s, e. g. 4.500e4 in 0.0##e-00 + ParseBack( sReturnStrg, sFormatStrg, i-1 ); + if( bIsNegative ) + { + sReturnStrg.append(c); + } + break; + case '$': + // append the string for the currency: + sReturnStrg.append(sCurrencyStrg); + break; + case ' ': + case '-': + case '+': + ParseBack( sReturnStrg, sFormatStrg, i-1 ); + sReturnStrg.append(c); + break; + case '\\': + ParseBack( sReturnStrg, sFormatStrg, i-1 ); + // special character found, output next + // character directly (if existing) + c = sFormatStrg[ ++i ]; + if( c!=0 ) + { + sReturnStrg.append(c); + } + break; + case CREATE_1000SEP_CHAR: + // ignore here, action has already been + // executed in AnalyseFormatString + break; + default: + // output characters and digits, too (like in Visual-Basic) + if( ( c>='a' && c<='z' ) || + ( c>='A' && c<='Z' ) || + ( c>='1' && c<='9' ) ) + { + sReturnStrg.append(c); + } + } + } + + // scan completed - rounding necessary? + if( !bScientific ) + { + short nNextDigit = GetDigitAtPosScan( nDigitPos, bFoundFirstDigit ); + if( nNextDigit>=5 ) + { + StrRoundDigit( sReturnStrg, sReturnStrg.getLength() - 1 ); + } + } + + if( nNoOfDigitsRight>0 ) + { + ParseBack( sReturnStrg, sFormatStrg, sFormatStrg.getLength()-1 ); + } + sReturnStrgFinal = sReturnStrg.makeStringAndClear(); +} + +OUString SbxBasicFormater::BasicFormatNull( std::u16string_view sFormatStrg ) +{ + bool bNullFormatFound; + OUString sNullFormatStrg = GetNullFormatString( sFormatStrg, bNullFormatFound ); + + if( bNullFormatFound ) + { + return sNullFormatStrg; + } + return "null"; +} + +OUString SbxBasicFormater::BasicFormat( double dNumber, const OUString& _sFormatStrg ) +{ + bool bPosFormatFound,bNegFormatFound,b0FormatFound; + OUString sFormatStrg = _sFormatStrg; + + // analyse format-string concerning predefined formats: + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_GENERALNUMBER ) ) + { + sFormatStrg = GENERALNUMBER_FORMAT; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_CURRENCY ) ) + { + sFormatStrg = sCurrencyFormatStrg; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_FIXED ) ) + { + sFormatStrg = FIXED_FORMAT; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_STANDARD ) ) + { + sFormatStrg = STANDARD_FORMAT; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_PERCENT ) ) + { + sFormatStrg = PERCENT_FORMAT; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_SCIENTIFIC ) ) + { + sFormatStrg = SCIENTIFIC_FORMAT; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_YESNO ) ) + { + return ( dNumber==0.0 ) ? sNoStrg : sYesStrg ; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_TRUEFALSE ) ) + { + return ( dNumber==0.0 ) ? sFalseStrg : sTrueStrg ; + } + if( sFormatStrg.equalsIgnoreAsciiCase( BASICFORMAT_ONOFF ) ) + { + return ( dNumber==0.0 ) ? sOffStrg : sOnStrg ; + } + + // analyse format-string concerning ';', i. e. format-strings for + // positive-, negative- and 0-values + OUString sPosFormatStrg = GetPosFormatString( sFormatStrg, bPosFormatFound ); + OUString sNegFormatStrg = GetNegFormatString( sFormatStrg, bNegFormatFound ); + OUString s0FormatStrg = Get0FormatString( sFormatStrg, b0FormatFound ); + + OUString sReturnStrg; + OUString sTempStrg; + + if( dNumber==0.0 ) + { + sTempStrg = sFormatStrg; + if( b0FormatFound ) + { + if( s0FormatStrg.isEmpty() && bPosFormatFound ) + { + sTempStrg = sPosFormatStrg; + } + else + { + sTempStrg = s0FormatStrg; + } + } + else if( bPosFormatFound ) + { + sTempStrg = sPosFormatStrg; + } + ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/false ); + } + else + { + if( dNumber<0.0 ) + { + if( bNegFormatFound ) + { + if( sNegFormatStrg.isEmpty() && bPosFormatFound ) + { + sTempStrg = "-" + sPosFormatStrg; + } + else + { + sTempStrg = sNegFormatStrg; + } + } + else + { + sTempStrg = sFormatStrg; + } + // if NO format-string especially for negative + // values is given, output the leading sign + ScanFormatString( dNumber, sTempStrg, sReturnStrg,/*bCreateSign=*/bNegFormatFound/*sNegFormatStrg!=EMPTYFORMATSTRING*/ ); + } + else // if( dNumber>0.0 ) + { + ScanFormatString( dNumber, + (/*sPosFormatStrg!=EMPTYFORMATSTRING*/bPosFormatFound ? sPosFormatStrg : sFormatStrg), + sReturnStrg,/*bCreateSign=*/false ); + } + } + return sReturnStrg; +} + +bool SbxBasicFormater::isBasicFormat( std::u16string_view sFormatStrg ) +{ + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_GENERALNUMBER ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_CURRENCY ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_FIXED ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_STANDARD ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_PERCENT ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_SCIENTIFIC ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_YESNO ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_TRUEFALSE ) ) + { + return true; + } + if( o3tl::equalsIgnoreAsciiCase( sFormatStrg, BASICFORMAT_ONOFF ) ) + { + return true; + } + return false; +} + +/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |