summaryrefslogtreecommitdiff
path: root/sc
diff options
context:
space:
mode:
authorIvo Hinkelmann <ihi@openoffice.org>2008-06-09 15:48:37 +0000
committerIvo Hinkelmann <ihi@openoffice.org>2008-06-09 15:48:37 +0000
commit984c00f6cadb57284c51073586b327bc766f6979 (patch)
tree131aa2482eb5e8469b8ec2142d91c83419d22d5e /sc
parentf5de7c16ac974330e864faefa71155d142d8ed51 (diff)
INTEGRATION: CWS odff03 (1.56.20); FILE MERGED
2008/05/09 07:43:50 er 1.56.20.8: sal_Int32/sal_Int8 type mismatch 2008/05/08 22:20:57 er 1.56.20.7: RESYNC: (1.56-1.57); FILE MERGED 2008/04/23 21:16:20 er 1.56.20.6: #i74245# LOOKUP in columns if range is wider than tall and handling of result array respectively range 2008/04/11 16:56:30 er 1.56.20.5: #i66930# make INDEX correctly return a vector of an area; patch from <lvyue> 2008/04/11 16:05:04 er 1.56.20.4: #i78781# make INDEX use Row parameter as Column argument if a row vector was passed and no other arguments were given; patch from <lvyue> 2008/04/10 18:19:31 er 1.56.20.3: #i86721# make N return 0 for string arguments as well; patch contributed by <lvyue> 2008/04/10 18:01:56 er 1.56.20.2: #i86643# make COUNT ignore errors and COUNTA count errors; patch contributed by <lvyue> 2008/04/10 15:52:14 er 1.56.20.1: #i87855# GetStVarParams: pop svString and break case to not generate error; patch contributed by <lvyue>
Diffstat (limited to 'sc')
-rw-r--r--sc/source/core/tool/interpr1.cxx744
1 files changed, 463 insertions, 281 deletions
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 68bbfa98d355..36d7c3280f27 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -7,7 +7,7 @@
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: interpr1.cxx,v $
- * $Revision: 1.58 $
+ * $Revision: 1.59 $
*
* This file is part of OpenOffice.org.
*
@@ -2257,7 +2257,14 @@ void ScInterpreter::ScN()
{
USHORT nErr = nGlobalError;
nGlobalError = 0;
- double fVal = GetDouble();
+ double fVal;
+ if ( GetRawStackType() == svString )
+ {
+ fVal = 0.0;
+ Pop();
+ }
+ else
+ fVal = GetDouble();
if ( nGlobalError == NOTAVAILABLE || nGlobalError == errIllegalArgument )
nGlobalError = 0; // N(#NA) and N("text") are ok
if ( !nGlobalError && nErr != NOTAVAILABLE )
@@ -3052,6 +3059,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
ScAddress aAdr;
ScRange aRange;
size_t nRefInList = 0;
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ nGlobalError = 0;
while (nParamCount-- > 0)
{
switch (GetStackType())
@@ -3121,6 +3130,13 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
case svSingleRef :
{
PopSingleRef( aAdr );
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
ScBaseCell* pCell = GetCell( aAdr );
if ( pCell )
{
@@ -3129,6 +3145,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
CellType eCellType = pCell->GetCellType();
if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
nCount++;
+ if ( nGlobalError )
+ nGlobalError = 0;
}
else if ( pCell->HasValueData() )
{
@@ -3149,6 +3167,13 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
break;
case ifSUMSQ: fRes += fVal * fVal; break;
case ifPRODUCT: fRes *= fVal; break;
+ case ifCOUNT:
+ if ( nGlobalError )
+ {
+ nGlobalError = 0;
+ nCount--;
+ }
+ break;
default: ; // nothing
}
}
@@ -3166,6 +3191,13 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
{
USHORT nErr = 0;
PopDoubleRef( aRange, nParamCount, nRefInList);
+ if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
+ {
+ nGlobalError = 0;
+ if ( eFunc == ifCOUNT2 )
+ ++nCount;
+ break;
+ }
if( eFunc == ifCOUNT2 )
{
ScBaseCell* pCell;
@@ -3180,6 +3212,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
}
while ( (pCell = aIter.GetNext()) != NULL );
}
+ if ( nGlobalError )
+ nGlobalError = 0;
}
else
{
@@ -3224,14 +3258,15 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
}
while (aValIter.GetNext(fVal, nErr));
break;
- default: // count
+ case ifCOUNT:
do
{
- SetError(nErr);
- nCount++;
+ if ( !nErr )
+ nCount++;
}
while (aValIter.GetNext(fVal, nErr));
break;
+ default: ; // nothing
}
SetError( nErr );
}
@@ -3287,6 +3322,20 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
}
}
break;
+ case svError:
+ {
+ Pop();
+ if ( eFunc == ifCOUNT )
+ {
+ nGlobalError = 0;
+ }
+ else if ( eFunc == ifCOUNT2 )
+ {
+ nCount++;
+ nGlobalError = 0;
+ }
+ }
+ break;
default :
while (nParamCount-- > 0)
PopError();
@@ -3438,17 +3487,16 @@ void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
break;
case svString :
{
+ Pop();
if ( bTextAsZero )
{
values.push_back(0.0);
rValCount++;
}
else
- {
- Pop();
SetError(errIllegalParameter);
- }
}
+ break;
default :
Pop();
SetError(errIllegalParameter);
@@ -3858,10 +3906,24 @@ 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)
+static sal_Int32 lcl_CompareMatrix2Query( SCSIZE i, const ScMatrix& rMat,
+ const ScQueryEntry& rEntry)
{
+ if (rMat.IsEmpty(i))
+ {
+ /* TODO: in case we introduced query for real empty this would have to
+ * be changed! */
+ return -1; // empty always less than anything else
+ }
+
+ /* FIXME: what is an empty path (result of IF(false;true_path) in
+ * comparisons? */
+
if (rMat.IsValue(i))
{
+ if (rEntry.bQueryByString)
+ return -1; // numeric always less than string
+
const double nVal1 = rMat.GetDouble(i);
const double nVal2 = rEntry.nVal;
if (nVal1 == nVal2)
@@ -3870,30 +3932,66 @@ static sal_Int8 lcl_CompareMatrix2Query(SCSIZE i, const ScMatrix& rMat, const Sc
return nVal1 < nVal2 ? -1 : 1;
}
+ if (!rEntry.bQueryByString)
+ return 1; // string always greater than numeric
+
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;
+ return ScGlobal::pCollator->compareString( rStr1, rStr2); // case-insensitive
}
/** 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)
+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;
+ if (rMat.IsValue(rIndex))
+ {
+ double nVal = rMat.GetDouble(rIndex);
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsValue(rIndex-1) &&
+ nVal == rMat.GetDouble(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsValue(rIndex+1) &&
+ nVal == rMat.GetDouble(rIndex+1))
+ ++rIndex;
+ }
+ else if (rMat.IsEmpty(rIndex))
+ {
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsEmpty(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsEmpty(rIndex+1))
+ ++rIndex;
+ }
+ else if (rMat.IsString(rIndex))
+ {
+ String aStr( rMat.GetString(rIndex));
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsString(rIndex-1) &&
+ aStr == rMat.GetString(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsString(rIndex+1) &&
+ aStr == rMat.GetString(rIndex+1))
+ ++rIndex;
+ }
+ else if (rMat.IsEmptyPath(rIndex))
+ {
+ if (bReverse)
+ while (rIndex > 0 && rMat.IsEmptyPath(rIndex-1))
+ --rIndex;
+ else
+ while (rIndex < nMatCount-1 && rMat.IsEmptyPath(rIndex+1))
+ ++rIndex;
+ }
}
void ScInterpreter::ScMatch()
@@ -4047,7 +4145,7 @@ void ScInterpreter::ScMatch()
for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
{
SCSIZE nMid = nFirst + nLen/2;
- sal_Int8 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry);
+ sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry);
if (nCmp == 0)
{
// exact match. find the last item with the same value.
@@ -4083,7 +4181,7 @@ void ScInterpreter::ScMatch()
if (nHitIndex == nMatCount-1) // last item
{
- sal_Int8 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry);
+ sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry);
if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
{
// either the last item is an exact match or the real
@@ -4600,353 +4698,423 @@ void ScInterpreter::ScLookup()
BYTE nParamCount = GetByte();
if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
return ;
- SCSIZE nC3 = 0, nC1 = 0;
- SCSIZE nR3 = 0, nR1 = 0;
- ScMatrixRef pMat3 = NULL;
- ScMatrixRef pMat1 = NULL;
- SCCOL nCol1 = 0;
- SCROW nRow1 = 0;
- SCTAB nTab1 = 0;
- SCCOL nCol2 = 0;
- SCROW nRow2 = 0;
- SCTAB nTab2;
- SCCOL nCol3 = 0;
- SCROW nRow3 = 0;
- SCTAB nTab3 = 0;
- SCCOL nCol4 = 0;
- SCROW nRow4 = 0;
- SCTAB nTab4;
- SCSIZE nDelta = 0;
-
- // param 3: data range
- if ( nParamCount == 3 )
+
+ ScMatrixRef pDataMat = NULL, pResMat = NULL;
+ SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
+ SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
+ SCTAB nTab1 = 0, nResTab = 0;
+ SCSIZE nLenMajor = 0; // length of major direction
+ bool bVertical = true; // whether to lookup vertically or horizontally
+
+ if (nParamCount == 3)
{
- if (GetStackType() == svDoubleRef)
+ switch (GetStackType())
{
- PopDoubleRef(nCol3, nRow3, nTab3, nCol4, nRow4, nTab4);
- if (nTab3 != nTab4 || (nCol3 != nCol4 && nRow3 != nRow4))
+ case svDoubleRef:
{
- PushIllegalParameter();
- return;
+ SCTAB nTabJunk;
+ PopDoubleRef(nResCol1, nResRow1, nResTab,
+ nResCol2, nResRow2, nTabJunk);
+ if (nResTab != nTabJunk ||
+ ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
+ {
+ // The result array must be a vector.
+ PushIllegalParameter();
+ return;
+ }
}
- }
- else if (GetStackType() == svMatrix)
- {
- pMat3 = PopMatrix();
- if (pMat3)
+ break;
+ case svMatrix:
{
- pMat3->GetDimensions(nC3, nR3);
- if (nC3 != 1 && nR3 != 1)
+ pResMat = PopMatrix();
+ if (!pResMat)
{
PushIllegalParameter();
return;
}
+ SCSIZE nC, nR;
+ pResMat->GetDimensions(nC, nR);
+ if (nC != 1 && nR != 1)
+ {
+ // Result matrix must be a vector.
+ PushIllegalParameter();
+ return;
+ }
}
- else
- {
+ break;
+ default:
PushIllegalParameter();
return;
- }
- }
- else
- {
- PushIllegalParameter();
- return;
}
}
- // param 2: key range, or key range and data range
- if (GetStackType() == svDoubleRef)
+ // Get the data-result range and also determine whether this is vertical
+ // lookup or horizontal lookup.
+
+ switch (GetStackType())
{
- PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
- if ( nTab1 != nTab2 || (nParamCount == 3 && nCol1 != nCol2 && nRow1 != nRow2) )
+ case svDoubleRef:
{
- PushIllegalParameter();
- return;
+ SCTAB nTabJunk;
+ PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
+ if (nTab1 != nTabJunk)
+ {
+ PushIllegalParameter();
+ return;
+ }
+ bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
+ nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
}
- }
- else if (GetStackType() == svMatrix)
- {
- pMat1 = PopMatrix();
- if (pMat1)
+ break;
+ case svMatrix:
{
- pMat1->GetDimensions(nC1, nR1);
- if (nC1 != 1 && nR1 != 1)
+ pDataMat = PopMatrix();
+ if (!pDataMat)
{
PushIllegalParameter();
return;
}
+
+ SCSIZE nC, nR;
+ pDataMat->GetDimensions(nC, nR);
+ bVertical = (nR >= nC);
+ nLenMajor = bVertical ? nR : nC;
}
- else
- {
+ break;
+ default:
PushIllegalParameter();
return;
- }
}
- else
+
+
+ if (nGlobalError)
{
PushIllegalParameter();
return;
}
- BOOL bSpMatrix, bSpVector;
- SCSIZE nMatCount, nVecCount;
- if (pMat1 == NULL)
+
+ // Get the lookup value.
+
+ String sStr;
+ ScQueryParam aParam;
+ ScQueryEntry& rEntry = aParam.GetEntry(0);
+
+ switch ( GetStackType() )
{
- if (nRow1 == nRow2)
- {
- nMatCount = static_cast<SCSIZE>(nCol2 - nCol1 + 1);
- bSpMatrix = FALSE;
- }
- else
+ case svDouble:
{
- nMatCount = static_cast<SCSIZE>(nRow2 - nRow1 + 1);
- bSpMatrix = TRUE;
+ rEntry.bQueryByString = FALSE;
+ rEntry.nVal = GetDouble();
}
- }
- else
- {
- if (nR1 == 1)
+ break;
+ case svString:
{
- nMatCount = nC1;
- bSpMatrix = FALSE;
+ sStr = GetString();
+ rEntry.bQueryByString = TRUE;
+ *rEntry.pStr = sStr;
}
- else
+ break;
+ case svDoubleRef :
+ case svSingleRef :
{
- nMatCount = nR1;
- bSpMatrix = TRUE;
+ ScAddress aAdr;
+ if ( !PopDoubleRefOrSingleRef( aAdr ) )
+ {
+ PushInt(0);
+ return ;
+ }
+ ScBaseCell* pCell = GetCell( aAdr );
+ if (HasCellValueData(pCell))
+ {
+ rEntry.bQueryByString = FALSE;
+ rEntry.nVal = GetCellValue( aAdr, pCell );
+ } else
+ {
+ if ( GetCellType( pCell ) == CELLTYPE_NOTE )
+ {
+ rEntry.bQueryByString = FALSE;
+ rEntry.nVal = 0.0;
+ } else
+ {
+ GetCellString(sStr, pCell);
+ rEntry.bQueryByString = TRUE;
+ *rEntry.pStr = sStr;
+ }
+ }
}
- }
- if ( nParamCount < 3 )
- {
- nVecCount = nMatCount;
- bSpVector = bSpMatrix;
- }
- else if (pMat3 == NULL)
- {
- if (nRow3 == nRow4)
+ break;
+ case svMatrix :
{
- nVecCount = static_cast<SCSIZE>(nCol4 - nCol3 + 1);
- bSpVector = FALSE;
+ ScMatValType nType = GetDoubleOrStringFromMatrix( rEntry.nVal,
+ *rEntry.pStr);
+ rEntry.bQueryByString = ScMatrix::IsStringType(nType);
}
- else
+ break;
+ default:
{
- nVecCount = static_cast<SCSIZE>(nRow4 - nRow3 + 1);
- bSpVector = TRUE;
+ PushIllegalParameter();
+ return;
}
}
- else
+
+ // Now, perform the search to compute the delta position (nDelta).
+
+ if (pDataMat)
{
- if (nR3 == 1)
+ // Data array is given as a matrix.
+
+ rEntry.bDoQuery = true;
+ rEntry.eOp = SC_LESS_EQUAL;
+ bool bFound = false;
+
+ SCSIZE nC, nR;
+ pDataMat->GetDimensions(nC, nR);
+
+ // In case of non-vector matrix, only search the first row or column.
+ ScMatrixRef pDataMat2;
+ if (bVertical)
{
- nVecCount = nC3;
- bSpVector = FALSE;
+ ScMatrixRef pTempMat(new ScMatrix(1, nR));
+ for (SCSIZE i = 0; i < nR; ++i)
+ if (pDataMat->IsValue(0, i))
+ pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
+ else
+ pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
+ pDataMat2 = pTempMat;
}
else
{
- nVecCount = nR3;
- bSpVector = TRUE;
+ ScMatrixRef pTempMat(new ScMatrix(nC, 1));
+ for (SCSIZE i = 0; i < nC; ++i)
+ if (pDataMat->IsValue(i, 0))
+ pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
+ else
+ pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
+ pDataMat2 = pTempMat;
}
- }
- if (nGlobalError == 0 && nVecCount == nMatCount)
- {
- String sStr;
- ScQueryParam aParam;
- aParam.nCol1 = nCol1;
- aParam.nRow1 = nRow1;
- aParam.nCol2 = (bSpMatrix ? nCol1 : nCol2);
- aParam.nRow2 = (bSpMatrix ? nRow2 : nRow1);
- aParam.bByRow = bSpMatrix;
- aParam.bMixedComparison = TRUE;
-
- ScQueryEntry& rEntry = aParam.GetEntry(0);
- rEntry.bDoQuery = TRUE;
- rEntry.eOp = SC_LESS_EQUAL;
- rEntry.nField = nCol1;
- switch ( GetStackType() )
+
+ // binary search for non-equality mode (the source data is
+ // assumed to be sorted in ascending order).
+
+ SCCOLROW nDelta = -1;
+
+ SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
+ for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
{
- case svDouble:
- {
- rEntry.bQueryByString = FALSE;
- rEntry.nVal = GetDouble();
- }
- break;
- case svString:
+ SCSIZE nMid = nFirst + nLen/2;
+ sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry);
+ if (nCmp == 0)
{
- sStr = GetString();
- rEntry.bQueryByString = TRUE;
- *rEntry.pStr = sStr;
+ // exact match. find the last item with the same value.
+ lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false);
+ nDelta = nMid;
+ bFound = true;
+ break;
}
- break;
- case svDoubleRef :
- case svSingleRef :
+
+ if (nLen == 1) // first and last items are next to each other.
{
- ScAddress aAdr;
- if ( !PopDoubleRefOrSingleRef( aAdr ) )
- {
- PushInt(0);
- return ;
- }
- ScBaseCell* pCell = GetCell( aAdr );
- if (HasCellValueData(pCell))
- {
- rEntry.bQueryByString = FALSE;
- rEntry.nVal = GetCellValue( aAdr, pCell );
- }
- else
- {
- if ( GetCellType( pCell ) == CELLTYPE_NOTE )
- {
- rEntry.bQueryByString = FALSE;
- rEntry.nVal = 0.0;
- }
- else
- {
- GetCellString(sStr, pCell);
- rEntry.bQueryByString = TRUE;
- *rEntry.pStr = sStr;
- }
- }
+ nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
+ // If already the 1st item is greater there's nothing found.
+ bFound = (nDelta >= 0);
+ break;
}
- break;
- case svMatrix :
+
+ if (nCmp < 0)
+ nFirst = nMid;
+ else
+ nLast = nMid;
+ }
+
+ if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
+ {
+ sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry);
+ if (nCmp <= 0)
{
- ScMatValType nType = GetDoubleOrStringFromMatrix( rEntry.nVal,
- *rEntry.pStr);
- rEntry.bQueryByString = ScMatrix::IsStringType( nType);
+ // either the last item is an exact match or the real
+ // hit is beyond the last item.
+ nDelta += 1;
+ bFound = true;
}
- break;
- default:
+ }
+ else if (nDelta > 0) // valid hit must be 2nd item or higher
+ {
+ // non-exact match
+ bFound = true;
+ }
+
+ if (!bFound)
+ {
+ PushNA();
+ return;
+ }
+
+ // Now that we've found the delta, push the result back to the cell.
+
+ if (pResMat)
+ {
+ // result array is matrix.
+ if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount())
{
- PushIllegalParameter();
+ PushNA();
return;
}
+ if (pResMat->IsValue(nDelta))
+ PushDouble(pResMat->GetDouble(nDelta));
+ else
+ PushString(pResMat->GetString(nDelta));
}
- if ( rEntry.bQueryByString )
- aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
- if (pMat1)
+ else if (nParamCount == 3)
{
- if (rEntry.bQueryByString)
+ // result array is cell range.
+ ScAddress aAdr;
+ aAdr.SetTab(nResTab);
+ bool bResVertical = (nResRow2 - nResRow1) > 0;
+ if (bResVertical)
{
-//!!!!!!!
-//! TODO: enable regex on matrix strings
-//!!!!!!!
- BOOL bFound = FALSE;
- sal_Int32 nRes;
- String aParamStr = *rEntry.pStr;
- SCSIZE i;
- for ( i = 0; i < nMatCount; i++)
+ SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
+ if (nTempRow > MAXROW)
{
- if (!pMat1->IsValue(i))
- {
- nRes = ScGlobal::pCollator->compareString(
- pMat1->GetString(i), aParamStr );
- if (nRes == COMPARE_EQUAL)
- {
- bFound = TRUE;
- nDelta = i;
- }
- else if (nRes == COMPARE_LESS)
- i = nMatCount+1;
- }
- }
- if (i == nMatCount+2 && !bFound)
- {
- PushNA();
+ PushDouble(0);
return;
}
- else if (!bFound)
- nDelta = i-1;
+ aAdr.SetCol(nResCol1);
+ aAdr.SetRow(nTempRow);
}
else
{
- BOOL bFound = FALSE;
- double fVal1;
- SCSIZE i;
- for ( i = 0; i < nMatCount; i++)
+ SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
+ if (nTempCol > MAXCOL)
{
- if (pMat1->IsValue(i))
- fVal1 = pMat1->GetDouble(i);
- else
- fVal1 = MAXDOUBLE;
- if (fVal1 == rEntry.nVal)
- {
- bFound = TRUE;
- nDelta = i;
- }
- else if (fVal1 > rEntry.nVal)
- i = nMatCount+1;
- }
- if (i == nMatCount+2 && !bFound)
- {
- PushNA();
+ PushDouble(0);
return;
}
- else if (!bFound)
- nDelta = i-1;
+ aAdr.SetCol(nTempCol);
+ aAdr.SetRow(nResRow1);
}
+ PushCellResultToken(true, aAdr, NULL, NULL);
}
else
{
- ScQueryCellIterator aCellIter(pDok, nTab1, aParam, FALSE);
- SCCOL nC;
- SCROW nR;
- // Advance Entry.nField in iterator upon switching columns if
- // lookup in row.
- aCellIter.SetAdvanceQueryParamEntryField( !bSpMatrix);
- if ( aCellIter.FindEqualOrSortedLastInRange( nC, nR ) )
- nDelta = bSpMatrix ? static_cast<SCSIZE>(nR - nRow1) :
- static_cast<SCSIZE>(nC - nCol1);
+ // no result array. Use the data array to get the final value from.
+ if (bVertical)
+ {
+ if (pDataMat->IsValue(nC-1, nDelta))
+ PushDouble(pDataMat->GetDouble(nC-1, nDelta));
+ else
+ PushString(pDataMat->GetString(nC-1, nDelta));
+ }
else
{
- PushNA();
- return;
+ if (pDataMat->IsValue(nDelta, nR-1))
+ PushDouble(pDataMat->GetDouble(nDelta, nR-1));
+ else
+ PushString(pDataMat->GetString(nDelta, nR-1));
}
}
+
+ return;
}
- else
+
+ // Perform cell range search.
+
+ aParam.nCol1 = nCol1;
+ aParam.nRow1 = nRow1;
+ aParam.nCol2 = bVertical ? nCol1 : nCol2;
+ aParam.nRow2 = bVertical ? nRow2 : nRow1;
+ aParam.bByRow = bVertical;
+ aParam.bMixedComparison = true;
+
+ rEntry.bDoQuery = TRUE;
+ rEntry.eOp = SC_LESS_EQUAL;
+ rEntry.nField = nCol1;
+ if ( rEntry.bQueryByString )
+ aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
+
+ ScQueryCellIterator aCellIter(pDok, nTab1, aParam, FALSE);
+ SCCOL nC;
+ SCROW nR;
+ // Advance Entry.nField in iterator upon switching columns if
+ // lookup in row.
+ aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
+ if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
{
- PushIllegalParameter();
+ PushNA();
return;
}
- if (pMat3)
+
+ SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
+
+ if (pResMat)
{
- if (pMat3->IsValue(nDelta))
- PushDouble(pMat3->GetDouble(nDelta));
+ // Use the matrix result array.
+ if (pResMat->IsValue(nDelta))
+ PushDouble(pResMat->GetDouble(nDelta));
else
- PushString(pMat3->GetString(nDelta));
+ PushString(pResMat->GetString(nDelta));
}
- else
+ else if (nParamCount == 3)
{
+ // Use the result array vector. Note that the result array is assumed
+ // to be a vector (i.e. 1-dimensinoal array).
+
ScAddress aAdr;
- if ( nParamCount < 3 )
+ aAdr.SetTab(nResTab);
+ bool bResVertical = (nResRow2 - nResRow1) > 0;
+ if (bResVertical)
{
- if (bSpVector)
+ SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
+ if (nTempRow > MAXROW)
{
- aAdr.SetCol( nCol2 ); // data in right col of key/data range
- aAdr.SetRow( sal::static_int_cast<SCROW>( nRow1 + nDelta ) );
+ PushDouble(0);
+ return;
}
- else
+ aAdr.SetCol(nResCol1);
+ aAdr.SetRow(nTempRow);
+ }
+ else
+ {
+ SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
+ if (nTempCol > MAXCOL)
{
- aAdr.SetCol( sal::static_int_cast<SCCOL>( nCol1 + nDelta ) );
- aAdr.SetRow( nRow2 ); // data in lower row of key/data range
+ PushDouble(0);
+ return;
}
- aAdr.SetTab( nTab1 );
+ aAdr.SetCol(nTempCol);
+ aAdr.SetRow(nResRow1);
}
- else
+ PushCellResultToken(true, aAdr, NULL, NULL);
+ }
+ else
+ {
+ // Regardless of whether or not the result array exists, the last
+ // array is always used as the "result" array.
+
+ ScAddress aAdr;
+ aAdr.SetTab(nTab1);
+ if (bVertical)
{
- if (bSpVector)
+ SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
+ if (nTempRow > MAXROW)
{
- aAdr.SetCol( nCol3 );
- aAdr.SetRow( sal::static_int_cast<SCROW>( nRow3 + nDelta ) );
+ PushDouble(0);
+ return;
}
- else
+ aAdr.SetCol(nCol2);
+ aAdr.SetRow(nTempRow);
+ }
+ else
+ {
+ SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
+ if (nTempCol > MAXCOL)
{
- aAdr.SetCol( sal::static_int_cast<SCCOL>( nCol3 + nDelta ) );
- aAdr.SetRow( nRow3 );
+ PushDouble(0);
+ return;
}
- aAdr.SetTab( nTab3 );
+ aAdr.SetCol(nTempCol);
+ aAdr.SetRow(nRow2);
}
- PushCellResultToken( true, aAdr, NULL, NULL);
+ PushCellResultToken(true, aAdr, NULL, NULL);
}
}
@@ -6274,36 +6442,36 @@ void ScInterpreter::ScIndex()
else
PushDouble( pMat->GetDouble( nElement));
}
- else if (nRow == 0)
+ else if (nCol == 0)
{
ScMatrixRef pResMat = GetNewMat(nC, 1);
if (pResMat)
{
- SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
+ SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
for (SCSIZE i = 0; i < nC; i++)
- if (!pMat->IsString(i, nColMinus1))
+ if (!pMat->IsString(i, nRowMinus1))
pResMat->PutDouble(pMat->GetDouble(i,
- nColMinus1), i, 0);
+ nRowMinus1), i, 0);
else
pResMat->PutString(pMat->GetString(i,
- nColMinus1), i, 0);
+ nRowMinus1), i, 0);
PushMatrix(pResMat);
}
else
PushIllegalArgument();
}
- else if (nCol == 0)
+ else if (nRow == 0)
{
ScMatrixRef pResMat = GetNewMat(1, nR);
if (pResMat)
{
- SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
+ SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
for (SCSIZE i = 0; i < nR; i++)
- if (!pMat->IsString(nRowMinus1, i))
- pResMat->PutDouble(pMat->GetDouble(nRowMinus1,
+ if (!pMat->IsString(nColMinus1, i))
+ pResMat->PutDouble(pMat->GetDouble(nColMinus1,
i), i);
else
- pResMat->PutString(pMat->GetString(nRowMinus1,
+ pResMat->PutString(pMat->GetString(nColMinus1,
i), i);
PushMatrix(pResMat);
}
@@ -6346,6 +6514,7 @@ void ScInterpreter::ScIndex()
SCCOL nCol2 = 0;
SCROW nRow2 = 0;
SCTAB nTab2 = 0;
+ BOOL bRowArray = FALSE;
if (GetStackType() == svRefList)
{
ScTokenRef xRef = PopToken();
@@ -6357,12 +6526,19 @@ void ScInterpreter::ScIndex()
ScRange aRange( ScAddress::UNINITIALIZED);
DoubleRefToRange( (*(xRef->GetRefList()))[nArea-1], aRange);
aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if ( nParamCount == 2 && nRow1 == nRow2 )
+ bRowArray = TRUE;
}
else
+ {
PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
+ if ( nParamCount == 2 && nRow1 == nRow2 )
+ bRowArray = TRUE;
+ }
if ( nTab1 != nTab2 ||
(nCol > 0 && nCol1+nCol-1 > nCol2) ||
- (nRow > 0 && nRow1+nRow-1 > nRow2) )
+ (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
+ ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
PushIllegalArgument();
else if (nCol == 0 && nRow == 0)
{
@@ -6383,6 +6559,12 @@ void ScInterpreter::ScIndex()
{
if ( nCol1 == nCol2 )
PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
+ else if ( bRowArray )
+ {
+ nCol =(SCCOL) nRow;
+ nRow = 1;
+ PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
+ }
else
PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
nCol2, nRow1+nRow-1, nTab1);