blob: de183635f305947148f61bd07ac28ba3cf2ad04a [file] [log] [blame]
/**************************************************************
*
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*
*************************************************************/
// MARKER(update_precomp.py): autogen include statement, do not remove
#include "precompiled_sc.hxx"
// INCLUDE ---------------------------------------------------------------
#include <cstddef>
#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 sal_uInt16 nMemPoolDoubleRawToken = 0x0400 / sizeof(ScDoubleRawToken);
IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRawToken, nMemPoolDoubleRawToken, nMemPoolDoubleRawToken )
// Need a whole bunch of ScSingleRefToken
const sal_uInt16 nMemPoolSingleRefToken = (0x4000 - 64) / sizeof(ScSingleRefToken);
IMPL_FIXEDMEMPOOL_NEWDEL( ScSingleRefToken, nMemPoolSingleRefToken, nMemPoolSingleRefToken )
// Need quite a lot of ScDoubleRefToken
const sal_uInt16 nMemPoolDoubleRefToken = (0x2000 - 64) / sizeof(ScDoubleRefToken);
IMPL_FIXEDMEMPOOL_NEWDEL( ScDoubleRefToken, nMemPoolDoubleRefToken, nMemPoolDoubleRefToken )
// --- helpers --------------------------------------------------------------
inline sal_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( sal_uInt16 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;
}
sal_uInt16 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<sal_uInt16>( 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 sal_uInt16 nOffset = lcl_ScRawTokenOffset(); // offset of sbyte
sal_uInt16 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<sal_uInt16>( n + GetStrLenBytes( cStr ) + GetStrLenBytes( 1 ) ); break;
case svSingleRef:
case svDoubleRef: n += sizeof(aRef); break;
case svMatrix: n += sizeof(ScMatrix*); break;
case svIndex: n += sizeof(sal_uInt16); break;
case svJump: n += nJump[ 0 ] * 2 + 2; break;
case svExternal: n = sal::static_int_cast<sal_uInt16>( n + GetStrLenBytes( cStr+1 ) + GetStrLenBytes( 2 ) ); break;
default:
{
DBG_ERROR1( "unknown ScRawToken::Clone() type %d", int(eType));
}
}
}
p = (ScRawToken*) new sal_uInt8[ n ];
memcpy( p, this, n * sizeof(sal_uInt8) );
}
p->nRefCnt = 0;
p->bRaw = sal_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 [] (sal_uInt8*) 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)
sal_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 sal_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==
}
sal_Bool ScToken::Is3DRef() const
{
switch ( eType )
{
case svDoubleRef :
if ( GetSingleRef2().IsFlag3D() )
return sal_True;
//! fallthru
case svSingleRef :
if ( GetSingleRef().IsFlag3D() )
return sal_True;
break;
case svExternalSingleRef:
case svExternalDoubleRef:
return sal_True;
default:
{
// added to avoid warnings
}
}
return sal_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 ); }
sal_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 ); }
sal_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);
}
sal_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; }
sal_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()
{
}
sal_uInt16 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 );
}
sal_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( const ScExternalSingleRefToken& r ) :
ScToken( svExternalDoubleRef, ocExternalRef),
mnFileId( r.GetIndex()),
maTabName( r.GetString())
{
maDoubleRef.Ref1 = maDoubleRef.Ref2 = r.GetSingleRef();
}
ScExternalDoubleRefToken::~ScExternalDoubleRefToken()
{
}
sal_uInt16 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 );
}
sal_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() {}
sal_uInt16 ScExternalNameToken::GetIndex() const
{
return mnFileId;
}
const String& ScExternalNameToken::GetString() const
{
return maName;
}
sal_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; }
sal_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;
}
sal_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->());
}
sal_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;
}
sal_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; }
sal_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;
}
sal_Bool ScTokenArray::ImplGetReference( ScRange& rRange, sal_Bool bValidOnly ) const
{
sal_Bool bIs = sal_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;
}
sal_Bool ScTokenArray::IsReference( ScRange& rRange ) const
{
return ImplGetReference( rRange, sal_False );
}
sal_Bool ScTokenArray::IsValidReference( ScRange& rRange ) const
{
return ImplGetReference( rRange, sal_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( sal_uInt16 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( sal_uInt16 i = 0; i < nRPN; i++, pp++ )
{
FormulaToken* t = *pp;
if( t->GetRef() > 1 )
{
FormulaToken** p2 = pCode;
sal_uInt16 nIdx = 0xFFFF;
for( sal_uInt16 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 = sal_uInt16( nStart );
return AddMatrix( pArray );
}
FormulaToken* ScTokenArray::MergeRangeReference( const ScAddress & rPos )
{
if (!pCode || !nLen)
return NULL;
sal_uInt16 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 ) );
}
sal_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 sal_False;
break;
case DIR_RIGHT :
if ( rPos.Col() < MAXCOL )
nCol = static_cast<SCCOL>(nExtend = rPos.Col()) + 1;
else
return sal_False;
break;
case DIR_TOP :
if ( rPos.Row() > 0 )
nRow = (nExtend = rPos.Row()) - 1;
else
return sal_False;
break;
case DIR_LEFT :
if ( rPos.Col() > 0 )
nCol = static_cast<SCCOL>(nExtend = rPos.Col()) - 1;
else
return sal_False;
break;
default:
DBG_ERRORFILE( "unknown Direction" );
return sal_False;
}
if ( pRPN && nRPN )
{
FormulaToken* t = pRPN[nRPN-1];
if ( t->GetType() == svByte )
{
sal_uInt8 nParamCount = t->GetByte();
if ( nParamCount && nRPN > nParamCount )
{
sal_Bool bRet = sal_False;
sal_uInt16 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 = sal_True;
}
break;
case DIR_RIGHT :
if ( rRef.nCol == nCol
&& static_cast<SCCOLROW>(rRef.nCol)
> nExtend )
{
nExtend = rRef.nCol;
bRet = sal_True;
}
break;
case DIR_TOP :
if ( rRef.nRow == nRow
&& rRef.nRow < nExtend )
{
nExtend = rRef.nRow;
bRet = sal_True;
}
break;
case DIR_LEFT :
if ( rRef.nCol == nCol
&& static_cast<SCCOLROW>(rRef.nCol)
< nExtend )
{
nExtend = rRef.nCol;
bRet = sal_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 = sal_True;
}
break;
case DIR_RIGHT :
if ( rRef.Ref1.nCol == nCol &&
static_cast<SCCOLROW>(rRef.Ref2.nCol)
> nExtend )
{
nExtend = rRef.Ref2.nCol;
bRet = sal_True;
}
break;
case DIR_TOP :
if ( rRef.Ref2.nRow == nRow
&& rRef.Ref1.nRow < nExtend )
{
nExtend = rRef.Ref1.nRow;
bRet = sal_True;
}
break;
case DIR_LEFT :
if ( rRef.Ref2.nCol == nCol &&
static_cast<SCCOLROW>(rRef.Ref1.nCol)
< nExtend )
{
nExtend = rRef.Ref1.nCol;
bRet = sal_True;
}
break;
}
}
break;
default:
{
// added to avoid warnings
}
} // switch
} // for
return bRet;
}
}
}
return sal_False;
}
void ScTokenArray::ReadjustRelative3DReferences( const ScAddress& rOldPos,
const ScAddress& rNewPos )
{
for ( sal_uInt16 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;
case svExternalDoubleRef:
{
ScSingleRefData& rRef2 = static_cast<ScToken*>(pCode[j])->GetSingleRef2();
rRef2.CalcAbsIfRel( rOldPos );
rRef2.CalcRelFromAbs( rNewPos );
}
//! fallthru
case svExternalSingleRef:
{
ScSingleRefData& rRef1 = static_cast<ScToken*>(pCode[j])->GetSingleRef();
rRef1.CalcAbsIfRel( rOldPos );
rRef1.CalcRelFromAbs( rNewPos );
}
break;
default:
{
// added to avoid warnings
}
}
}
}