diff options
author | Kurt Zenker <kz@openoffice.org> | 2008-03-06 14:32:04 +0000 |
---|---|---|
committer | Kurt Zenker <kz@openoffice.org> | 2008-03-06 14:32:04 +0000 |
commit | 2091b3c8b14b2345098d0b4d318332cd4e886c70 (patch) | |
tree | b4ee24878a3de4191258dd420f87430afa12d672 /sc | |
parent | f273b8e07c477bbebb6c3eb703ae2936ceac4025 (diff) |
INTEGRATION: CWS odff (1.51.38); FILE MERGED
2008/02/27 18:32:38 er 1.51.38.21: RESYNC: (1.53-1.55); FILE MERGED
2008/02/20 16:41:50 er 1.51.38.20: #i32340# ISBLANK needs to distinguish between inherited / non-inherited emptiness; corrected ISNUMBER and ISTEXT/ISNONTEXT handling of svEmptyCell
2008/02/13 15:50:10 dr 1.51.38.19: 'warnings'
2008/02/12 11:21:12 er 1.51.38.18: #i77280# make CHOOSE() select an endpoint path in case of error so ISERROR(CHOOSE()) yields TRUE
2008/02/07 13:10:02 er 1.51.38.17: Always wanted to do this, now I'm taking the opportunity: :retab on selected files and all tabs are gone, producing hopefully easier to read diffs in future.
2008/02/06 22:27:46 er 1.51.38.16: #i8947# MATCH with array/matrix as lookup parameter; applied patch from <kohei>
2008/02/06 10:16:22 er 1.51.38.15: for clarity and safety on signed types, comparison on >0
2008/01/31 22:15:16 er 1.51.38.14: more consistent error codes, IllegalArgument vs. IllegalParameter
2008/01/31 20:05:32 er 1.51.38.13: now that we have error token: some PopError() instead of Pop() and some PushError(...) instead of SetError(...)
2008/01/31 15:34:23 er 1.51.38.12: #i32340# ScFormulaResult, third wave
2008/01/21 18:51:17 er 1.51.38.11: RESYNC: (1.51-1.53); FILE MERGED
2008/01/11 19:54:56 er 1.51.38.10: ScErrorToken matrix cases
2008/01/10 16:54:27 er 1.51.38.9: introduce ScErrorToken, get rid of secondary error stack
2008/01/08 15:39:30 er 1.51.38.8: #i38759# ScMin/ScMax: for MS-Excel interoperability the result of an empty set (no value at all in the arguments given) is zero instead of error; even if that could be regarded as mathematical nonsense..; patch from Lv Yue <lvyue>, slightly modified
2008/01/07 19:42:01 er 1.51.38.7: #i85000# shrinking the source range is the better approach
2008/01/07 13:11:42 er 1.51.38.6: #i85000# ScSumIf: Xcl silent cutaway style ignoring out-of-sheet-bounds
2008/01/07 11:37:32 er 1.51.38.5: #i85000# ScSumIf: if 3rd parameter use only upper left and take geometry from 1st parameter; patch from Kohei
2008/01/04 18:43:15 er 1.51.38.4: #i32341# make AREAS() handle RefList
2008/01/04 16:45:15 er 1.51.38.3: #i32341# get rid of INDEX() special treatment and use RefList instead
2007/12/19 20:15:02 er 1.51.38.2: #i32341# ocUnion: functions handling svRefList
2007/12/17 15:59:34 er 1.51.38.1: #i32341# union / range list operator ocUnion; first wave
Diffstat (limited to 'sc')
-rw-r--r-- | sc/source/core/tool/interpr1.cxx | 1571 |
1 files changed, 915 insertions, 656 deletions
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx index aa6704f2ccfa..1d24faee53ac 100644 --- a/sc/source/core/tool/interpr1.cxx +++ b/sc/source/core/tool/interpr1.cxx @@ -4,9 +4,9 @@ * * $RCSfile: interpr1.cxx,v $ * - * $Revision: 1.55 $ + * $Revision: 1.56 $ * - * last change: $Author: rt $ $Date: 2008-01-29 15:22:31 $ + * last change: $Author: kz $ $Date: 2008-03-06 15:32:04 $ * * The Contents of this file are made available subject to * the terms of GNU Lesser General Public License Version 2.1. @@ -76,11 +76,9 @@ #define SC_DOUBLE_MAXVALUE 1.7e307 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack, 8, 4 ) -IMPL_FIXEDMEMPOOL_NEWDEL( ScErrorStack, 8, 4 ) IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter, 32, 16 ) ScTokenStack* ScInterpreter::pGlobalStack = NULL; -ScErrorStack* ScInterpreter::pGlobalErrorStack = NULL; BOOL ScInterpreter::bGlobalStackInUse = FALSE; @@ -100,7 +98,7 @@ void ScInterpreter::ScIfJump() { ScMatrixRef pMat = PopMatrix(); if ( !pMat ) - SetIllegalArgument(); + PushIllegalParameter(); else { ScTokenRef xNew; @@ -110,7 +108,7 @@ void ScInterpreter::ScIfJump() SCSIZE nCols, nRows; pMat->GetDimensions( nCols, nRows ); if ( nCols == 0 || nRows == 0 ) - SetIllegalParameter(); + PushIllegalArgument(); else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find( pCur)) != pTokenMatrixMap->end())) xNew = (*aMapIter).second; @@ -218,6 +216,9 @@ void ScInterpreter::ScIfJump() void ScInterpreter::ScChoseJump() { + // We have to set a jump, if there was none chosen because of an error set + // it to endpoint. + bool bHaveJump = false; const short* pJump = pCur->GetJump(); short nJumpCount = pJump[ 0 ]; MatrixDoubleRefToMatrix(); @@ -227,7 +228,7 @@ void ScInterpreter::ScChoseJump() { ScMatrixRef pMat = PopMatrix(); if ( !pMat ) - SetIllegalArgument(); + PushIllegalParameter(); else { ScTokenRef xNew; @@ -237,7 +238,7 @@ void ScInterpreter::ScChoseJump() SCSIZE nCols, nRows; pMat->GetDimensions( nCols, nRows ); if ( nCols == 0 || nRows == 0 ) - SetIllegalParameter(); + PushIllegalParameter(); else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find( pCur)) != pTokenMatrixMap->end())) xNew = (*aMapIter).second; @@ -293,18 +294,24 @@ void ScInterpreter::ScChoseJump() PushTempToken( xNew); // set endpoint of path for main code line aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] ); + bHaveJump = true; } } break; default: { double nJumpIndex = ::rtl::math::approxFloor( GetDouble() ); - if ((nJumpIndex >= 1) && (nJumpIndex < nJumpCount)) + if (!nGlobalError && (nJumpIndex >= 1) && (nJumpIndex < nJumpCount)) + { aCode.Jump( pJump[ (short) nJumpIndex ], pJump[ nJumpCount ] ); + bHaveJump = true; + } else - SetError(errIllegalArgument); + PushIllegalArgument(); } } + if (!bHaveJump) + aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] ); } @@ -369,39 +376,31 @@ bool ScInterpreter::JumpMatrix( short nStackLevel ) else { ScBaseCell* pCell = GetCell( aAdr ); - switch ( GetCellType( pCell ) ) + if (HasCellEmptyData( pCell)) + pResMat->PutEmpty( nC, nR ); + else if (HasCellValueData( pCell)) { - case CELLTYPE_NONE: - case CELLTYPE_NOTE: - pResMat->PutEmpty( nC, nR ); - break; - default: + double fVal = GetCellValue( aAdr, pCell); + if ( nGlobalError ) { - if ( HasCellValueData( pCell ) ) - { - double fVal = GetCellValue( aAdr, pCell); - if ( nGlobalError ) - { - fVal = CreateDoubleError( - nGlobalError); - nGlobalError = 0; - } - pResMat->PutDouble( fVal, nC, nR ); - } - else - { - String aStr; - GetCellString( aStr, pCell ); - if ( nGlobalError ) - { - pResMat->PutDouble( CreateDoubleError( - nGlobalError), nC, nR); - nGlobalError = 0; - } - else - pResMat->PutString( aStr, nC, nR); - } + fVal = CreateDoubleError( + nGlobalError); + nGlobalError = 0; + } + pResMat->PutDouble( fVal, nC, nR ); + } + else + { + String aStr; + GetCellString( aStr, pCell ); + if ( nGlobalError ) + { + pResMat->PutDouble( CreateDoubleError( + nGlobalError), nC, nR); + nGlobalError = 0; } + else + pResMat->PutString( aStr, nC, nR); } } } @@ -431,39 +430,31 @@ bool ScInterpreter::JumpMatrix( short nStackLevel ) rAdr.SetCol( static_cast<SCCOL>(nCol) ); rAdr.SetRow( static_cast<SCROW>(nRow) ); ScBaseCell* pCell = GetCell( rAdr ); - switch ( GetCellType( pCell ) ) + if (HasCellEmptyData( pCell)) + pResMat->PutEmpty( nC, nR ); + else if (HasCellValueData( pCell)) { - case CELLTYPE_NONE: - case CELLTYPE_NOTE: - pResMat->PutEmpty( nC, nR ); - break; - default: + double fCellVal = GetCellValue( rAdr, pCell); + if ( nGlobalError ) { - if ( HasCellValueData( pCell ) ) - { - double fCellVal = GetCellValue( rAdr, pCell); - if ( nGlobalError ) - { - fCellVal = CreateDoubleError( - nGlobalError); - nGlobalError = 0; - } - pResMat->PutDouble( fCellVal, nC, nR ); - } - else - { - String aStr; - GetCellString( aStr, pCell ); - if ( nGlobalError ) - { - pResMat->PutDouble( CreateDoubleError( - nGlobalError), nC, nR); - nGlobalError = 0; - } - else - pResMat->PutString( aStr, nC, nR ); - } + fCellVal = CreateDoubleError( + nGlobalError); + nGlobalError = 0; } + pResMat->PutDouble( fCellVal, nC, nR ); + } + else + { + String aStr; + GetCellString( aStr, pCell ); + if ( nGlobalError ) + { + pResMat->PutDouble( CreateDoubleError( + nGlobalError), nC, nR); + nGlobalError = 0; + } + else + pResMat->PutString( aStr, nC, nR ); } } } @@ -510,6 +501,14 @@ bool ScInterpreter::JumpMatrix( short nStackLevel ) } } break; + case svError: + { + PopError(); + double fVal = CreateDoubleError( nGlobalError); + nGlobalError = 0; + pResMat->PutDouble( fVal, nC, nR ); + } + break; default: { Pop(); @@ -547,7 +546,10 @@ bool ScInterpreter::JumpMatrix( short nStackLevel ) for ( ScTokenVec::const_iterator i = pParams->begin(); i != pParams->end(); ++i ) { - Push( *(*i)); + // This is not the current state of the interpreter, so + // push without error, and elements' errors are coded into + // double. + PushWithoutError( *(*i)); } } aCode.Jump( nStart, nNext, nStop ); @@ -656,13 +658,16 @@ double ScInterpreter::CompareFunc( const ScCompare& rComp ) double ScInterpreter::Compare() { - nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL; String aVal1, aVal2; ScCompare aComp( &aVal1, &aVal2 ); for( short i = 1; i >= 0; i-- ) { - switch ( GetStackType() ) + switch ( GetRawStackType() ) { + case svEmptyCell: + aComp.bEmpty[ i ] = TRUE; + break; + case svMissing: case svDouble: aComp.nVal[ i ] = GetDouble(); aComp.bVal[ i ] = TRUE; @@ -678,45 +683,46 @@ double ScInterpreter::Compare() if ( !PopDoubleRefOrSingleRef( aAdr ) ) break; ScBaseCell* pCell = GetCell( aAdr ); - if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE ) + if (HasCellEmptyData( pCell)) + aComp.bEmpty[ i ] = TRUE; + else if (HasCellStringData( pCell)) { - if (HasCellStringData(pCell)) - { - GetCellString(*aComp.pVal[ i ], pCell); - aComp.bVal[ i ] = FALSE; - } - else - { - aComp.nVal[ i ] = GetCellValue( aAdr, pCell ); - aComp.bVal[ i ] = TRUE; - } + GetCellString( *aComp.pVal[ i ], pCell); + aComp.bVal[ i ] = FALSE; } else - aComp.bEmpty[ i ] = TRUE; + { + aComp.nVal[ i ] = GetCellValue( aAdr, pCell ); + aComp.bVal[ i ] = TRUE; + } } break; default: - SetError(errIllegalParameter); + SetError( errIllegalParameter); break; } } if( nGlobalError ) return 0; + nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL; return CompareFunc( aComp ); } ScMatrixRef ScInterpreter::CompareMat() { - nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL; String aVal1, aVal2; ScCompare aComp( &aVal1, &aVal2 ); ScMatrixRef pMat[2]; ScAddress aAdr; for( short i = 1; i >= 0; i-- ) { - switch (GetStackType()) + switch (GetRawStackType()) { + case svEmptyCell: + aComp.bEmpty[ i ] = TRUE; + break; + case svMissing: case svDouble: aComp.nVal[ i ] = GetDouble(); aComp.bVal[ i ] = TRUE; @@ -729,34 +735,31 @@ ScMatrixRef ScInterpreter::CompareMat() { PopSingleRef( aAdr ); ScBaseCell* pCell = GetCell( aAdr ); - if ( pCell && pCell->GetCellType() != CELLTYPE_NOTE ) + if (HasCellEmptyData( pCell)) + aComp.bEmpty[ i ] = TRUE; + else if (HasCellStringData( pCell)) { - if (HasCellStringData(pCell)) - { - GetCellString(*aComp.pVal[ i ], pCell); - aComp.bVal[ i ] = FALSE; - } - else - { - aComp.nVal[ i ] = GetCellValue( aAdr, pCell ); - aComp.bVal[ i ] = TRUE; - } + GetCellString( *aComp.pVal[ i ], pCell); + aComp.bVal[ i ] = FALSE; } else - aComp.bEmpty[ i ] = TRUE; + { + aComp.nVal[ i ] = GetCellValue( aAdr, pCell ); + aComp.bVal[ i ] = TRUE; + } } break; case svDoubleRef: case svMatrix: pMat[ i ] = GetMatrix(); if ( !pMat[ i ] ) - SetError(errIllegalParameter); + SetError( errIllegalParameter); else pMat[i]->SetErrorInterpreter( NULL); // errors are transported as DoubleError inside matrix break; default: - SetError(errIllegalParameter); + SetError( errIllegalParameter); break; } } @@ -829,6 +832,7 @@ ScMatrixRef ScInterpreter::CompareMat() } } } + nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL; return pResMat; } @@ -839,7 +843,7 @@ void ScInterpreter::ScEqual() { ScMatrixRef pMat = CompareMat(); if ( !pMat ) - SetIllegalParameter(); + PushIllegalParameter(); else { pMat->CompareEqual(); @@ -857,7 +861,7 @@ void ScInterpreter::ScNotEqual() { ScMatrixRef pMat = CompareMat(); if ( !pMat ) - SetIllegalParameter(); + PushIllegalParameter(); else { pMat->CompareNotEqual(); @@ -875,7 +879,7 @@ void ScInterpreter::ScLess() { ScMatrixRef pMat = CompareMat(); if ( !pMat ) - SetIllegalParameter(); + PushIllegalParameter(); else { pMat->CompareLess(); @@ -893,7 +897,7 @@ void ScInterpreter::ScGreater() { ScMatrixRef pMat = CompareMat(); if ( !pMat ) - SetIllegalParameter(); + PushIllegalParameter(); else { pMat->CompareGreater(); @@ -911,7 +915,7 @@ void ScInterpreter::ScLessEqual() { ScMatrixRef pMat = CompareMat(); if ( !pMat ) - SetIllegalParameter(); + PushIllegalParameter(); else { pMat->CompareLessEqual(); @@ -929,7 +933,7 @@ void ScInterpreter::ScGreaterEqual() { ScMatrixRef pMat = CompareMat(); if ( !pMat ) - SetIllegalParameter(); + PushIllegalParameter(); else { pMat->CompareGreaterEqual(); @@ -944,12 +948,13 @@ void ScInterpreter::ScGreaterEqual() void ScInterpreter::ScAnd() { nFuncFmtType = NUMBERFORMAT_LOGICAL; - BYTE nParamCount = GetByte(); + short nParamCount = GetByte(); if ( MustHaveParamCountMin( nParamCount, 1 ) ) { BOOL bHaveValue = FALSE; short nRes = TRUE; - while( nParamCount-- ) + size_t nRefInList = 0; + while( nParamCount-- > 0) { if ( !nGlobalError ) { @@ -980,9 +985,10 @@ void ScInterpreter::ScAnd() } break; case svDoubleRef: + case svRefList: { ScRange aRange; - PopDoubleRef( aRange ); + PopDoubleRef( aRange, nParamCount, nRefInList); if ( !nGlobalError ) { double fVal; @@ -1017,12 +1023,12 @@ void ScInterpreter::ScAnd() else nRes &= (fVal != 0.0); } - // else: GetMatrix hat errIllegalParameter gesetzt + // else: GetMatrix did set errIllegalParameter } break; default: Pop(); - SetError( errIllegalParameter ); + SetError( errIllegalParameter); } } else @@ -1031,7 +1037,7 @@ void ScInterpreter::ScAnd() if ( bHaveValue ) PushInt( nRes ); else - SetNoValue(); + PushNoValue(); } } @@ -1039,12 +1045,13 @@ void ScInterpreter::ScAnd() void ScInterpreter::ScOr() { nFuncFmtType = NUMBERFORMAT_LOGICAL; - BYTE nParamCount = GetByte(); + short nParamCount = GetByte(); if ( MustHaveParamCountMin( nParamCount, 1 ) ) { BOOL bHaveValue = FALSE; short nRes = FALSE; - while( nParamCount-- ) + size_t nRefInList = 0; + while( nParamCount-- > 0) { if ( !nGlobalError ) { @@ -1075,9 +1082,10 @@ void ScInterpreter::ScOr() } break; case svDoubleRef: + case svRefList: { ScRange aRange; - PopDoubleRef( aRange ); + PopDoubleRef( aRange, nParamCount, nRefInList); if ( !nGlobalError ) { double fVal; @@ -1113,12 +1121,12 @@ void ScInterpreter::ScOr() else nRes |= (fVal != 0.0); } - // else: GetMatrix hat errIllegalParameter gesetzt + // else: GetMatrix did set errIllegalParameter } break; default: Pop(); - SetError( errIllegalParameter ); + SetError( errIllegalParameter); } } else @@ -1127,7 +1135,7 @@ void ScInterpreter::ScOr() if ( bHaveValue ) PushInt( nRes ); else - SetNoValue(); + PushNoValue(); } } @@ -1143,14 +1151,14 @@ void ScInterpreter::ScNeg() { ScMatrixRef pMat = GetMatrix(); if ( !pMat ) - PushError(); + PushIllegalParameter(); else { SCSIZE nC, nR; pMat->GetDimensions( nC, nR ); ScMatrixRef pResMat = GetNewMat( nC, nR); if ( !pResMat ) - PushError(); + PushIllegalArgument(); else { SCSIZE nCount = nC * nR; @@ -1197,14 +1205,14 @@ void ScInterpreter::ScNot() { ScMatrixRef pMat = GetMatrix(); if ( !pMat ) - PushError(); + PushIllegalParameter(); else { SCSIZE nC, nR; pMat->GetDimensions( nC, nR ); ScMatrixRef pResMat = GetNewMat( nC, nR); if ( !pResMat ) - PushError(); + PushIllegalArgument(); else { SCSIZE nCount = nC * nR; @@ -1348,7 +1356,7 @@ void ScInterpreter::ScArcCosHyp() { double nVal = GetDouble(); if (nVal < 1.0) - SetIllegalArgument(); + PushIllegalArgument(); else PushDouble(log(nVal + sqrt((nVal * nVal) - 1.0))); } @@ -1358,7 +1366,7 @@ void ScInterpreter::ScArcTanHyp() { double nVal = GetDouble(); if (fabs(nVal) >= 1.0) - SetIllegalArgument(); + PushIllegalArgument(); else PushDouble(0.5 * log((1.0 + nVal) / (1.0 - nVal))); } @@ -1368,7 +1376,7 @@ void ScInterpreter::ScArcCotHyp() { double nVal = GetDouble(); if (fabs(nVal) <= 1.0) - SetIllegalArgument(); + PushIllegalArgument(); else PushDouble(0.5 * log((nVal + 1.0) / (nVal - 1.0))); } @@ -1386,7 +1394,7 @@ void ScInterpreter::ScSqrt() if (fVal >= 0.0) PushDouble(sqrt(fVal)); else - SetIllegalArgument(); + PushIllegalArgument(); } @@ -1394,14 +1402,25 @@ void ScInterpreter::ScIsEmpty() { short nRes = 0; nFuncFmtType = NUMBERFORMAT_LOGICAL; - switch ( GetStackType() ) + switch ( GetRawStackType() ) { + case svEmptyCell: + { + const ScToken* p = PopToken(); + if (!static_cast<const ScEmptyCellToken*>(p)->IsInherited()) + nRes = 1; + } + break; case svDoubleRef : case svSingleRef : { ScAddress aAdr; if ( !PopDoubleRefOrSingleRef( aAdr ) ) break; + // NOTE: this could test also on inherited emptiness, but then the + // cell tested wouldn't be empty. Must correspond with + // ScCountEmptyCells(). + // if (HasCellEmptyData( GetCell( aAdr))) CellType eCellType = GetCellType( GetCell( aAdr ) ); if((eCellType == CELLTYPE_NONE) || (eCellType == CELLTYPE_NOTE)) nRes = 1; @@ -1437,8 +1456,12 @@ short ScInterpreter::IsString() { nFuncFmtType = NUMBERFORMAT_LOGICAL; short nRes = 0; - switch ( GetStackType() ) + switch ( GetRawStackType() ) { + case svString: + Pop(); + nRes = 1; + break; case svDoubleRef : case svSingleRef : { @@ -1455,7 +1478,8 @@ short ScInterpreter::IsString() nRes = 1; break; case CELLTYPE_FORMULA : - nRes = !((ScFormulaCell*)pCell)->IsValue(); + nRes = !((ScFormulaCell*)pCell)->IsValue() && + !((ScFormulaCell*)pCell)->IsEmpty(); break; default: ; // nothing @@ -1463,11 +1487,6 @@ short ScInterpreter::IsString() } } break; - case svString: - PopError(); - if ( !nGlobalError ) - nRes = 1; - break; case svMatrix: { ScMatrixRef pMat = PopMatrix(); @@ -1505,7 +1524,7 @@ void ScInterpreter::ScIsNonString() } -void ScInterpreter::ScIsLogical(UINT16 /* aOldNumType */) +void ScInterpreter::ScIsLogical() { short nRes = 0; switch ( GetStackType() ) @@ -1559,6 +1578,7 @@ void ScInterpreter::ScType() { switch ( GetCellType( pCell ) ) { + // NOTE: this is Xcl nonsense! case CELLTYPE_NOTE : nType = 1; // empty cell is value (0) break; @@ -1580,7 +1600,7 @@ void ScInterpreter::ScType() nType = 8; break; default: - SetIllegalParameter(); + PushIllegalArgument(); } } else @@ -1646,7 +1666,7 @@ void ScInterpreter::ScCell() bError = !PopDoubleRefOrSingleRef( aCellPos ); String aInfoType( GetString() ); if( bError || nGlobalError ) - SetIllegalParameter(); + PushIllegalParameter(); else { String aFuncResult; @@ -1831,7 +1851,7 @@ void ScInterpreter::ScCell() PushInt( lcl_FormatHasOpenPar( pFormat ) ? 1 : 0 ); } else - SetIllegalArgument(); + PushIllegalArgument(); } } } @@ -1859,6 +1879,13 @@ void ScInterpreter::ScIsRef() nRes = 1; } break; + case svRefList : + { + ScTokenRef x = PopToken(); + if ( !nGlobalError ) + nRes = !x->GetRefList()->empty(); + } + break; default: Pop(); } @@ -1871,8 +1898,12 @@ void ScInterpreter::ScIsValue() { nFuncFmtType = NUMBERFORMAT_LOGICAL; short nRes = 0; - switch ( GetStackType() ) + switch ( GetRawStackType() ) { + case svDouble: + Pop(); + nRes = 1; + break; case svDoubleRef : case svSingleRef : { @@ -1888,7 +1919,8 @@ void ScInterpreter::ScIsValue() nRes = 1; break; case CELLTYPE_FORMULA : - nRes = ((ScFormulaCell*)pCell)->IsValue(); + nRes = ((ScFormulaCell*)pCell)->IsValue() && + !((ScFormulaCell*)pCell)->IsEmpty(); break; default: ; // nothing @@ -1896,9 +1928,6 @@ void ScInterpreter::ScIsValue() } } break; - case svString: - Pop(); - break; case svMatrix: { ScMatrixRef pMat = PopMatrix(); @@ -1921,9 +1950,7 @@ void ScInterpreter::ScIsValue() } break; default: - PopError(); - if ( !nGlobalError ) - nRes = 1; + Pop(); } nGlobalError = 0; PushInt( nRes ); @@ -2363,11 +2390,10 @@ void ScInterpreter::ScT() } break; case svString : + ; // leave on stack break; default : - SetError(errUnknownOpCode); - PushInt(0); - + PushError( errUnknownOpCode); } } @@ -2377,11 +2403,15 @@ void ScInterpreter::ScValue() String aInputString; double fVal; - switch ( GetStackType() ) + switch ( GetRawStackType() ) { - case svDouble: - PushDouble( PopDouble() ); + case svMissing: + case svEmptyCell: + Pop(); + PushInt(0); return; + case svDouble: + return; // leave on stack //break; case svSingleRef: @@ -2426,7 +2456,7 @@ void ScInterpreter::ScValue() // evaluated below break; default: - SetIllegalArgument(); + PushIllegalArgument(); } } break; @@ -2439,7 +2469,7 @@ void ScInterpreter::ScValue() if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal)) PushDouble(fVal); else - SetIllegalArgument(); + PushIllegalArgument(); } @@ -2474,7 +2504,7 @@ void ScInterpreter::ScChar() //2do: make it full range unicode? double fVal = GetDouble(); if (fVal < 0.0 || fVal >= 256.0) - SetIllegalArgument(); + PushIllegalArgument(); else { String aStr( '0' ); @@ -2770,12 +2800,15 @@ void ScInterpreter::ScAsc() void ScInterpreter::ScMin( BOOL bTextAsZero ) { - BYTE nParamCount = GetByte(); - double nMin = SC_DOUBLE_MAXVALUE; + short nParamCount = GetByte(); + if (!MustHaveParamCountMin( nParamCount, 1)) + return; + double nMin = ::std::numeric_limits<double>::max(); double nVal = 0.0; ScAddress aAdr; ScRange aRange; - for (short i = 0; i < nParamCount; i++) + size_t nRefInList = 0; + while (nParamCount-- > 0) { switch (GetStackType()) { @@ -2804,9 +2837,10 @@ void ScInterpreter::ScMin( BOOL bTextAsZero ) } break; case svDoubleRef : + case svRefList : { USHORT nErr = 0; - PopDoubleRef( aRange ); + PopDoubleRef( aRange, nParamCount, nRefInList); ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero ); if (aValIter.GetFirst(nVal, nErr)) { @@ -2878,8 +2912,8 @@ void ScInterpreter::ScMin( BOOL bTextAsZero ) SetError(errIllegalParameter); } } - if (nMin == SC_DOUBLE_MAXVALUE) - SetIllegalArgument(); + if ( nVal < nMin ) + PushDouble(0.0); else PushDouble(nMin); } @@ -2890,12 +2924,15 @@ void ScInterpreter::ScMin( BOOL bTextAsZero ) void ScInterpreter::ScMax( BOOL bTextAsZero ) { - BYTE nParamCount = GetByte(); - double nMax = -SC_DOUBLE_MAXVALUE; + short nParamCount = GetByte(); + if (!MustHaveParamCountMin( nParamCount, 1)) + return; + double nMax = -(::std::numeric_limits<double>::max()); double nVal = 0.0; ScAddress aAdr; ScRange aRange; - for (short i = 0; i < nParamCount; i++) + size_t nRefInList = 0; + while (nParamCount-- > 0) { switch (GetStackType()) { @@ -2924,9 +2961,10 @@ void ScInterpreter::ScMax( BOOL bTextAsZero ) } break; case svDoubleRef : + case svRefList : { USHORT nErr = 0; - PopDoubleRef( aRange ); + PopDoubleRef( aRange, nParamCount, nRefInList); ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero ); if (aValIter.GetFirst(nVal, nErr)) { @@ -2998,8 +3036,8 @@ void ScInterpreter::ScMax( BOOL bTextAsZero ) SetError(errIllegalParameter); } } - if (nMax == -SC_DOUBLE_MAXVALUE) - SetIllegalArgument(); + if ( nVal > nMax ) + PushDouble(0.0); else PushDouble(nMax); } @@ -3010,7 +3048,7 @@ void ScInterpreter::ScMax( BOOL bTextAsZero ) double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero ) { - BYTE nParamCount = GetByte(); + short nParamCount = GetByte(); double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0; double fVal = 0.0; double fMem = 0.0; @@ -3018,7 +3056,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero ) ULONG nCount = 0; ScAddress aAdr; ScRange aRange; - for (short i = 0; i < nParamCount; i++) + size_t nRefInList = 0; + while (nParamCount-- > 0) { switch (GetStackType()) { @@ -3050,7 +3089,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero ) } else { - for ( ; i < nParamCount; i++ ) + while (nParamCount-- > 0) Pop(); SetError( errNoValue ); } @@ -3128,9 +3167,10 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero ) } break; case svDoubleRef : + case svRefList : { USHORT nErr = 0; - PopDoubleRef( aRange ); + PopDoubleRef( aRange, nParamCount, nRefInList); if( eFunc == ifCOUNT2 ) { ScBaseCell* pCell; @@ -3253,8 +3293,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero ) } break; default : - for ( ; i < nParamCount; i++ ) - Pop(); + while (nParamCount-- > 0) + PopError(); SetError(errIllegalParameter); } } @@ -3314,7 +3354,7 @@ void ScInterpreter::ScCount2() void ScInterpreter::GetStVarParams( double& rVal, double& rValCount, BOOL bTextAsZero ) { - BYTE nParamCount = GetByte(); + short nParamCount = GetByte(); std::vector<double> values; double fSum = 0.0; @@ -3324,7 +3364,8 @@ void ScInterpreter::GetStVarParams( double& rVal, double& rValCount, rValCount = 0.0; ScAddress aAdr; ScRange aRange; - for (USHORT i = 0; i < nParamCount; i++) + size_t nRefInList = 0; + while (nParamCount-- > 0) { switch (GetStackType()) { @@ -3355,9 +3396,10 @@ void ScInterpreter::GetStVarParams( double& rVal, double& rValCount, } break; case svDoubleRef : + case svRefList : { USHORT nErr = 0; - PopDoubleRef( aRange ); + PopDoubleRef( aRange, nParamCount, nRefInList); ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero ); if (aValIter.GetFirst(fVal, nErr)) { @@ -3501,7 +3543,7 @@ void ScInterpreter::ScColumns() SCCOL nCol2; SCROW nRow2; SCTAB nTab2; - for (USHORT i = 1; i <= nParamCount; i++) + while (nParamCount-- > 0) { switch ( GetStackType() ) { @@ -3544,7 +3586,7 @@ void ScInterpreter::ScRows() SCCOL nCol2; SCROW nRow2; SCTAB nTab2; - for (USHORT i = 1; i <= nParamCount; i++) + while (nParamCount-- > 0) { switch ( GetStackType() ) { @@ -3591,7 +3633,7 @@ void ScInterpreter::ScTables() SCCOL nCol2; SCROW nRow2; SCTAB nTab2; - for (USHORT i = 1; i <= nParamCount; i++) + while (nParamCount-- > 0) { switch ( GetStackType() ) { @@ -3818,9 +3860,51 @@ void ScInterpreter::ScTable() } } +/** returns -1 when the matrix value is smaller than the query value, 0 when + they are equal, and 1 when the matrix value is larger than the query + value. */ +static sal_Int8 lcl_CompareMatrix2Query(SCSIZE i, const ScMatrix& rMat, const ScQueryEntry& rEntry) +{ + if (rMat.IsValue(i)) + { + const double nVal1 = rMat.GetDouble(i); + const double nVal2 = rEntry.nVal; + if (nVal1 == nVal2) + return 0; + + return nVal1 < nVal2 ? -1 : 1; + } + + if (!rEntry.pStr) + // this should not happen! + return 1; + + const String& rStr1 = rMat.GetString(i); + const String& rStr2 = *rEntry.pStr; + if (rStr1 == rStr2) + return 0; + + return rStr1 < rStr2 ? -1 : 1; +} + +/** returns the last item with the identical value as the original item + value. */ +static void lcl_GetLastMatch(SCSIZE& rIndex, const ScMatrix& rMat, SCSIZE nMatCount, + bool bReverse) +{ + double nVal = rMat.GetDouble(rIndex); + if (bReverse) + while (rIndex > 0 && nVal == rMat.GetDouble(rIndex-1)) + --rIndex; + else + while (rIndex < nMatCount-1 && nVal == rMat.GetDouble(rIndex+1)) + ++rIndex; +} void ScInterpreter::ScMatch() { + ScMatrixRef pMatSrc = NULL; + BYTE nParamCount = GetByte(); if ( MustHaveParamCount( nParamCount, 2, 3 ) ) { @@ -3829,24 +3913,33 @@ void ScInterpreter::ScMatch() fTyp = GetDouble(); else fTyp = 1.0; - SCCOL nCol1; - SCROW nRow1; - SCTAB nTab1; - SCCOL nCol2; - SCROW nRow2; - SCTAB nTab2; + SCCOL nCol1 = 0; + SCROW nRow1 = 0; + SCTAB nTab1 = 0; + SCCOL nCol2 = 0; + SCROW nRow2 = 0; + SCTAB nTab2 = 0; if (GetStackType() == svDoubleRef) { PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2)) { - SetIllegalParameter(); + PushIllegalParameter(); + return; + } + } + else if (GetStackType() == svMatrix) + { + pMatSrc = PopMatrix(); + if (!pMatSrc) + { + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } if (nGlobalError == 0) @@ -3915,12 +4008,106 @@ void ScInterpreter::ScMatch() break; default: { - SetIllegalParameter(); + PushIllegalParameter(); return; } } if ( rEntry.bQueryByString ) rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); + + if (pMatSrc) // The source data is matrix array. + { + SCSIZE nC, nR; + pMatSrc->GetDimensions( nC, nR); + if (nC > 1 && nR > 1) + { + // The source matrix must be a vector. + PushIllegalParameter(); + return; + } + SCSIZE nMatCount = (nC == 1) ? nR : nC; + + // simple serial search for equality mode (source data doesn't + // need to be sorted). + + if (rEntry.eOp == SC_EQUAL) + { + for (SCSIZE i = 0; i < nMatCount; ++i) + { + if (lcl_CompareMatrix2Query( i, *pMatSrc, rEntry) == 0) + { + PushDouble(i+1); // found ! + return; + } + } + PushNA(); // not found + return; + } + + // binary search for non-equality mode (the source data is + // assumed to be sorted). + + bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL); + SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0; + for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst) + { + SCSIZE nMid = nFirst + nLen/2; + sal_Int8 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry); + if (nCmp == 0) + { + // exact match. find the last item with the same value. + lcl_GetLastMatch( nMid, *pMatSrc, nMatCount, !bAscOrder); + PushDouble( nMid+1); + return; + } + + if (nLen == 1) // first and last items are next to each other. + { + if (nCmp < 0) + nHitIndex = bAscOrder ? nLast : nFirst; + else + nHitIndex = bAscOrder ? nFirst : nLast; + break; + } + + if (nCmp < 0) + { + if (bAscOrder) + nFirst = nMid; + else + nLast = nMid; + } + else + { + if (bAscOrder) + nLast = nMid; + else + nFirst = nMid; + } + } + + if (nHitIndex == nMatCount-1) // last item + { + sal_Int8 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry); + if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0)) + { + // either the last item is an exact match or the real + // hit is beyond the last item. + PushDouble( nHitIndex+1); + return; + } + } + + if (nHitIndex > 0) // valid hit must be 2nd item or higher + { + PushDouble( nHitIndex); // non-exact match + return; + } + + PushNA(); + return; + } + SCCOLROW nDelta = 0; if (nCol1 == nCol2) { // search row in column @@ -3929,7 +4116,7 @@ void ScInterpreter::ScMatch() ScAddress aResultPos( nCol1, nRow1, nTab1); if (!LookupQueryWithCache( aResultPos, rParam)) { - SetNA(); + PushNA(); return; } nDelta = aResultPos.Row() - nRow1; @@ -3949,7 +4136,7 @@ void ScInterpreter::ScMatch() nC = aCellIter.GetCol(); else { - SetNA(); + PushNA(); return; } } @@ -3958,7 +4145,7 @@ void ScInterpreter::ScMatch() SCROW nR; if ( !aCellIter.FindEqualOrSortedLastInRange( nC, nR ) ) { - SetNA(); + PushNA(); return; } } @@ -3967,7 +4154,7 @@ void ScInterpreter::ScMatch() PushDouble((double) (nDelta + 1)); } else - SetIllegalParameter(); + PushIllegalParameter(); } } @@ -3991,28 +4178,29 @@ void ScInterpreter::ScCountEmptyCells() } break; case svDoubleRef : + case svRefList : { - SCCOL nCol1; - SCROW nRow1; - SCTAB nTab1; - SCCOL nCol2; - SCROW nRow2; - SCTAB nTab2; - PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); - nMaxCount = static_cast<ULONG>(nRow2 - nRow1 + 1) * - static_cast<ULONG>(nCol2 - nCol1 + 1) * - static_cast<ULONG>(nTab2 - nTab1 + 1); - ScBaseCell* pCell; - ScCellIterator aDocIter(pDok, nCol1, nRow1, nTab1, - nCol2, nRow2, nTab2, glSubTotal); - if ( (pCell = aDocIter.GetFirst()) != NULL ) + ScRange aRange; + short nParam = 1; + size_t nRefInList = 0; + while (nParam-- > 0) { - do + PopDoubleRef( aRange, nParam, nRefInList); + nMaxCount += + static_cast<ULONG>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) * + static_cast<ULONG>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) * + static_cast<ULONG>(aRange.aEnd.Tab() - aRange.aStart.Tab() + 1); + ScBaseCell* pCell; + ScCellIterator aDocIter( pDok, aRange, glSubTotal); + if ( (pCell = aDocIter.GetFirst()) != NULL ) { - if ((eCellType = pCell->GetCellType()) != CELLTYPE_NONE - && eCellType != CELLTYPE_NOTE) - nCount++; - } while ( (pCell = aDocIter.GetNext()) != NULL ); + do + { + if ((eCellType = pCell->GetCellType()) != CELLTYPE_NONE + && eCellType != CELLTYPE_NOTE) + nCount++; + } while ( (pCell = aDocIter.GetNext()) != NULL ); + } } } break; @@ -4083,79 +4271,92 @@ void ScInterpreter::ScCountIf() bIsString = FALSE; } } - SCCOL nCol1; - SCROW nRow1; - SCTAB nTab1; - SCCOL nCol2; - SCROW nRow2; - SCTAB nTab2; - switch ( GetStackType() ) - { - case svDoubleRef : - PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); - break; - case svSingleRef : - PopSingleRef( nCol1, nRow1, nTab1 ); - nCol2 = nCol1; - nRow2 = nRow1; - nTab2 = nTab1; - break; - default: - SetIllegalParameter(); - return ; - } - if ( nTab1 != nTab2 ) - { - SetIllegalParameter(); - return; - } - if (nCol1 > nCol2) - { - SetIllegalParameter(); - return; - } - if (nGlobalError == 0) + double fSum = 0.0; + short nParam = 1; + size_t nRefInList = 0; + while (nParam-- > 0) { - ScQueryParam rParam; - rParam.nRow1 = nRow1; - rParam.nRow2 = nRow2; - - ScQueryEntry& rEntry = rParam.GetEntry(0); - rEntry.bDoQuery = TRUE; - if (!bIsString) + SCCOL nCol1; + SCROW nRow1; + SCTAB nTab1; + SCCOL nCol2; + SCROW nRow2; + SCTAB nTab2; + switch ( GetStackType() ) { - rEntry.bQueryByString = FALSE; - rEntry.nVal = fVal; - rEntry.eOp = SC_EQUAL; + case svDoubleRef : + case svRefList : + { + ScRange aRange; + PopDoubleRef( aRange, nParam, nRefInList); + aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + } + break; + case svSingleRef : + PopSingleRef( nCol1, nRow1, nTab1 ); + nCol2 = nCol1; + nRow2 = nRow1; + nTab2 = nTab1; + break; + default: + PushIllegalParameter(); + return ; } - else + if ( nTab1 != nTab2 ) { - rParam.FillInExcelSyntax(rString, 0); - sal_uInt32 nIndex = 0; - rEntry.bQueryByString = - !(pFormatter->IsNumberFormat( - *rEntry.pStr, nIndex, rEntry.nVal)); - if ( rEntry.bQueryByString ) - rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); - } - double fSum = 0.0; - rParam.nCol1 = nCol1; - rParam.nCol2 = nCol2; - rEntry.nField = nCol1; - ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); - // Entry.nField im Iterator bei Spaltenwechsel weiterschalten - aCellIter.SetAdvanceQueryParamEntryField( TRUE ); - if ( aCellIter.GetFirst() ) + PushIllegalParameter(); + return; + } + if (nCol1 > nCol2) { - do + PushIllegalParameter(); + return; + } + if (nGlobalError == 0) + { + ScQueryParam rParam; + rParam.nRow1 = nRow1; + rParam.nRow2 = nRow2; + + ScQueryEntry& rEntry = rParam.GetEntry(0); + rEntry.bDoQuery = TRUE; + if (!bIsString) { - fSum++; - } while ( aCellIter.GetNext() ); + rEntry.bQueryByString = FALSE; + rEntry.nVal = fVal; + rEntry.eOp = SC_EQUAL; + } + else + { + rParam.FillInExcelSyntax(rString, 0); + sal_uInt32 nIndex = 0; + rEntry.bQueryByString = + !(pFormatter->IsNumberFormat( + *rEntry.pStr, nIndex, rEntry.nVal)); + if ( rEntry.bQueryByString ) + rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); + } + rParam.nCol1 = nCol1; + rParam.nCol2 = nCol2; + rEntry.nField = nCol1; + ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); + // Entry.nField im Iterator bei Spaltenwechsel weiterschalten + aCellIter.SetAdvanceQueryParamEntryField( TRUE ); + if ( aCellIter.GetFirst() ) + { + do + { + fSum++; + } while ( aCellIter.GetNext() ); + } + } + else + { + PushIllegalParameter(); + return; } - PushDouble(fSum); } - else - SetIllegalParameter(); + PushDouble(fSum); } } @@ -4168,31 +4369,35 @@ void ScInterpreter::ScSumIf() SCCOL nCol3 = 0; SCROW nRow3 = 0; SCTAB nTab3 = 0; - SCCOL nCol4 = 0; - SCROW nRow4 = 0; - SCTAB nTab4; - if (nParamCount == 3) + + bool bSumExtraRange = (nParamCount == 3); + if (bSumExtraRange) { + // Save only the upperleft cell in case of cell range. The geometry + // of the 3rd parameter is taken from the 1st parameter. + switch ( GetStackType() ) { case svDoubleRef : - PopDoubleRef( nCol3, nRow3, nTab3, nCol4, nRow4, nTab4 ); + { + SCCOL nColJunk = 0; + SCROW nRowJunk = 0; + SCTAB nTabJunk = 0; + PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk ); + if ( nTabJunk != nTab3 ) + { + PushIllegalParameter(); + return; + } + } break; case svSingleRef : PopSingleRef( nCol3, nRow3, nTab3 ); - nCol4 = nCol3; - nRow4 = nRow3; - nTab4 = nTab3; break; default: - SetIllegalParameter(); + PushIllegalParameter(); return ; } - if ( nTab3 != nTab4 ) - { - SetIllegalParameter(); - return; - } } String rString; double fVal = 0.0; @@ -4250,108 +4455,147 @@ void ScInterpreter::ScSumIf() bIsString = FALSE; } } - SCCOL nCol1; - SCROW nRow1; - SCTAB nTab1; - SCCOL nCol2; - SCROW nRow2; - SCTAB nTab2; - switch ( GetStackType() ) - { - case svDoubleRef : - PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); - break; - case svSingleRef : - PopSingleRef( nCol1, nRow1, nTab1 ); - nCol2 = nCol1; - nRow2 = nRow1; - nTab2 = nTab1; - break; - default: - SetIllegalParameter(); - return ; - } - if ( nTab1 != nTab2 ) - { - SetIllegalParameter(); - return; - } - if (nParamCount != 3) - { - nCol3 = nCol1; - nRow3 = nRow1; - nTab3 = nTab1; - nCol4 = nCol2; - nRow4 = nRow2; - nTab4 = nTab2; - } - else if (nCol4 - nCol3 != nCol2 - nCol1 || - nRow4 - nRow3 != nRow2 - nRow1 || nCol1 > nCol2) - { - SetIllegalParameter(); - return; - } - if (nGlobalError == 0) + + double fSum = 0.0; + double fMem = 0.0; + BOOL bNull = TRUE; + short nParam = 1; + size_t nRefInList = 0; + while (nParam-- > 0) { - ScQueryParam rParam; - rParam.nRow1 = nRow1; - rParam.nRow2 = nRow2; + SCCOL nCol1; + SCROW nRow1; + SCTAB nTab1; + SCCOL nCol2; + SCROW nRow2; + SCTAB nTab2; + switch ( GetStackType() ) + { + case svRefList : + if (bSumExtraRange) + { + PushIllegalParameter(); + return; + } + else + { + ScRange aRange; + PopDoubleRef( aRange, nParam, nRefInList); + aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + } + break; + case svDoubleRef : + PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); + break; + case svSingleRef : + PopSingleRef( nCol1, nRow1, nTab1 ); + nCol2 = nCol1; + nRow2 = nRow1; + nTab2 = nTab1; + break; + default: + PushIllegalParameter(); + return ; + } + if ( nTab1 != nTab2 ) + { + PushIllegalParameter(); + return; + } - ScQueryEntry& rEntry = rParam.GetEntry(0); - rEntry.bDoQuery = TRUE; - if (!bIsString) + if (bSumExtraRange) { - rEntry.bQueryByString = FALSE; - rEntry.nVal = fVal; - rEntry.eOp = SC_EQUAL; + // Take the range geometry of the 1st parameter and apply it to + // the 3rd. If parts of the resulting range would point outside + // the sheet, don't complain but silently ignore and simply cut + // them away, this is what Xcl does :-/ + + // For the cut-away part we also don't need to determine the + // criteria match, so shrink the source range accordingly, + // instead of the result range. + SCCOL nColDelta = nCol2 - nCol1; + SCROW nRowDelta = nRow2 - nRow1; + if (nCol3 + nColDelta > MAXCOL) + { + SCCOL nNewDelta = MAXCOL - nCol3; + nCol2 = nCol1 + nNewDelta; + } + + if (nRow3 + nRowDelta > MAXROW) + { + SCROW nNewDelta = MAXROW - nRow3; + nRow2 = nRow1 + nNewDelta; + } } else { - rParam.FillInExcelSyntax(rString, 0); - sal_uInt32 nIndex = 0; - rEntry.bQueryByString = - !(pFormatter->IsNumberFormat( - *rEntry.pStr, nIndex, rEntry.nVal)); - if ( rEntry.bQueryByString ) - rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); - } - double fSum = 0.0; - double fMem = 0.0; - BOOL bNull = TRUE; - ScAddress aAdr; - aAdr.SetTab( nTab3 ); - rParam.nCol1 = nCol1; - rParam.nCol2 = nCol2; - rEntry.nField = nCol1; - long nColDiff = nCol3 - nCol1; - long nRowDiff = nRow3 - nRow1; - ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); - // Entry.nField im Iterator bei Spaltenwechsel weiterschalten - aCellIter.SetAdvanceQueryParamEntryField( TRUE ); - if ( aCellIter.GetFirst() ) + nCol3 = nCol1; + nRow3 = nRow1; + nTab3 = nTab1; + } + + if (nGlobalError == 0) { - do + ScQueryParam rParam; + rParam.nRow1 = nRow1; + rParam.nRow2 = nRow2; + + ScQueryEntry& rEntry = rParam.GetEntry(0); + rEntry.bDoQuery = TRUE; + if (!bIsString) { - aAdr.SetCol( sal::static_int_cast<SCCOL>( aCellIter.GetCol() + nColDiff ) ); - aAdr.SetRow( sal::static_int_cast<SCROW>( aCellIter.GetRow() + nRowDiff ) ); - ScBaseCell* pCell = GetCell( aAdr ); - if ( HasCellValueData(pCell) ) + rEntry.bQueryByString = FALSE; + rEntry.nVal = fVal; + rEntry.eOp = SC_EQUAL; + } + else + { + rParam.FillInExcelSyntax(rString, 0); + sal_uInt32 nIndex = 0; + rEntry.bQueryByString = + !(pFormatter->IsNumberFormat( + *rEntry.pStr, nIndex, rEntry.nVal)); + if ( rEntry.bQueryByString ) + rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); + } + ScAddress aAdr; + aAdr.SetTab( nTab3 ); + rParam.nCol1 = nCol1; + rParam.nCol2 = nCol2; + rEntry.nField = nCol1; + SCCOL nColDiff = nCol3 - nCol1; + SCROW nRowDiff = nRow3 - nRow1; + ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE); + // Increment Entry.nField in iterator when switching to next column. + aCellIter.SetAdvanceQueryParamEntryField( TRUE ); + if ( aCellIter.GetFirst() ) + { + do { - fVal = GetCellValue( aAdr, pCell ); - if ( bNull && fVal != 0.0 ) + aAdr.SetCol( aCellIter.GetCol() + nColDiff); + aAdr.SetRow( aCellIter.GetRow() + nRowDiff); + ScBaseCell* pCell = GetCell( aAdr ); + if ( HasCellValueData(pCell) ) { - bNull = FALSE; - fMem = fVal; + fVal = GetCellValue( aAdr, pCell ); + if ( bNull && fVal != 0.0 ) + { + bNull = FALSE; + fMem = fVal; + } + else + fSum += fVal; } - else - fSum += fVal; - } - } while ( aCellIter.GetNext() ); + } while ( aCellIter.GetNext() ); + } + } + else + { + PushIllegalParameter(); + return; } - PushDouble( ::rtl::math::approxAdd( fSum, fMem ) ); } - else - SetIllegalParameter(); + PushDouble( ::rtl::math::approxAdd( fSum, fMem ) ); } } @@ -4387,7 +4631,7 @@ void ScInterpreter::ScLookup() PopDoubleRef(nCol3, nRow3, nTab3, nCol4, nRow4, nTab4); if (nTab3 != nTab4 || (nCol3 != nCol4 && nRow3 != nRow4)) { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -4399,19 +4643,19 @@ void ScInterpreter::ScLookup() pMat3->GetDimensions(nC3, nR3); if (nC3 != 1 && nR3 != 1) { - SetIllegalParameter(); + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -4422,7 +4666,7 @@ void ScInterpreter::ScLookup() PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); if ( nTab1 != nTab2 || (nParamCount == 3 && nCol1 != nCol2 && nRow1 != nRow2) ) { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -4434,19 +4678,19 @@ void ScInterpreter::ScLookup() pMat1->GetDimensions(nC1, nR1); if (nC1 != 1 && nR1 != 1) { - SetIllegalParameter(); + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } BOOL bSpMatrix, bSpVector; @@ -4578,7 +4822,7 @@ void ScInterpreter::ScLookup() break; default: { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -4612,7 +4856,7 @@ void ScInterpreter::ScLookup() } if (i == nMatCount+2 && !bFound) { - SetNA(); + PushNA(); return; } else if (!bFound) @@ -4639,7 +4883,7 @@ void ScInterpreter::ScLookup() } if (i == nMatCount+2 && !bFound) { - SetNA(); + PushNA(); return; } else if (!bFound) @@ -4659,14 +4903,14 @@ void ScInterpreter::ScLookup() static_cast<SCSIZE>(nC - nCol1); else { - SetNA(); + PushNA(); return; } } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } if (pMat3) @@ -4707,15 +4951,7 @@ void ScInterpreter::ScLookup() } aAdr.SetTab( nTab3 ); } - ScBaseCell* pCell = GetCell( aAdr ); - if (HasCellValueData(pCell)) - PushDouble(GetCellValue( aAdr, pCell )); - else - { - String aStr; - GetCellString(aStr, pCell); - PushString(aStr); - } + PushCellResultToken( true, aAdr, NULL, NULL); } } @@ -4744,7 +4980,7 @@ void ScInterpreter::ScHLookup() PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); if (nTab1 != nTab2) { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -4755,18 +4991,18 @@ void ScInterpreter::ScHLookup() pMat->GetDimensions(nC, nR); else { - SetIllegalParameter(); + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } if ( fIndex < 0.0 || (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) ) { - SetIllegalArgument(); + PushIllegalArgument(); return; } SCROW nZIndex = static_cast<SCROW>(fIndex); @@ -4842,7 +5078,7 @@ void ScInterpreter::ScHLookup() break; default: { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -4933,7 +5169,7 @@ void ScInterpreter::ScHLookup() static_cast<SCSIZE>(nZIndex))); } else - SetNA(); + PushNA(); } else { @@ -4957,23 +5193,15 @@ void ScInterpreter::ScHLookup() } if ( bFound ) { - ScBaseCell* pCell; ScAddress aAdr( nCol, nZIndex, nTab1 ); - if ( HasCellValueData( pCell = GetCell( aAdr ) ) ) - PushDouble(GetCellValue( aAdr, pCell )); - else - { - String aStr; - GetCellString(aStr, pCell); - PushString(aStr); - } + PushCellResultToken( true, aAdr, NULL, NULL); } else - SetNA(); + PushNA(); } } else - SetIllegalParameter(); + PushIllegalParameter(); } } @@ -5002,7 +5230,7 @@ void ScInterpreter::ScVLookup() PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); if (nTab1 != nTab2) { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -5013,24 +5241,26 @@ void ScInterpreter::ScVLookup() pMat->GetDimensions(nC, nR); else { - SetIllegalParameter(); + PushIllegalParameter(); return; } } else { - SetIllegalParameter(); + PushIllegalParameter(); return; } if ( fIndex < 0.0 || (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) { - SetIllegalArgument(); + PushIllegalArgument(); return; } SCCOL nSpIndex = static_cast<SCCOL>(fIndex); if (!pMat) nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 ); // value column - if (nGlobalError == 0) + if (nGlobalError) + PushError( nGlobalError); + else { String sStr; ScQueryParam rParam; @@ -5100,7 +5330,7 @@ void ScInterpreter::ScVLookup() break; default: { - SetIllegalParameter(); + PushIllegalParameter(); return; } } @@ -5194,7 +5424,7 @@ void ScInterpreter::ScVLookup() static_cast<SCSIZE>(nSpIndex), nDelta)); } else - SetNA(); + PushNA(); } else { @@ -5204,23 +5434,13 @@ void ScInterpreter::ScVLookup() ScAddress aResultPos( nCol1, nRow1, nTab1); if (LookupQueryWithCache( aResultPos, rParam)) { - ScBaseCell* pCell; ScAddress aAdr( nSpIndex, aResultPos.Row(), nTab1 ); - if ( HasCellValueData( pCell = GetCell( aAdr ) ) ) - PushDouble(GetCellValue( aAdr, pCell )); - else - { - String aStr; - GetCellString(aStr, pCell); - PushString(aStr); - } + PushCellResultToken( true, aAdr, NULL, NULL); } else - SetNA(); + PushNA(); } } - else - SetIllegalParameter(); } } @@ -5233,12 +5453,12 @@ void ScInterpreter::ScSubTotal() BYTE nParamCount = GetByte(); if ( MustHaveParamCountMin( nParamCount, 2 ) ) { - // Wir muessen den 1. Parameter tief aus dem Stack herausfischen! + // We must fish the 1st parameter deep from the stack! And push it on top. const ScToken* p = pStack[ sp - nParamCount ]; PushTempToken( *p ); int nFunc = (int) ::rtl::math::approxFloor( GetDouble() ); if( nFunc < 1 || nFunc > 11 ) - SetIllegalParameter(); + PushIllegalArgument(); // simulate return on stack, not SetError(...) else { cPar = nParamCount - 1; @@ -5256,11 +5476,11 @@ void ScInterpreter::ScSubTotal() case SUBTOTAL_FUNC_SUM : ScSum(); break; case SUBTOTAL_FUNC_VAR : ScVar(); break; case SUBTOTAL_FUNC_VARP : ScVarP(); break; - default : SetIllegalParameter(); break; + default : PushIllegalArgument(); break; } glSubTotal = FALSE; } - // den abgefischten 1. Parameter entfernen + // Get rid of the 1st (fished) parameter. double nVal = GetDouble(); Pop(); PushDouble( nVal ); @@ -5490,7 +5710,7 @@ void ScInterpreter::DBIterator( ScIterFunc eFunc ) SetError(nErr); } else - SetIllegalParameter(); + SetError( errIllegalParameter); switch( eFunc ) { case ifCOUNT: nErg = nCount; break; @@ -5552,7 +5772,7 @@ void ScInterpreter::ScDBCount() PushDouble( nCount ); } else - SetIllegalParameter(); + PushIllegalParameter(); } @@ -5575,7 +5795,7 @@ void ScInterpreter::ScDBCount2() PushDouble(nCount); } else - SetIllegalParameter(); + PushIllegalParameter(); } @@ -5632,7 +5852,7 @@ void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount ) SetError(nErr); } else - SetIllegalParameter(); + SetError( errIllegalParameter); vMean = fSum / values.size(); @@ -5732,7 +5952,7 @@ void ScInterpreter::ScIndirectXL() } while (false); - SetIllegalArgument(); + PushIllegalArgument(); } } } @@ -5788,7 +6008,7 @@ void ScInterpreter::ScIndirect() } while (false); - SetIllegalArgument(); + PushIllegalArgument(); } } } @@ -5809,7 +6029,7 @@ void ScInterpreter::ScAddressFunc() SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble()); if (nCol < 1 || nCol > MAXCOL + 1 || nRow < 1 || nRow > MAXROW + 1) { - SetIllegalParameter(); + PushIllegalArgument(); return; } else @@ -5866,7 +6086,7 @@ void ScInterpreter::ScAddressXL() switch ( n ) { default : - SetNoValue(); + PushNoValue(); return; case 5: @@ -5895,7 +6115,7 @@ void ScInterpreter::ScAddressXL() if( nCol < 1 || nCol > MAXCOL + 1 || nRow < 1 || nRow > MAXROW + 1 ) { - SetNoValue(); + PushNoValue(); return; } @@ -5937,7 +6157,7 @@ void ScInterpreter::ScOffset() SCTAB nTab2; if (nColNew == 0 || nRowNew == 0) { - SetIllegalParameter(); + PushIllegalArgument(); return; } if (GetStackType() == svSingleRef) @@ -5948,7 +6168,7 @@ void ScInterpreter::ScOffset() nCol1 = (SCCOL)((long) nCol1 + nColPlus); nRow1 = (SCROW)((long) nRow1 + nRowPlus); if (!ValidCol(nCol1) || !ValidRow(nRow1)) - SetIllegalParameter(); + PushIllegalArgument(); else PushSingleRef(nCol1, nRow1, nTab1); } @@ -5964,7 +6184,7 @@ void ScInterpreter::ScOffset() nRow2 = (SCROW)((long)nRow1+nRowNew-1); if (!ValidCol(nCol1) || !ValidRow(nRow1) || !ValidCol(nCol2) || !ValidRow(nRow2)) - SetIllegalParameter(); + PushIllegalArgument(); else PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); } @@ -5982,12 +6202,12 @@ void ScInterpreter::ScOffset() nRow2 = (SCROW)((long)nRow1+nRowNew-1); if (!ValidCol(nCol1) || !ValidRow(nRow1) || !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2) - SetIllegalParameter(); + PushIllegalArgument(); else PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); } else - SetIllegalParameter(); + PushIllegalParameter(); } } @@ -5997,13 +6217,14 @@ void ScInterpreter::ScIndex() BYTE nParamCount = GetByte(); if ( MustHaveParamCount( nParamCount, 1, 4 ) ) { - short nBereich, nMaxAnz, nCount; + long nArea; + size_t nAreaCount; SCCOL nCol; SCROW nRow; if (nParamCount == 4) - nBereich = (short) ::rtl::math::approxFloor(GetDouble()); + nArea = (long) ::rtl::math::approxFloor(GetDouble()); else - nBereich = 1; + nArea = 1; if (nParamCount >= 3) nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble()); else @@ -6012,216 +6233,224 @@ void ScInterpreter::ScIndex() nRow = (SCROW) ::rtl::math::approxFloor(GetDouble()); else nRow = 0; - if (GetStackType() == svByte) // vorher MultiSelektion? - nMaxAnz = (short) PopByte(); - else // sonst Einzelselektion - nMaxAnz = 1; - if (nBereich > nMaxAnz || nBereich < 1 || nCol < 0 || nRow < 0) + if (GetStackType() == svRefList) + nAreaCount = (sp ? pStack[sp-1]->GetRefList()->size() : 0); + else + nAreaCount = 1; // one reference or array or whatever + if (nAreaCount == 0 || (size_t)nArea > nAreaCount) { - SetIllegalParameter(); + PushError( errNoRef); return; } - if (GetStackType() == svMatrix) + else if (nArea < 1 || nCol < 0 || nRow < 0) { - if (nBereich != 1) - SetError(errIllegalParameter); - USHORT nOldSp = sp; - ScMatrixRef pMat = GetMatrix(); - if (pMat) - { - SCSIZE nC, nR; - pMat->GetDimensions(nC, nR); - // Access one element of a vector independent of col/row - // orientation? - bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1)); - SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol), - static_cast<SCSIZE>(nRow)); - if (nC == 0 || nR == 0 || - (!bVector && (static_cast<SCSIZE>(nCol) > nC || - static_cast<SCSIZE>(nRow) > nR)) || - (bVector && nElement > nC * nR)) - SetIllegalArgument(); - else if (nCol == 0 && nRow == 0) - sp = nOldSp; - else if (bVector) - { - --nElement; - if (pMat->IsString( nElement)) - PushString( pMat->GetString( nElement)); - else - PushDouble( pMat->GetDouble( nElement)); - } - else if (nRow == 0) + PushIllegalArgument(); + return; + } + switch (GetStackType()) + { + case svMatrix: { - ScMatrixRef pResMat = GetNewMat(nC, 1); - if (pResMat) + if (nArea != 1) + SetError(errIllegalArgument); + USHORT nOldSp = sp; + ScMatrixRef pMat = GetMatrix(); + if (pMat) { - SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1); - for (SCSIZE i = 0; i < nC; i++) - if (!pMat->IsString(i, nColMinus1)) - pResMat->PutDouble(pMat->GetDouble(i, - nColMinus1), i, 0); + SCSIZE nC, nR; + pMat->GetDimensions(nC, nR); + // Access one element of a vector independent of col/row + // orientation? + bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1)); + SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol), + static_cast<SCSIZE>(nRow)); + if (nC == 0 || nR == 0 || + (!bVector && (static_cast<SCSIZE>(nCol) > nC || + static_cast<SCSIZE>(nRow) > nR)) || + (bVector && nElement > nC * nR)) + PushIllegalArgument(); + else if (nCol == 0 && nRow == 0) + sp = nOldSp; + else if (bVector) + { + --nElement; + if (pMat->IsString( nElement)) + PushString( pMat->GetString( nElement)); else - pResMat->PutString(pMat->GetString(i, - nColMinus1), i, 0); - PushMatrix(pResMat); - } - else - PushError(); - } - else if (nCol == 0) - { - ScMatrixRef pResMat = GetNewMat(1, nR); - if (pResMat) - { - SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1); - for (SCSIZE i = 0; i < nR; i++) - if (!pMat->IsString(nRowMinus1, i)) - pResMat->PutDouble(pMat->GetDouble(nRowMinus1, - i), i); + PushDouble( pMat->GetDouble( nElement)); + } + else if (nRow == 0) + { + ScMatrixRef pResMat = GetNewMat(nC, 1); + if (pResMat) + { + SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1); + for (SCSIZE i = 0; i < nC; i++) + if (!pMat->IsString(i, nColMinus1)) + pResMat->PutDouble(pMat->GetDouble(i, + nColMinus1), i, 0); + else + pResMat->PutString(pMat->GetString(i, + nColMinus1), i, 0); + PushMatrix(pResMat); + } else - pResMat->PutString(pMat->GetString(nRowMinus1, - i), i); - PushMatrix(pResMat); + PushIllegalArgument(); + } + else if (nCol == 0) + { + ScMatrixRef pResMat = GetNewMat(1, nR); + if (pResMat) + { + SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1); + for (SCSIZE i = 0; i < nR; i++) + if (!pMat->IsString(nRowMinus1, i)) + pResMat->PutDouble(pMat->GetDouble(nRowMinus1, + i), i); + else + pResMat->PutString(pMat->GetString(nRowMinus1, + i), i); + PushMatrix(pResMat); + } + else + PushIllegalArgument(); + } + else + { + if (!pMat->IsString( static_cast<SCSIZE>(nCol-1), + static_cast<SCSIZE>(nRow-1))) + PushDouble( pMat->GetDouble( + static_cast<SCSIZE>(nCol-1), + static_cast<SCSIZE>(nRow-1))); + else + PushString( pMat->GetString( + static_cast<SCSIZE>(nCol-1), + static_cast<SCSIZE>(nRow-1))); + } } - else - PushError(); - } - else - { - if (!pMat->IsString( static_cast<SCSIZE>(nCol-1), - static_cast<SCSIZE>(nRow-1))) - PushDouble( pMat->GetDouble( - static_cast<SCSIZE>(nCol-1), - static_cast<SCSIZE>(nRow-1))); - else - PushString( pMat->GetString( - static_cast<SCSIZE>(nCol-1), - static_cast<SCSIZE>(nRow-1))); } - } - } - else if (GetStackType() == svSingleRef || GetStackType() == svDoubleRef) - { - ScAddress aDummyAdr; - ScRange aDummyRange; - SCCOL nCol1 = 0; - SCROW nRow1 = 0; - SCTAB nTab1 = 0; - SCCOL nCol2 = 0; - SCROW nRow2 = 0; - SCTAB nTab2 = MAXTAB+1; - nCount = nMaxAnz; // Refs liegen umgekehrt auf dem Stack! - while (nCount > nBereich && !nGlobalError) // erste Refs weg - { - nCount--; - if ( GetStackType() == svSingleRef ) - PopSingleRef( aDummyAdr ); - else if ( GetStackType() == svDoubleRef ) - PopDoubleRef( aDummyRange ); - } - while (nCount > nBereich-1 && !nGlobalError) // richtigen Teilbezug - { - nCount--; - if (GetStackType() == svSingleRef) - PopSingleRef(nCol1, nRow1, nTab1); - else if (GetStackType() == svDoubleRef) - PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); - } - while (nCount > 0 && !nGlobalError) // restliche Refs weg - { - nCount--; - if ( GetStackType() == svSingleRef ) - PopSingleRef( aDummyAdr ); - else if ( GetStackType() == svDoubleRef ) - PopDoubleRef( aDummyRange ); - } - if (nTab2 == MAXTAB+1) // SingleRef - { - if (nCol > 1 || nRow > 1) - SetIllegalParameter(); - else - PushSingleRef(nCol1, nRow1, nTab1); - } - else // DoubleRef - { - if ( nTab1 != nTab2 || - (nCol > 0 && nCol1+nCol-1 > nCol2) || - (nRow > 0 && nRow1+nRow-1 > nRow2) ) - SetIllegalParameter(); - else if (nCol == 0 && nRow == 0) + break; + case svSingleRef: { - if ( nCol1 == nCol2 && nRow1 == nRow2 ) - PushSingleRef( nCol1, nRow1, nTab1 ); + SCCOL nCol1 = 0; + SCROW nRow1 = 0; + SCTAB nTab1 = 0; + PopSingleRef( nCol1, nRow1, nTab1); + if (nCol > 1 || nRow > 1) + PushIllegalArgument(); else - PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 ); + PushSingleRef( nCol1, nRow1, nTab1); } - else if (nRow == 0) + break; + case svDoubleRef: + case svRefList: { - if ( nRow1 == nRow2 ) - PushSingleRef( nCol1+nCol-1, nRow1, nTab1 ); + SCCOL nCol1 = 0; + SCROW nRow1 = 0; + SCTAB nTab1 = 0; + SCCOL nCol2 = 0; + SCROW nRow2 = 0; + SCTAB nTab2 = 0; + if (GetStackType() == svRefList) + { + ScTokenRef xRef = PopToken(); + if (nGlobalError || !xRef) + { + PushIllegalParameter(); + return; + } + ScRange aRange( ScAddress::UNINITIALIZED); + DoubleRefToRange( (*(xRef->GetRefList()))[nArea-1], aRange); + aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + } else - PushDoubleRef( nCol1+nCol-1, nRow1, nTab1, - nCol1+nCol-1, nRow2, nTab1 ); - } - else if (nCol == 0) - { - if ( nCol1 == nCol2 ) - PushSingleRef( nCol1, nRow1+nRow-1, nTab1 ); + PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); + if ( nTab1 != nTab2 || + (nCol > 0 && nCol1+nCol-1 > nCol2) || + (nRow > 0 && nRow1+nRow-1 > nRow2) ) + PushIllegalArgument(); + else if (nCol == 0 && nRow == 0) + { + if ( nCol1 == nCol2 && nRow1 == nRow2 ) + PushSingleRef( nCol1, nRow1, nTab1 ); + else + PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 ); + } + else if (nRow == 0) + { + if ( nRow1 == nRow2 ) + PushSingleRef( nCol1+nCol-1, nRow1, nTab1 ); + else + PushDoubleRef( nCol1+nCol-1, nRow1, nTab1, + nCol1+nCol-1, nRow2, nTab1 ); + } + else if (nCol == 0) + { + if ( nCol1 == nCol2 ) + PushSingleRef( nCol1, nRow1+nRow-1, nTab1 ); + else + PushDoubleRef( nCol1, nRow1+nRow-1, nTab1, + nCol2, nRow1+nRow-1, nTab1); + } else - PushDoubleRef(nCol1, nRow1+nRow-1, nTab1, - nCol2, nRow1+nRow-1, nTab1); + PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1); } - else - PushSingleRef(nCol1+nCol-1, nRow1+nRow-1, nTab1); - } + break; + default: + PushIllegalParameter(); } - else - SetIllegalParameter(); } } void ScInterpreter::ScMultiArea() { - // Hier ist nichts zu tun, der paramCount von ScMultiSelektion - // bleibt auf dem Stack !! - // Den muessen die nachfolgenden Funktionen (Index ...) wegraeumen !! + // Legacy support, convert to RefList + BYTE nParamCount = GetByte(); + if (MustHaveParamCountMin( nParamCount, 1)) + { + while (!nGlobalError && nParamCount-- > 1) + { + ScUnionFunc(); + } + } } void ScInterpreter::ScAreas() { BYTE nParamCount = GetByte(); - double fMaxAnz = 1.0; - ScAddress aDummyAdr; - ScRange aDummyRange; - for (USHORT i = 0; i < nParamCount && nGlobalError == 0; i++) + if (MustHaveParamCount( nParamCount, 1)) { - if (GetStackType() == svByte) // vorher MultiSelektion? + size_t nCount = 0; + switch (GetStackType()) { - double fCount = 0.0; - fMaxAnz = (double) GetByte(); - while (fCount < fMaxAnz && !nGlobalError) // mehrere Refs - { - fCount++; - if (GetStackType() == svSingleRef) - PopSingleRef( aDummyAdr ); - else if (GetStackType() == svDoubleRef) - PopDoubleRef( aDummyRange ); - else - SetIllegalParameter(); - } + case svSingleRef: + { + ScTokenRef xT = PopToken(); + ValidateRef( xT->GetSingleRef()); + ++nCount; + } + break; + case svDoubleRef: + { + ScTokenRef xT = PopToken(); + ValidateRef( xT->GetDoubleRef()); + ++nCount; + } + break; + case svRefList: + { + ScTokenRef xT = PopToken(); + ValidateRef( *(xT->GetRefList())); + nCount += xT->GetRefList()->size(); + } + break; + default: + SetError( errIllegalParameter); } - else if (GetStackType() == svSingleRef) - PopSingleRef( aDummyAdr ); - else if (GetStackType() == svDoubleRef) - PopDoubleRef( aDummyRange ); - else - SetIllegalParameter(); + PushDouble( double(nCount)); } - if (nGlobalError == 0) - PushDouble((double)nParamCount + fMaxAnz - 1.0); } @@ -6237,7 +6466,7 @@ void ScInterpreter::ScCurrency() fDec = ::rtl::math::approxFloor(GetDouble()); if (fDec < -15.0 || fDec > 15.0) { - SetIllegalArgument(); + PushIllegalArgument(); return; } } @@ -6274,7 +6503,7 @@ void ScInterpreter::ScCurrency() aStr, &pColor, ScGlobal::eLnge)) - SetError(errIllegalParameter); + SetError(errIllegalArgument); } else { @@ -6294,7 +6523,7 @@ void ScInterpreter::ScReplace() short nPos = (short) GetDouble(); String aOldStr( GetString() ); if( nPos < 1 || nCount < 1 ) - SetIllegalArgument(); + PushIllegalArgument(); else { aOldStr.Erase( nPos-1, nCount ); @@ -6323,7 +6552,7 @@ void ScInterpreter::ScFixed() fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 )); if (fDec < -15.0 || fDec > 15.0) { - SetIllegalArgument(); + PushIllegalArgument(); return; } } @@ -6358,7 +6587,7 @@ void ScInterpreter::ScFixed() aStr, &pColor, ScGlobal::eLnge)) - SetIllegalParameter(); + PushIllegalArgument(); else PushString(aStr); } @@ -6377,12 +6606,12 @@ void ScInterpreter::ScFind() fAnz = 1.0; String sStr = GetString(); if( fAnz < 1.0 || fAnz > (double) sStr.Len() ) - SetNoValue(); + PushNoValue(); else { xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 ); if (nPos == STRING_NOTFOUND) - SetNoValue(); + PushNoValue(); else PushDouble((double)(nPos + 1)); } @@ -6413,7 +6642,7 @@ void ScInterpreter::ScLeft() double nVal = ::rtl::math::approxFloor(GetDouble()); if ( nVal < 0.0 || nVal > STRING_MAXLEN ) { - SetIllegalParameter(); + PushIllegalArgument(); return ; } else @@ -6439,7 +6668,7 @@ void ScInterpreter::ScRight() double nVal = ::rtl::math::approxFloor(GetDouble()); if ( nVal < 0.0 || nVal > STRING_MAXLEN ) { - SetIllegalParameter(); + PushIllegalArgument(); return ; } else @@ -6466,7 +6695,7 @@ void ScInterpreter::ScSearch() fAnz = ::rtl::math::approxFloor(GetDouble()); if (fAnz > double(STRING_MAXLEN)) { - SetIllegalParameter(); + PushIllegalArgument(); return; } } @@ -6477,7 +6706,7 @@ void ScInterpreter::ScSearch() xub_StrLen nPos = (xub_StrLen) fAnz - 1; xub_StrLen nEndPos = sStr.Len(); if( nPos >= nEndPos ) - SetNoValue(); + PushNoValue(); else { utl::SearchParam::SearchType eSearchType = @@ -6487,7 +6716,7 @@ void ScInterpreter::ScSearch() utl::TextSearch sT( sPar, *ScGlobal::pCharClass ); int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos); if (!nBool) - SetNoValue(); + PushNoValue(); else PushDouble((double)(nPos) + 1); } @@ -6503,7 +6732,7 @@ void ScInterpreter::ScMid() double fAnfang = ::rtl::math::approxFloor(GetDouble()); const String& rStr = GetString(); if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN)) - SetIllegalParameter(); + PushIllegalArgument(); else PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz )); } @@ -6528,7 +6757,7 @@ void ScInterpreter::ScText() eCellLang = ScGlobal::eLnge; if ( !pFormatter->GetPreviewStringGuess( sFormatString, fVal, aStr, &pColor, eCellLang ) ) - SetIllegalParameter(); + PushIllegalArgument(); else PushString(aStr); } @@ -6546,7 +6775,7 @@ void ScInterpreter::ScSubstitute() double fAnz = ::rtl::math::approxFloor(GetDouble()); if( fAnz < 1 || fAnz > STRING_MAXLEN ) { - SetIllegalParameter(); + PushIllegalArgument(); return; } else @@ -6596,11 +6825,10 @@ void ScInterpreter::ScRept() double fAnz = ::rtl::math::approxFloor(GetDouble()); String aStr( GetString() ); if ( fAnz < 0.0 ) - SetIllegalParameter(); + PushIllegalArgument(); else if ( fAnz * aStr.Len() > STRING_MAXLEN ) { - SetError( errStringOverflow ); - PushInt(0); + PushError( errStringOverflow ); } else if ( fAnz == 0.0 ) PushString( EMPTY_STRING ); @@ -6626,7 +6854,7 @@ void ScInterpreter::ScConcat() { BYTE nParamCount = GetByte(); String aRes; - while( nParamCount-- ) + while( nParamCount-- > 0) { const String& rStr = GetString(); aRes.Insert( rStr, 0 ); @@ -6642,6 +6870,37 @@ void ScInterpreter::ScErrorType() nGlobalError = 0; switch ( GetStackType() ) { + case svRefList : + { + ScTokenRef x = PopToken(); + if (nGlobalError) + nErr = nGlobalError; + else + { + const ScRefList* pRefList = x->GetRefList(); + size_t n = pRefList->size(); + if (!n) + nErr = errNoRef; + else if (n > 1) + nErr = errNoValue; + else + { + ScRange aRange; + DoubleRefToRange( (*pRefList)[0], aRange); + if (nGlobalError) + nErr = nGlobalError; + else + { + ScAddress aAdr; + if ( DoubleRefToPosSingleRef( aRange, aAdr ) ) + nErr = pDok->GetErrCode( aAdr ); + else + nErr = nGlobalError; + } + } + } + } + break; case svDoubleRef : { ScRange aRange; @@ -6680,7 +6939,7 @@ void ScInterpreter::ScErrorType() else { nGlobalError = nOldError; - SetNA(); + PushNA(); } } |