diff options
Diffstat (limited to 'sc/source/core/tool/token.cxx')
-rw-r--r-- | sc/source/core/tool/token.cxx | 1836 |
1 files changed, 1836 insertions, 0 deletions
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx new file mode 100644 index 000000000000..81862c49fd21 --- /dev/null +++ b/sc/source/core/tool/token.cxx @@ -0,0 +1,1836 @@ +/************************************************************************* + * + * 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 --------------------------------------------------------------- + +#if STLPORT_VERSION<321 +#include <stddef.h> +#else +#include <cstddef> +#endif +#include <cstdio> + +#include <string.h> +#include <tools/mempool.hxx> +#include <tools/debug.hxx> + +#include "token.hxx" +#include "tokenarray.hxx" +#include "compiler.hxx" +#include <formula/compiler.hrc> +#include "rechead.hxx" +#include "parclass.hxx" +#include "jumpmatrix.hxx" +#include "rangeseq.hxx" +#include "externalrefmgr.hxx" +#include "document.hxx" + +using ::std::vector; + +#include <com/sun/star/sheet/ComplexReference.hpp> +#include <com/sun/star/sheet/ExternalReference.hpp> +#include <com/sun/star/sheet/ReferenceFlags.hpp> + +using namespace formula; +using namespace com::sun::star; + +namespace +{ + void lcl_SingleRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI ) + { + rRef.InitFlags(); + + rRef.nCol = static_cast<SCsCOL>(rAPI.Column); + rRef.nRow = static_cast<SCsROW>(rAPI.Row); + rRef.nTab = static_cast<SCsTAB>(rAPI.Sheet); + rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn); + rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow); + rRef.nRelTab = static_cast<SCsTAB>(rAPI.RelativeSheet); + + rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 ); + rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 ); + rRef.SetTabRel( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_RELATIVE ) != 0 ); + rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 ); + rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 ); + rRef.SetTabDeleted( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_DELETED ) != 0 ); + rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 ); + rRef.SetRelName( ( rAPI.Flags & sheet::ReferenceFlags::RELATIVE_NAME ) != 0 ); + } + + void lcl_ExternalRefToCalc( ScSingleRefData& rRef, const sheet::SingleReference& rAPI ) + { + rRef.InitFlags(); + + rRef.nCol = static_cast<SCsCOL>(rAPI.Column); + rRef.nRow = static_cast<SCsROW>(rAPI.Row); + rRef.nTab = 0; + rRef.nRelCol = static_cast<SCsCOL>(rAPI.RelativeColumn); + rRef.nRelRow = static_cast<SCsROW>(rAPI.RelativeRow); + rRef.nRelTab = 0; + + rRef.SetColRel( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_RELATIVE ) != 0 ); + rRef.SetRowRel( ( rAPI.Flags & sheet::ReferenceFlags::ROW_RELATIVE ) != 0 ); + rRef.SetTabRel( false ); // sheet index must be absolute for external refs + rRef.SetColDeleted( ( rAPI.Flags & sheet::ReferenceFlags::COLUMN_DELETED ) != 0 ); + rRef.SetRowDeleted( ( rAPI.Flags & sheet::ReferenceFlags::ROW_DELETED ) != 0 ); + rRef.SetTabDeleted( false ); // sheet must not be deleted for external refs + rRef.SetFlag3D( ( rAPI.Flags & sheet::ReferenceFlags::SHEET_3D ) != 0 ); + rRef.SetRelName( false ); + } +// +} // namespace +// +// ImpTokenIterator wird je Interpreter angelegt, mehrfache auch durch +// SubCode via FormulaTokenIterator Push/Pop moeglich +IMPL_FIXEDMEMPOOL_NEWDEL( ImpTokenIterator, 32, 16 ) + +// Align MemPools on 4k boundaries - 64 bytes (4k is a MUST for OS/2) + +// Since RawTokens are temporary for the compiler, don't align on 4k and waste memory. +// ScRawToken size is FixMembers + MAXSTRLEN + ~4 ~= 1036 +IMPL_FIXEDMEMPOOL_NEWDEL( ScRawToken, 8, 4 ) +// Some ScDoubleRawToken, FixMembers + sizeof(double) ~= 16 +const USHORT nMemPoolDoubleRawToken = 0x0400 / sizeof(ScDoubleRawToken); +IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken, nMemPoolDoubleRawToken, nMemPoolDoubleRawToken ) + +// Need a whole bunch of ScSingleRefToken +const USHORT nMemPoolSingleRefToken = (0x4000 - 64) / sizeof(ScSingleRefToken); +IMPL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken, nMemPoolSingleRefToken, nMemPoolSingleRefToken ) +// Need quite a lot of ScDoubleRefToken +const USHORT nMemPoolDoubleRefToken = (0x2000 - 64) / sizeof(ScDoubleRefToken); +IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken, nMemPoolDoubleRefToken, nMemPoolDoubleRefToken ) + +// --- helpers -------------------------------------------------------------- + +inline BOOL lcl_IsReference( OpCode eOp, StackVar eType ) +{ + return + (eOp == ocPush && (eType == svSingleRef || eType == svDoubleRef)) + || (eOp == ocColRowNameAuto && eType == svDoubleRef) + || (eOp == ocColRowName && eType == svSingleRef) + || (eOp == ocMatRef && eType == svSingleRef) + ; +} + + +// --- class ScRawToken ----------------------------------------------------- + +xub_StrLen ScRawToken::GetStrLen( const sal_Unicode* pStr ) +{ + if ( !pStr ) + return 0; + register const sal_Unicode* p = pStr; + while ( *p ) + p++; + return sal::static_int_cast<xub_StrLen>( p - pStr ); +} + + +void ScRawToken::SetOpCode( OpCode e ) +{ + eOp = e; + switch (eOp) + { + case ocIf: + eType = svJump; + nJump[ 0 ] = 3; // If, Else, Behind + break; + case ocChose: + eType = svJump; + nJump[ 0 ] = MAXJUMPCOUNT+1; + break; + case ocMissing: + eType = svMissing; + break; + case ocSep: + case ocOpen: + case ocClose: + case ocArrayRowSep: + case ocArrayColSep: + case ocArrayOpen: + case ocArrayClose: + eType = svSep; + break; + default: + eType = svByte; + sbyte.cByte = 0; + sbyte.bHasForceArray = ScParameterClassification::HasForceArray( eOp); + } + nRefCnt = 0; +} + +void ScRawToken::SetString( const sal_Unicode* pStr ) +{ + eOp = ocPush; + eType = svString; + if ( pStr ) + { + xub_StrLen nLen = GetStrLen( pStr ) + 1; + if( nLen > MAXSTRLEN ) + nLen = MAXSTRLEN; + memcpy( cStr, pStr, GetStrLenBytes( nLen ) ); + cStr[ nLen-1 ] = 0; + } + else + cStr[0] = 0; + nRefCnt = 0; +} + +void ScRawToken::SetSingleReference( const ScSingleRefData& rRef ) +{ + eOp = ocPush; + eType = svSingleRef; + aRef.Ref1 = + aRef.Ref2 = rRef; + nRefCnt = 0; +} + +void ScRawToken::SetDoubleReference( const ScComplexRefData& rRef ) +{ + eOp = ocPush; + eType = svDoubleRef; + aRef = rRef; + nRefCnt = 0; +} + +void ScRawToken::SetDouble(double rVal) +{ + eOp = ocPush; + eType = svDouble; + nValue = rVal; + nRefCnt = 0; +} + +void ScRawToken::SetName( USHORT n ) +{ + eOp = ocName; + eType = svIndex; + nIndex = n; + nRefCnt = 0; +} + +void ScRawToken::SetExternalSingleRef( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) +{ + eOp = ocExternalRef; + eType = svExternalSingleRef; + nRefCnt = 0; + + extref.nFileId = nFileId; + extref.aRef.Ref1 = + extref.aRef.Ref2 = rRef; + + xub_StrLen n = rTabName.Len(); + memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode)); + extref.cTabName[n] = 0; +} + +void ScRawToken::SetExternalDoubleRef( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef ) +{ + eOp = ocExternalRef; + eType = svExternalDoubleRef; + nRefCnt = 0; + + extref.nFileId = nFileId; + extref.aRef = rRef; + + xub_StrLen n = rTabName.Len(); + memcpy(extref.cTabName, rTabName.GetBuffer(), n*sizeof(sal_Unicode)); + extref.cTabName[n] = 0; +} + +void ScRawToken::SetExternalName( sal_uInt16 nFileId, const String& rName ) +{ + eOp = ocExternalRef; + eType = svExternalName; + nRefCnt = 0; + + extname.nFileId = nFileId; + + xub_StrLen n = rName.Len(); + memcpy(extname.cName, rName.GetBuffer(), n*sizeof(sal_Unicode)); + extname.cName[n] = 0; +} + +//UNUSED2008-05 void ScRawToken::SetInt(int rVal) +//UNUSED2008-05 { +//UNUSED2008-05 eOp = ocPush; +//UNUSED2008-05 eType = svDouble; +//UNUSED2008-05 nValue = (double)rVal; +//UNUSED2008-05 nRefCnt = 0; +//UNUSED2008-05 +//UNUSED2008-05 } +//UNUSED2008-05 void ScRawToken::SetMatrix( ScMatrix* p ) +//UNUSED2008-05 { +//UNUSED2008-05 eOp = ocPush; +//UNUSED2008-05 eType = svMatrix; +//UNUSED2008-05 pMat = p; +//UNUSED2008-05 nRefCnt = 0; +//UNUSED2008-05 } +//UNUSED2008-05 +//UNUSED2008-05 ScComplexRefData& ScRawToken::GetReference() +//UNUSED2008-05 { +//UNUSED2008-05 DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "GetReference: no Ref" ); +//UNUSED2008-05 return aRef; +//UNUSED2008-05 } +//UNUSED2008-05 +//UNUSED2008-05 void ScRawToken::SetReference( ScComplexRefData& rRef ) +//UNUSED2008-05 { +//UNUSED2008-05 DBG_ASSERT( lcl_IsReference( eOp, GetType() ), "SetReference: no Ref" ); +//UNUSED2008-05 aRef = rRef; +//UNUSED2008-05 if( GetType() == svSingleRef ) +//UNUSED2008-05 aRef.Ref2 = aRef.Ref1; +//UNUSED2008-05 } + +void ScRawToken::SetExternal( const sal_Unicode* pStr ) +{ + eOp = ocExternal; + eType = svExternal; + xub_StrLen nLen = GetStrLen( pStr ) + 1; + if( nLen >= MAXSTRLEN ) + nLen = MAXSTRLEN-1; + // Platz fuer Byte-Parameter lassen! + memcpy( cStr+1, pStr, GetStrLenBytes( nLen ) ); + cStr[ nLen+1 ] = 0; + nRefCnt = 0; +} + +USHORT lcl_ScRawTokenOffset() +{ + // offset of sbyte in ScRawToken + // offsetof(ScRawToken, sbyte) gives a warning with gcc, because ScRawToken is no POD + + ScRawToken aToken; + return static_cast<USHORT>( reinterpret_cast<char*>(&aToken.sbyte) - reinterpret_cast<char*>(&aToken) ); +} + +ScRawToken* ScRawToken::Clone() const +{ + ScRawToken* p; + if ( eType == svDouble ) + { + p = (ScRawToken*) new ScDoubleRawToken; + p->eOp = eOp; + p->eType = eType; + p->nValue = nValue; + } + else + { + static USHORT nOffset = lcl_ScRawTokenOffset(); // offset of sbyte + USHORT n = nOffset; + + if (eOp == ocExternalRef) + { + switch (eType) + { + case svExternalSingleRef: + case svExternalDoubleRef: n += sizeof(extref); break; + case svExternalName: n += sizeof(extname); break; + default: + { + DBG_ERROR1( "unknown ScRawToken::Clone() external type %d", int(eType)); + } + } + } + else + { + switch( eType ) + { + case svSep: break; + case svByte: n += sizeof(ScRawToken::sbyte); break; + case svDouble: n += sizeof(double); break; + case svString: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break; + case svSingleRef: + case svDoubleRef: n += sizeof(aRef); break; + case svMatrix: n += sizeof(ScMatrix*); break; + case svIndex: n += sizeof(USHORT); break; + case svJump: n += nJump[ 0 ] * 2 + 2; break; + case svExternal: n = sal::static_int_cast<USHORT>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break; + default: + { + DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType)); + } + } + } + p = (ScRawToken*) new BYTE[ n ]; + memcpy( p, this, n * sizeof(BYTE) ); + } + p->nRefCnt = 0; + p->bRaw = FALSE; + return p; +} + + +FormulaToken* ScRawToken::CreateToken() const +{ +#ifdef DBG_UTIL +#define IF_NOT_OPCODE_ERROR(o,c) if (eOp!=o) DBG_ERROR1( #c "::ctor: OpCode %d lost, converted to " #o "; maybe inherit from FormulaToken instead!", int(eOp)) +#else +#define IF_NOT_OPCODE_ERROR(o,c) +#endif + switch ( GetType() ) + { + case svByte : + return new FormulaByteToken( eOp, sbyte.cByte, sbyte.bHasForceArray ); + case svDouble : + IF_NOT_OPCODE_ERROR( ocPush, FormulaDoubleToken); + return new FormulaDoubleToken( nValue ); + case svString : + if (eOp == ocPush) + return new FormulaStringToken( String( cStr ) ); + else + return new FormulaStringOpToken( eOp, String( cStr ) ); + case svSingleRef : + if (eOp == ocPush) + return new ScSingleRefToken( aRef.Ref1 ); + else + return new ScSingleRefToken( aRef.Ref1, eOp ); + case svDoubleRef : + if (eOp == ocPush) + return new ScDoubleRefToken( aRef ); + else + return new ScDoubleRefToken( aRef, eOp ); + case svMatrix : + IF_NOT_OPCODE_ERROR( ocPush, ScMatrixToken); + return new ScMatrixToken( pMat ); + case svIndex : + return new FormulaIndexToken( eOp, nIndex ); + case svExternalSingleRef: + { + String aTabName(extref.cTabName); + return new ScExternalSingleRefToken(extref.nFileId, aTabName, extref.aRef.Ref1); + } + case svExternalDoubleRef: + { + String aTabName(extref.cTabName); + return new ScExternalDoubleRefToken(extref.nFileId, aTabName, extref.aRef); + } + case svExternalName: + { + String aName(extname.cName); + return new ScExternalNameToken( extname.nFileId, aName ); + } + case svJump : + return new FormulaJumpToken( eOp, (short*) nJump ); + case svExternal : + return new FormulaExternalToken( eOp, sbyte.cByte, String( cStr+1 ) ); + case svFAP : + return new FormulaFAPToken( eOp, sbyte.cByte, NULL ); + case svMissing : + IF_NOT_OPCODE_ERROR( ocMissing, FormulaMissingToken); + return new FormulaMissingToken; + case svSep : + return new FormulaToken( svSep,eOp ); + case svUnknown : + return new FormulaUnknownToken( eOp ); + default: + { + DBG_ERROR1( "unknown ScRawToken::CreateToken() type %d", int(GetType())); + return new FormulaUnknownToken( ocBad ); + } + } +#undef IF_NOT_OPCODE_ERROR +} + + +void ScRawToken::Delete() +{ + if ( bRaw ) + delete this; // FixedMemPool ScRawToken + else + { // created per Clone + switch ( eType ) + { + case svDouble : + delete (ScDoubleRawToken*) this; // FixedMemPool ScDoubleRawToken + break; + default: + delete [] (BYTE*) this; + } + } +} + + +// --- class ScToken -------------------------------------------------------- + +ScSingleRefData lcl_ScToken_InitSingleRef() +{ + ScSingleRefData aRef; + aRef.InitAddress( ScAddress() ); + return aRef; +} + +ScComplexRefData lcl_ScToken_InitDoubleRef() +{ + ScComplexRefData aRef; + aRef.Ref1 = lcl_ScToken_InitSingleRef(); + aRef.Ref2 = aRef.Ref1; + return aRef; +} + +ScToken::~ScToken() +{ +} + +// TextEqual: if same formula entered (for optimization in sort) +BOOL ScToken::TextEqual( const FormulaToken& _rToken ) const +{ + if ( eType == svSingleRef || eType == svDoubleRef ) + { + // in relative Refs only compare relative parts + + if ( eType != _rToken.GetType() || GetOpCode() != _rToken.GetOpCode() ) + return FALSE; + + const ScToken& rToken = static_cast<const ScToken&>(_rToken); + ScComplexRefData aTemp1; + if ( eType == svSingleRef ) + { + aTemp1.Ref1 = GetSingleRef(); + aTemp1.Ref2 = aTemp1.Ref1; + } + else + aTemp1 = GetDoubleRef(); + + ScComplexRefData aTemp2; + if ( rToken.eType == svSingleRef ) + { + aTemp2.Ref1 = rToken.GetSingleRef(); + aTemp2.Ref2 = aTemp2.Ref1; + } + else + aTemp2 = rToken.GetDoubleRef(); + + ScAddress aPos; + aTemp1.SmartRelAbs(aPos); + aTemp2.SmartRelAbs(aPos); + + // memcmp doesn't work because of the alignment byte after bFlags. + // After SmartRelAbs only absolute parts have to be compared. + return aTemp1.Ref1.nCol == aTemp2.Ref1.nCol && + aTemp1.Ref1.nRow == aTemp2.Ref1.nRow && + aTemp1.Ref1.nTab == aTemp2.Ref1.nTab && + aTemp1.Ref1.bFlags == aTemp2.Ref1.bFlags && + aTemp1.Ref2.nCol == aTemp2.Ref2.nCol && + aTemp1.Ref2.nRow == aTemp2.Ref2.nRow && + aTemp1.Ref2.nTab == aTemp2.Ref2.nTab && + aTemp1.Ref2.bFlags == aTemp2.Ref2.bFlags; + } + else + return *this == _rToken; // else normal operator== +} + + +BOOL ScToken::Is3DRef() const +{ + switch ( eType ) + { + case svDoubleRef : + if ( GetSingleRef2().IsFlag3D() ) + return TRUE; + //! fallthru + case svSingleRef : + if ( GetSingleRef().IsFlag3D() ) + return TRUE; + break; + default: + { + // added to avoid warnings + } + } + return FALSE; +} + +// static +FormulaTokenRef ScToken::ExtendRangeReference( FormulaToken & rTok1, FormulaToken & rTok2, + const ScAddress & rPos, bool bReuseDoubleRef ) +{ + + StackVar sv1, sv2; + // Doing a RangeOp with RefList is probably utter nonsense, but Xcl + // supports it, so do we. + if (((sv1 = rTok1.GetType()) != svSingleRef && sv1 != svDoubleRef && sv1 != svRefList && + sv1 != svExternalSingleRef && sv1 != svExternalDoubleRef ) || + ((sv2 = rTok2.GetType()) != svSingleRef && sv2 != svDoubleRef && sv2 != svRefList)) + return NULL; + + ScToken *p1 = static_cast<ScToken*>(&rTok1); + ScToken *p2 = static_cast<ScToken*>(&rTok2); + + ScTokenRef xRes; + bool bExternal = (sv1 == svExternalSingleRef); + if ((sv1 == svSingleRef || bExternal) && sv2 == svSingleRef) + { + // Range references like Sheet1.A1:A2 are generalized and built by + // first creating a DoubleRef from the first SingleRef, effectively + // generating Sheet1.A1:A1, and then extending that with A2 as if + // Sheet1.A1:A1:A2 was encountered, so the mechanisms to adjust the + // references apply as well. + + /* Given the current structure of external references an external + * reference can only be extended if the second reference does not + * point to a different sheet. 'file'#Sheet1.A1:A2 is ok, + * 'file'#Sheet1.A1:Sheet2.A2 is not. Since we can't determine from a + * svSingleRef whether the sheet would be different from the one given + * in the external reference, we have to bail out if there is any sheet + * specified. NOTE: Xcl does handle external 3D references as in + * '[file]Sheet1:Sheet2'!A1:A2 + * + * FIXME: For OOo syntax be smart and remember an external singleref + * encountered and if followed by ocRange and singleref, create an + * external singleref for the second singleref. Both could then be + * merged here. For Xcl syntax already parse an external range + * reference entirely, cumbersome. */ + + const ScSingleRefData& rRef2 = p2->GetSingleRef(); + if (bExternal && rRef2.IsFlag3D()) + return NULL; + + ScComplexRefData aRef; + aRef.Ref1 = aRef.Ref2 = p1->GetSingleRef(); + aRef.Ref2.SetFlag3D( false); + aRef.Extend( rRef2, rPos); + if (bExternal) + xRes = new ScExternalDoubleRefToken( p1->GetIndex(), p1->GetString(), aRef); + else + xRes = new ScDoubleRefToken( aRef); + } + else + { + bExternal |= (sv1 == svExternalDoubleRef); + const ScRefList* pRefList = NULL; + if (sv1 == svDoubleRef) + { + xRes = (bReuseDoubleRef && p1->GetRef() == 1 ? p1 : static_cast<ScToken*>(p1->Clone())); + sv1 = svUnknown; // mark as handled + } + else if (sv2 == svDoubleRef) + { + xRes = (bReuseDoubleRef && p2->GetRef() == 1 ? p2 : static_cast<ScToken*>(p2->Clone())); + sv2 = svUnknown; // mark as handled + } + else if (sv1 == svRefList) + pRefList = p1->GetRefList(); + else if (sv2 == svRefList) + pRefList = p2->GetRefList(); + if (pRefList) + { + if (!pRefList->size()) + return NULL; + if (bExternal) + return NULL; // external reference list not possible + xRes = new ScDoubleRefToken( (*pRefList)[0] ); + } + if (!xRes) + return NULL; // shouldn't happen.. + StackVar sv[2] = { sv1, sv2 }; + ScToken* pt[2] = { p1, p2 }; + ScComplexRefData& rRef = xRes->GetDoubleRef(); + for (size_t i=0; i<2; ++i) + { + switch (sv[i]) + { + case svSingleRef: + rRef.Extend( pt[i]->GetSingleRef(), rPos); + break; + case svDoubleRef: + rRef.Extend( pt[i]->GetDoubleRef(), rPos); + break; + case svRefList: + { + const ScRefList* p = pt[i]->GetRefList(); + if (!p->size()) + return NULL; + ScRefList::const_iterator it( p->begin()); + ScRefList::const_iterator end( p->end()); + for ( ; it != end; ++it) + { + rRef.Extend( *it, rPos); + } + } + break; + case svExternalSingleRef: + if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D()) + return NULL; // no other sheets with external refs + else + rRef.Extend( pt[i]->GetSingleRef(), rPos); + break; + case svExternalDoubleRef: + if (rRef.Ref1.IsFlag3D() || rRef.Ref2.IsFlag3D()) + return NULL; // no other sheets with external refs + else + rRef.Extend( pt[i]->GetDoubleRef(), rPos); + break; + default: + ; // nothing, prevent compiler warning + } + } + } + return FormulaTokenRef(xRes.get()); +} + +const ScSingleRefData& ScToken::GetSingleRef() const +{ + DBG_ERRORFILE( "ScToken::GetSingleRef: virtual dummy called" ); + static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); + return aDummySingleRef; +} + +ScSingleRefData& ScToken::GetSingleRef() +{ + DBG_ERRORFILE( "ScToken::GetSingleRef: virtual dummy called" ); + static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); + return aDummySingleRef; +} + +const ScComplexRefData& ScToken::GetDoubleRef() const +{ + DBG_ERRORFILE( "ScToken::GetDoubleRef: virtual dummy called" ); + static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef(); + return aDummyDoubleRef; +} + +ScComplexRefData& ScToken::GetDoubleRef() +{ + DBG_ERRORFILE( "ScToken::GetDoubleRef: virtual dummy called" ); + static ScComplexRefData aDummyDoubleRef = lcl_ScToken_InitDoubleRef(); + return aDummyDoubleRef; +} + +const ScSingleRefData& ScToken::GetSingleRef2() const +{ + DBG_ERRORFILE( "ScToken::GetSingleRef2: virtual dummy called" ); + static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); + return aDummySingleRef; +} + +ScSingleRefData& ScToken::GetSingleRef2() +{ + DBG_ERRORFILE( "ScToken::GetSingleRef2: virtual dummy called" ); + static ScSingleRefData aDummySingleRef = lcl_ScToken_InitSingleRef(); + return aDummySingleRef; +} + +void ScToken::CalcAbsIfRel( const ScAddress& /* rPos */ ) +{ + DBG_ERRORFILE( "ScToken::CalcAbsIfRel: virtual dummy called" ); +} + +void ScToken::CalcRelFromAbs( const ScAddress& /* rPos */ ) +{ + DBG_ERRORFILE( "ScToken::CalcRelFromAbs: virtual dummy called" ); +} + +const ScMatrix* ScToken::GetMatrix() const +{ + DBG_ERRORFILE( "ScToken::GetMatrix: virtual dummy called" ); + return NULL; +} + +ScMatrix* ScToken::GetMatrix() +{ + DBG_ERRORFILE( "ScToken::GetMatrix: virtual dummy called" ); + return NULL; +} + + +ScJumpMatrix* ScToken::GetJumpMatrix() const +{ + DBG_ERRORFILE( "ScToken::GetJumpMatrix: virtual dummy called" ); + return NULL; +} +const ScRefList* ScToken::GetRefList() const +{ + DBG_ERRORFILE( "ScToken::GetRefList: virtual dummy called" ); + return NULL; +} + +ScRefList* ScToken::GetRefList() +{ + DBG_ERRORFILE( "ScToken::GetRefList: virtual dummy called" ); + return NULL; +} +// ========================================================================== +// real implementations of virtual functions +// -------------------------------------------------------------------------- + + + + +const ScSingleRefData& ScSingleRefToken::GetSingleRef() const { return aSingleRef; } +ScSingleRefData& ScSingleRefToken::GetSingleRef() { return aSingleRef; } +void ScSingleRefToken::CalcAbsIfRel( const ScAddress& rPos ) + { aSingleRef.CalcAbsIfRel( rPos ); } +void ScSingleRefToken::CalcRelFromAbs( const ScAddress& rPos ) + { aSingleRef.CalcRelFromAbs( rPos ); } +BOOL ScSingleRefToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && aSingleRef == static_cast<const ScToken&>(r).GetSingleRef(); +} + + +const ScSingleRefData& ScDoubleRefToken::GetSingleRef() const { return aDoubleRef.Ref1; } +ScSingleRefData& ScDoubleRefToken::GetSingleRef() { return aDoubleRef.Ref1; } +const ScComplexRefData& ScDoubleRefToken::GetDoubleRef() const { return aDoubleRef; } +ScComplexRefData& ScDoubleRefToken::GetDoubleRef() { return aDoubleRef; } +const ScSingleRefData& ScDoubleRefToken::GetSingleRef2() const { return aDoubleRef.Ref2; } +ScSingleRefData& ScDoubleRefToken::GetSingleRef2() { return aDoubleRef.Ref2; } +void ScDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos ) + { aDoubleRef.CalcAbsIfRel( rPos ); } +void ScDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos ) + { aDoubleRef.CalcRelFromAbs( rPos ); } +BOOL ScDoubleRefToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && aDoubleRef == static_cast<const ScToken&>(r).GetDoubleRef(); +} + + +const ScRefList* ScRefListToken::GetRefList() const { return &aRefList; } + ScRefList* ScRefListToken::GetRefList() { return &aRefList; } +void ScRefListToken::CalcAbsIfRel( const ScAddress& rPos ) +{ + for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it) + (*it).CalcAbsIfRel( rPos); +} +void ScRefListToken::CalcRelFromAbs( const ScAddress& rPos ) +{ + for (ScRefList::iterator it( aRefList.begin()); it != aRefList.end(); ++it) + (*it).CalcRelFromAbs( rPos); +} +BOOL ScRefListToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && &aRefList == static_cast<const ScToken&>(r).GetRefList(); +} + + +const ScMatrix* ScMatrixToken::GetMatrix() const { return pMatrix; } +ScMatrix* ScMatrixToken::GetMatrix() { return pMatrix; } +BOOL ScMatrixToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && pMatrix == static_cast<const ScToken&>(r).GetMatrix(); +} + +// ============================================================================ + +ScExternalSingleRefToken::ScExternalSingleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& r ) : + ScToken( svExternalSingleRef, ocExternalRef), + mnFileId(nFileId), + maTabName(rTabName), + maSingleRef(r) +{ +} + +ScExternalSingleRefToken::ScExternalSingleRefToken( const ScExternalSingleRefToken& r ) : + ScToken(r), + mnFileId(r.mnFileId), + maTabName(r.maTabName), + maSingleRef(r.maSingleRef) +{ +} + +ScExternalSingleRefToken::~ScExternalSingleRefToken() +{ +} + +USHORT ScExternalSingleRefToken::GetIndex() const +{ + return mnFileId; +} + +const String& ScExternalSingleRefToken::GetString() const +{ + return maTabName; +} + +const ScSingleRefData& ScExternalSingleRefToken::GetSingleRef() const +{ + return maSingleRef; +} + +ScSingleRefData& ScExternalSingleRefToken::GetSingleRef() +{ + return maSingleRef; +} + +void ScExternalSingleRefToken::CalcAbsIfRel( const ScAddress& rPos ) +{ + maSingleRef.CalcAbsIfRel( rPos ); +} + +void ScExternalSingleRefToken::CalcRelFromAbs( const ScAddress& rPos ) +{ + maSingleRef.CalcRelFromAbs( rPos ); +} + +BOOL ScExternalSingleRefToken::operator ==( const FormulaToken& r ) const +{ + if (!FormulaToken::operator==(r)) + return false; + + if (mnFileId != r.GetIndex()) + return false; + + if (maTabName != r.GetString()) + return false; + + return maSingleRef == static_cast<const ScToken&>(r).GetSingleRef(); +} + +// ============================================================================ + +ScExternalDoubleRefToken::ScExternalDoubleRefToken( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& r ) : + ScToken( svExternalDoubleRef, ocExternalRef), + mnFileId(nFileId), + maTabName(rTabName), + maDoubleRef(r) +{ +} + +ScExternalDoubleRefToken::ScExternalDoubleRefToken( const ScExternalDoubleRefToken& r ) : + ScToken(r), + mnFileId(r.mnFileId), + maTabName(r.maTabName), + maDoubleRef(r.maDoubleRef) +{ +} + +ScExternalDoubleRefToken::~ScExternalDoubleRefToken() +{ +} + +USHORT ScExternalDoubleRefToken::GetIndex() const +{ + return mnFileId; +} + +const String& ScExternalDoubleRefToken::GetString() const +{ + return maTabName; +} + +const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef() const +{ + return maDoubleRef.Ref1; +} + +ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef() +{ + return maDoubleRef.Ref1; +} + +const ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2() const +{ + return maDoubleRef.Ref2; +} + +ScSingleRefData& ScExternalDoubleRefToken::GetSingleRef2() +{ + return maDoubleRef.Ref2; +} + +const ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef() const +{ + return maDoubleRef; +} + +ScComplexRefData& ScExternalDoubleRefToken::GetDoubleRef() +{ + return maDoubleRef; +} + +void ScExternalDoubleRefToken::CalcAbsIfRel( const ScAddress& rPos ) +{ + maDoubleRef.CalcAbsIfRel( rPos ); +} + +void ScExternalDoubleRefToken::CalcRelFromAbs( const ScAddress& rPos ) +{ + maDoubleRef.CalcRelFromAbs( rPos ); +} + +BOOL ScExternalDoubleRefToken::operator ==( const FormulaToken& r ) const +{ + if (!ScToken::operator==(r)) + return false; + + if (mnFileId != r.GetIndex()) + return false; + + if (maTabName != r.GetString()) + return false; + + return maDoubleRef == static_cast<const ScToken&>(r).GetDoubleRef(); +} + +// ============================================================================ + +ScExternalNameToken::ScExternalNameToken( sal_uInt16 nFileId, const String& rName ) : + ScToken( svExternalName, ocExternalRef), + mnFileId(nFileId), + maName(rName) +{ +} + +ScExternalNameToken::ScExternalNameToken( const ScExternalNameToken& r ) : + ScToken(r), + mnFileId(r.mnFileId), + maName(r.maName) +{ +} + +ScExternalNameToken::~ScExternalNameToken() {} + +USHORT ScExternalNameToken::GetIndex() const +{ + return mnFileId; +} + +const String& ScExternalNameToken::GetString() const +{ + return maName; +} + +BOOL ScExternalNameToken::operator==( const FormulaToken& r ) const +{ + if ( !FormulaToken::operator==(r) ) + return false; + + if (mnFileId != r.GetIndex()) + return false; + + xub_StrLen nLen = maName.Len(); + const String& rName = r.GetString(); + if (nLen != rName.Len()) + return false; + + const sal_Unicode* p1 = maName.GetBuffer(); + const sal_Unicode* p2 = rName.GetBuffer(); + for (xub_StrLen j = 0; j < nLen; ++j) + { + if (p1[j] != p2[j]) + return false; + } + return true; +} + +// ============================================================================ + +ScJumpMatrix* ScJumpMatrixToken::GetJumpMatrix() const { return pJumpMatrix; } +BOOL ScJumpMatrixToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && pJumpMatrix == static_cast<const ScToken&>(r).GetJumpMatrix(); +} +ScJumpMatrixToken::~ScJumpMatrixToken() +{ + delete pJumpMatrix; +} + +double ScEmptyCellToken::GetDouble() const { return 0.0; } +const String & ScEmptyCellToken::GetString() const +{ + static String aDummyString; + return aDummyString; +} +BOOL ScEmptyCellToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && + bInherited == static_cast< const ScEmptyCellToken & >(r).IsInherited() && + bDisplayedAsString == static_cast< const ScEmptyCellToken & >(r).IsDisplayedAsString(); +} + + +double ScMatrixCellResultToken::GetDouble() const { return xUpperLeft->GetDouble(); } +const String & ScMatrixCellResultToken::GetString() const { return xUpperLeft->GetString(); } +const ScMatrix* ScMatrixCellResultToken::GetMatrix() const { return xMatrix; } +// Non-const GetMatrix() is private and unused but must be implemented to +// satisfy vtable linkage. +ScMatrix* ScMatrixCellResultToken::GetMatrix() +{ + return const_cast<ScMatrix*>(xMatrix.operator->()); +} +BOOL ScMatrixCellResultToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && + xUpperLeft == static_cast<const ScMatrixCellResultToken &>(r).xUpperLeft && + xMatrix == static_cast<const ScMatrixCellResultToken &>(r).xMatrix; +} + + +BOOL ScMatrixFormulaCellToken::operator==( const FormulaToken& r ) const +{ + const ScMatrixFormulaCellToken* p = dynamic_cast<const ScMatrixFormulaCellToken*>(&r); + return p && ScMatrixCellResultToken::operator==( r ) && + nCols == p->nCols && nRows == p->nRows; +} +void ScMatrixFormulaCellToken::Assign( const formula::FormulaToken& r ) +{ + if (this == &r) + return; + const ScMatrixCellResultToken* p = dynamic_cast<const ScMatrixCellResultToken*>(&r); + if (p) + ScMatrixCellResultToken::Assign( *p); + else + { + DBG_ASSERT( r.GetType() != svMatrix, "ScMatrixFormulaCellToken::operator=: assigning ScMatrixToken to ScMatrixFormulaCellToken is not proper, use ScMatrixCellResultToken instead"); + if (r.GetType() == svMatrix) + { + xUpperLeft = NULL; + xMatrix = static_cast<const ScToken&>(r).GetMatrix(); + } + else + { + xUpperLeft = &r; + xMatrix = NULL; + } + } +} +void ScMatrixFormulaCellToken::SetUpperLeftDouble( double f ) +{ + switch (GetUpperLeftType()) + { + case svDouble: + const_cast<FormulaToken*>(xUpperLeft.get())->GetDoubleAsReference() = f; + break; + case svUnknown: + if (!xUpperLeft) + { + xUpperLeft = new FormulaDoubleToken( f); + break; + } + // fall thru + default: + { + DBG_ERRORFILE("ScMatrixFormulaCellToken::SetUpperLeftDouble: not modifying unhandled token type"); + } + } +} + + +double ScHybridCellToken::GetDouble() const { return fDouble; } +const String & ScHybridCellToken::GetString() const { return aString; } +BOOL ScHybridCellToken::operator==( const FormulaToken& r ) const +{ + return FormulaToken::operator==( r ) && + fDouble == r.GetDouble() && aString == r.GetString() && + aFormula == static_cast<const ScHybridCellToken &>(r).GetFormula(); +} + + + + +////////////////////////////////////////////////////////////////////////// + +bool ScTokenArray::AddFormulaToken(const com::sun::star::sheet::FormulaToken& _aToken,formula::ExternalReferenceHelper* _pRef) +{ + bool bError = FormulaTokenArray::AddFormulaToken(_aToken,_pRef); + if ( bError ) + { + bError = false; + const OpCode eOpCode = static_cast<OpCode>(_aToken.OpCode); //! assuming equal values for the moment + + const uno::TypeClass eClass = _aToken.Data.getValueTypeClass(); + switch ( eClass ) + { + case uno::TypeClass_STRUCT: + { + uno::Type aType = _aToken.Data.getValueType(); + if ( aType.equals( cppu::UnoType<sheet::SingleReference>::get() ) ) + { + ScSingleRefData aSingleRef; + sheet::SingleReference aApiRef; + _aToken.Data >>= aApiRef; + lcl_SingleRefToCalc( aSingleRef, aApiRef ); + if ( eOpCode == ocPush ) + AddSingleReference( aSingleRef ); + else if ( eOpCode == ocColRowName ) + AddColRowName( aSingleRef ); + else + bError = true; + } + else if ( aType.equals( cppu::UnoType<sheet::ComplexReference>::get() ) ) + { + ScComplexRefData aComplRef; + sheet::ComplexReference aApiRef; + _aToken.Data >>= aApiRef; + lcl_SingleRefToCalc( aComplRef.Ref1, aApiRef.Reference1 ); + lcl_SingleRefToCalc( aComplRef.Ref2, aApiRef.Reference2 ); + + if ( eOpCode == ocPush ) + AddDoubleReference( aComplRef ); + else + bError = true; + } + else if ( aType.equals( cppu::UnoType<sheet::ExternalReference>::get() ) ) + { + sheet::ExternalReference aApiExtRef; + if( (eOpCode == ocPush) && (_aToken.Data >>= aApiExtRef) && (0 <= aApiExtRef.Index) && (aApiExtRef.Index <= SAL_MAX_UINT16) ) + { + sal_uInt16 nFileId = static_cast< sal_uInt16 >( aApiExtRef.Index ); + sheet::SingleReference aApiSRef; + sheet::ComplexReference aApiCRef; + ::rtl::OUString aName; + if( aApiExtRef.Reference >>= aApiSRef ) + { + // try to resolve cache index to sheet name + size_t nCacheId = static_cast< size_t >( aApiSRef.Sheet ); + String aTabName = _pRef->getCacheTableName( nFileId, nCacheId ); + if( aTabName.Len() > 0 ) + { + ScSingleRefData aSingleRef; + // convert column/row settings, set sheet index to absolute + lcl_ExternalRefToCalc( aSingleRef, aApiSRef ); + AddExternalSingleReference( nFileId, aTabName, aSingleRef ); + } + else + bError = true; + } + else if( aApiExtRef.Reference >>= aApiCRef ) + { + // try to resolve cache index to sheet name. + size_t nCacheId = static_cast< size_t >( aApiCRef.Reference1.Sheet ); + String aTabName = _pRef->getCacheTableName( nFileId, nCacheId ); + if( aTabName.Len() > 0 ) + { + ScComplexRefData aComplRef; + // convert column/row settings, set sheet index to absolute + lcl_ExternalRefToCalc( aComplRef.Ref1, aApiCRef.Reference1 ); + lcl_ExternalRefToCalc( aComplRef.Ref2, aApiCRef.Reference2 ); + // NOTE: This assumes that cached sheets are in consecutive order! + aComplRef.Ref2.nTab = aComplRef.Ref1.nTab + static_cast<SCsTAB>(aApiCRef.Reference2.Sheet - aApiCRef.Reference1.Sheet); + AddExternalDoubleReference( nFileId, aTabName, aComplRef ); + } + else + bError = true; + } + else if( aApiExtRef.Reference >>= aName ) + { + if( aName.getLength() > 0 ) + AddExternalName( nFileId, aName ); + else + bError = true; + } + else + bError = true; + } + else + bError = true; + } + else + bError = true; // unknown struct + } + break; + case uno::TypeClass_SEQUENCE: + { + if ( eOpCode != ocPush ) + bError = true; // not an inline array + else if (!_aToken.Data.getValueType().equals( getCppuType( + (uno::Sequence< uno::Sequence< uno::Any > > *)0))) + bError = true; // unexpected sequence type + else + { + ScMatrixRef xMat = ScSequenceToMatrix::CreateMixedMatrix( _aToken.Data); + if (xMat) + AddMatrix( xMat); + else + bError = true; + } + } + break; + default: + bError = true; + } + } + return bError; +} +BOOL ScTokenArray::ImplGetReference( ScRange& rRange, BOOL bValidOnly ) const +{ + BOOL bIs = FALSE; + if ( pCode && nLen == 1 ) + { + const FormulaToken* pToken = pCode[0]; + if ( pToken ) + { + if ( pToken->GetType() == svSingleRef ) + { + const ScSingleRefData& rRef = ((const ScSingleRefToken*)pToken)->GetSingleRef(); + rRange.aStart = rRange.aEnd = ScAddress( rRef.nCol, rRef.nRow, rRef.nTab ); + bIs = !bValidOnly || !rRef.IsDeleted(); + } + else if ( pToken->GetType() == svDoubleRef ) + { + const ScComplexRefData& rCompl = ((const ScDoubleRefToken*)pToken)->GetDoubleRef(); + const ScSingleRefData& rRef1 = rCompl.Ref1; + const ScSingleRefData& rRef2 = rCompl.Ref2; + rRange.aStart = ScAddress( rRef1.nCol, rRef1.nRow, rRef1.nTab ); + rRange.aEnd = ScAddress( rRef2.nCol, rRef2.nRow, rRef2.nTab ); + bIs = !bValidOnly || (!rRef1.IsDeleted() && !rRef2.IsDeleted()); + } + } + } + return bIs; +} + +BOOL ScTokenArray::IsReference( ScRange& rRange ) const +{ + return ImplGetReference( rRange, FALSE ); +} + +BOOL ScTokenArray::IsValidReference( ScRange& rRange ) const +{ + return ImplGetReference( rRange, TRUE ); +} + +//////////////////////////////////////////////////////////////////////////// + +ScTokenArray::ScTokenArray() +{ +} + +ScTokenArray::ScTokenArray( const ScTokenArray& rArr ) : FormulaTokenArray(rArr) +{ +} + +ScTokenArray::~ScTokenArray() +{ +} + + + +ScTokenArray& ScTokenArray::operator=( const ScTokenArray& rArr ) +{ + Clear(); + Assign( rArr ); + return *this; +} + +ScTokenArray* ScTokenArray::Clone() const +{ + ScTokenArray* p = new ScTokenArray(); + p->nLen = nLen; + p->nRPN = nRPN; + p->nRefs = nRefs; + p->nMode = nMode; + p->nError = nError; + p->bHyperLink = bHyperLink; + FormulaToken** pp; + if( nLen ) + { + pp = p->pCode = new FormulaToken*[ nLen ]; + memcpy( pp, pCode, nLen * sizeof( ScToken* ) ); + for( USHORT i = 0; i < nLen; i++, pp++ ) + { + *pp = (*pp)->Clone(); + (*pp)->IncRef(); + } + } + if( nRPN ) + { + pp = p->pRPN = new FormulaToken*[ nRPN ]; + memcpy( pp, pRPN, nRPN * sizeof( ScToken* ) ); + for( USHORT i = 0; i < nRPN; i++, pp++ ) + { + FormulaToken* t = *pp; + if( t->GetRef() > 1 ) + { + FormulaToken** p2 = pCode; + USHORT nIdx = 0xFFFF; + for( USHORT j = 0; j < nLen; j++, p2++ ) + { + if( *p2 == t ) + { + nIdx = j; break; + } + } + if( nIdx == 0xFFFF ) + *pp = t->Clone(); + else + *pp = p->pCode[ nIdx ]; + } + else + *pp = t->Clone(); + (*pp)->IncRef(); + } + } + return p; +} + +FormulaToken* ScTokenArray::AddRawToken( const ScRawToken& r ) +{ + return Add( r.CreateToken() ); +} + +// Utility function to ensure that there is strict alternation of values and +// seperators. +static bool +checkArraySep( bool & bPrevWasSep, bool bNewVal ) +{ + bool bResult = (bPrevWasSep == bNewVal); + bPrevWasSep = bNewVal; + return bResult; +} + +FormulaToken* ScTokenArray::MergeArray( ) +{ + int nCol = -1, nRow = 0; + int i, nPrevRowSep = -1, nStart = 0; + bool bPrevWasSep = false; // top of stack is ocArrayClose + FormulaToken* t; + bool bNumeric = false; // numeric value encountered in current element + + // (1) Iterate from the end to the start to find matrix dims + // and do basic validation. + for ( i = nLen ; i-- > nStart ; ) + { + t = pCode[i]; + switch ( t->GetOpCode() ) + { + case ocPush : + if( checkArraySep( bPrevWasSep, false ) ) + { + return NULL; + } + + // no references or nested arrays + if ( t->GetType() != svDouble && t->GetType() != svString ) + { + return NULL; + } + bNumeric = (t->GetType() == svDouble); + break; + + case ocMissing : + case ocTrue : + case ocFalse : + if( checkArraySep( bPrevWasSep, false ) ) + { + return NULL; + } + bNumeric = false; + break; + + case ocArrayColSep : + case ocSep : + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + bNumeric = false; + break; + + case ocArrayClose : + // not possible with the , but check just in case + // something changes in the future + if( i != (nLen-1)) + { + return NULL; + } + + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + + nPrevRowSep = i; + bNumeric = false; + break; + + case ocArrayOpen : + nStart = i; // stop iteration + // fall through to ArrayRowSep + + case ocArrayRowSep : + if( checkArraySep( bPrevWasSep, true ) ) + { + return NULL; + } + + if( nPrevRowSep < 0 || // missing ocArrayClose + ((nPrevRowSep - i) % 2) == 1) // no complex elements + { + return NULL; + } + + if( nCol < 0 ) + { + nCol = (nPrevRowSep - i) / 2; + } + else if( (nPrevRowSep - i)/2 != nCol) // irregular array + { + return NULL; + } + + nPrevRowSep = i; + nRow++; + bNumeric = false; + break; + + case ocNegSub : + case ocAdd : + // negation or unary plus must precede numeric value + if( !bNumeric ) + { + return NULL; + } + --nPrevRowSep; // shorten this row by 1 + bNumeric = false; // one level only, no --42 + break; + + case ocSpaces : + // ignore spaces + --nPrevRowSep; // shorten this row by 1 + break; + + default : + // no functions or operators + return NULL; + } + } + if( nCol <= 0 || nRow <= 0 ) + return NULL; + + // fprintf (stderr, "Array (cols = %d, rows = %d)\n", nCol, nRow ); + + int nSign = 1; + ScMatrix* pArray = new ScMatrix( nCol, nRow ); + for ( i = nStart, nCol = 0, nRow = 0 ; i < nLen ; i++ ) + { + t = pCode[i]; + + switch ( t->GetOpCode() ) + { + case ocPush : + if ( t->GetType() == svDouble ) + { + pArray->PutDouble( t->GetDouble() * nSign, nCol, nRow ); + nSign = 1; + } + else if ( t->GetType() == svString ) + { + pArray->PutString( t->GetString(), nCol, nRow ); + } + break; + + case ocMissing : + pArray->PutEmpty( nCol, nRow ); + break; + + case ocTrue : + pArray->PutBoolean( true, nCol, nRow ); + break; + + case ocFalse : + pArray->PutBoolean( false, nCol, nRow ); + break; + + case ocArrayColSep : + case ocSep : + nCol++; + break; + + case ocArrayRowSep : + nRow++; nCol = 0; + break; + + case ocNegSub : + nSign = -nSign; + break; + + default : + break; + } + pCode[i] = NULL; + t->DecRef(); + } + nLen = USHORT( nStart ); + return AddMatrix( pArray ); +} + + +FormulaToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos ) +{ + if (!pCode || !nLen) + return NULL; + USHORT nIdx = nLen; + FormulaToken *p1, *p2, *p3; // ref, ocRange, ref + // The actual types are checked in ExtendRangeReference(). + if (((p3 = PeekPrev(nIdx)) != 0) && + (((p2 = PeekPrev(nIdx)) != 0) && p2->GetOpCode() == ocRange) && + ((p1 = PeekPrev(nIdx)) != 0)) + { + FormulaTokenRef p = ScToken::ExtendRangeReference( *p1, *p3, rPos, true); + if (p) + { + p->IncRef(); + p1->DecRef(); + p2->DecRef(); + p3->DecRef(); + nLen -= 2; + pCode[ nLen-1 ] = p; + nRefs--; + } + } + return pCode[ nLen-1 ]; +} + +FormulaToken* ScTokenArray::AddOpCode( OpCode e ) +{ + ScRawToken t; + t.SetOpCode( e ); + return AddRawToken( t ); +} + +FormulaToken* ScTokenArray::AddSingleReference( const ScSingleRefData& rRef ) +{ + return Add( new ScSingleRefToken( rRef ) ); +} + +FormulaToken* ScTokenArray::AddMatrixSingleReference( const ScSingleRefData& rRef ) +{ + return Add( new ScSingleRefToken( rRef, ocMatRef ) ); +} + +FormulaToken* ScTokenArray::AddDoubleReference( const ScComplexRefData& rRef ) +{ + return Add( new ScDoubleRefToken( rRef ) ); +} + +FormulaToken* ScTokenArray::AddMatrix( ScMatrix* p ) +{ + return Add( new ScMatrixToken( p ) ); +} + +FormulaToken* ScTokenArray::AddExternalName( sal_uInt16 nFileId, const String& rName ) +{ + return Add( new ScExternalNameToken(nFileId, rName) ); +} + +FormulaToken* ScTokenArray::AddExternalSingleReference( sal_uInt16 nFileId, const String& rTabName, const ScSingleRefData& rRef ) +{ + return Add( new ScExternalSingleRefToken(nFileId, rTabName, rRef) ); +} + +FormulaToken* ScTokenArray::AddExternalDoubleReference( sal_uInt16 nFileId, const String& rTabName, const ScComplexRefData& rRef ) +{ + return Add( new ScExternalDoubleRefToken(nFileId, rTabName, rRef) ); +} + +FormulaToken* ScTokenArray::AddColRowName( const ScSingleRefData& rRef ) +{ + return Add( new ScSingleRefToken( rRef, ocColRowName ) ); +} + +BOOL ScTokenArray::GetAdjacentExtendOfOuterFuncRefs( SCCOLROW& nExtend, + const ScAddress& rPos, ScDirection eDir ) +{ + SCCOL nCol = 0; + SCROW nRow = 0; + switch ( eDir ) + { + case DIR_BOTTOM : + if ( rPos.Row() < MAXROW ) + nRow = (nExtend = rPos.Row()) + 1; + else + return FALSE; + break; + case DIR_RIGHT : + if ( rPos.Col() < MAXCOL ) + nCol = static_cast<SCCOL>(nExtend = rPos.Col()) + 1; + else + return FALSE; + break; + case DIR_TOP : + if ( rPos.Row() > 0 ) + nRow = (nExtend = rPos.Row()) - 1; + else + return FALSE; + break; + case DIR_LEFT : + if ( rPos.Col() > 0 ) + nCol = static_cast<SCCOL>(nExtend = rPos.Col()) - 1; + else + return FALSE; + break; + default: + DBG_ERRORFILE( "unknown Direction" ); + return FALSE; + } + if ( pRPN && nRPN ) + { + FormulaToken* t = pRPN[nRPN-1]; + if ( t->GetType() == svByte ) + { + BYTE nParamCount = t->GetByte(); + if ( nParamCount && nRPN > nParamCount ) + { + BOOL bRet = FALSE; + USHORT nParam = nRPN - nParamCount - 1; + for ( ; nParam < nRPN-1; nParam++ ) + { + FormulaToken* p = pRPN[nParam]; + switch ( p->GetType() ) + { + case svSingleRef : + { + ScSingleRefData& rRef = static_cast<ScToken*>(p)->GetSingleRef(); + rRef.CalcAbsIfRel( rPos ); + switch ( eDir ) + { + case DIR_BOTTOM : + if ( rRef.nRow == nRow + && rRef.nRow > nExtend ) + { + nExtend = rRef.nRow; + bRet = TRUE; + } + break; + case DIR_RIGHT : + if ( rRef.nCol == nCol + && static_cast<SCCOLROW>(rRef.nCol) + > nExtend ) + { + nExtend = rRef.nCol; + bRet = TRUE; + } + break; + case DIR_TOP : + if ( rRef.nRow == nRow + && rRef.nRow < nExtend ) + { + nExtend = rRef.nRow; + bRet = TRUE; + } + break; + case DIR_LEFT : + if ( rRef.nCol == nCol + && static_cast<SCCOLROW>(rRef.nCol) + < nExtend ) + { + nExtend = rRef.nCol; + bRet = TRUE; + } + break; + } + } + break; + case svDoubleRef : + { + ScComplexRefData& rRef = static_cast<ScToken*>(p)->GetDoubleRef(); + rRef.CalcAbsIfRel( rPos ); + switch ( eDir ) + { + case DIR_BOTTOM : + if ( rRef.Ref1.nRow == nRow + && rRef.Ref2.nRow > nExtend ) + { + nExtend = rRef.Ref2.nRow; + bRet = TRUE; + } + break; + case DIR_RIGHT : + if ( rRef.Ref1.nCol == nCol && + static_cast<SCCOLROW>(rRef.Ref2.nCol) + > nExtend ) + { + nExtend = rRef.Ref2.nCol; + bRet = TRUE; + } + break; + case DIR_TOP : + if ( rRef.Ref2.nRow == nRow + && rRef.Ref1.nRow < nExtend ) + { + nExtend = rRef.Ref1.nRow; + bRet = TRUE; + } + break; + case DIR_LEFT : + if ( rRef.Ref2.nCol == nCol && + static_cast<SCCOLROW>(rRef.Ref1.nCol) + < nExtend ) + { + nExtend = rRef.Ref1.nCol; + bRet = TRUE; + } + break; + } + } + break; + default: + { + // added to avoid warnings + } + } // switch + } // for + return bRet; + } + } + } + return FALSE; +} + + +void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos, + const ScAddress& rNewPos ) +{ + for ( USHORT j=0; j<nLen; ++j ) + { + switch ( pCode[j]->GetType() ) + { + case svDoubleRef : + { + ScSingleRefData& rRef2 = static_cast<ScToken*>(pCode[j])->GetSingleRef2(); + // Also adjust if the reference is of the form Sheet1.A2:A3 + if ( rRef2.IsFlag3D() || static_cast<ScToken*>(pCode[j])->GetSingleRef().IsFlag3D() ) + { + rRef2.CalcAbsIfRel( rOldPos ); + rRef2.CalcRelFromAbs( rNewPos ); + } + } + //! fallthru + case svSingleRef : + { + ScSingleRefData& rRef1 = static_cast<ScToken*>(pCode[j])->GetSingleRef(); + if ( rRef1.IsFlag3D() ) + { + rRef1.CalcAbsIfRel( rOldPos ); + rRef1.CalcRelFromAbs( rNewPos ); + } + } + break; + default: + { + // added to avoid warnings + } + } + } +} + + |