You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@openoffice.apache.org by or...@apache.org on 2012/09/17 10:06:23 UTC

svn commit: r1386501 [5/10] - in /incubator/ooo/branches/writer001: ./ ext_libraries/ratscan/ ext_sources/ main/ main/autodoc/source/display/html/ main/basegfx/inc/basegfx/numeric/ main/basegfx/source/numeric/ main/basegfx/source/tools/ main/basic/sour...

Modified: incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr1.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr1.cxx?rev=1386501&r1=1386500&r2=1386501&view=diff
==============================================================================
--- incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr1.cxx (original)
+++ incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr1.cxx Mon Sep 17 08:06:09 2012
@@ -1332,6 +1332,106 @@ void ScInterpreter::ScOr()
     }
 }
 
+void ScInterpreter::ScXor()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScXor" );
+    nFuncFmtType = NUMBERFORMAT_LOGICAL;
+    short nParamCount = GetByte();
+    if ( MustHaveParamCountMin( nParamCount, 1 ) )
+    {
+        bool bHaveValue = false;
+        short nRes = 0;
+        size_t nRefInList = 0;
+        while( nParamCount-- > 0)
+        {
+            if ( !nGlobalError )
+            {
+                switch ( GetStackType() )
+                {
+                    case svDouble :
+                        bHaveValue = true;
+                        nRes ^= ( PopDouble() != 0.0 );
+                        break;
+                    case svString :
+                        Pop();
+                        SetError( errNoValue );
+                        break;
+                    case svSingleRef :
+                        {
+                            ScAddress aAdr;
+                            PopSingleRef( aAdr );
+                            if ( !nGlobalError )
+                            {
+                                ScBaseCell* pCell = GetCell( aAdr );
+                                if ( HasCellValueData( pCell ) )
+                                {
+                                    bHaveValue = true;
+                                    nRes ^= ( GetCellValue( aAdr, pCell ) != 0.0 );
+                                }
+                                /* TODO: set error? Excel doesn't have XOR, but
+                                 * doesn't set an error in this case for AND and
+                                 * OR. */
+                            }
+                        }
+                        break;
+                    case svDoubleRef:
+                    case svRefList:
+                        {
+                            ScRange aRange;
+                            PopDoubleRef( aRange, nParamCount, nRefInList);
+                            if ( !nGlobalError )
+                            {
+                                double fVal;
+                                sal_uInt16 nErr = 0;
+                                ScValueIterator aValIter( pDok, aRange );
+                                if ( aValIter.GetFirst( fVal, nErr ) )
+                                {
+                                    bHaveValue = true;
+                                    do
+                                    {
+                                        nRes ^= ( fVal != 0.0 );
+                                    } while ( (nErr == 0) &&
+                                            aValIter.GetNext( fVal, nErr ) );
+                                }
+                                SetError( nErr );
+                            }
+                        }
+                        break;
+                    case svMatrix:
+                        {
+                            bHaveValue = true;
+                            ScMatrixRef pMat = GetMatrix();
+                            if ( pMat )
+                            {
+                                bHaveValue = true;
+                                double fVal = pMat->Xor();
+                                sal_uInt16 nErr = GetDoubleErrorValue( fVal );
+                                if ( nErr )
+                                {
+                                    SetError( nErr );
+                                    nRes = 0;
+                                }
+                                else
+                                    nRes ^= (fVal != 0.0);
+                            }
+                            // else: GetMatrix did set errIllegalParameter
+                        }
+                        break;
+                    default:
+                        Pop();
+                        SetError( errIllegalParameter);
+                }
+            }
+            else
+                Pop();
+        }
+        if ( bHaveValue )
+            PushInt( nRes );
+        else
+            PushNoValue();
+    }
+}
+
 
 void ScInterpreter::ScNeg()
 {
@@ -4409,89 +4509,134 @@ void ScInterpreter::ScCountEmptyCells()
 }
 
 
-void ScInterpreter::ScCountIf()
+double ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc )
 {
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountIf" );
-    if ( MustHaveParamCount( GetByte(), 2 ) )
+    sal_uInt8 nParamCount = GetByte();
+    if ( MustHaveParamCount( nParamCount, 2, 3 ) )
     {
+        SCCOL nCol3 = 0;
+        SCROW nRow3 = 0;
+        SCTAB nTab3 = 0;
+
+        ScMatrixRef pSumExtraMatrix;
+        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 :
+                    {
+                        SCCOL nColJunk = 0;
+                        SCROW nRowJunk = 0;
+                        SCTAB nTabJunk = 0;
+                        PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
+                        if ( nTabJunk != nTab3 )
+                        {
+                            SetError( errIllegalParameter);
+                        }
+                    }
+                    break;
+                case svSingleRef :
+                    PopSingleRef( nCol3, nRow3, nTab3 );
+                    break;
+                case svMatrix:
+                    pSumExtraMatrix = PopMatrix();
+                    //! nCol3, nRow3, nTab3 remain 0
+                    break;
+                default:
+                    SetError( errIllegalParameter);
+            }
+        }
         String rString;
         double fVal = 0.0;
-        sal_Bool bIsString = sal_True;
+        bool bIsString = true;
         switch ( GetStackType() )
         {
             case svDoubleRef :
             case svSingleRef :
-            {
-                ScAddress aAdr;
-                if ( !PopDoubleRefOrSingleRef( aAdr ) )
-                {
-                    PushInt(0);
-                    return ;
-                }
-                ScBaseCell* pCell = GetCell( aAdr );
-                switch ( GetCellType( pCell ) )
                 {
-                    case CELLTYPE_VALUE :
-                        fVal = GetCellValue( aAdr, pCell );
-                        bIsString = sal_False;
-                        break;
-                    case CELLTYPE_FORMULA :
-                        if( ((ScFormulaCell*)pCell)->IsValue() )
-                        {
+                    ScAddress aAdr;
+                    if ( !PopDoubleRefOrSingleRef( aAdr ) )
+                        return 0;
+
+                    ScBaseCell* pCell = GetCell( aAdr );
+                    switch ( GetCellType( pCell ) )
+                    {
+                        case CELLTYPE_VALUE :
                             fVal = GetCellValue( aAdr, pCell );
-                            bIsString = sal_False;
-                        }
-                        else
+                            bIsString = false;
+                            break;
+                        case CELLTYPE_FORMULA :
+                            if( ((ScFormulaCell*)pCell)->IsValue() )
+                            {
+                                fVal = GetCellValue( aAdr, pCell );
+                                bIsString = false;
+                            }
+                            else
+                                GetCellString(rString, pCell);
+                            break;
+                        case CELLTYPE_STRING :
+                        case CELLTYPE_EDIT :
                             GetCellString(rString, pCell);
-                        break;
-                    case CELLTYPE_STRING :
-                    case CELLTYPE_EDIT :
-                        GetCellString(rString, pCell);
-                        break;
-                    default:
-                        fVal = 0.0;
-                        bIsString = sal_False;
+                            break;
+                        default:
+                            fVal = 0.0;
+                            bIsString = false;
+                    }
                 }
-            }
-            break;
-            case svMatrix :
-            {
-                ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
-                        rString);
-                bIsString = ScMatrix::IsNonValueType( nType);
-            }
-            break;
+                break;
             case svString:
                 rString = GetString();
-            break;
+                break;
+            case svMatrix :
+                {
+                    ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
+                    bIsString = ScMatrix::IsNonValueType( nType);
+                }
+                break;
             default:
-            {
-                fVal = GetDouble();
-                bIsString = sal_False;
-            }
+                {
+                    fVal = GetDouble();
+                    bIsString = false;
+                }
         }
+
         double fSum = 0.0;
+        double fMem = 0.0;
+        double fRes = 0.0;
+        double fCount = 0.0;
+        bool bNull = true;
         short nParam = 1;
         size_t nRefInList = 0;
         while (nParam-- > 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;
             ScMatrixRef pQueryMatrix;
             switch ( GetStackType() )
             {
-                case svDoubleRef :
                 case svRefList :
+                    if (bSumExtraRange)
+                    {
+                        SetError( errIllegalParameter);
+                    }
+                    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;
@@ -4503,8 +4648,7 @@ void ScInterpreter::ScCountIf()
                         pQueryMatrix = PopMatrix();
                         if (!pQueryMatrix)
                         {
-                            PushIllegalParameter();
-                            return;
+                            SetError( errIllegalParameter);
                         }
                         nCol1 = 0;
                         nRow1 = 0;
@@ -4517,19 +4661,58 @@ void ScInterpreter::ScCountIf()
                     }
                     break;
                 default:
-                    PushIllegalParameter();
-                    return ;
+                    SetError( errIllegalParameter);
             }
             if ( nTab1 != nTab2 )
             {
-                PushIllegalParameter();
-                return;
+                SetError( errIllegalParameter);
             }
-            if (nCol1 > nCol2)
+
+            if (bSumExtraRange)
             {
-                PushIllegalParameter();
-                return;
+                // 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;
+                SCCOL nMaxCol;
+                SCROW nMaxRow;
+                if (pSumExtraMatrix)
+                {
+                    SCSIZE nC, nR;
+                    pSumExtraMatrix->GetDimensions( nC, nR);
+                    nMaxCol = static_cast<SCCOL>(nC - 1);
+                    nMaxRow = static_cast<SCROW>(nR - 1);
+                }
+                else
+                {
+                    nMaxCol = MAXCOL;
+                    nMaxRow = MAXROW;
+                }
+                if (nCol3 + nColDelta > nMaxCol)
+                {
+                    SCCOL nNewDelta = nMaxCol - nCol3;
+                    nCol2 = nCol1 + nNewDelta;
+                }
+
+                if (nRow3 + nRowDelta > nMaxRow)
+                {
+                    SCROW nNewDelta = nMaxRow - nRow3;
+                    nRow2 = nRow1 + nNewDelta;
+                }
+            }
+            else
+            {
+                nCol3 = nCol1;
+                nRow3 = nRow1;
+                nTab3 = nTab1;
             }
+
             if (nGlobalError == 0)
             {
                 ScQueryParam rParam;
@@ -4537,10 +4720,10 @@ void ScInterpreter::ScCountIf()
                 rParam.nRow2       = nRow2;
 
                 ScQueryEntry& rEntry = rParam.GetEntry(0);
-                rEntry.bDoQuery = sal_True;
+                rEntry.bDoQuery = true;
                 if (!bIsString)
                 {
-                    rEntry.bQueryByString = sal_False;
+                    rEntry.bQueryByString = false;
                     rEntry.nVal = fVal;
                     rEntry.eOp = SC_EQUAL;
                 }
@@ -4554,9 +4737,13 @@ void ScInterpreter::ScCountIf()
                     if ( rEntry.bQueryByString )
                         rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
                 }
+                ScAddress aAdr;
+                aAdr.SetTab( nTab3 );
                 rParam.nCol1  = nCol1;
                 rParam.nCol2  = nCol2;
                 rEntry.nField = nCol1;
+                SCsCOL nColDiff = nCol3 - nCol1;
+                SCsROW nRowDiff = nRow3 - nRow1;
                 if (pQueryMatrix)
                 {
                     // Never case-sensitive.
@@ -4564,87 +4751,148 @@ void ScInterpreter::ScCountIf()
                     ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
                     if (nGlobalError || !pResultMatrix)
                     {
-                        PushIllegalParameter();
-                        return;
+                        SetError( errIllegalParameter);
                     }
 
-                    SCSIZE nSize = pResultMatrix->GetElementCount();
-                    for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
-                    {
-                        if (pResultMatrix->IsValue( nIndex) && 
-                                pResultMatrix->GetDouble( nIndex))
-                            ++fSum;
-                    }
-                }
-                else
-                {
-                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
-                    // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
-                    aCellIter.SetAdvanceQueryParamEntryField( sal_True );
-                    if ( aCellIter.GetFirst() )
+                    if (pSumExtraMatrix)
                     {
-                        do
+                        for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
                         {
-                            fSum++;
-                        } while ( aCellIter.GetNext() );
-                    }
-                }
-            }
-            else
-            {
-                PushIllegalParameter();
-                return;
-            }
-        }
-        PushDouble(fSum);
-    }
-}
-
-
-void ScInterpreter::ScSumIf()
-{
-    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumIf" );
-    sal_uInt8 nParamCount = GetByte();
-    if ( MustHaveParamCount( nParamCount, 2, 3 ) )
-    {
-        SCCOL nCol3 = 0;
-        SCROW nRow3 = 0;
-        SCTAB nTab3 = 0;
-
-        ScMatrixRef pSumExtraMatrix;
-        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 :
+                            for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+                            {
+                                if (pResultMatrix->IsValue( nCol, nRow) && 
+                                        pResultMatrix->GetDouble( nCol, nRow))
+                                {
+                                    SCSIZE nC = nCol + nColDiff;
+                                    SCSIZE nR = nRow + nRowDiff;
+                                    if (pSumExtraMatrix->IsValue( nC, nR))
+                                    {
+                                        fVal = pSumExtraMatrix->GetDouble( nC, nR);
+                                        ++fCount;
+                                        if ( bNull && fVal != 0.0 )
+                                        {
+                                            bNull = false;
+                                            fMem = fVal;
+                                        }
+                                        else
+                                            fSum += fVal;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+                        {
+                            for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+                            {
+                                if (pResultMatrix->GetDouble( nCol, nRow))
+                                {
+                                    aAdr.SetCol( nCol + nColDiff);
+                                    aAdr.SetRow( nRow + nRowDiff);
+                                    ScBaseCell* pCell = GetCell( aAdr );
+                                    if ( HasCellValueData(pCell) )
+                                    {
+                                        fVal = GetCellValue( aAdr, pCell );
+                                        ++fCount;
+                                        if ( bNull && fVal != 0.0 )
+                                        {
+                                            bNull = false;
+                                            fMem = fVal;
+                                        }
+                                        else
+                                            fSum += fVal;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+                else
                 {
-                    SCCOL nColJunk = 0;
-                    SCROW nRowJunk = 0;
-                    SCTAB nTabJunk = 0;
-                    PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
-                    if ( nTabJunk != nTab3 )
+                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
+                    // Increment Entry.nField in iterator when switching to next column.
+                    aCellIter.SetAdvanceQueryParamEntryField( true );
+                    if ( aCellIter.GetFirst() )
                     {
-                        PushIllegalParameter();
-                        return;
+                        if (pSumExtraMatrix)
+                        {
+                            do
+                            {
+                                SCSIZE nC = aCellIter.GetCol() + nColDiff;
+                                SCSIZE nR = aCellIter.GetRow() + nRowDiff;
+                                if (pSumExtraMatrix->IsValue( nC, nR))
+                                {
+                                    fVal = pSumExtraMatrix->GetDouble( nC, nR);
+                                    ++fCount;
+                                    if ( bNull && fVal != 0.0 )
+                                    {
+                                        bNull = false;
+                                        fMem = fVal;
+                                    }
+                                    else
+                                        fSum += fVal;
+                                }
+                            } while ( aCellIter.GetNext() );
+                        }
+                        else
+                        {
+                            do
+                            {
+                                aAdr.SetCol( aCellIter.GetCol() + nColDiff);
+                                aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
+                                ScBaseCell* pCell = GetCell( aAdr );
+                                if ( HasCellValueData(pCell) )
+                                {
+                                    fVal = GetCellValue( aAdr, pCell );
+                                    ++fCount;
+                                    if ( bNull && fVal != 0.0 )
+                                    {
+                                        bNull = false;
+                                        fMem = fVal;
+                                    }
+                                    else
+                                        fSum += fVal;
+                                }
+                            } while ( aCellIter.GetNext() );
+                        }
                     }
                 }
-                break;
-                case svSingleRef :
-                    PopSingleRef( nCol3, nRow3, nTab3 );
-                break;
-                case svMatrix:
-                    pSumExtraMatrix = PopMatrix();
-                    //! nCol3, nRow3, nTab3 remain 0
-                break;
-                default:
-                    PushIllegalParameter();
-                    return ;
+            }
+            else
+            {
+                SetError( errIllegalParameter);
             }
         }
+
+        switch( eFunc )
+        {
+            case ifSUMIF:     fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
+            case ifAVERAGEIF: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
+        }
+        return fRes;
+    }
+    return 0;
+}
+
+void ScInterpreter::ScSumIf()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumIf" );
+    PushDouble( IterateParametersIf( ifSUMIF));
+}
+
+void ScInterpreter::ScAverageIf()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScAverageIf" );
+    PushDouble( IterateParametersIf( ifAVERAGEIF));
+}
+
+void ScInterpreter::ScCountIf()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountIf" );
+    if ( MustHaveParamCount( GetByte(), 2 ) )
+    {
         String rString;
         double fVal = 0.0;
         sal_Bool bIsString = sal_True;
@@ -4685,26 +4933,22 @@ void ScInterpreter::ScSumIf()
                 }
             }
             break;
-            case svString:
-                rString = GetString();
-            break;
             case svMatrix :
             {
-                ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
-                        rString);
+                ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
                 bIsString = ScMatrix::IsNonValueType( nType);
             }
             break;
+            case svString:
+                rString = GetString();
+            break;
             default:
             {
                 fVal = GetDouble();
                 bIsString = sal_False;
             }
         }
-
-        double fSum = 0.0;
-        double fMem = 0.0;
-        sal_Bool bNull = sal_True;
+        double fCount = 0.0;
         short nParam = 1;
         size_t nRefInList = 0;
         while (nParam-- > 0)
@@ -4718,22 +4962,14 @@ void ScInterpreter::ScSumIf()
             ScMatrixRef pQueryMatrix;
             switch ( GetStackType() )
             {
+                case svDoubleRef :
                 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;
@@ -4764,66 +5000,256 @@ void ScInterpreter::ScSumIf()
             }
             if ( nTab1 != nTab2 )
             {
-                PushIllegalArgument();
+                PushIllegalParameter();
                 return;
             }
-
-            if (bSumExtraRange)
+            if (nCol1 > nCol2)
             {
-                // 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 :-/
+                PushIllegalParameter();
+                return;
+            }
+            if (nGlobalError == 0)
+            {
+                ScQueryParam rParam;
+                rParam.nRow1       = nRow1;
+                rParam.nRow2       = nRow2;
 
-                // 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;
-                SCCOL nMaxCol;
-                SCROW nMaxRow;
-                if (pSumExtraMatrix)
+                ScQueryEntry& rEntry = rParam.GetEntry(0);
+                rEntry.bDoQuery = sal_True;
+                if (!bIsString)
                 {
-                    SCSIZE nC, nR;
-                    pSumExtraMatrix->GetDimensions( nC, nR);
-                    nMaxCol = static_cast<SCCOL>(nC - 1);
-                    nMaxRow = static_cast<SCROW>(nR - 1);
+                    rEntry.bQueryByString = sal_False;
+                    rEntry.nVal = fVal;
+                    rEntry.eOp = SC_EQUAL;
                 }
                 else
                 {
-                    nMaxCol = MAXCOL;
-                    nMaxRow = MAXROW;
+                    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 );
                 }
-                if (nCol3 + nColDelta > nMaxCol)
+                rParam.nCol1  = nCol1;
+                rParam.nCol2  = nCol2;
+                rEntry.nField = nCol1;
+                if (pQueryMatrix)
                 {
-                    SCCOL nNewDelta = nMaxCol - nCol3;
-                    nCol2 = nCol1 + nNewDelta;
-                }
+                    // Never case-sensitive.
+                    ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
+                    ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
+                    if (nGlobalError || !pResultMatrix)
+                    {
+                        PushIllegalParameter();
+                        return;
+                    }
 
-                if (nRow3 + nRowDelta > nMaxRow)
+                    SCSIZE nSize = pResultMatrix->GetElementCount();
+                    for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
+                    {
+                        if (pResultMatrix->IsValue( nIndex) && 
+                                pResultMatrix->GetDouble( nIndex))
+                            ++fCount;
+                    }
+                }
+                else
                 {
-                    SCROW nNewDelta = nMaxRow - nRow3;
-                    nRow2 = nRow1 + nNewDelta;
+                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
+                    // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
+                    aCellIter.SetAdvanceQueryParamEntryField( sal_True );
+                    if ( aCellIter.GetFirst() )
+                    {
+                        do
+                        {
+                            fCount++;
+                        } while ( aCellIter.GetNext() );
+                    }
                 }
             }
             else
             {
-                nCol3 = nCol1;
-                nRow3 = nRow1;
-                nTab3 = nTab1;
+                PushIllegalParameter();
+                return;
             }
+        }
+        PushDouble(fCount);
+    }
+}
+
+double ScInterpreter::IterateParametersIfs( ScIterFuncIfs eFunc )
+{
+    sal_uInt8 nParamCount = GetByte();
+    sal_uInt8 nQueryCount = nParamCount / 2;
 
+    bool bCheck;
+    if ( eFunc == ifCOUNTIFS )
+        bCheck = (nParamCount >= 2) && (nParamCount % 2 == 0);
+    else
+        bCheck = (nParamCount >= 3) && (nParamCount % 2 == 1);
+
+    if ( !bCheck )
+    {
+        SetError( errParameterExpected);
+    }
+    else
+    {
+        ScMatrixRef pResMat;
+        double fVal = 0.0;
+        double fSum = 0.0;
+        double fMem = 0.0;
+        double fRes = 0.0;
+        double fCount = 0.0;
+        short nParam = 1;
+        size_t nRefInList = 0;
+        SCCOL nDimensionCols = 0;
+        SCROW nDimensionRows = 0;
+
+        while (nParamCount > 1 && !nGlobalError)
+        {
+            // take criteria
+            String rString;
+            fVal = 0.0;
+            bool bIsString = true;
+            switch ( GetStackType() )
+            {
+                case svDoubleRef :
+                case svSingleRef :
+                    {
+                        ScAddress aAdr;
+                        if ( !PopDoubleRefOrSingleRef( aAdr ) )
+                            return 0;
+
+                        ScBaseCell* pCell = GetCell( aAdr );
+                        switch ( GetCellType( pCell ) )
+                        {
+                            case CELLTYPE_VALUE :
+                                fVal = GetCellValue( aAdr, pCell );
+                                bIsString = false;
+                                break;
+                            case CELLTYPE_FORMULA :
+                                if( ((ScFormulaCell*)pCell)->IsValue() )
+                                {
+                                    fVal = GetCellValue( aAdr, pCell );
+                                    bIsString = false;
+                                }
+                                else
+                                    GetCellString(rString, pCell);
+                                break;
+                            case CELLTYPE_STRING :
+                            case CELLTYPE_EDIT :
+                                GetCellString(rString, pCell);
+                                break;
+                            default:
+                                fVal = 0.0;
+                                bIsString = false;
+                        }
+                    }
+                    break;
+                case svString:
+                    rString = GetString();
+                    break;
+                case svMatrix :
+                    {
+                        ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
+                        bIsString = ScMatrix::IsNonValueType( nType);
+                    }
+                    break;
+                default:
+                    {
+                        fVal = GetDouble();
+                        bIsString = false;
+                    }
+            }
+
+            if (nGlobalError)
+                continue;   // and bail out, no need to evaluate other arguments
+
+            // take range
+            nParam = 1;
+            nRefInList = 0;
+            SCCOL nCol1 = 0;
+            SCROW nRow1 = 0;
+            SCTAB nTab1 = 0;
+            SCCOL nCol2 = 0;
+            SCROW nRow2 = 0;
+            SCTAB nTab2 = 0;
+            ScMatrixRef pQueryMatrix;
+            switch ( GetStackType() )
+            {
+                case svRefList :
+                    {
+                        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;
+                case svMatrix:
+                    {
+                        pQueryMatrix = PopMatrix();
+                        if (!pQueryMatrix)
+                        {
+                            SetError( errIllegalParameter);
+                        }
+                        nCol1 = 0;
+                        nRow1 = 0;
+                        nTab1 = 0;
+                        SCSIZE nC, nR;
+                        pQueryMatrix->GetDimensions( nC, nR);
+                        nCol2 = static_cast<SCCOL>(nC - 1);
+                        nRow2 = static_cast<SCROW>(nR - 1);
+                        nTab2 = 0;
+                    }
+                    break;
+                default:
+                    SetError( errIllegalParameter);
+            }
+            if ( nTab1 != nTab2 )
+                SetError( errIllegalArgument);
+
+            // All reference ranges must be of same dimension and size.
+            if (!nDimensionCols)
+                nDimensionCols = nCol2 - nCol1 + 1;
+            if (!nDimensionRows)
+                nDimensionRows = nRow2 - nRow1 + 1;
+            if ((nDimensionCols != (nCol2 - nCol1 + 1)) || (nDimensionRows != (nRow2 - nRow1 + 1)))
+                SetError ( errIllegalArgument);
+
+            // recalculate matrix values
             if (nGlobalError == 0)
             {
+                // initialize temporary result matrix
+                if (!pResMat)
+                {
+                    SCSIZE nResC, nResR;
+                    nResC = nCol2 - nCol1 + 1;
+                    nResR = nRow2 - nRow1 + 1;
+                    pResMat = GetNewMat(nResC, nResR);
+                    if (!pResMat)
+                        SetError( errIllegalParameter);
+                    else
+                        pResMat->FillDouble( 0.0, 0, 0, nResC-1, nResR-1);
+                }
+
                 ScQueryParam rParam;
                 rParam.nRow1       = nRow1;
                 rParam.nRow2       = nRow2;
 
                 ScQueryEntry& rEntry = rParam.GetEntry(0);
-                rEntry.bDoQuery = sal_True;
+                rEntry.bDoQuery = true;
                 if (!bIsString)
                 {
-                    rEntry.bQueryByString = sal_False;
+                    rEntry.bQueryByString = false;
                     rEntry.nVal = fVal;
                     rEntry.eOp = SC_EQUAL;
                 }
@@ -4838,12 +5264,12 @@ void ScInterpreter::ScSumIf()
                         rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
                 }
                 ScAddress aAdr;
-                aAdr.SetTab( nTab3 );
+                aAdr.SetTab( nTab1 );
                 rParam.nCol1  = nCol1;
                 rParam.nCol2  = nCol2;
                 rEntry.nField = nCol1;
-                SCsCOL nColDiff = nCol3 - nCol1;
-                SCsROW nRowDiff = nRow3 - nRow1;
+                SCsCOL nColDiff = -nCol1;
+                SCsROW nRowDiff = -nRow1;
                 if (pQueryMatrix)
                 {
                     // Never case-sensitive.
@@ -4851,122 +5277,206 @@ void ScInterpreter::ScSumIf()
                     ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
                     if (nGlobalError || !pResultMatrix)
                     {
-                        PushIllegalParameter();
-                        return;
+                        SetError( errIllegalParameter);
                     }
 
-                    if (pSumExtraMatrix)
+                    for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
                     {
-                        for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
+                        for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
                         {
-                            for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
+                            if (pResultMatrix->IsValue( nCol, nRow) &&
+                                    pResultMatrix->GetDouble( nCol, nRow))
                             {
-                                if (pResultMatrix->IsValue( nCol, nRow) && 
-                                        pResultMatrix->GetDouble( nCol, nRow))
-                                {
-                                    SCSIZE nC = nCol + nColDiff;
-                                    SCSIZE nR = nRow + nRowDiff;
-                                    if (pSumExtraMatrix->IsValue( nC, nR))
-                                    {
-                                        fVal = pSumExtraMatrix->GetDouble( nC, nR);
-                                        if ( bNull && fVal != 0.0 )
-                                        {
-                                            bNull = sal_False;
-                                            fMem = fVal;
-                                        }
-                                        else
-                                            fSum += fVal;
-                                    }
-                                }
-                            }
-                        }
-                    }
-                    else
-                    {
-                        for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
-                        {
-                            for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
-                            {
-                                if (pResultMatrix->GetDouble( nCol, nRow))
-                                {
-                                    aAdr.SetCol( nCol + nColDiff);
-                                    aAdr.SetRow( nRow + nRowDiff);
-                                    ScBaseCell* pCell = GetCell( aAdr );
-                                    if ( HasCellValueData(pCell) )
-                                    {
-                                        fVal = GetCellValue( aAdr, pCell );
-                                        if ( bNull && fVal != 0.0 )
-                                        {
-                                            bNull = sal_False;
-                                            fMem = fVal;
-                                        }
-                                        else
-                                            fSum += fVal;
-                                    }
-                                }
+                                SCSIZE nC = nCol + nColDiff;
+                                SCSIZE nR = nRow + nRowDiff;
+                                pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR);
                             }
                         }
                     }
                 }
                 else
                 {
-                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
+                    ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
                     // Increment Entry.nField in iterator when switching to next column.
-                    aCellIter.SetAdvanceQueryParamEntryField( sal_True );
+                    aCellIter.SetAdvanceQueryParamEntryField( true );
                     if ( aCellIter.GetFirst() )
                     {
-                        if (pSumExtraMatrix)
+                        do
                         {
-                            do
+                            SCSIZE nC = aCellIter.GetCol() + nColDiff;
+                            SCSIZE nR = aCellIter.GetRow() + nRowDiff;
+                            pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR);
+                        } while ( aCellIter.GetNext() );
+                    }
+                }
+            }
+            nParamCount -= 2;
+        }
+
+        if (nGlobalError)
+            return 0;   // bail out
+
+        // main range - only for AVERAGEIFS and SUMIFS
+        if (nParamCount == 1)
+        {
+            nParam = 1;
+            nRefInList = 0;
+            bool bNull = true;
+            SCCOL nMainCol1 = 0;
+            SCROW nMainRow1 = 0;
+            SCTAB nMainTab1 = 0;
+            SCCOL nMainCol2 = 0;
+            SCROW nMainRow2 = 0;
+            SCTAB nMainTab2 = 0;
+            ScMatrixRef pMainMatrix;
+            switch ( GetStackType() )
+            {
+                case svRefList :
+                    {
+                        ScRange aRange;
+                        PopDoubleRef( aRange, nParam, nRefInList);
+                        aRange.GetVars( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2);
+                    }
+                    break;
+                case svDoubleRef :
+                    PopDoubleRef( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2 );
+                    break;
+                case svSingleRef :
+                    PopSingleRef( nMainCol1, nMainRow1, nMainTab1 );
+                    nMainCol2 = nMainCol1;
+                    nMainRow2 = nMainRow1;
+                    nMainTab2 = nMainTab1;
+                    break;
+                case svMatrix:
+                    {
+                        pMainMatrix = PopMatrix();
+                        if (!pMainMatrix)
+                        {
+                            SetError( errIllegalParameter);
+                        }
+                        nMainCol1 = 0;
+                        nMainRow1 = 0;
+                        nMainTab1 = 0;
+                        SCSIZE nC, nR;
+                        pMainMatrix->GetDimensions( nC, nR);
+                        nMainCol2 = static_cast<SCCOL>(nC - 1);
+                        nMainRow2 = static_cast<SCROW>(nR - 1);
+                        nMainTab2 = 0;
+                    }
+                    break;
+                default:
+                    SetError( errIllegalParameter);
+            }
+            if ( nMainTab1 != nMainTab2 )
+                SetError( errIllegalArgument);
+
+            // All reference ranges must be of same dimension and size.
+            if ((nDimensionCols != (nMainCol2 - nMainCol1 + 1)) || (nDimensionRows != (nMainRow2 - nMainRow1 + 1)))
+                SetError ( errIllegalArgument);
+
+            if (nGlobalError)
+                return 0;   // bail out
+
+            // end-result calculation
+            ScAddress aAdr;
+            aAdr.SetTab( nMainTab1 );
+            if (pMainMatrix)
+            {
+                SCSIZE nC, nR;
+                pResMat->GetDimensions(nC, nR);
+                for (SCSIZE nCol = 0; nCol < nC; ++nCol)
+                {
+                    for (SCSIZE nRow = 0; nRow < nR; ++nRow)
+                    {
+                        if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
+                        {
+                            if (pMainMatrix->IsValue( nCol, nRow))
                             {
-                                SCSIZE nC = aCellIter.GetCol() + nColDiff;
-                                SCSIZE nR = aCellIter.GetRow() + nRowDiff;
-                                if (pSumExtraMatrix->IsValue( nC, nR))
+                                fVal = pMainMatrix->GetDouble( nCol, nRow);
+                                ++fCount;
+                                if ( bNull && fVal != 0.0 )
                                 {
-                                    fVal = pSumExtraMatrix->GetDouble( nC, nR);
-                                    if ( bNull && fVal != 0.0 )
-                                    {
-                                        bNull = sal_False;
-                                        fMem = fVal;
-                                    }
-                                    else
-                                        fSum += fVal;
+                                    bNull = false;
+                                    fMem = fVal;
                                 }
-                            } while ( aCellIter.GetNext() );
+                                else
+                                    fSum += fVal;
+                            }
                         }
-                        else
+                    }
+                }
+            }
+            else
+            {
+                SCSIZE nC, nR;
+                pResMat->GetDimensions(nC, nR);
+                for (SCSIZE nCol = 0; nCol < nC; ++nCol)
+                {
+                    for (SCSIZE nRow = 0; nRow < nR; ++nRow)
+                    {
+                        if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
                         {
-                            do
+                            aAdr.SetCol( static_cast<SCCOL>(nCol) + nMainCol1);
+                            aAdr.SetRow( static_cast<SCROW>(nRow) + nMainRow1);
+                            ScBaseCell* pCell = GetCell( aAdr );
+                            if ( HasCellValueData(pCell) )
                             {
-                                aAdr.SetCol( aCellIter.GetCol() + nColDiff);
-                                aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
-                                ScBaseCell* pCell = GetCell( aAdr );
-                                if ( HasCellValueData(pCell) )
+                                fVal = GetCellValue( aAdr, pCell );
+                                ++fCount;
+                                if ( bNull && fVal != 0.0 )
                                 {
-                                    fVal = GetCellValue( aAdr, pCell );
-                                    if ( bNull && fVal != 0.0 )
-                                    {
-                                        bNull = sal_False;
-                                        fMem = fVal;
-                                    }
-                                    else
-                                        fSum += fVal;
+                                    bNull = false;
+                                    fMem = fVal;
                                 }
-                            } while ( aCellIter.GetNext() );
+                                else
+                                    fSum += fVal;
+                            }
                         }
                     }
                 }
             }
-            else
+        }
+        else
+        {
+            SCSIZE nC, nR;
+            pResMat->GetDimensions(nC, nR);
+            for (SCSIZE nCol = 0; nCol < nC; ++nCol)
             {
-                PushIllegalParameter();
-                return;
+                for (SCSIZE nRow = 0; nRow < nR; ++nRow)
+                    if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
+                        ++fCount;
             }
         }
-        PushDouble( ::rtl::math::approxAdd( fSum, fMem ) );
+
+        switch( eFunc )
+        {
+            case ifSUMIFS:     fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
+            case ifAVERAGEIFS: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
+            case ifCOUNTIFS:   fRes = fCount; break;
+            default: ; // nothing
+        }
+        return fRes;
     }
+    return 0;
 }
 
+void ScInterpreter::ScSumIfs()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScSumIfs" );
+    PushDouble( IterateParametersIfs( ifSUMIFS));
+}
+
+void ScInterpreter::ScAverageIfs()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScAverageIfs" );
+    PushDouble( IterateParametersIfs( ifAVERAGEIFS));
+}
+
+void ScInterpreter::ScCountIfs()
+{
+    RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScCountIfs" );
+    PushDouble( IterateParametersIfs( ifCOUNTIFS));
+}
 
 void ScInterpreter::ScLookup()
 {

Modified: incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr4.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr4.cxx?rev=1386501&r1=1386500&r2=1386501&view=diff
==============================================================================
--- incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr4.cxx (original)
+++ incubator/ooo/branches/writer001/main/sc/source/core/tool/interpr4.cxx Mon Sep 17 08:06:09 2012
@@ -3446,6 +3446,7 @@ StackVar ScInterpreter::Interpret()
                 case ocGreaterEqual     : ScGreaterEqual();             break;
                 case ocAnd              : ScAnd();                      break;
                 case ocOr               : ScOr();                       break;
+                case ocXor              : ScXor();                      break;
                 case ocIntersect        : ScIntersect();                break;
                 case ocRange            : ScRangeFunc();                break;
                 case ocUnion            : ScUnionFunc();                break;
@@ -3621,6 +3622,10 @@ StackVar ScInterpreter::Interpret()
                 case ocCountEmptyCells  : ScCountEmptyCells();          break;
                 case ocCountIf          : ScCountIf();                  break;
                 case ocSumIf            : ScSumIf();                    break;
+                case ocAverageIf        : ScAverageIf();                break;
+                case ocSumIfs           : ScSumIfs();                   break;
+                case ocAverageIfs       : ScAverageIfs();               break;
+                case ocCountIfs         : ScCountIfs();                 break;
                 case ocLookup           : ScLookup();                   break;
                 case ocVLookup          : ScVLookup();                  break;
                 case ocHLookup          : ScHLookup();                  break;

Modified: incubator/ooo/branches/writer001/main/sc/source/core/tool/parclass.cxx
URL: http://svn.apache.org/viewvc/incubator/ooo/branches/writer001/main/sc/source/core/tool/parclass.cxx?rev=1386501&r1=1386500&r2=1386501&view=diff
==============================================================================
--- incubator/ooo/branches/writer001/main/sc/source/core/tool/parclass.cxx (original)
+++ incubator/ooo/branches/writer001/main/sc/source/core/tool/parclass.cxx Mon Sep 17 08:06:09 2012
@@ -48,154 +48,162 @@
  * - OpCodes not specified at all will have at least one and only parameters of
  *   type Value, no check is done on the count of parameters => no Bounds type
  *   is returned.
- * - For OpCodes with a variable number of parameters the type of the last
- *   parameter specified determines the type of all following parameters.
+ * - For OpCodes with a variable number of parameters the type(s) of the last
+ *   repeated parameter(s) specified determine(s) the type(s) of all following
+ *   parameters.
  */
 
 const ScParameterClassification::RawData ScParameterClassification::pRawData[] =
 {
+    // { OpCode, {{ Type, ... }, nRepeatLast }},
+
     // IF() and CHOOSE() are somewhat special, since the ScJumpMatrix is
     // created inside those functions and ConvertMatrixParameters() is not
     // called for them.
-    { ocIf,              {{ Array, Reference, Reference                          }, false }},
-    { ocChose,           {{ Array, Reference                                     }, true }},
+    { ocIf,              {{ Array, Reference, Reference                          }, 0 }},
+    { ocChose,           {{ Array, Reference                                     }, 1 }},
     // Other specials.
-    { ocOpen,            {{ Bounds                                               }, false }},
-    { ocClose,           {{ Bounds                                               }, false }},
-    { ocSep,             {{ Bounds                                               }, false }},
-    { ocNoName,          {{ Bounds                                               }, false }},
-    { ocErrCell,         {{ Bounds                                               }, false }},
-    { ocStop,            {{ Bounds                                               }, false }},
-    { ocUnion,           {{ Reference, Reference                                 }, false }},
-    { ocRange,           {{ Reference, Reference                                 }, false }},
+    { ocOpen,            {{ Bounds                                               }, 0 }},
+    { ocClose,           {{ Bounds                                               }, 0 }},
+    { ocSep,             {{ Bounds                                               }, 0 }},
+    { ocNoName,          {{ Bounds                                               }, 0 }},
+    { ocErrCell,         {{ Bounds                                               }, 0 }},
+    { ocStop,            {{ Bounds                                               }, 0 }},
+    { ocUnion,           {{ Reference, Reference                                 }, 0 }},
+    { ocRange,           {{ Reference, Reference                                 }, 0 }},
     // Functions with Value parameters only but not in resource.
-    { ocBackSolver,      {{ Value, Value, Value                                  }, false }},
-    { ocTableOp,         {{ Value, Value, Value, Value, Value                    }, false }},
+    { ocBackSolver,      {{ Value, Value, Value                                  }, 0 }},
+    { ocTableOp,         {{ Value, Value, Value, Value, Value                    }, 0 }},
     // Operators and functions.
-    { ocAdd,             {{ Array, Array                                         }, false }},
-    { ocAmpersand,       {{ Array, Array                                         }, false }},
-    { ocAnd,             {{ Reference                                            }, true }},
-    { ocAreas,           {{ Reference                                            }, false }},
-    { ocAveDev,          {{ Reference                                            }, true }},
-    { ocAverage,         {{ Reference                                            }, true }},
-    { ocAverageA,        {{ Reference                                            }, true }},
-    { ocCell,            {{ Value, Reference                                     }, false }},
-    { ocColumn,          {{ Reference                                            }, false }},
-    { ocColumns,         {{ Reference                                            }, true }},
-    { ocCorrel,          {{ ForceArray, ForceArray                               }, false }},
-    { ocCount,           {{ Reference                                            }, true }},
-    { ocCount2,          {{ Reference                                            }, true }},
-    { ocCountEmptyCells, {{ Reference                                            }, false }},
-    { ocCountIf,         {{ Reference, Value                                     }, false }},
-    { ocCovar,           {{ ForceArray, ForceArray                               }, false }},
-    { ocDBAverage,       {{ Reference, Reference, Reference                      }, false }},
-    { ocDBCount,         {{ Reference, Reference, Reference                      }, false }},
-    { ocDBCount2,        {{ Reference, Reference, Reference                      }, false }},
-    { ocDBGet,           {{ Reference, Reference, Reference                      }, false }},
-    { ocDBMax,           {{ Reference, Reference, Reference                      }, false }},
-    { ocDBMin,           {{ Reference, Reference, Reference                      }, false }},
-    { ocDBProduct,       {{ Reference, Reference, Reference                      }, false }},
-    { ocDBStdDev,        {{ Reference, Reference, Reference                      }, false }},
-    { ocDBStdDevP,       {{ Reference, Reference, Reference                      }, false }},
-    { ocDBSum,           {{ Reference, Reference, Reference                      }, false }},
-    { ocDBVar,           {{ Reference, Reference, Reference                      }, false }},
-    { ocDBVarP,          {{ Reference, Reference, Reference                      }, false }},
-    { ocDevSq,           {{ Reference                                            }, true }},
-    { ocDiv,             {{ Array, Array                                         }, false }},
-    { ocEqual,           {{ Array, Array                                         }, false }},
-    { ocForecast,        {{ Value, ForceArray, ForceArray                        }, false }},
-    { ocFrequency,       {{ Reference, Reference                                 }, false }},
-    { ocFTest,           {{ ForceArray, ForceArray                               }, false }},
-    { ocGeoMean,         {{ Reference                                            }, true }},
-    { ocGCD,             {{ Reference                                            }, true }},
-    { ocGreater,         {{ Array, Array                                         }, false }},
-    { ocGreaterEqual,    {{ Array, Array                                         }, false }},
-    { ocGrowth,          {{ Reference, Reference, Reference, Value               }, false }},
-    { ocHarMean,         {{ Reference                                            }, true }},
-    { ocHLookup,         {{ Value, Reference, Value, Value                       }, false }},
-    { ocIRR,             {{ Reference, Value                                     }, false }},
-    { ocIndex,           {{ Reference, Value, Value, Value                       }, false }},
-    { ocIntercept,       {{ ForceArray, ForceArray                               }, false }},
-    { ocIntersect,       {{ Reference, Reference                                 }, false }},
-    { ocIsRef,           {{ Reference                                            }, false }},
-    { ocLCM,             {{ Reference                                            }, true }},
-    { ocKurt,            {{ Reference                                            }, true }},
-    { ocLarge,           {{ Reference, Value                                     }, false }},
-    { ocLess,            {{ Array, Array                                         }, false }},
-    { ocLessEqual,       {{ Array, Array                                         }, false }},
-    { ocLookup,          {{ Value, ReferenceOrForceArray, ReferenceOrForceArray  }, false }},
-    { ocMatch,           {{ Value, Reference, Reference                          }, false }},
-    { ocMatDet,          {{ ForceArray                                           }, false }},
-    { ocMatInv,          {{ ForceArray                                           }, false }},
-    { ocMatMult,         {{ ForceArray, ForceArray                               }, false }},
-    { ocMatTrans,        {{ Array                                                }, false }}, // strange, but Xcl doesn't force MatTrans array
-    { ocMatValue,        {{ Reference, Value, Value                              }, false }},
-    { ocMax,             {{ Reference                                            }, true }},
-    { ocMaxA,            {{ Reference                                            }, true }},
-    { ocMedian,          {{ Reference                                            }, true }},
-    { ocMin,             {{ Reference                                            }, true }},
-    { ocMinA,            {{ Reference                                            }, true }},
-    { ocMIRR,            {{ Reference, Value, Value                              }, false }},
-    { ocModalValue,      {{ ForceArray                                           }, true }},
-    { ocMul,             {{ Array, Array                                         }, false }},
-    { ocMultiArea,       {{ Reference                                            }, true }},
-    { ocN,               {{ Reference                                            }, false }},
-    { ocNPV,             {{ Value, Reference                                     }, true }},
-    { ocNeg,             {{ Array                                                }, false }},
-    { ocNegSub,          {{ Array                                                }, false }},
-    { ocNot,             {{ Array                                                }, false }},
-    { ocNotEqual,        {{ Array, Array                                         }, false }},
-    { ocOffset,          {{ Reference, Value, Value, Value, Value                }, false }},
-    { ocOr,              {{ Reference                                            }, true }},
-    { ocPearson,         {{ ForceArray, ForceArray                               }, false }},
-    { ocPercentile,      {{ Reference, Value                                     }, false }},
-    { ocPercentrank,     {{ Reference, Value                                     }, false }},
-    { ocPow,             {{ Array, Array                                         }, false }},
-    { ocPower,           {{ Array, Array                                         }, false }},
-    { ocProb,            {{ ForceArray, ForceArray, Value, Value                 }, false }},
-    { ocProduct,         {{ Reference                                            }, true }},
-    { ocQuartile,        {{ Reference, Value                                     }, false }},
-    { ocRank,            {{ Value, Reference, Value                              }, false }},
-    { ocRGP,             {{ Reference, Reference, Value, Value                   }, false }},
-    { ocRKP,             {{ Reference, Reference, Value, Value                   }, false }},
-    { ocRow,             {{ Reference                                            }, false }},
-    { ocRows,            {{ Reference                                            }, true }},
-    { ocRSQ,             {{ ForceArray, ForceArray                               }, false }},
-    { ocSchiefe,         {{ Reference                                            }, true }},
-    { ocSlope,           {{ ForceArray, ForceArray                               }, false }},
-    { ocSmall,           {{ Reference, Value                                     }, false }},
-    { ocStDev,           {{ Reference                                            }, true }},
-    { ocStDevA,          {{ Reference                                            }, true }},
-    { ocStDevP,          {{ Reference                                            }, true }},
-    { ocStDevPA,         {{ Reference                                            }, true }},
-    { ocSTEYX,           {{ ForceArray, ForceArray                               }, false }},
-    { ocSub,             {{ Array, Array                                         }, false }},
-    { ocSubTotal,        {{ Value, Reference                                     }, true }},
-    { ocSum,             {{ Reference                                            }, true }},
-    { ocSumIf,           {{ Reference, Value, Reference                          }, false }},
-    { ocSumProduct,      {{ ForceArray                                           }, true }},
-    { ocSumSQ,           {{ Reference                                            }, true }},
-    { ocSumX2MY2,        {{ ForceArray, ForceArray                               }, false }},
-    { ocSumX2DY2,        {{ ForceArray, ForceArray                               }, false }},
-    { ocSumXMY2,         {{ ForceArray, ForceArray                               }, false }},
-    { ocTable,           {{ Reference                                            }, false }},
-    { ocTables,          {{ Reference                                            }, true }},
-    { ocTrend,           {{ Reference, Reference, Reference, Value               }, false }},
-    { ocTrimMean,        {{ Reference, Value                                     }, false }},
-    { ocTTest,           {{ ForceArray, ForceArray, Value, Value                 }, false }},
-    { ocVar,             {{ Reference                                            }, true }},
-    { ocVarA,            {{ Reference                                            }, true }},
-    { ocVarP,            {{ Reference                                            }, true }},
-    { ocVarPA,           {{ Reference                                            }, true }},
-    { ocVLookup,         {{ Value, Reference, Value, Value                       }, false }},
-    { ocZTest,           {{ Reference, Value, Value                              }, false }},
+    { ocAdd,             {{ Array, Array                                         }, 0 }},
+    { ocAmpersand,       {{ Array, Array                                         }, 0 }},
+    { ocAnd,             {{ Reference                                            }, 1 }},
+    { ocAreas,           {{ Reference                                            }, 0 }},
+    { ocAveDev,          {{ Reference                                            }, 1 }},
+    { ocAverage,         {{ Reference                                            }, 1 }},
+    { ocAverageA,        {{ Reference                                            }, 1 }},
+    { ocAverageIf,       {{ Reference, Value, Reference                          }, 0 }},
+    { ocAverageIfs,      {{ Reference, Reference, Value                          }, 2 }},
+    { ocCell,            {{ Value, Reference                                     }, 0 }},
+    { ocColumn,          {{ Reference                                            }, 0 }},
+    { ocColumns,         {{ Reference                                            }, 1 }},
+    { ocCorrel,          {{ ForceArray, ForceArray                               }, 0 }},
+    { ocCount,           {{ Reference                                            }, 1 }},
+    { ocCount2,          {{ Reference                                            }, 1 }},
+    { ocCountEmptyCells, {{ Reference                                            }, 0 }},
+    { ocCountIf,         {{ Reference, Value                                     }, 0 }},
+    { ocCountIfs,        {{ Reference, Value                                     }, 2 }},
+    { ocCovar,           {{ ForceArray, ForceArray                               }, 0 }},
+    { ocDBAverage,       {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBCount,         {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBCount2,        {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBGet,           {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBMax,           {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBMin,           {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBProduct,       {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBStdDev,        {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBStdDevP,       {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBSum,           {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBVar,           {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDBVarP,          {{ Reference, Reference, Reference                      }, 0 }},
+    { ocDevSq,           {{ Reference                                            }, 1 }},
+    { ocDiv,             {{ Array, Array                                         }, 0 }},
+    { ocEqual,           {{ Array, Array                                         }, 0 }},
+    { ocForecast,        {{ Value, ForceArray, ForceArray                        }, 0 }},
+    { ocFrequency,       {{ Reference, Reference                                 }, 0 }},
+    { ocFTest,           {{ ForceArray, ForceArray                               }, 0 }},
+    { ocGeoMean,         {{ Reference                                            }, 1 }},
+    { ocGCD,             {{ Reference                                            }, 1 }},
+    { ocGreater,         {{ Array, Array                                         }, 0 }},
+    { ocGreaterEqual,    {{ Array, Array                                         }, 0 }},
+    { ocGrowth,          {{ Reference, Reference, Reference, Value               }, 0 }},
+    { ocHarMean,         {{ Reference                                            }, 1 }},
+    { ocHLookup,         {{ Value, Reference, Value, Value                       }, 0 }},
+    { ocIRR,             {{ Reference, Value                                     }, 0 }},
+    { ocIndex,           {{ Reference, Value, Value, Value                       }, 0 }},
+    { ocIntercept,       {{ ForceArray, ForceArray                               }, 0 }},
+    { ocIntersect,       {{ Reference, Reference                                 }, 0 }},
+    { ocIsRef,           {{ Reference                                            }, 0 }},
+    { ocLCM,             {{ Reference                                            }, 1 }},
+    { ocKurt,            {{ Reference                                            }, 1 }},
+    { ocLarge,           {{ Reference, Value                                     }, 0 }},
+    { ocLess,            {{ Array, Array                                         }, 0 }},
+    { ocLessEqual,       {{ Array, Array                                         }, 0 }},
+    { ocLookup,          {{ Value, ReferenceOrForceArray, ReferenceOrForceArray  }, 0 }},
+    { ocMatch,           {{ Value, Reference, Reference                          }, 0 }},
+    { ocMatDet,          {{ ForceArray                                           }, 0 }},
+    { ocMatInv,          {{ ForceArray                                           }, 0 }},
+    { ocMatMult,         {{ ForceArray, ForceArray                               }, 0 }},
+    { ocMatTrans,        {{ Array                                                }, 0 }}, // strange, but Xcl doesn't force MatTrans array
+    { ocMatValue,        {{ Reference, Value, Value                              }, 0 }},
+    { ocMax,             {{ Reference                                            }, 1 }},
+    { ocMaxA,            {{ Reference                                            }, 1 }},
+    { ocMedian,          {{ Reference                                            }, 1 }},
+    { ocMin,             {{ Reference                                            }, 1 }},
+    { ocMinA,            {{ Reference                                            }, 1 }},
+    { ocMIRR,            {{ Reference, Value, Value                              }, 0 }},
+    { ocModalValue,      {{ ForceArray                                           }, 1 }},
+    { ocMul,             {{ Array, Array                                         }, 0 }},
+    { ocMultiArea,       {{ Reference                                            }, 1 }},
+    { ocN,               {{ Reference                                            }, 0 }},
+    { ocNPV,             {{ Value, Reference                                     }, 1 }},
+    { ocNeg,             {{ Array                                                }, 0 }},
+    { ocNegSub,          {{ Array                                                }, 0 }},
+    { ocNot,             {{ Array                                                }, 0 }},
+    { ocNotEqual,        {{ Array, Array                                         }, 0 }},
+    { ocOffset,          {{ Reference, Value, Value, Value, Value                }, 0 }},
+    { ocOr,              {{ Reference                                            }, 1 }},
+    { ocPearson,         {{ ForceArray, ForceArray                               }, 0 }},
+    { ocPercentile,      {{ Reference, Value                                     }, 0 }},
+    { ocPercentrank,     {{ Reference, Value                                     }, 0 }},
+    { ocPow,             {{ Array, Array                                         }, 0 }},
+    { ocPower,           {{ Array, Array                                         }, 0 }},
+    { ocProb,            {{ ForceArray, ForceArray, Value, Value                 }, 0 }},
+    { ocProduct,         {{ Reference                                            }, 1 }},
+    { ocQuartile,        {{ Reference, Value                                     }, 0 }},
+    { ocRank,            {{ Value, Reference, Value                              }, 0 }},
+    { ocRGP,             {{ Reference, Reference, Value, Value                   }, 0 }},
+    { ocRKP,             {{ Reference, Reference, Value, Value                   }, 0 }},
+    { ocRow,             {{ Reference                                            }, 0 }},
+    { ocRows,            {{ Reference                                            }, 1 }},
+    { ocRSQ,             {{ ForceArray, ForceArray                               }, 0 }},
+    { ocSchiefe,         {{ Reference                                            }, 1 }},
+    { ocSlope,           {{ ForceArray, ForceArray                               }, 0 }},
+    { ocSmall,           {{ Reference, Value                                     }, 0 }},
+    { ocStDev,           {{ Reference                                            }, 1 }},
+    { ocStDevA,          {{ Reference                                            }, 1 }},
+    { ocStDevP,          {{ Reference                                            }, 1 }},
+    { ocStDevPA,         {{ Reference                                            }, 1 }},
+    { ocSTEYX,           {{ ForceArray, ForceArray                               }, 0 }},
+    { ocSub,             {{ Array, Array                                         }, 0 }},
+    { ocSubTotal,        {{ Value, Reference                                     }, 1 }},
+    { ocSum,             {{ Reference                                            }, 1 }},
+    { ocSumIf,           {{ Reference, Value, Reference                          }, 0 }},
+    { ocSumIfs,          {{ Reference, Reference, Value                          }, 2 }},
+    { ocSumProduct,      {{ ForceArray                                           }, 1 }},
+    { ocSumSQ,           {{ Reference                                            }, 1 }},
+    { ocSumX2MY2,        {{ ForceArray, ForceArray                               }, 0 }},
+    { ocSumX2DY2,        {{ ForceArray, ForceArray                               }, 0 }},
+    { ocSumXMY2,         {{ ForceArray, ForceArray                               }, 0 }},
+    { ocTable,           {{ Reference                                            }, 0 }},
+    { ocTables,          {{ Reference                                            }, 1 }},
+    { ocTrend,           {{ Reference, Reference, Reference, Value               }, 0 }},
+    { ocTrimMean,        {{ Reference, Value                                     }, 0 }},
+    { ocTTest,           {{ ForceArray, ForceArray, Value, Value                 }, 0 }},
+    { ocVar,             {{ Reference                                            }, 1 }},
+    { ocVarA,            {{ Reference                                            }, 1 }},
+    { ocVarP,            {{ Reference                                            }, 1 }},
+    { ocVarPA,           {{ Reference                                            }, 1 }},
+    { ocVLookup,         {{ Value, Reference, Value, Value                       }, 0 }},
+    { ocXor,             {{ Reference                                            }, 1 }},
+    { ocZTest,           {{ Reference, Value, Value                              }, 0 }},
     // Excel doubts:
     // ocT: Excel says (and handles) Reference, error? This means no position
     // dependent SingleRef if DoubleRef, and no array calculation, just the
     // upper left corner. We never did that.
-    { ocT, {{ Value }, false }},
+    { ocT, {{ Value }, 0 }},
     // The stopper.
-    { ocNone, {{ Bounds }, false } }
+    { ocNone, {{ Bounds }, 0 } }
 };
 
 ScParameterClassification::RunData * ScParameterClassification::pData = NULL;
@@ -227,18 +235,19 @@ void ScParameterClassification::Init()
 #endif
             memcpy( &(pRun->aData), &(pRaw->aData), sizeof(CommonData));
             // fill 0-initialized fields with real values
-            if ( pRun->aData.bRepeatLast )
+            if ( pRun->aData.nRepeatLast )
             {
-                Type eLast = Unknown;
                 for ( size_t j=0; j < CommonData::nMaxParams; ++j )
                 {
                     if ( pRun->aData.nParam[j] )
-                    {
-                        eLast = pRun->aData.nParam[j];
                         pRun->nMinParams = sal::static_int_cast<sal_uInt8>( j+1 );
-                    }
+                    else if (j >= pRun->aData.nRepeatLast)
+                        pRun->aData.nParam[j] =  pRun->aData.nParam[j - pRun->aData.nRepeatLast];
                     else
-                        pRun->aData.nParam[j] = eLast;
+                    {
+                        DBG_ERROR2( "bad classification: eOp %d, repeated param %d negative offset", pRaw->eOp, j);
+                        pRun->aData.nParam[j] =  Unknown;
+                    }
                 }
             }
             else
@@ -299,15 +308,23 @@ ScParameterClassification::Type ScParame
     }
     if ( 0 <= (short)eOp && eOp <= SC_OPCODE_LAST_OPCODE_ID )
     {
+        sal_uInt8 nRepeat;
+        Type eType;
         if ( nParameter < CommonData::nMaxParams )
+            eType = pData[eOp].aData.nParam[nParameter];
+        else if ( (nRepeat = pData[eOp].aData.nRepeatLast) > 0 )
         {
-            Type eT = pData[eOp].aData.nParam[nParameter];
-            return eT == Unknown ? Value : eT;
+            // The usual case is 1 repeated parameter, we don't need to
+            // calculate that on each call.
+            sal_uInt16 nParam = (nRepeat > 1 ?
+                    (pData[eOp].nMinParams -
+                     ((nParameter - pData[eOp].nMinParams) % nRepeat)) :
+                    pData[eOp].nMinParams);
+            return pData[eOp].aData.nParam[nParam];
         }
-        else if ( pData[eOp].aData.bRepeatLast )
-            return pData[eOp].aData.nParam[CommonData::nMaxParams-1];
         else
-            return Bounds;
+            eType = Bounds;
+        return eType == Unknown ? Value : eType;
     }
     return Unknown;
 }
@@ -402,25 +419,30 @@ void ScParameterClassification::MergeArg
 
         RunData* pRun = &pData[ pDesc->nFIndex ];
         sal_uInt16 nArgs = pDesc->GetSuppressedArgCount();
-        if ( nArgs >= VAR_ARGS )
+        if ( nArgs >= PAIRED_VAR_ARGS )
+        {
+            nArgs -= PAIRED_VAR_ARGS - 2;
+            pRun->aData.nRepeatLast = 2;
+        }
+        else if ( nArgs >= VAR_ARGS )
         {
             nArgs -= VAR_ARGS - 1;
-            pRun->aData.bRepeatLast = true;
+            pRun->aData.nRepeatLast = 1;
         }
         if ( nArgs > CommonData::nMaxParams )
         {
             DBG_ERROR2( "ScParameterClassification::Init: too many arguments in listed function: %s: %d",
                     ByteString( *(pDesc->pFuncName),
                         RTL_TEXTENCODING_UTF8).GetBuffer(), nArgs);
-            nArgs = CommonData::nMaxParams;
-            pRun->aData.bRepeatLast = true;
+            nArgs = CommonData::nMaxParams - 1;
+            pRun->aData.nRepeatLast = 1;
         }
         pRun->nMinParams = static_cast< sal_uInt8 >( nArgs );
         for ( size_t j=0; j < nArgs; ++j )
         {
             pRun->aData.nParam[j] = Value;
         }
-        if ( pRun->aData.bRepeatLast )
+        if ( pRun->aData.nRepeatLast )
         {
             for ( size_t j = nArgs; j < CommonData::nMaxParams; ++j )
             {