diff options
Diffstat (limited to 'sc/source/core/tool/interpr2.cxx')
-rw-r--r-- | sc/source/core/tool/interpr2.cxx | 3029 |
1 files changed, 0 insertions, 3029 deletions
diff --git a/sc/source/core/tool/interpr2.cxx b/sc/source/core/tool/interpr2.cxx deleted file mode 100644 index 659cdfb48..000000000 --- a/sc/source/core/tool/interpr2.cxx +++ /dev/null @@ -1,3029 +0,0 @@ -/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ -/************************************************************************* - * - * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. - * - * Copyright 2000, 2010 Oracle and/or its affiliates. - * - * OpenOffice.org - a multi-platform office productivity suite - * - * This file is part of OpenOffice.org. - * - * OpenOffice.org is free software: you can redistribute it and/or modify - * it under the terms of the GNU Lesser General Public License version 3 - * only, as published by the Free Software Foundation. - * - * OpenOffice.org is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU Lesser General Public License version 3 for more details - * (a copy is included in the LICENSE file that accompanied this code). - * - * You should have received a copy of the GNU Lesser General Public License - * version 3 along with OpenOffice.org. If not, see - * <http://www.openoffice.org/license.html> - * for a copy of the LGPLv3 License. - * - ************************************************************************/ - -// MARKER(update_precomp.py): autogen include statement, do not remove -#include "precompiled_sc.hxx" - -// INCLUDE --------------------------------------------------------------- - -#include <sfx2/linkmgr.hxx> -#include <sfx2/dispatch.hxx> -#include <sfx2/objsh.hxx> -#include <svl/stritem.hxx> -#include <svl/zforlist.hxx> -#include <rtl/logfile.hxx> -#include <sal/macros.h> - -#include "interpre.hxx" -#include "attrib.hxx" -#include "sc.hrc" -#include "ddelink.hxx" -#include "scmatrix.hxx" -#include "compiler.hxx" -#include "cell.hxx" -#include "document.hxx" -#include "dociter.hxx" -#include "docoptio.hxx" -#include "unitconv.hxx" -#include "globstr.hrc" -#include "hints.hxx" -#include "dpobject.hxx" -#include "postit.hxx" - -#include <string.h> -#include <math.h> - -using namespace formula; -// STATIC DATA ----------------------------------------------------------- - -#define D_TIMEFACTOR 86400.0 -#define SCdEpsilon 1.0E-7 - -//----------------------------------------------------------------------------- -// Datum und Zeit -//----------------------------------------------------------------------------- - -double ScInterpreter::GetDateSerial( sal_Int16 nYear, sal_Int16 nMonth, sal_Int16 nDay, bool bStrict ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDateSerial" ); - if ( nYear < 100 && !bStrict ) - nYear = pFormatter->ExpandTwoDigitYear( nYear ); - // Do not use a default Date ctor here because it asks system time with a - // performance penalty. - sal_Int16 nY, nM, nD; - if (bStrict) - nY = nYear, nM = nMonth, nD = nDay; - else - { - if (nMonth > 0) - { - nY = nYear + (nMonth-1) / 12; - nM = ((nMonth-1) % 12) + 1; - } - else - { - nY = nYear + (nMonth-12) / 12; - nM = 12 - (-nMonth) % 12; - } - nD = 1; - } - Date aDate( nD, nM, nY); - if (!bStrict) - aDate += nDay - 1; - if (aDate.IsValid()) - return (double) (aDate - *(pFormatter->GetNullDate())); - else - { - SetError(errNoValue); - return 0; - } -} - -//----------------------------------------------------------------------------- -// Funktionen -//----------------------------------------------------------------------------- - -void ScInterpreter::ScGetActDate() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActDate" ); - nFuncFmtType = NUMBERFORMAT_DATE; - Date aActDate; - long nDiff = aActDate - *(pFormatter->GetNullDate()); - PushDouble((double) nDiff); -} - -void ScInterpreter::ScGetActTime() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetActTime" ); - nFuncFmtType = NUMBERFORMAT_DATETIME; - Date aActDate; - long nDiff = aActDate - *(pFormatter->GetNullDate()); - Time aActTime; - double nTime = ((double)aActTime.Get100Sec() / 100 + - (double)(aActTime.GetSec() + - (aActTime.GetMin() * 60) + - (aActTime.GetHour() * 3600))) / D_TIMEFACTOR; - PushDouble( (double) nDiff + nTime ); -} - -void ScInterpreter::ScGetYear() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetYear" ); - Date aDate = *(pFormatter->GetNullDate()); - aDate += (long) ::rtl::math::approxFloor(GetDouble()); - PushDouble( (double) aDate.GetYear() ); -} - -void ScInterpreter::ScGetMonth() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMonth" ); - Date aDate = *(pFormatter->GetNullDate()); - aDate += (long) ::rtl::math::approxFloor(GetDouble()); - PushDouble( (double) aDate.GetMonth() ); -} - -void ScInterpreter::ScGetDay() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDay" ); - Date aDate = *(pFormatter->GetNullDate()); - aDate += (long)::rtl::math::approxFloor(GetDouble()); - PushDouble((double) aDate.GetDay()); -} - -void ScInterpreter::ScGetMin() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetMin" ); - double fTime = GetDouble(); - fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg - long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 3600; - PushDouble( (double) (nVal/60) ); -} - -void ScInterpreter::ScGetSec() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetSec" ); - double fTime = GetDouble(); - fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg - long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) % 60; - PushDouble( (double) nVal ); -} - -void ScInterpreter::ScGetHour() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetHour" ); - double fTime = GetDouble(); - fTime -= ::rtl::math::approxFloor(fTime); // Datumsanteil weg - long nVal = (long)::rtl::math::approxFloor(fTime*D_TIMEFACTOR+0.5) / 3600; - PushDouble((double) nVal); -} - -void ScInterpreter::ScGetDateValue() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDateValue" ); - String aInputString = GetString(); - sal_uInt32 nFIndex = 0; // damit default Land/Spr. - double fVal; - if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal)) - { - short eType = pFormatter->GetType(nFIndex); - if (eType == NUMBERFORMAT_DATE || eType == NUMBERFORMAT_DATETIME) - PushDouble(::rtl::math::approxFloor(fVal)); - else - PushIllegalArgument(); - } - else - PushIllegalArgument(); -} - -void ScInterpreter::ScGetDayOfWeek() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDayOfWeek" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 1, 2 ) ) - { - short nFlag; - if (nParamCount == 2) - nFlag = (short) ::rtl::math::approxFloor(GetDouble()); - else - nFlag = 1; - - Date aDate = *(pFormatter->GetNullDate()); - aDate += (long)::rtl::math::approxFloor(GetDouble()); - int nVal = (int) aDate.GetDayOfWeek(); - if (nFlag == 1) - { - if (nVal == 6) - nVal = 1; - else - nVal += 2; - } - else if (nFlag == 2) - nVal += 1; - PushInt( nVal ); - } -} - -void ScInterpreter::ScGetWeekOfYear() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetWeekOfYear" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - short nFlag = (short) ::rtl::math::approxFloor(GetDouble()); - - Date aDate = *(pFormatter->GetNullDate()); - aDate += (long)::rtl::math::approxFloor(GetDouble()); - PushInt( (int) aDate.GetWeekOfYear( nFlag == 1 ? SUNDAY : MONDAY )); - } -} - -void ScInterpreter::ScEasterSunday() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEasterSunday" ); - nFuncFmtType = NUMBERFORMAT_DATE; - if ( MustHaveParamCount( GetByte(), 1 ) ) - { - sal_Int16 nDay, nMonth, nYear; - nYear = (sal_Int16) ::rtl::math::approxFloor( GetDouble() ); - if ( nYear < 100 ) - nYear = pFormatter->ExpandTwoDigitYear( nYear ); - // don't worry, be happy :) - int B,C,D,E,F,G,H,I,K,L,M,N,O; - N = nYear % 19; - B = int(nYear / 100); - C = nYear % 100; - D = int(B / 4); - E = B % 4; - F = int((B + 8) / 25); - G = int((B - F + 1) / 3); - H = (19 * N + B - D - G + 15) % 30; - I = int(C / 4); - K = C % 4; - L = (32 + 2 * E + 2 * I - H - K) % 7; - M = int((N + 11 * H + 22 * L) / 451); - O = H + L - 7 * M + 114; - nDay = sal::static_int_cast<sal_Int16>( O % 31 + 1 ); - nMonth = sal::static_int_cast<sal_Int16>( int(O / 31) ); - PushDouble( GetDateSerial( nYear, nMonth, nDay, true ) ); - } -} - -void ScInterpreter::ScGetDate() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDate" ); - nFuncFmtType = NUMBERFORMAT_DATE; - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - sal_Int16 nDay = (sal_Int16) ::rtl::math::approxFloor(GetDouble()); - sal_Int16 nMonth = (sal_Int16) ::rtl::math::approxFloor(GetDouble()); - sal_Int16 nYear = (sal_Int16) ::rtl::math::approxFloor(GetDouble()); - if (nYear < 0) - PushIllegalArgument(); - else - { - PushDouble(GetDateSerial(nYear, nMonth, nDay, false)); - } - } -} - -void ScInterpreter::ScGetTime() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTime" ); - nFuncFmtType = NUMBERFORMAT_TIME; - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double nSec = GetDouble(); - double nMin = GetDouble(); - double nHour = GetDouble(); - PushDouble( ( (nHour * 3600) + (nMin * 60) + nSec ) / D_TIMEFACTOR ); - } -} - -void ScInterpreter::ScGetDiffDate() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double nDate2 = GetDouble(); - double nDate1 = GetDouble(); - PushDouble(nDate1 - nDate2); - } -} - -void ScInterpreter::ScGetDiffDate360() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetDiffDate360" ); - /* Implementation follows - * http://www.bondmarkets.com/eCommerce/SMD_Fields_030802.pdf - * Appendix B: Day-Count Bases, there are 7 different ways to calculate the - * 30-days count. That document also claims that Excel implements the "PSA - * 30" or "NASD 30" method (funny enough they also state that Excel is the - * only tool that does so). - * - * Note that the definiton given in - * http://msdn.microsoft.com/library/en-us/office97/html/SEB7C.asp - * is _not_ the way how it is actually calculated by Excel (that would not - * even match any of the 7 methods mentioned above) and would result in the - * following test cases producing wrong results according to that appendix B: - * - * 28-Feb-95 31-Aug-95 181 instead of 180 - * 29-Feb-96 31-Aug-96 181 instead of 180 - * 30-Jan-96 31-Mar-96 61 instead of 60 - * 31-Jan-96 31-Mar-96 61 instead of 60 - * - * Still, there is a difference between OOoCalc and Excel: - * In Excel: - * 02-Feb-99 31-Mar-00 results in 419 - * 31-Mar-00 02-Feb-99 results in -418 - * In Calc the result is 419 respectively -419. I consider the -418 a bug in Excel. - */ - - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 2, 3 ) ) - { - sal_Bool bFlag; - if (nParamCount == 3) - bFlag = GetBool(); - else - bFlag = false; - double nDate2 = GetDouble(); - double nDate1 = GetDouble(); - if (nGlobalError) - PushError( nGlobalError); - else - { - double fSign; - // #i84934# only for non-US European algorithm swap dates. Else - // follow Excel's meaningless extrapolation for "interoperability". - if (bFlag && (nDate2 < nDate1)) - { - fSign = nDate1; - nDate1 = nDate2; - nDate2 = fSign; - fSign = -1.0; - } - else - fSign = 1.0; - Date aDate1 = *(pFormatter->GetNullDate()); - aDate1 += (long) ::rtl::math::approxFloor(nDate1); - Date aDate2 = *(pFormatter->GetNullDate()); - aDate2 += (long) ::rtl::math::approxFloor(nDate2); - if (aDate1.GetDay() == 31) - aDate1 -= (sal_uLong) 1; - else if (!bFlag) - { - if (aDate1.GetMonth() == 2) - { - switch ( aDate1.GetDay() ) - { - case 28 : - if ( !aDate1.IsLeapYear() ) - aDate1.SetDay(30); - break; - case 29 : - aDate1.SetDay(30); - break; - } - } - } - if (aDate2.GetDay() == 31) - { - if (!bFlag ) - { - if (aDate1.GetDay() == 30) - aDate2 -= (sal_uLong) 1; - } - else - aDate2.SetDay(30); - } - PushDouble( fSign * (double) - ( (double) aDate2.GetDay() + (double) aDate2.GetMonth() * 30.0 + - (double) aDate2.GetYear() * 360.0 - - (double) aDate1.GetDay() - (double) aDate1.GetMonth() * 30.0 - - (double)aDate1.GetYear() * 360.0) ); - } - } -} - -void ScInterpreter::ScGetTimeValue() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetTimeValue" ); - String aInputString = GetString(); - sal_uInt32 nFIndex = 0; // damit default Land/Spr. - double fVal; - if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal)) - { - short eType = pFormatter->GetType(nFIndex); - if (eType == NUMBERFORMAT_TIME || eType == NUMBERFORMAT_DATETIME) - { - double fDateVal = rtl::math::approxFloor(fVal); - double fTimeVal = fVal - fDateVal; - PushDouble(fTimeVal); - } - else - PushIllegalArgument(); - } - else - PushIllegalArgument(); -} - -void ScInterpreter::ScPlusMinus() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPlusMinus" ); - double nVal = GetDouble(); - short n = 0; - if (nVal < 0.0) - n = -1; - else if (nVal > 0.0) - n = 1; - PushInt( n ); -} - -void ScInterpreter::ScAbs() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAbs" ); - PushDouble(fabs(GetDouble())); -} - -void ScInterpreter::ScInt() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInt" ); - PushDouble(::rtl::math::approxFloor(GetDouble())); -} - - -void ScInterpreter::RoundNumber( rtl_math_RoundingMode eMode ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RoundNumber" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 1, 2 ) ) - { - double fVal = 0.0; - if (nParamCount == 1) - fVal = ::rtl::math::round( GetDouble(), 0, eMode ); - else - { - sal_Int32 nDec = (sal_Int32) ::rtl::math::approxFloor(GetDouble()); - if( nDec < -20 || nDec > 20 ) - PushIllegalArgument(); - else - fVal = ::rtl::math::round( GetDouble(), (short)nDec, eMode ); - } - PushDouble(fVal); - } -} - -void ScInterpreter::ScRound() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRound" ); - RoundNumber( rtl_math_RoundingMode_Corrected ); -} - -void ScInterpreter::ScRoundDown() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundDown" ); - RoundNumber( rtl_math_RoundingMode_Down ); -} - -void ScInterpreter::ScRoundUp() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRoundUp" ); - RoundNumber( rtl_math_RoundingMode_Up ); -} - -void ScInterpreter::ScCeil() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCeil" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 2, 3 ) ) - { - sal_Bool bAbs = ( nParamCount == 3 ? GetBool() : false ); - double fDec = GetDouble(); - double fVal = GetDouble(); - if ( fDec == 0.0 ) - PushInt(0); - else if (fVal*fDec < 0.0) - PushIllegalArgument(); - else - { - if ( !bAbs && fVal < 0.0 ) - PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec); - else - PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec); - } - } -} - -void ScInterpreter::ScFloor() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFloor" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 2, 3 ) ) - { - sal_Bool bAbs = ( nParamCount == 3 ? GetBool() : false ); - double fDec = GetDouble(); - double fVal = GetDouble(); - if ( fDec == 0.0 ) - PushInt(0); - else if (fVal*fDec < 0.0) - PushIllegalArgument(); - else - { - if ( !bAbs && fVal < 0.0 ) - PushDouble(::rtl::math::approxCeil(fVal/fDec) * fDec); - else - PushDouble(::rtl::math::approxFloor(fVal/fDec) * fDec); - } - } -} - -void ScInterpreter::ScEven() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEven" ); - double fVal = GetDouble(); - if (fVal < 0.0) - PushDouble(::rtl::math::approxFloor(fVal/2.0) * 2.0); - else - PushDouble(::rtl::math::approxCeil(fVal/2.0) * 2.0); -} - -void ScInterpreter::ScOdd() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOdd" ); - double fVal = GetDouble(); - if (fVal >= 0.0) - { - fVal = ::rtl::math::approxCeil(fVal); - if (fmod(fVal, 2.0) == 0.0) - fVal += 1.0; - } - else - { - fVal = ::rtl::math::approxFloor(fVal); - if (fmod(fVal, 2.0) == 0.0) - fVal -= 1.0; - } - PushDouble(fVal); -} - -void ScInterpreter::ScArcTan2() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan2" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double nVal2 = GetDouble(); - double nVal1 = GetDouble(); - PushDouble(atan2(nVal2, nVal1)); - } -} - -void ScInterpreter::ScLog() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 1, 2 ) ) - { - double nBase; - if (nParamCount == 2) - nBase = GetDouble(); - else - nBase = 10.0; - double nVal = GetDouble(); - if (nVal > 0.0 && nBase > 0.0 && nBase != 1.0) - PushDouble(log(nVal) / log(nBase)); - else - PushIllegalArgument(); - } -} - -void ScInterpreter::ScLn() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLn" ); - double fVal = GetDouble(); - if (fVal > 0.0) - PushDouble(log(fVal)); - else - PushIllegalArgument(); -} - -void ScInterpreter::ScLog10() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLog10" ); - double fVal = GetDouble(); - if (fVal > 0.0) - PushDouble(log10(fVal)); - else - PushIllegalArgument(); -} - -void ScInterpreter::ScNPV() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNPV" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - short nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 2, 31 ) ) - { - double nVal = 0.0; - // Wir drehen den Stack um!! - FormulaToken* pTemp[ 31 ]; - for( short i = 0; i < nParamCount; i++ ) - pTemp[ i ] = pStack[ sp - i - 1 ]; - memcpy( &pStack[ sp - nParamCount ], pTemp, nParamCount * sizeof( FormulaToken* ) ); - if (nGlobalError == 0) - { - double nCount = 1.0; - double nZins = GetDouble(); - --nParamCount; - size_t nRefInList = 0; - ScRange aRange; - while (nParamCount-- > 0) - { - switch (GetStackType()) - { - case svDouble : - { - nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount)); - nCount++; - } - break; - case svSingleRef : - { - nVal += (GetDouble() / pow(1.0 + nZins, (double)nCount)); - nCount++; - } - break; - case svDoubleRef : - case svRefList : - { - sal_uInt16 nErr = 0; - double nCellVal; - PopDoubleRef( aRange, nParamCount, nRefInList); - ScValueIterator aValIter(pDok, aRange, glSubTotal); - if (aValIter.GetFirst(nCellVal, nErr)) - { - nVal += (nCellVal / pow(1.0 + nZins, (double)nCount)); - nCount++; - while ((nErr == 0) && aValIter.GetNext(nCellVal, nErr)) - { - nVal += (nCellVal / pow(1.0 + nZins, (double)nCount)); - nCount++; - } - SetError(nErr); - } - } - break; - default : SetError(errIllegalParameter); break; - } - } - } - PushDouble(nVal); - } -} - -void ScInterpreter::ScIRR() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIRR" ); - double fSchaetzwert; - nFuncFmtType = NUMBERFORMAT_PERCENT; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 1, 2 ) ) - return; - if (nParamCount == 2) - fSchaetzwert = GetDouble(); - else - fSchaetzwert = 0.1; - sal_uInt16 sPos = sp; // Stack-Position merken - double fEps = 1.0; - double x, xNeu, fWert, fZaehler, fNenner, nCount; - if (fSchaetzwert == -1.0) - x = 0.1; // default gegen Nulldivisionen - else - x = fSchaetzwert; // Startwert - switch (GetStackType()) - { - case svDoubleRef : - break; - default: - { - PushIllegalParameter(); - return; - } - } - const sal_uInt16 nIterationsMax = 20; - sal_uInt16 nItCount = 0; - ScRange aRange; - while (fEps > SCdEpsilon && nItCount < nIterationsMax) - { // Newton-Verfahren: - sp = sPos; // Stack zuruecksetzen - nCount = 0.0; - fZaehler = 0.0; - fNenner = 0.0; - sal_uInt16 nErr = 0; - PopDoubleRef( aRange ); - ScValueIterator aValIter(pDok, aRange, glSubTotal); - if (aValIter.GetFirst(fWert, nErr)) - { - fZaehler += fWert / pow(1.0+x,(double)nCount); - fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0); - nCount++; - while ((nErr == 0) && aValIter.GetNext(fWert, nErr)) - { - fZaehler += fWert / pow(1.0+x,(double)nCount); - fNenner += -nCount * fWert / pow(1.0+x,nCount+1.0); - nCount++; - } - SetError(nErr); - } - xNeu = x - fZaehler / fNenner; // x(i+1) = x(i)-f(x(i))/f'(x(i)) - nItCount++; - fEps = fabs(xNeu - x); - x = xNeu; - } - if (fSchaetzwert == 0.0 && fabs(x) < SCdEpsilon) - x = 0.0; // auf Null normieren - if (fEps < SCdEpsilon) - PushDouble(x); - else - PushError( errNoConvergence); -} - -void ScInterpreter::ScMIRR() -{ // range_of_values ; rate_invest ; rate_reinvest - nFuncFmtType = NUMBERFORMAT_PERCENT; - if( MustHaveParamCount( GetByte(), 3 ) ) - { - double fRate1_reinvest = GetDouble() + 1; - double fRate1_invest = GetDouble() + 1; - - ScRange aRange; - PopDoubleRef( aRange ); - - if( nGlobalError ) - PushError( nGlobalError); - else - { - double fNPV_reinvest = 0.0; - double fPow_reinvest = 1.0; - double fNPV_invest = 0.0; - double fPow_invest = 1.0; - ScValueIterator aValIter( pDok, aRange, glSubTotal ); - double fCellValue; - sal_uLong nCount = 0; - sal_uInt16 nIterError = 0; - - sal_Bool bLoop = aValIter.GetFirst( fCellValue, nIterError ); - while( bLoop ) - { - if( fCellValue > 0.0 ) // reinvestments - fNPV_reinvest += fCellValue * fPow_reinvest; - else if( fCellValue < 0.0 ) // investments - fNPV_invest += fCellValue * fPow_invest; - fPow_reinvest /= fRate1_reinvest; - fPow_invest /= fRate1_invest; - nCount++; - - bLoop = aValIter.GetNext( fCellValue, nIterError ); - } - if( nIterError ) - PushError( nIterError ); - else - { - double fResult = -fNPV_reinvest / fNPV_invest; - fResult *= pow( fRate1_reinvest, (double) nCount - 1 ); - fResult = pow( fResult, 1.0 / (nCount - 1) ); - PushDouble( fResult - 1.0 ); - } - } - } -} - - -void ScInterpreter::ScISPMT() -{ // rate ; period ; total_periods ; invest - if( MustHaveParamCount( GetByte(), 4 ) ) - { - double fInvest = GetDouble(); - double fTotal = GetDouble(); - double fPeriod = GetDouble(); - double fRate = GetDouble(); - - if( nGlobalError ) - PushError( nGlobalError); - else - PushDouble( fInvest * fRate * (fPeriod / fTotal - 1.0) ); - } -} - - -//----------------------- Finanzfunktionen ------------------------------------ - -double ScInterpreter::ScGetBw(double fZins, double fZzr, double fRmz, - double fZw, double fF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMIRR" ); - double fBw; - if (fZins == 0.0) - fBw = fZw + fRmz * fZzr; - else if (fF > 0.0) - fBw = (fZw * pow(1.0 + fZins, -fZzr)) - + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr + 1.0)) / fZins) - + fRmz; - else - fBw = (fZw * pow(1.0 + fZins, -fZzr)) - + (fRmz * (1.0 - pow(1.0 + fZins, -fZzr)) / fZins); - return -fBw; -} - -void ScInterpreter::ScBW() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBW" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - double nRmz, nZzr, nZins, nZw = 0, nFlag = 0; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 5 ) ) - return; - if (nParamCount == 5) - nFlag = GetDouble(); - if (nParamCount >= 4) - nZw = GetDouble(); - nRmz = GetDouble(); - nZzr = GetDouble(); - nZins = GetDouble(); - PushDouble(ScGetBw(nZins, nZzr, nRmz, nZw, nFlag)); -} - -void ScInterpreter::ScDIA() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDIA" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - if ( MustHaveParamCount( GetByte(), 4 ) ) - { - double nZr = GetDouble(); - double nDauer = GetDouble(); - double nRest = GetDouble(); - double nWert = GetDouble(); - double nDia = ((nWert - nRest) * (nDauer - nZr + 1.0)) / - ((nDauer * (nDauer + 1.0)) / 2.0); - PushDouble(nDia); - } -} - -double ScInterpreter::ScGetGDA(double fWert, double fRest, double fDauer, - double fPeriode, double fFaktor) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetGDA" ); - double fGda, fZins, fAlterWert, fNeuerWert; - fZins = fFaktor / fDauer; - if (fZins >= 1.0) - { - fZins = 1.0; - if (fPeriode == 1.0) - fAlterWert = fWert; - else - fAlterWert = 0.0; - } - else - fAlterWert = fWert * pow(1.0 - fZins, fPeriode - 1.0); - fNeuerWert = fWert * pow(1.0 - fZins, fPeriode); - - if (fNeuerWert < fRest) - fGda = fAlterWert - fRest; - else - fGda = fAlterWert - fNeuerWert; - if (fGda < 0.0) - fGda = 0.0; - return fGda; -} - -void ScInterpreter::ScGDA() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 4, 5 ) ) - { - double nFaktor; - if (nParamCount == 5) - nFaktor = GetDouble(); - else - nFaktor = 2.0; - double nPeriode = GetDouble(); - double nDauer = GetDouble(); - double nRest = GetDouble(); - double nWert = GetDouble(); - if (nWert < 0.0 || nRest < 0.0 || nFaktor <= 0.0 || nRest > nWert - || nPeriode < 1.0 || nPeriode > nDauer) - PushIllegalArgument(); - else - PushDouble(ScGetGDA(nWert, nRest, nDauer, nPeriode, nFaktor)); - } -} - -void ScInterpreter::ScGDA2() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGDA2" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 4, 5 ) ) - return ; - double nMonate; - if (nParamCount == 4) - nMonate = 12.0; - else - nMonate = ::rtl::math::approxFloor(GetDouble()); - double nPeriode = GetDouble(); - double nDauer = GetDouble(); - double nRest = GetDouble(); - double nWert = GetDouble(); - if (nMonate < 1.0 || nMonate > 12.0 || nDauer > 1200.0 || nRest < 0.0 || - nPeriode > (nDauer + 1.0) || nRest > nWert || nWert < 0.0) - { - PushIllegalArgument(); - return; - } - double nAbRate = 1.0 - pow(nRest / nWert, 1.0 / nDauer); - nAbRate = ::rtl::math::approxFloor((nAbRate * 1000.0) + 0.5) / 1000.0; - double nErsteAbRate = nWert * nAbRate * nMonate / 12.0; - double nGda2 = 0.0; - if (::rtl::math::approxFloor(nPeriode) == 1) - nGda2 = nErsteAbRate; - else - { - double nSummAbRate = nErsteAbRate; - double nMin = nDauer; - if (nMin > nPeriode) nMin = nPeriode; - sal_uInt16 iMax = (sal_uInt16)::rtl::math::approxFloor(nMin); - for (sal_uInt16 i = 2; i <= iMax; i++) - { - nGda2 = (nWert - nSummAbRate) * nAbRate; - nSummAbRate += nGda2; - } - if (nPeriode > nDauer) - nGda2 = ((nWert - nSummAbRate) * nAbRate * (12.0 - nMonate)) / 12.0; - } - PushDouble(nGda2); -} - - -double ScInterpreter::ScInterVDB(double fWert,double fRest,double fDauer, - double fDauer1,double fPeriode,double fFaktor) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScInterVDB" ); - double fVdb=0; - double fIntEnd = ::rtl::math::approxCeil(fPeriode); - sal_uLong nLoopEnd = (sal_uLong) fIntEnd; - - double fTerm, fLia; - double fRestwert = fWert - fRest; - sal_Bool bNowLia = false; - - double fGda; - sal_uLong i; - fLia=0; - for ( i = 1; i <= nLoopEnd; i++) - { - if(!bNowLia) - { - fGda = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor); - fLia = fRestwert/ (fDauer1 - (double) (i-1)); - - if (fLia > fGda) - { - fTerm = fLia; - bNowLia = sal_True; - } - else - { - fTerm = fGda; - fRestwert -= fGda; - } - } - else - { - fTerm = fLia; - } - - if ( i == nLoopEnd) - fTerm *= ( fPeriode + 1.0 - fIntEnd ); - - fVdb += fTerm; - } - return fVdb; -} - - -inline double DblMin( double a, double b ) -{ - return (a < b) ? a : b; -} - -void ScInterpreter::ScVDB() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVDB" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 5, 7 ) ) - { - double fWert, fRest, fDauer, fAnfang, fEnde, fFaktor, fVdb = 0.0; - sal_Bool bFlag; - if (nParamCount == 7) - bFlag = GetBool(); - else - bFlag = false; - if (nParamCount >= 6) - fFaktor = GetDouble(); - else - fFaktor = 2.0; - fEnde = GetDouble(); - fAnfang = GetDouble(); - fDauer = GetDouble(); - fRest = GetDouble(); - fWert = GetDouble(); - if (fAnfang < 0.0 || fEnde < fAnfang || fEnde > fDauer || fWert < 0.0 - || fRest > fWert || fFaktor <= 0.0) - PushIllegalArgument(); - else - { - double fIntStart = ::rtl::math::approxFloor(fAnfang); - double fIntEnd = ::rtl::math::approxCeil(fEnde); - sal_uLong nLoopStart = (sal_uLong) fIntStart; - sal_uLong nLoopEnd = (sal_uLong) fIntEnd; - - fVdb = 0.0; - if (bFlag) - { - for (sal_uLong i = nLoopStart + 1; i <= nLoopEnd; i++) - { - double fTerm = ScGetGDA(fWert, fRest, fDauer, (double) i, fFaktor); - - // Teilperioden am Anfang / Ende beruecksichtigen: - if ( i == nLoopStart+1 ) - fTerm *= ( DblMin( fEnde, fIntStart + 1.0 ) - fAnfang ); - else if ( i == nLoopEnd ) - fTerm *= ( fEnde + 1.0 - fIntEnd ); - - fVdb += fTerm; - } - } - else - { - - double fDauer1=fDauer; - - //@Die Frage aller Fragen: "Ist das hier richtig" - if(!::rtl::math::approxEqual(fAnfang,::rtl::math::approxFloor(fAnfang))) - { - if(fFaktor>1) - { - if(fAnfang>fDauer/2 || ::rtl::math::approxEqual(fAnfang,fDauer/2)) - { - double fPart=fAnfang-fDauer/2; - fAnfang=fDauer/2; - fEnde-=fPart; - fDauer1+=1; - } - } - } - - fWert-=ScInterVDB(fWert,fRest,fDauer,fDauer1,fAnfang,fFaktor); - fVdb=ScInterVDB(fWert,fRest,fDauer,fDauer-fAnfang,fEnde-fAnfang,fFaktor); - } - } - PushDouble(fVdb); - } -} - -void ScInterpreter::ScLaufz() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLaufz" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double nZukunft = GetDouble(); - double nGegenwart = GetDouble(); - double nZins = GetDouble(); - PushDouble(log(nZukunft / nGegenwart) / log(1.0 + nZins)); - } -} - -void ScInterpreter::ScLIA() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLIA" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double nDauer = GetDouble(); - double nRest = GetDouble(); - double nWert = GetDouble(); - PushDouble((nWert - nRest) / nDauer); - } -} - -double ScInterpreter::ScGetRmz(double fZins, double fZzr, double fBw, - double fZw, double fF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetRmz" ); - double fRmz; - if (fZins == 0.0) - fRmz = (fBw + fZw) / fZzr; - else - { - double fTerm = pow(1.0 + fZins, fZzr); - if (fF > 0.0) - fRmz = (fZw * fZins / (fTerm - 1.0) - + fBw * fZins / (1.0 - 1.0 / fTerm)) / (1.0+fZins); - else - fRmz = fZw * fZins / (fTerm - 1.0) - + fBw * fZins / (1.0 - 1.0 / fTerm); - } - return -fRmz; -} - -void ScInterpreter::ScRMZ() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRMZ" ); - double nZins, nZzr, nBw, nZw = 0, nFlag = 0; - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 5 ) ) - return; - if (nParamCount == 5) - nFlag = GetDouble(); - if (nParamCount >= 4) - nZw = GetDouble(); - nBw = GetDouble(); - nZzr = GetDouble(); - nZins = GetDouble(); - PushDouble(ScGetRmz(nZins, nZzr, nBw, nZw, nFlag)); -} - -void ScInterpreter::ScZGZ() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZGZ" ); - nFuncFmtType = NUMBERFORMAT_PERCENT; - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - double nZukunftswert = GetDouble(); - double nGegenwartswert = GetDouble(); - double nZeitraum = GetDouble(); - PushDouble(pow(nZukunftswert / nGegenwartswert, 1.0 / nZeitraum) - 1.0); - } -} - -double ScInterpreter::ScGetZw(double fZins, double fZzr, double fRmz, - double fBw, double fF) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZw" ); - double fZw; - if (fZins == 0.0) - fZw = fBw + fRmz * fZzr; - else - { - double fTerm = pow(1.0 + fZins, fZzr); - if (fF > 0.0) - fZw = fBw * fTerm + fRmz*(1.0 + fZins)*(fTerm - 1.0)/fZins; - else - fZw = fBw * fTerm + fRmz*(fTerm - 1.0)/fZins; - } - return -fZw; -} - -void ScInterpreter::ScZW() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZW" ); - double nZins, nZzr, nRmz, nBw = 0, nFlag = 0; - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 5 ) ) - return; - if (nParamCount == 5) - nFlag = GetDouble(); - if (nParamCount >= 4) - nBw = GetDouble(); - nRmz = GetDouble(); - nZzr = GetDouble(); - nZins = GetDouble(); - PushDouble(ScGetZw(nZins, nZzr, nRmz, nBw, nFlag)); -} - -void ScInterpreter::ScZZR() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZZR" ); - double nZins, nRmz, nBw, nZw = 0, nFlag = 0; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 5 ) ) - return; - if (nParamCount == 5) - nFlag = GetDouble(); - if (nParamCount >= 4) - nZw = GetDouble(); - nBw = GetDouble(); - nRmz = GetDouble(); - nZins = GetDouble(); - if (nZins == 0.0) - PushDouble(-(nBw + nZw)/nRmz); - else if (nFlag > 0.0) - PushDouble(log(-(nZins*nZw-nRmz*(1.0+nZins))/(nZins*nBw+nRmz*(1.0+nZins))) - /log(1.0+nZins)); - else - PushDouble(log(-(nZins*nZw-nRmz)/(nZins*nBw+nRmz))/log(1.0+nZins)); -} - -bool ScInterpreter::RateIteration( double fNper, double fPayment, double fPv, - double fFv, double fPayType, double & fGuess ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::RateIteration" ); - // See also #i15090# - // Newton-Raphson method: x(i+1) = x(i) - f(x(i)) / f'(x(i)) - // This solution handles integer and non-integer values of Nper different. - // If ODFF will constraint Nper to integer, the distinction of cases can be - // removed; only the integer-part is needed then. - bool bValid = true, bFound = false; - double fX, fXnew, fTerm, fTermDerivation; - double fGeoSeries, fGeoSeriesDerivation; - const sal_uInt16 nIterationsMax = 150; - sal_uInt16 nCount = 0; - const double fEpsilonSmall = 1.0E-14; - // convert any fPayType situation to fPayType == zero situation - fFv = fFv - fPayment * fPayType; - fPv = fPv + fPayment * fPayType; - if (fNper == ::rtl::math::round( fNper, 0, rtl_math_RoundingMode_Corrected )) - { // Nper is an integer value - fX = fGuess; - double fPowN, fPowNminus1; // for (1.0+fX)^Nper and (1.0+fX)^(Nper-1) - while (!bFound && nCount < nIterationsMax) - { - fPowNminus1 = pow( 1.0+fX, fNper-1.0); - fPowN = fPowNminus1 * (1.0+fX); - if (rtl::math::approxEqual( fabs(fX), 0.0)) - { - fGeoSeries = fNper; - fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0; - } - else - { - fGeoSeries = (fPowN-1.0)/fX; - fGeoSeriesDerivation = fNper * fPowNminus1 / fX - fGeoSeries / fX; - } - fTerm = fFv + fPv *fPowN+ fPayment * fGeoSeries; - fTermDerivation = fPv * fNper * fPowNminus1 + fPayment * fGeoSeriesDerivation; - if (fabs(fTerm) < fEpsilonSmall) - bFound = true; // will catch root which is at an extreme - else - { - if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0)) - fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope - else - fXnew = fX - fTerm / fTermDerivation; - nCount++; - // more accuracy not possible in oscillating cases - bFound = (fabs(fXnew - fX) < SCdEpsilon); - fX = fXnew; - } - } - // Gnumeric returns roots < -1, Excel gives an error in that cases, - // ODFF says nothing about it. Enable the statement, if you want Excel's - // behavior - //bValid =(fX >=-1.0); - } - else - { // Nper is not an integer value. - fX = (fGuess < -1.0) ? -1.0 : fGuess; // start with a valid fX - while (bValid && !bFound && nCount < nIterationsMax) - { - if (rtl::math::approxEqual( fabs(fX), 0.0)) - { - fGeoSeries = fNper; - fGeoSeriesDerivation = fNper * (fNper-1.0)/2.0; - } - else - { - fGeoSeries = (pow( 1.0+fX, fNper) - 1.0) / fX; - fGeoSeriesDerivation = fNper * pow( 1.0+fX, fNper-1.0) / fX - fGeoSeries / fX; - } - fTerm = fFv + fPv *pow(1.0 + fX,fNper)+ fPayment * fGeoSeries; - fTermDerivation = fPv * fNper * pow( 1.0+fX, fNper-1.0) + fPayment * fGeoSeriesDerivation; - if (fabs(fTerm) < fEpsilonSmall) - bFound = true; // will catch root which is at an extreme - else - { - if (rtl::math::approxEqual( fabs(fTermDerivation), 0.0)) - fXnew = fX + 1.1 * SCdEpsilon; // move away from zero slope - else - fXnew = fX - fTerm / fTermDerivation; - nCount++; - // more accuracy not possible in oscillating cases - bFound = (fabs(fXnew - fX) < SCdEpsilon); - fX = fXnew; - bValid = (fX >= -1.0); // otherwise pow(1.0+fX,fNper) will fail - } - } - } - fGuess = fX; // return approximate root - return bValid && bFound; -} - -// In Calc UI it is the function RATE(Nper;Pmt;Pv;Fv;Type;Guess) -void ScInterpreter::ScZins() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZins" ); - double fPv, fPayment, fNper; - // defaults for missing arguments, see ODFF spec - double fFv = 0, fPayType = 0, fGuess = 0.1; - bool bValid = true; - nFuncFmtType = NUMBERFORMAT_PERCENT; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 3, 6 ) ) - return; - if (nParamCount == 6) - fGuess = GetDouble(); - if (nParamCount >= 5) - fPayType = GetDouble(); - if (nParamCount >= 4) - fFv = GetDouble(); - fPv = GetDouble(); - fPayment = GetDouble(); - fNper = GetDouble(); - if (fNper <= 0.0) // constraint from ODFF spec - { - PushIllegalArgument(); - return; - } - // other values for fPayType might be meaningful, - // ODFF spec is not clear yet, enable statement if you want only 0 and 1 - //if (fPayType != 0.0) fPayType = 1.0; - bValid = RateIteration(fNper, fPayment, fPv, fFv, fPayType, fGuess); - if (!bValid) - SetError(errNoConvergence); - PushDouble(fGuess); -} - -double ScInterpreter::ScGetZinsZ(double fZins, double fZr, double fZzr, double fBw, - double fZw, double fF, double& fRmz) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetZinsZ" ); - fRmz = ScGetRmz(fZins, fZzr, fBw, fZw, fF); // fuer kapz auch bei fZr == 1 - double fZinsZ; - nFuncFmtType = NUMBERFORMAT_CURRENCY; - if (fZr == 1.0) - { - if (fF > 0.0) - fZinsZ = 0.0; - else - fZinsZ = -fBw; - } - else - { - if (fF > 0.0) - fZinsZ = ScGetZw(fZins, fZr-2.0, fRmz, fBw, 1.0) - fRmz; - else - fZinsZ = ScGetZw(fZins, fZr-1.0, fRmz, fBw, 0.0); - } - return fZinsZ * fZins; -} - -void ScInterpreter::ScZinsZ() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScZinsZ" ); - double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0; - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 4, 6 ) ) - return; - if (nParamCount == 6) - nFlag = GetDouble(); - if (nParamCount >= 5) - nZw = GetDouble(); - nBw = GetDouble(); - nZzr = GetDouble(); - nZr = GetDouble(); - nZins = GetDouble(); - if (nZr < 1.0 || nZr > nZzr) - PushIllegalArgument(); - else - { - double nRmz; - PushDouble(ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz)); - } -} - -void ScInterpreter::ScKapz() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKapz" ); - double nZins, nZr, nZzr, nBw, nZw = 0, nFlag = 0; - nFuncFmtType = NUMBERFORMAT_CURRENCY; - sal_uInt8 nParamCount = GetByte(); - if ( !MustHaveParamCount( nParamCount, 4, 6 ) ) - return; - if (nParamCount == 6) - nFlag = GetDouble(); - if (nParamCount >= 5) - nZw = GetDouble(); - nBw = GetDouble(); - nZzr = GetDouble(); - nZr = GetDouble(); - nZins = GetDouble(); - if (nZr < 1.0 || nZr > nZzr) - PushIllegalArgument(); - else - { - double nRmz; - double nZinsz = ScGetZinsZ(nZins, nZr, nZzr, nBw, nZw, nFlag, nRmz); - PushDouble(nRmz - nZinsz); - } -} - -void ScInterpreter::ScKumZinsZ() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumZinsZ" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - if ( MustHaveParamCount( GetByte(), 6 ) ) - { - double fZins, fZzr, fBw, fAnfang, fEnde, fF; - fF = GetDouble(); - fEnde = ::rtl::math::approxFloor(GetDouble()); - fAnfang = ::rtl::math::approxFloor(GetDouble()); - fBw = GetDouble(); - fZzr = GetDouble(); - fZins = GetDouble(); - if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 || - fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0) - PushIllegalArgument(); - else - { - sal_uLong nAnfang = (sal_uLong) fAnfang; - sal_uLong nEnde = (sal_uLong) fEnde ; - double fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF); - double fZinsZ = 0.0; - if (nAnfang == 1) - { - if (fF <= 0.0) - fZinsZ = -fBw; - nAnfang++; - } - for (sal_uLong i = nAnfang; i <= nEnde; i++) - { - if (fF > 0.0) - fZinsZ += ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz; - else - fZinsZ += ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0); - } - fZinsZ *= fZins; - PushDouble(fZinsZ); - } - } -} - -void ScInterpreter::ScKumKapZ() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScKumKapZ" ); - nFuncFmtType = NUMBERFORMAT_CURRENCY; - if ( MustHaveParamCount( GetByte(), 6 ) ) - { - double fZins, fZzr, fBw, fAnfang, fEnde, fF; - fF = GetDouble(); - fEnde = ::rtl::math::approxFloor(GetDouble()); - fAnfang = ::rtl::math::approxFloor(GetDouble()); - fBw = GetDouble(); - fZzr = GetDouble(); - fZins = GetDouble(); - if (fAnfang < 1.0 || fEnde < fAnfang || fZins <= 0.0 || - fEnde > fZzr || fZzr <= 0.0 || fBw <= 0.0) - PushIllegalArgument(); - else - { - double fRmz = ScGetRmz(fZins, fZzr, fBw, 0.0, fF); - double fKapZ = 0.0; - sal_uLong nAnfang = (sal_uLong) fAnfang; - sal_uLong nEnde = (sal_uLong) fEnde; - if (nAnfang == 1) - { - if (fF <= 0.0) - fKapZ = fRmz + fBw * fZins; - else - fKapZ = fRmz; - nAnfang++; - } - for (sal_uLong i = nAnfang; i <= nEnde; i++) - { - if (fF > 0.0) - fKapZ += fRmz - (ScGetZw(fZins, (double)(i-2), fRmz, fBw, 1.0) - fRmz) * fZins; - else - fKapZ += fRmz - ScGetZw(fZins, (double)(i-1), fRmz, fBw, 0.0) * fZins; - } - PushDouble(fKapZ); - } - } -} - -void ScInterpreter::ScEffektiv() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEffektiv" ); - nFuncFmtType = NUMBERFORMAT_PERCENT; - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double fPerioden = GetDouble(); - double fNominal = GetDouble(); - if (fPerioden < 1.0 || fNominal <= 0.0) - PushIllegalArgument(); - else - { - fPerioden = ::rtl::math::approxFloor(fPerioden); - PushDouble(pow(1.0 + fNominal/fPerioden, fPerioden) - 1.0); - } - } -} - -void ScInterpreter::ScNominal() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNominal" ); - nFuncFmtType = NUMBERFORMAT_PERCENT; - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double fPerioden = GetDouble(); - double fEffektiv = GetDouble(); - if (fPerioden < 1.0 || fEffektiv <= 0.0) - PushIllegalArgument(); - else - { - fPerioden = ::rtl::math::approxFloor(fPerioden); - PushDouble( (pow(fEffektiv + 1.0, 1.0 / fPerioden) - 1.0) * fPerioden ); - } - } -} - -void ScInterpreter::ScMod() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMod" ); - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double fVal2 = GetDouble(); // Denominator - double fVal1 = GetDouble(); // Numerator - if (fVal2 == floor(fVal2)) // a pure integral number stored in double - { - double fResult = fmod(fVal1,fVal2); - if ( (fResult != 0.0) && - ((fVal1 > 0.0 && fVal2 < 0.0) || (fVal1 < 0.0 && fVal2 > 0.0))) - fResult += fVal2 ; - PushDouble( fResult ); - } - else - { - PushDouble( ::rtl::math::approxSub( fVal1, - ::rtl::math::approxFloor(fVal1 / fVal2) * fVal2)); - } - } -} - -/** (Goal Seek) Find a value of x that is a root of f(x) - - This function is used internally for the goal seek operation. It uses the - Regula Falsi (aka false position) algorithm to find a root of f(x). The - start value and the target value are to be given by the user in the - goal seek dialog. The f(x) in this case is defined as the formula in the - formula cell minus target value. This function may also perform additional - search in the horizontal directions when the f(x) is discrete in order to - ensure a non-zero slope necessary for deriving a subsequent x that is - reasonably close to the root of interest. - - @change 24.10.2004 by Kohei Yoshida (kohei@openoffice.org) - - @see #i28955# -*/ -void ScInterpreter::ScBackSolver() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBackSolver" ); - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - sal_Bool bDoneIteration = false; - ScAddress aValueAdr, aFormulaAdr; - double fTargetVal = GetDouble(); - PopSingleRef( aFormulaAdr ); - PopSingleRef( aValueAdr ); - - if (nGlobalError == 0) - { - ScBaseCell* pVCell = GetCell( aValueAdr ); - // CELLTYPE_NOTE: kein Value aber von Formel referiert - sal_Bool bTempCell = (!pVCell || pVCell->GetCellType() == CELLTYPE_NOTE); - ScBaseCell* pFCell = GetCell( aFormulaAdr ); - - if ( ((pVCell && pVCell->GetCellType() == CELLTYPE_VALUE) || bTempCell) - && pFCell && pFCell->GetCellType() == CELLTYPE_FORMULA ) - { - ScRange aVRange( aValueAdr, aValueAdr ); // fuer SetDirty - double fSaveVal; // Original value to be restored later if necessary - ScPostIt* pNote = 0; - - if ( bTempCell ) - { - pNote = pVCell ? pVCell->ReleaseNote() : 0; - fSaveVal = 0.0; - pVCell = new ScValueCell( fSaveVal ); - pDok->PutCell( aValueAdr, pVCell ); - } - else - fSaveVal = GetCellValue( aValueAdr, pVCell ); - - const sal_uInt16 nMaxIter = 100; - const double fEps = 1E-10; - const double fDelta = 1E-6; - - double fBestX, fXPrev; - double fBestF, fFPrev; - fBestX = fXPrev = fSaveVal; - - ScFormulaCell* pFormula = (ScFormulaCell*) pFCell; - ScValueCell* pValue = (ScValueCell*) pVCell; - - pFormula->Interpret(); - sal_Bool bError = ( pFormula->GetErrCode() != 0 ); - // bError always corresponds with fF - - fFPrev = pFormula->GetValue() - fTargetVal; - - fBestF = fabs( fFPrev ); - if ( fBestF < fDelta ) - bDoneIteration = sal_True; - - double fX = fXPrev + fEps; - double fF = fFPrev; - double fSlope; - - sal_uInt16 nIter = 0; - - sal_Bool bHorMoveError = false; - // Nach der Regula Falsi Methode - while ( !bDoneIteration && ( nIter++ < nMaxIter ) ) - { - pValue->SetValue( fX ); - pDok->SetDirty( aVRange ); - pFormula->Interpret(); - bError = ( pFormula->GetErrCode() != 0 ); - fF = pFormula->GetValue() - fTargetVal; - - if ( fF == fFPrev && !bError ) - { - // HORIZONTAL SEARCH: Keep moving x in both directions until the f(x) - // becomes different from the previous f(x). This routine is needed - // when a given function is discrete, in which case the resulting slope - // may become zero which ultimately causes the goal seek operation - // to fail. #i28955# - - sal_uInt16 nHorIter = 0; - const double fHorStepAngle = 5.0; - const double fHorMaxAngle = 80.0; - int nHorMaxIter = static_cast<int>( fHorMaxAngle / fHorStepAngle ); - sal_Bool bDoneHorMove = false; - - while ( !bDoneHorMove && !bHorMoveError && nHorIter++ < nHorMaxIter ) - { - double fHorAngle = fHorStepAngle * static_cast<double>( nHorIter ); - double fHorTangent = ::rtl::math::tan( fHorAngle * F_PI / 180 ); - - sal_uInt16 nIdx = 0; - while( nIdx++ < 2 && !bDoneHorMove ) - { - double fHorX; - if ( nIdx == 1 ) - fHorX = fX + fabs(fF)*fHorTangent; - else - fHorX = fX - fabs(fF)*fHorTangent; - - pValue->SetValue( fHorX ); - pDok->SetDirty( aVRange ); - pFormula->Interpret(); - bHorMoveError = ( pFormula->GetErrCode() != 0 ); - if ( bHorMoveError ) - break; - - fF = pFormula->GetValue() - fTargetVal; - if ( fF != fFPrev ) - { - fX = fHorX; - bDoneHorMove = sal_True; - } - } - } - if ( !bDoneHorMove ) - bHorMoveError = sal_True; - } - - if ( bError ) - { - // move closer to last valid value (fXPrev), keep fXPrev & fFPrev - double fDiff = ( fXPrev - fX ) / 2; - if (fabs(fDiff) < fEps) - fDiff = (fDiff < 0.0) ? - fEps : fEps; - fX += fDiff; - } - else if ( bHorMoveError ) - break; - else if ( fabs(fF) < fDelta ) - { - // converged to root - fBestX = fX; - bDoneIteration = sal_True; - } - else - { - if ( fabs(fF) + fDelta < fBestF ) - { - fBestX = fX; - fBestF = fabs(fF); - } - - if ( ( fXPrev - fX ) != 0 ) - { - fSlope = ( fFPrev - fF ) / ( fXPrev - fX ); - if ( fabs( fSlope ) < fEps ) - fSlope = fSlope < 0.0 ? -fEps : fEps; - } - else - fSlope = fEps; - - fXPrev = fX; - fFPrev = fF; - fX = fX - ( fF / fSlope ); - } - } - - // Try a nice rounded input value if possible. - const double fNiceDelta = (bDoneIteration && fabs(fBestX) >= 1e-3 ? 1e-3 : fDelta); - double nX = ::rtl::math::approxFloor((fBestX / fNiceDelta) + 0.5) * fNiceDelta; - - if ( bDoneIteration ) - { - pValue->SetValue( nX ); - pDok->SetDirty( aVRange ); - pFormula->Interpret(); - if ( fabs( pFormula->GetValue() - fTargetVal ) > fabs( fF ) ) - nX = fBestX; - } - else if ( bError || bHorMoveError ) - { - nX = fBestX; - } - if ( bTempCell ) - { - pVCell = pNote ? new ScNoteCell( pNote ) : 0; - pDok->PutCell( aValueAdr, pVCell ); - } - else - pValue->SetValue( fSaveVal ); - pDok->SetDirty( aVRange ); - pFormula->Interpret(); - if ( !bDoneIteration ) - SetError(NOTAVAILABLE); - PushDouble(nX); - } - else - { - if ( !bDoneIteration ) - SetError(NOTAVAILABLE); - PushInt(0); // falsche Zelltypen - } - } - else - { - if ( !bDoneIteration ) - SetError(NOTAVAILABLE); - PushInt(0); // nGlobalError - } - } -} - -void ScInterpreter::ScIntersect() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIntersect" ); - formula::FormulaTokenRef p2nd = PopToken(); - formula::FormulaTokenRef p1st = PopToken(); - - if (nGlobalError || !p2nd || !p1st) - { - PushIllegalArgument(); - return; - } - - StackVar sv1 = p1st->GetType(); - StackVar sv2 = p2nd->GetType(); - if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) || - (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)) - { - PushIllegalArgument(); - return; - } - - ScToken* x1 = static_cast<ScToken*>(p1st.get()); - ScToken* x2 = static_cast<ScToken*>(p2nd.get()); - if (sv1 == svRefList || sv2 == svRefList) - { - // Now this is a bit nasty but it simplifies things, and having - // intersections with lists isn't too common, if at all.. - // Convert a reference to list. - ScToken* xt[2] = { x1, x2 }; - StackVar sv[2] = { sv1, sv2 }; - for (size_t i=0; i<2; ++i) - { - if (sv[i] == svSingleRef) - { - ScComplexRefData aRef; - aRef.Ref1 = aRef.Ref2 = xt[i]->GetSingleRef(); - xt[i] = new ScRefListToken; - xt[i]->GetRefList()->push_back( aRef); - } - else if (sv[i] == svDoubleRef) - { - ScComplexRefData aRef = xt[i]->GetDoubleRef(); - xt[i] = new ScRefListToken; - xt[i]->GetRefList()->push_back( aRef); - } - } - x1 = xt[0], x2 = xt[1]; - - x1->CalcAbsIfRel( aPos); - x2->CalcAbsIfRel( aPos); - ScTokenRef xRes = new ScRefListToken; - ScRefList* pRefList = xRes->GetRefList(); - ScRefList::const_iterator end1( x1->GetRefList()->end()); - ScRefList::const_iterator end2( x2->GetRefList()->end()); - for (ScRefList::const_iterator it1( x1->GetRefList()->begin()); - it1 != end1; ++it1) - { - const ScSingleRefData& r11 = (*it1).Ref1; - const ScSingleRefData& r12 = (*it1).Ref2; - for (ScRefList::const_iterator it2( x2->GetRefList()->begin()); - it2 != end2; ++it2) - { - const ScSingleRefData& r21 = (*it2).Ref1; - const ScSingleRefData& r22 = (*it2).Ref2; - SCCOL nCol1 = ::std::max( r11.nCol, r21.nCol); - SCROW nRow1 = ::std::max( r11.nRow, r21.nRow); - SCTAB nTab1 = ::std::max( r11.nTab, r21.nTab); - SCCOL nCol2 = ::std::min( r12.nCol, r22.nCol); - SCROW nRow2 = ::std::min( r12.nRow, r22.nRow); - SCTAB nTab2 = ::std::min( r12.nTab, r22.nTab); - if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1) - ; // nothing - else - { - ScComplexRefData aRef; - aRef.InitRange( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); - pRefList->push_back( aRef); - } - } - } - size_t n = pRefList->size(); - if (!n) - PushError( errNoRef); - else if (n == 1) - { - const ScComplexRefData& rRef = (*pRefList)[0]; - if (rRef.Ref1 == rRef.Ref2) - PushTempToken( new ScSingleRefToken( rRef.Ref1)); - else - PushTempToken( new ScDoubleRefToken( rRef)); - } - else - PushTempToken( xRes.get()); - } - else - { - ScToken* pt[2] = { x1, x2 }; - StackVar sv[2] = { sv1, sv2 }; - SCCOL nC1[2], nC2[2]; - SCROW nR1[2], nR2[2]; - SCTAB nT1[2], nT2[2]; - for (size_t i=0; i<2; ++i) - { - switch (sv[i]) - { - case svSingleRef: - case svDoubleRef: - pt[i]->CalcAbsIfRel( aPos); - { - const ScSingleRefData& r = pt[i]->GetSingleRef(); - nC1[i] = r.nCol; - nR1[i] = r.nRow; - nT1[i] = r.nTab; - } - if (sv[i] == svDoubleRef) - { - const ScSingleRefData& r = pt[i]->GetSingleRef2(); - nC2[i] = r.nCol; - nR2[i] = r.nRow; - nT2[i] = r.nTab; - } - else - { - nC2[i] = nC1[i]; - nR2[i] = nR1[i]; - nT2[i] = nT1[i]; - } - break; - default: - ; // nothing, prevent compiler warning - } - } - SCCOL nCol1 = ::std::max( nC1[0], nC1[1]); - SCROW nRow1 = ::std::max( nR1[0], nR1[1]); - SCTAB nTab1 = ::std::max( nT1[0], nT1[1]); - SCCOL nCol2 = ::std::min( nC2[0], nC2[1]); - SCROW nRow2 = ::std::min( nR2[0], nR2[1]); - SCTAB nTab2 = ::std::min( nT2[0], nT2[1]); - if (nCol2 < nCol1 || nRow2 < nRow1 || nTab2 < nTab1) - PushError( errNoRef); - else if (nCol2 == nCol1 && nRow2 == nRow1 && nTab2 == nTab1) - PushSingleRef( nCol1, nRow1, nTab1); - else - PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); - } -} - - -void ScInterpreter::ScRangeFunc() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRangeFunc" ); - formula::FormulaTokenRef x2 = PopToken(); - formula::FormulaTokenRef x1 = PopToken(); - - if (nGlobalError || !x2 || !x1) - { - PushIllegalArgument(); - return; - } - FormulaTokenRef xRes = ScToken::ExtendRangeReference( *x1, *x2, aPos, false); - if (!xRes) - PushIllegalArgument(); - else - PushTempToken( xRes.get()); -} - - -void ScInterpreter::ScUnionFunc() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnionFunc" ); - formula::FormulaTokenRef p2nd = PopToken(); - formula::FormulaTokenRef p1st = PopToken(); - - if (nGlobalError || !p2nd || !p1st) - { - PushIllegalArgument(); - return; - } - - StackVar sv1 = p1st->GetType(); - StackVar sv2 = p2nd->GetType(); - if ((sv1 != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList) || - (sv2 != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)) - { - PushIllegalArgument(); - return; - } - - ScToken* x1 = static_cast<ScToken*>(p1st.get()); - ScToken* x2 = static_cast<ScToken*>(p2nd.get()); - - - ScTokenRef xRes; - // Append to an existing RefList if there is one. - if (sv1 == svRefList) - { - xRes = x1; - sv1 = svUnknown; // mark as handled - } - else if (sv2 == svRefList) - { - xRes = x2; - sv2 = svUnknown; // mark as handled - } - else - xRes = new ScRefListToken; - ScRefList* pRes = xRes->GetRefList(); - ScToken* pt[2] = { x1, x2 }; - StackVar sv[2] = { sv1, sv2 }; - for (size_t i=0; i<2; ++i) - { - if (pt[i] == xRes) - continue; - switch (sv[i]) - { - case svSingleRef: - { - ScComplexRefData aRef; - aRef.Ref1 = aRef.Ref2 = pt[i]->GetSingleRef(); - pRes->push_back( aRef); - } - break; - case svDoubleRef: - pRes->push_back( pt[i]->GetDoubleRef()); - break; - case svRefList: - { - const ScRefList* p = pt[i]->GetRefList(); - ScRefList::const_iterator it( p->begin()); - ScRefList::const_iterator end( p->end()); - for ( ; it != end; ++it) - { - pRes->push_back( *it); - } - } - break; - default: - ; // nothing, prevent compiler warning - } - } - ValidateRef( *pRes); // set #REF! if needed - PushTempToken( xRes.get()); -} - - -void ScInterpreter::ScCurrent() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrent" ); - FormulaTokenRef xTok( PopToken()); - if (xTok) - { - PushTempToken( xTok.get()); - PushTempToken( xTok.get()); - } - else - PushError( errUnknownStackVariable); -} - -void ScInterpreter::ScStyle() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStyle" ); - sal_uInt8 nParamCount = GetByte(); - if (nParamCount >= 1 && nParamCount <= 3) - { - String aStyle2; // Vorlage nach Timer - if (nParamCount >= 3) - aStyle2 = GetString(); - long nTimeOut = 0; // Timeout - if (nParamCount >= 2) - nTimeOut = (long)(GetDouble()*1000.0); - String aStyle1 = GetString(); // Vorlage fuer sofort - - if (nTimeOut < 0) - nTimeOut = 0; - - // - // Request ausfuehren, um Vorlage anzuwenden - // - - if ( !pDok->IsClipOrUndo() ) - { - SfxObjectShell* pShell = pDok->GetDocumentShell(); - if (pShell) - { - //! notify object shell directly - - ScRange aRange(aPos); - ScAutoStyleHint aHint( aRange, aStyle1, nTimeOut, aStyle2 ); - pShell->Broadcast( aHint ); - } - } - - PushDouble(0.0); - } - else - PushIllegalParameter(); -} - -ScDdeLink* lcl_GetDdeLink( sfx2::LinkManager* pLinkMgr, - const String& rA, const String& rT, const String& rI, sal_uInt8 nM ) -{ - sal_uInt16 nCount = pLinkMgr->GetLinks().Count(); - for (sal_uInt16 i=0; i<nCount; i++ ) - { - ::sfx2::SvBaseLink* pBase = *pLinkMgr->GetLinks()[i]; - if (pBase->ISA(ScDdeLink)) - { - ScDdeLink* pLink = (ScDdeLink*)pBase; - if ( pLink->GetAppl() == rA && - pLink->GetTopic() == rT && - pLink->GetItem() == rI && - pLink->GetMode() == nM ) - return pLink; - } - } - - return NULL; -} - -void ScInterpreter::ScDde() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDde" ); - // Applikation, Datei, Bereich - // Application, Topic, Item - - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 3, 4 ) ) - { - sal_uInt8 nMode = SC_DDE_DEFAULT; - if (nParamCount == 4) - nMode = (sal_uInt8) ::rtl::math::approxFloor(GetDouble()); - String aItem = GetString(); - String aTopic = GetString(); - String aAppl = GetString(); - - if (nMode > SC_DDE_TEXT) - nMode = SC_DDE_DEFAULT; - - // temporary documents (ScFunctionAccess) have no DocShell - // and no LinkManager -> abort - - sfx2::LinkManager* pLinkMgr = pDok->GetLinkManager(); - if (!pLinkMgr) - { - PushNoValue(); - return; - } - - // Nach dem Laden muss neu interpretiert werden (Verknuepfungen aufbauen) - - if ( pMyFormulaCell->GetCode()->IsRecalcModeNormal() ) - pMyFormulaCell->GetCode()->SetRecalcModeOnLoad(); - - // solange der Link nicht ausgewertet ist, Idle abklemmen - // (um zirkulaere Referenzen zu vermeiden) - - sal_Bool bOldDis = pDok->IsIdleDisabled(); - pDok->DisableIdle( sal_True ); - - // Link-Objekt holen / anlegen - - ScDdeLink* pLink = lcl_GetDdeLink( pLinkMgr, aAppl, aTopic, aItem, nMode ); - - //! Dde-Links (zusaetzlich) effizienter am Dokument speichern !!!!! - // ScDdeLink* pLink = pDok->GetDdeLink( aAppl, aTopic, aItem ); - - sal_Bool bWasError = ( pMyFormulaCell->GetRawError() != 0 ); - - if (!pLink) - { - pLink = new ScDdeLink( pDok, aAppl, aTopic, aItem, nMode ); - pLinkMgr->InsertDDELink( pLink, aAppl, aTopic, aItem ); - if ( pLinkMgr->GetLinks().Count() == 1 ) // erster ? - { - SfxBindings* pBindings = pDok->GetViewBindings(); - if (pBindings) - pBindings->Invalidate( SID_LINKS ); // Link-Manager enablen - } - - //! asynchron auswerten ??? - pLink->TryUpdate(); // TryUpdate ruft Update nicht mehrfach auf - - // StartListening erst nach dem Update, sonst circular reference - pMyFormulaCell->StartListening( *pLink ); - } - else - { - pMyFormulaCell->StartListening( *pLink ); - } - - // Wenn aus dem Reschedule beim Ausfuehren des Links ein Fehler - // (z.B. zirkulaere Referenz) entstanden ist, der vorher nicht da war, - // das Fehler-Flag zuruecksetzen: - - if ( pMyFormulaCell->GetRawError() && !bWasError ) - pMyFormulaCell->SetErrCode(0); - - // Wert abfragen - - const ScMatrix* pLinkMat = pLink->GetResult(); - if (pLinkMat) - { - SCSIZE nC, nR; - pLinkMat->GetDimensions(nC, nR); - ScMatrixRef pNewMat = GetNewMat( nC, nR); - if (pNewMat) - { - pLinkMat->MatCopy(*pNewMat); // kopieren - PushMatrix( pNewMat ); - } - else - PushIllegalArgument(); - } - else - PushNA(); - - pDok->DisableIdle( bOldDis ); - pLinkMgr->CloseCachedComps(); - } -} - -void ScInterpreter::ScBase() -{ // Value, Base [, MinLen] - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 2, 3 ) ) - { - static const sal_Unicode pDigits[] = { - '0','1','2','3','4','5','6','7','8','9', - 'A','B','C','D','E','F','G','H','I','J','K','L','M', - 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', - 0 - }; - static const int nDigits = SAL_N_ELEMENTS(pDigits)-1; - xub_StrLen nMinLen; - if ( nParamCount == 3 ) - { - double fLen = ::rtl::math::approxFloor( GetDouble() ); - if ( 1.0 <= fLen && fLen < STRING_MAXLEN ) - nMinLen = (xub_StrLen) fLen; - else if ( fLen == 0.0 ) - nMinLen = 1; - else - nMinLen = 0; // Error - } - else - nMinLen = 1; - double fBase = ::rtl::math::approxFloor( GetDouble() ); - double fVal = ::rtl::math::approxFloor( GetDouble() ); - double fChars = ((fVal > 0.0 && fBase > 0.0) ? - (ceil( log( fVal ) / log( fBase ) ) + 2.0) : - 2.0); - if ( fChars >= STRING_MAXLEN ) - nMinLen = 0; // Error - - if ( !nGlobalError && nMinLen && 2 <= fBase && fBase <= nDigits && 0 <= fVal ) - { - const xub_StrLen nConstBuf = 128; - sal_Unicode aBuf[nConstBuf]; - xub_StrLen nBuf = Max( (xub_StrLen) fChars, (xub_StrLen) (nMinLen+1) ); - sal_Unicode* pBuf = (nBuf <= nConstBuf ? aBuf : new sal_Unicode[nBuf]); - for ( xub_StrLen j = 0; j < nBuf; ++j ) - { - pBuf[j] = '0'; - } - sal_Unicode* p = pBuf + nBuf - 1; - *p = 0; - if ( fVal <= (sal_uLong)(~0) ) - { - sal_uLong nVal = (sal_uLong) fVal; - sal_uLong nBase = (sal_uLong) fBase; - while ( nVal && p > pBuf ) - { - *--p = pDigits[ nVal % nBase ]; - nVal /= nBase; - } - fVal = (double) nVal; - } - else - { - sal_Bool bDirt = false; - while ( fVal && p > pBuf ) - { -//! mit fmod Rundungsfehler ab 2**48 -// double fDig = ::rtl::math::approxFloor( fmod( fVal, fBase ) ); -// so ist es etwas besser - double fInt = ::rtl::math::approxFloor( fVal / fBase ); - double fMult = fInt * fBase; -#if OSL_DEBUG_LEVEL > 1 - // =BASIS(1e308;36) => GPF mit - // nDig = (size_t) ::rtl::math::approxFloor( fVal - fMult ); - // trotz vorheriger Pruefung ob fVal >= fMult - double fDebug1 = fVal - fMult; - // fVal := 7,5975311883090e+290 - // fMult := 7,5975311883090e+290 - // fDebug1 := 1,3848924157003e+275 <- RoundOff-Error - // fVal != fMult, aber: ::rtl::math::approxEqual( fVal, fMult ) == TRUE - double fDebug2 = ::rtl::math::approxSub( fVal, fMult ); - // und ::rtl::math::approxSub( fVal, fMult ) == 0 - double fDebug3 = ( fInt ? fVal / fInt : 0.0 ); - // Nach dem strange fDebug1 und fVal < fMult ist eigentlich - // fDebug2 == fBase, trotzdem wird das mit einem Vergleich - // nicht erkannt, dann schlaegt bDirt zu und alles wird wieder gut.. - - // prevent compiler warnings - (void)fDebug1; (void)fDebug2; (void)fDebug3; -#endif - size_t nDig; - if ( fVal < fMult ) - { // da ist was gekippt - bDirt = sal_True; - nDig = 0; - } - else - { - double fDig = ::rtl::math::approxFloor( ::rtl::math::approxSub( fVal, fMult ) ); - if ( bDirt ) - { - bDirt = false; - --fDig; - } - if ( fDig <= 0.0 ) - nDig = 0; - else if ( fDig >= fBase ) - nDig = ((size_t) fBase) - 1; - else - nDig = (size_t) fDig; - } - *--p = pDigits[ nDig ]; - fVal = fInt; - } - } - if ( fVal ) - PushError( errStringOverflow ); - else - { - if ( nBuf - (p - pBuf) <= nMinLen ) - p = pBuf + nBuf - 1 - nMinLen; - PushStringBuffer( p ); - } - if ( pBuf != aBuf ) - delete [] pBuf; - } - else - PushIllegalArgument(); - } -} - - -void ScInterpreter::ScDecimal() -{ // Text, Base - if ( MustHaveParamCount( GetByte(), 2 ) ) - { - double fBase = ::rtl::math::approxFloor( GetDouble() ); - String aStr( GetString() ); - if ( !nGlobalError && 2 <= fBase && fBase <= 36 ) - { - double fVal = 0.0; - int nBase = (int) fBase; - register const sal_Unicode* p = aStr.GetBuffer(); - while ( *p == ' ' || *p == '\t' ) - p++; // strip leading white space - if ( nBase == 16 ) - { // evtl. hex-prefix strippen - if ( *p == 'x' || *p == 'X' ) - p++; - else if ( *p == '0' && (*(p+1) == 'x' || *(p+1) == 'X') ) - p += 2; - } - while ( *p ) - { - int n; - if ( '0' <= *p && *p <= '9' ) - n = *p - '0'; - else if ( 'A' <= *p && *p <= 'Z' ) - n = 10 + (*p - 'A'); - else if ( 'a' <= *p && *p <= 'z' ) - n = 10 + (*p - 'a'); - else - n = nBase; - if ( nBase <= n ) - { - if ( *(p+1) == 0 && - ( (nBase == 2 && (*p == 'b' || *p == 'B')) - ||(nBase == 16 && (*p == 'h' || *p == 'H')) ) - ) - ; // 101b und F00Dh sind ok - else - { - PushIllegalArgument(); - return ; - } - } - else - fVal = fVal * fBase + n; - p++; - - } - PushDouble( fVal ); - } - else - PushIllegalArgument(); - } -} - - -void ScInterpreter::ScConvert() -{ // Value, FromUnit, ToUnit - if ( MustHaveParamCount( GetByte(), 3 ) ) - { - String aToUnit( GetString() ); - String aFromUnit( GetString() ); - double fVal = GetDouble(); - if ( nGlobalError ) - PushError( nGlobalError); - else - { // erst die angegebene Reihenfolge suchen, wenn nicht gefunden den Kehrwert - double fConv; - if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aFromUnit, aToUnit ) ) - PushDouble( fVal * fConv ); - else if ( ScGlobal::GetUnitConverter()->GetValue( fConv, aToUnit, aFromUnit ) ) - PushDouble( fVal / fConv ); - else - PushNA(); - } - } -} - - -void ScInterpreter::ScRoman() -{ // Value [Mode] - sal_uInt8 nParamCount = GetByte(); - if( MustHaveParamCount( nParamCount, 1, 2 ) ) - { - double fMode = (nParamCount == 2) ? ::rtl::math::approxFloor( GetDouble() ) : 0.0; - double fVal = ::rtl::math::approxFloor( GetDouble() ); - if( nGlobalError ) - PushError( nGlobalError); - else if( (fMode >= 0.0) && (fMode < 5.0) && (fVal >= 0.0) && (fVal < 4000.0) ) - { - static const sal_Unicode pChars[] = { 'M', 'D', 'C', 'L', 'X', 'V', 'I' }; - static const sal_uInt16 pValues[] = { 1000, 500, 100, 50, 10, 5, 1 }; - static const sal_uInt16 nMaxIndex = (sal_uInt16)(SAL_N_ELEMENTS(pValues) - 1); - - String aRoman; - sal_uInt16 nVal = (sal_uInt16) fVal; - sal_uInt16 nMode = (sal_uInt16) fMode; - - for( sal_uInt16 i = 0; i <= nMaxIndex / 2; i++ ) - { - sal_uInt16 nIndex = 2 * i; - sal_uInt16 nDigit = nVal / pValues[ nIndex ]; - - if( (nDigit % 5) == 4 ) - { - sal_uInt16 nIndex2 = (nDigit == 4) ? nIndex - 1 : nIndex - 2; - sal_uInt16 nSteps = 0; - while( (nSteps < nMode) && (nIndex < nMaxIndex) ) - { - nSteps++; - if( pValues[ nIndex2 ] - pValues[ nIndex + 1 ] <= nVal ) - nIndex++; - else - nSteps = nMode; - } - aRoman += pChars[ nIndex ]; - aRoman += pChars[ nIndex2 ]; - nVal = sal::static_int_cast<sal_uInt16>( nVal + pValues[ nIndex ] ); - nVal = sal::static_int_cast<sal_uInt16>( nVal - pValues[ nIndex2 ] ); - } - else - { - if( nDigit > 4 ) - aRoman += pChars[ nIndex - 1 ]; - aRoman.Expand( aRoman.Len() + (nDigit % 5), pChars[ nIndex ] ); - nVal %= pValues[ nIndex ]; - } - } - - PushString( aRoman ); - } - else - PushIllegalArgument(); - } -} - - -sal_Bool lcl_GetArabicValue( sal_Unicode cChar, sal_uInt16& rnValue, sal_Bool& rbIsDec ) -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBase" ); - switch( cChar ) - { - case 'M': rnValue = 1000; rbIsDec = sal_True; break; - case 'D': rnValue = 500; rbIsDec = false; break; - case 'C': rnValue = 100; rbIsDec = sal_True; break; - case 'L': rnValue = 50; rbIsDec = false; break; - case 'X': rnValue = 10; rbIsDec = sal_True; break; - case 'V': rnValue = 5; rbIsDec = false; break; - case 'I': rnValue = 1; rbIsDec = sal_True; break; - default: return false; - } - return sal_True; -} - - -void ScInterpreter::ScArabic() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArabic" ); - String aRoman( GetString() ); - if( nGlobalError ) - PushError( nGlobalError); - else - { - aRoman.ToUpperAscii(); - - sal_uInt16 nValue = 0; - sal_uInt16 nValidRest = 3999; - sal_uInt16 nCharIndex = 0; - sal_uInt16 nCharCount = aRoman.Len(); - sal_Bool bValid = sal_True; - - while( bValid && (nCharIndex < nCharCount) ) - { - sal_uInt16 nDigit1 = 0; - sal_uInt16 nDigit2 = 0; - sal_Bool bIsDec1 = false; - sal_Bool bIsDec2 = false; - bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex ), nDigit1, bIsDec1 ); - if( bValid && (nCharIndex + 1 < nCharCount) ) - bValid = lcl_GetArabicValue( aRoman.GetChar( nCharIndex + 1 ), nDigit2, bIsDec2 ); - if( bValid ) - { - if( nDigit1 >= nDigit2 ) - { - nValue = sal::static_int_cast<sal_uInt16>( nValue + nDigit1 ); - nValidRest %= (nDigit1 * (bIsDec1 ? 5 : 2)); - bValid = (nValidRest >= nDigit1); - if( bValid ) - nValidRest = sal::static_int_cast<sal_uInt16>( nValidRest - nDigit1 ); - nCharIndex++; - } - else if( nDigit1 * 2 != nDigit2 ) - { - sal_uInt16 nDiff = nDigit2 - nDigit1; - nValue = sal::static_int_cast<sal_uInt16>( nValue + nDiff ); - bValid = (nValidRest >= nDiff); - if( bValid ) - nValidRest = nDigit1 - 1; - nCharIndex += 2; - } - else - bValid = false; - } - } - if( bValid ) - PushInt( nValue ); - else - PushIllegalArgument(); - } -} - - -void ScInterpreter::ScHyperLink() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHyperLink" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 1, 2 ) ) - { - double fVal = 0.0; - String aStr; - ScMatValType nResultType = SC_MATVAL_STRING; - - if ( nParamCount == 2 ) - { - switch ( GetStackType() ) - { - case svDouble: - fVal = GetDouble(); - nResultType = SC_MATVAL_VALUE; - break; - case svString: - aStr = GetString(); - break; - case svSingleRef: - case svDoubleRef: - { - ScAddress aAdr; - if ( !PopDoubleRefOrSingleRef( aAdr ) ) - break; - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellEmptyData( pCell)) - nResultType = SC_MATVAL_EMPTY; - else - { - sal_uInt16 nErr = GetCellErrCode( pCell ); - if (nErr) - SetError( nErr); - else if (HasCellValueData( pCell)) - { - fVal = GetCellValue( aAdr, pCell ); - nResultType = SC_MATVAL_VALUE; - } - else - GetCellString( aStr, pCell ); - } - } - break; - case svMatrix: - nResultType = GetDoubleOrStringFromMatrix( fVal, aStr); - break; - case svMissing: - case svEmptyCell: - Pop(); - // mimic xcl - fVal = 0.0; - nResultType = SC_MATVAL_VALUE; - break; - default: - PopError(); - SetError( errIllegalArgument); - } - } - String aUrl = GetString(); - ScMatrixRef pResMat = GetNewMat( 1, 2); - if (nGlobalError) - { - fVal = CreateDoubleError( nGlobalError); - nResultType = SC_MATVAL_VALUE; - } - if (nParamCount == 2 || nGlobalError) - { - if (ScMatrix::IsValueType( nResultType)) - pResMat->PutDouble( fVal, 0); - else if (ScMatrix::IsRealStringType( nResultType)) - pResMat->PutString( aStr, 0); - else // EmptyType, EmptyPathType, mimic xcl - pResMat->PutDouble( 0.0, 0 ); - } - else - pResMat->PutString( aUrl, 0 ); - pResMat->PutString( aUrl, 1 ); - bMatrixFormula = true; - PushMatrix(pResMat); - } -} - - -sal_Bool lclConvertMoney( const String& aSearchUnit, double& rfRate, int& rnDec ) -{ - struct ConvertInfo - { - const sal_Char* pCurrText; - double fRate; - int nDec; - }; - ConvertInfo aConvertTable[] = { - { "EUR", 1.0, 2 }, - { "ATS", 13.7603, 2 }, - { "BEF", 40.3399, 0 }, - { "DEM", 1.95583, 2 }, - { "ESP", 166.386, 0 }, - { "FIM", 5.94573, 2 }, - { "FRF", 6.55957, 2 }, - { "IEP", 0.787564, 2 }, - { "ITL", 1936.27, 0 }, - { "LUF", 40.3399, 0 }, - { "NLG", 2.20371, 2 }, - { "PTE", 200.482, 2 }, - { "GRD", 340.750, 2 }, - { "SIT", 239.640, 2 }, - { "MTL", 0.429300, 2 }, - { "CYP", 0.585274, 2 }, - { "SKK", 30.1260, 2 } - }; - - const size_t nConversionCount = SAL_N_ELEMENTS(aConvertTable); - for ( size_t i = 0; i < nConversionCount; i++ ) - if ( aSearchUnit.EqualsIgnoreCaseAscii( aConvertTable[i].pCurrText ) ) - { - rfRate = aConvertTable[i].fRate; - rnDec = aConvertTable[i].nDec; - return sal_True; - } - return false; -} - -void ScInterpreter::ScEuroConvert() -{ //Value, FromUnit, ToUnit[, FullPrecision, [TriangulationPrecision]] - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 3, 5 ) ) - { - double nPrecision = 0.0; - if ( nParamCount == 5 ) - { - nPrecision = ::rtl::math::approxFloor(GetDouble()); - if ( nPrecision < 3 ) - { - PushIllegalArgument(); - return; - } - } - sal_Bool bFullPrecision = false; - if ( nParamCount >= 4 ) - bFullPrecision = GetBool(); - String aToUnit( GetString() ); - String aFromUnit( GetString() ); - double fVal = GetDouble(); - if ( nGlobalError ) - PushError( nGlobalError); - else - { - double fFromRate; - double fToRate; - int nFromDec; - int nToDec; - String aEur( RTL_CONSTASCII_USTRINGPARAM("EUR")); - if ( lclConvertMoney( aFromUnit, fFromRate, nFromDec ) - && lclConvertMoney( aToUnit, fToRate, nToDec ) ) - { - double fRes; - if ( aFromUnit.EqualsIgnoreCaseAscii( aToUnit ) ) - fRes = fVal; - else - { - if ( aFromUnit.EqualsIgnoreCaseAscii( aEur ) ) - fRes = fVal * fToRate; - else - { - double fIntermediate = fVal / fFromRate; - if ( nPrecision ) - fIntermediate = ::rtl::math::round( fIntermediate, - (int) nPrecision ); - fRes = fIntermediate * fToRate; - } - if ( !bFullPrecision ) - fRes = ::rtl::math::round( fRes, nToDec ); - } - PushDouble( fRes ); - } - else - PushIllegalArgument(); - } - } -} - - -// BAHTTEXT =================================================================== - -#define UTF8_TH_0 "\340\270\250\340\270\271\340\270\231\340\270\242\340\271\214" -#define UTF8_TH_1 "\340\270\253\340\270\231\340\270\266\340\271\210\340\270\207" -#define UTF8_TH_2 "\340\270\252\340\270\255\340\270\207" -#define UTF8_TH_3 "\340\270\252\340\270\262\340\270\241" -#define UTF8_TH_4 "\340\270\252\340\270\265\340\271\210" -#define UTF8_TH_5 "\340\270\253\340\271\211\340\270\262" -#define UTF8_TH_6 "\340\270\253\340\270\201" -#define UTF8_TH_7 "\340\271\200\340\270\210\340\271\207\340\270\224" -#define UTF8_TH_8 "\340\271\201\340\270\233\340\270\224" -#define UTF8_TH_9 "\340\271\200\340\270\201\340\271\211\340\270\262" -#define UTF8_TH_10 "\340\270\252\340\270\264\340\270\232" -#define UTF8_TH_11 "\340\271\200\340\270\255\340\271\207\340\270\224" -#define UTF8_TH_20 "\340\270\242\340\270\265\340\271\210" -#define UTF8_TH_1E2 "\340\270\243\340\271\211\340\270\255\340\270\242" -#define UTF8_TH_1E3 "\340\270\236\340\270\261\340\270\231" -#define UTF8_TH_1E4 "\340\270\253\340\270\241\340\270\267\340\271\210\340\270\231" -#define UTF8_TH_1E5 "\340\271\201\340\270\252\340\270\231" -#define UTF8_TH_1E6 "\340\270\245\340\271\211\340\270\262\340\270\231" -#define UTF8_TH_DOT0 "\340\270\226\340\271\211\340\270\247\340\270\231" -#define UTF8_TH_BAHT "\340\270\232\340\270\262\340\270\227" -#define UTF8_TH_SATANG "\340\270\252\340\270\225\340\270\262\340\270\207\340\270\204\340\271\214" -#define UTF8_TH_MINUS "\340\270\245\340\270\232" - -#define UTF8_STRINGPARAM( ascii ) ascii, static_cast< xub_StrLen >( sizeof( ascii ) - 1 ) -#define UTF8_CREATE( ascii ) ByteString( UTF8_STRINGPARAM( ascii ) ) -#define UTF8_APPEND( ascii ) Append( UTF8_STRINGPARAM( ascii ) ) -#define UTF8_PREPEND( ascii ) Insert( UTF8_CREATE( ascii ), 0 ) - -// local functions ------------------------------------------------------------ - -namespace { - -inline void lclSplitBlock( double& rfInt, sal_Int32& rnBlock, double fValue, double fSize ) -{ - rnBlock = static_cast< sal_Int32 >( modf( (fValue + 0.1) / fSize, &rfInt ) * fSize + 0.1 ); -} - -/** Appends a digit (0 to 9) to the passed string. */ -void lclAppendDigit( ByteString& rText, sal_Int32 nDigit ) -{ - switch( nDigit ) - { - case 0: rText.UTF8_APPEND( UTF8_TH_0 ); break; - case 1: rText.UTF8_APPEND( UTF8_TH_1 ); break; - case 2: rText.UTF8_APPEND( UTF8_TH_2 ); break; - case 3: rText.UTF8_APPEND( UTF8_TH_3 ); break; - case 4: rText.UTF8_APPEND( UTF8_TH_4 ); break; - case 5: rText.UTF8_APPEND( UTF8_TH_5 ); break; - case 6: rText.UTF8_APPEND( UTF8_TH_6 ); break; - case 7: rText.UTF8_APPEND( UTF8_TH_7 ); break; - case 8: rText.UTF8_APPEND( UTF8_TH_8 ); break; - case 9: rText.UTF8_APPEND( UTF8_TH_9 ); break; - default: OSL_FAIL( "lclAppendDigit - illegal digit" ); - } -} - -/** Appends a value raised to a power of 10: nDigit*10^nPow10. - @param nDigit A digit in the range from 1 to 9. - @param nPow10 A value in the range from 2 to 5. - */ -void lclAppendPow10( ByteString& rText, sal_Int32 nDigit, sal_Int32 nPow10 ) -{ - OSL_ENSURE( (1 <= nDigit) && (nDigit <= 9), "lclAppendPow10 - illegal digit" ); - lclAppendDigit( rText, nDigit ); - switch( nPow10 ) - { - case 2: rText.UTF8_APPEND( UTF8_TH_1E2 ); break; - case 3: rText.UTF8_APPEND( UTF8_TH_1E3 ); break; - case 4: rText.UTF8_APPEND( UTF8_TH_1E4 ); break; - case 5: rText.UTF8_APPEND( UTF8_TH_1E5 ); break; - default: OSL_FAIL( "lclAppendPow10 - illegal power" ); - } -} - -/** Appends a block of 6 digits (value from 1 to 999,999) to the passed string. */ -void lclAppendBlock( ByteString& rText, sal_Int32 nValue ) -{ - OSL_ENSURE( (1 <= nValue) && (nValue <= 999999), "lclAppendBlock - illegal value" ); - if( nValue >= 100000 ) - { - lclAppendPow10( rText, nValue / 100000, 5 ); - nValue %= 100000; - } - if( nValue >= 10000 ) - { - lclAppendPow10( rText, nValue / 10000, 4 ); - nValue %= 10000; - } - if( nValue >= 1000 ) - { - lclAppendPow10( rText, nValue / 1000, 3 ); - nValue %= 1000; - } - if( nValue >= 100 ) - { - lclAppendPow10( rText, nValue / 100, 2 ); - nValue %= 100; - } - if( nValue > 0 ) - { - sal_Int32 nTen = nValue / 10; - sal_Int32 nOne = nValue % 10; - if( nTen >= 1 ) - { - if( nTen >= 3 ) - lclAppendDigit( rText, nTen ); - else if( nTen == 2 ) - rText.UTF8_APPEND( UTF8_TH_20 ); - rText.UTF8_APPEND( UTF8_TH_10 ); - } - if( (nTen > 0) && (nOne == 1) ) - rText.UTF8_APPEND( UTF8_TH_11 ); - else if( nOne > 0 ) - lclAppendDigit( rText, nOne ); - } -} - -} // namespace - -// ---------------------------------------------------------------------------- - -void ScInterpreter::ScBahtText() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScBahtText" ); - sal_uInt8 nParamCount = GetByte(); - if ( MustHaveParamCount( nParamCount, 1 ) ) - { - double fValue = GetDouble(); - if( nGlobalError ) - { - PushError( nGlobalError); - return; - } - - // sign - bool bMinus = fValue < 0.0; - fValue = fabs( fValue ); - - // round to 2 digits after decimal point, fValue contains Satang as integer - fValue = ::rtl::math::approxFloor( fValue * 100.0 + 0.5 ); - - // split Baht and Satang - double fBaht = 0.0; - sal_Int32 nSatang = 0; - lclSplitBlock( fBaht, nSatang, fValue, 100.0 ); - - ByteString aText; - - // generate text for Baht value - if( fBaht == 0.0 ) - { - if( nSatang == 0 ) - aText.UTF8_APPEND( UTF8_TH_0 ); - } - else while( fBaht > 0.0 ) - { - ByteString aBlock; - sal_Int32 nBlock = 0; - lclSplitBlock( fBaht, nBlock, fBaht, 1.0e6 ); - if( nBlock > 0 ) - lclAppendBlock( aBlock, nBlock ); - // add leading "million", if there will come more blocks - if( fBaht > 0.0 ) - aBlock.UTF8_PREPEND( UTF8_TH_1E6 ); - aText.Insert( aBlock, 0 ); - } - if( aText.Len() > 0 ) - aText.UTF8_APPEND( UTF8_TH_BAHT ); - - // generate text for Satang value - if( nSatang == 0 ) - { - aText.UTF8_APPEND( UTF8_TH_DOT0 ); - } - else - { - lclAppendBlock( aText, nSatang ); - aText.UTF8_APPEND( UTF8_TH_SATANG ); - } - - // add the minus sign - if( bMinus ) - aText.UTF8_PREPEND( UTF8_TH_MINUS ); - - PushString( String( aText, RTL_TEXTENCODING_UTF8 ) ); - } -} - -// ============================================================================ - -void ScInterpreter::ScGetPivotData() -{ - RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGetPivotData" ); - sal_uInt8 nParamCount = GetByte(); - - if ( MustHaveParamCount( nParamCount, 2, 30 ) ) - { - // there must be an even number of args - // target, ref, then field/item pairs - if( (nParamCount % 2) == 1) - goto failed; - - bool bOldSyntax = false; - if ( nParamCount == 2 ) - { - // if the first parameter is a ref, assume old syntax - StackVar eFirstType = GetStackType( 2 ); - if ( eFirstType == svSingleRef || eFirstType == svDoubleRef ) - bOldSyntax = true; - } - - ScDPGetPivotDataField aTarget; // target field, and returns result - std::vector< ScDPGetPivotDataField > aFilters; - String aFilterList; - if ( bOldSyntax ) - aFilterList = GetString(); // old syntax: second parameter is list of constraints - else - { - // new syntax: separate name/value pairs - - sal_uInt16 nFilterCount = nParamCount / 2 - 1; - aFilters.resize( nFilterCount ); - - sal_uInt16 i = nFilterCount; - while( i-- > 0 ) - { - //! should allow numeric constraint values - aFilters[i].mbValIsStr = sal_True; - aFilters[i].maValStr = GetString(); - - aFilters[i].maFieldName = GetString(); - } - } - - // common to both syntaxes: a reference to the data pilot table - - ScRange aBlock; - switch ( GetStackType() ) - { - case svDoubleRef : - PopDoubleRef( aBlock ); - break; - - case svSingleRef : - { - ScAddress aAddr; - PopSingleRef( aAddr ); - aBlock = aAddr; - break; - } - default: - goto failed; - } - // NOTE : MS Excel docs claim to use the 'most recent' which is not - // exactly the same as what we do in ScDocument::GetDPAtBlock - // However we do need to use GetDPABlock - ScDPObject* pDPObj = pDok->GetDPAtBlock ( aBlock ); - if( NULL == pDPObj) - goto failed; - - if ( bOldSyntax ) - { - // fill aFilters / aTarget from aFilterList string - if ( !pDPObj->ParseFilters( aTarget, aFilters, aFilterList ) ) - goto failed; - } - else - aTarget.maFieldName = GetString(); // new syntax: first parameter is data field name - - if( pDPObj->GetPivotData( aTarget, aFilters ) ) - { - if( aTarget.mbValIsStr ) - PushString( aTarget.maValStr ); - else - PushDouble( aTarget.mnValNum ); - return; - } - } - -failed : - PushError( errNoRef ); -} - -/* vim:set shiftwidth=4 softtabstop=4 expandtab: */ |