summaryrefslogtreecommitdiff
path: root/sc/source/core/tool/token.cxx
diff options
context:
space:
mode:
Diffstat (limited to 'sc/source/core/tool/token.cxx')
-rw-r--r--sc/source/core/tool/token.cxx1836
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
+ }
+ }
+ }
+}
+
+