diff options
-rw-r--r-- | formula/source/core/api/FormulaCompiler.cxx | 26 | ||||
-rw-r--r-- | formula/source/core/api/token.cxx | 57 | ||||
-rw-r--r-- | include/formula/tokenarray.hxx | 16 |
3 files changed, 98 insertions, 1 deletions
diff --git a/formula/source/core/api/FormulaCompiler.cxx b/formula/source/core/api/FormulaCompiler.cxx index c4ca443ffef9..457beeefb4b1 100644 --- a/formula/source/core/api/FormulaCompiler.cxx +++ b/formula/source/core/api/FormulaCompiler.cxx @@ -1271,6 +1271,7 @@ void FormulaCompiler::Factor() else SetError( errPairExpected); sal_uInt8 nSepCount = 0; + const sal_uInt16 nSepPos = pArr->nIndex - 1; // separator position, if any if( !bNoParam ) { nSepCount++; @@ -1289,7 +1290,30 @@ void FormulaCompiler::Factor() pFacToken->SetByte( nSepCount ); if (nSepCount == 2) { - pFacToken->NewOpCode( ocWeek, FormulaToken::PrivateAccess()); + // An old mode!=1 indicates ISO week, remove argument if + // literal double value and keep function. Anything else + // can not be resolved, there exists no "like ISO but week + // starts on Sunday" mode in WEEKNUM and for an expression + // we can't determine, so let ISOWEEKNUM generate an error + // for two arguments in these cases. + if (pc >= 2 && pArr->nIndex == nSepPos + 3 && + pArr->pCode[nSepPos+1]->GetType() == svDouble && + pArr->pCode[nSepPos+1]->GetDouble() != 1.0 && + pArr->RemoveToken( nSepPos, 2) == 2) + { + // Remove the ocPush/svDouble just removed also from + // the compiler local RPN array. + --pCode, --pc; + (*pCode)->DecRef(); // may be dead now + pFacToken->SetByte( nSepCount - 1 ); + } + else + { + /* FIXME: introduce (hidden?) compatibility function? */ +#if 0 + pFacToken->NewOpCode( ocWeeknumCompat, FormulaToken::PrivateAccess()); +#endif + } } PutCode( pFacToken ); } diff --git a/formula/source/core/api/token.cxx b/formula/source/core/api/token.cxx index 339e927742fa..65211f362561 100644 --- a/formula/source/core/api/token.cxx +++ b/formula/source/core/api/token.cxx @@ -900,6 +900,63 @@ FormulaToken* FormulaTokenArray::ReplaceToken( sal_uInt16 nOffset, FormulaToken* } } +sal_uInt16 FormulaTokenArray::RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount ) +{ + if (nOffset < nLen) + { + SAL_WARN_IF( nOffset + nCount > nLen, "formula.core", + "FormulaTokenArray::RemoveToken - nOffset " << nOffset << " + nCount " << nCount << " > nLen " << nLen); + const sal_uInt16 nStop = ::std::min( static_cast<sal_uInt16>(nOffset + nCount), nLen); + nCount = nStop - nOffset; + for (sal_uInt16 j = nOffset; j < nStop; ++j) + { + FormulaToken* p = pCode[j]; + if (p->GetRef() > 1) + { + for (sal_uInt16 i=0; i < nRPN; ++i) + { + if (pRPN[i] == p) + { + // Shift remaining tokens in pRPN down. + for (sal_uInt16 x=i+1; x < nRPN; ++x) + { + pRPN[x-1] = pRPN[x]; + } + --nRPN; + + p->DecRef(); + if (p->GetRef() == 1) + break; // for + } + } + } + p->DecRef(); // may be dead now + } + + // Shift remaining tokens in pCode down. + for (sal_uInt16 x = nStop; x < nLen; ++x) + { + pCode[x-nCount] = pCode[x]; + } + nLen -= nCount; + + if (nIndex >= nOffset) + { + if (nIndex < nStop) + nIndex = nOffset + 1; + else + nIndex -= nStop - nOffset; + } + + return nCount; + } + else + { + SAL_WARN("formula.core","FormulaTokenArray::RemoveToken - nOffset " << nOffset << " >= nLen " << nLen); + return 0; + } +} + FormulaToken* FormulaTokenArray::Add( FormulaToken* t ) { if( !pCode ) diff --git a/include/formula/tokenarray.hxx b/include/formula/tokenarray.hxx index 6dcbcfc442d6..292b3182cb8b 100644 --- a/include/formula/tokenarray.hxx +++ b/include/formula/tokenarray.hxx @@ -148,6 +148,22 @@ protected: */ FormulaToken* ReplaceToken( sal_uInt16 nOffset, FormulaToken*, ReplaceMode eMode ); + /** Remove a sequence of tokens from pCode array, and pRPN array if the + tokens are referenced there. + + This' nLen and nRPN are adapted, as is nIndex if it points behind + nOffset. If nIndex points into the to be removed range + (nOffset < nIndex < nOffset+nCount) it is set to nOffset+1. + + @param nOffset + Start offset into pCode. + @param nCount + Count of tokens to remove. + + @return The actual number of tokens removed from pCode array. + */ + sal_uInt16 RemoveToken( sal_uInt16 nOffset, sal_uInt16 nCount ); + inline void SetCombinedBitsRecalcMode( ScRecalcMode nBits ) { nMode |= (nBits & ~RECALCMODE_EMASK); } inline ScRecalcMode GetCombinedBitsRecalcMode() const |