summaryrefslogtreecommitdiff
path: root/formula
diff options
context:
space:
mode:
authorEike Rathke <erack@redhat.com>2016-01-05 11:54:32 +0100
committerEike Rathke <erack@redhat.com>2016-01-05 14:49:48 +0100
commit3e5deb8ccfaf0b73fb6cf394822e560dc036a686 (patch)
tree90032d987bc6269aed48702f8f2db8d0558bb492 /formula
parent933f9da205632de75740cfd71443cbd908a18676 (diff)
tdf#96198 detect old ISO/WEEKNUM usage with two arguments, tdf#50950 follow-up
5.0 and earlier implemented WEEKNUM(date,mode) with mode!=1 such that effectively an ISO 8601 week number was calculated. WEEKNUM was wrongly saved as ISOWEEKNUM (even with two parameters though it is defined to have only one) so that when reading it we can try to detect a literal double argument for mode and if it is not 1 remove it to keep ISOWEEKNUM(date) instead of calling WEEKNUM(date,mode) which wouldn't match. A further change to 5.0 to accept also only one parameter in WEEKNUM(date) and for this default the mode to not 1 for ISO week will yield forward compatibility. Change-Id: I88de7dd809d69b6826a190505d2a1dd3fe79c90b (cherry picked from commit 2f79244cb3fcc4cbfd2b818380ea9d62b49aaade)
Diffstat (limited to 'formula')
-rw-r--r--formula/source/core/api/FormulaCompiler.cxx26
-rw-r--r--formula/source/core/api/token.cxx57
2 files changed, 82 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 )