[Libreoffice-commits] core.git: 15 commits - i18npool/source sc/inc sc/qa sc/source

Eike Rathke erack at redhat.com
Mon May 22 09:01:23 UTC 2017


 i18npool/source/localedata/data/locale.dtd |   14 +
 sc/inc/token.hxx                           |    8 -
 sc/qa/unit/ucalc.hxx                       |    2 
 sc/qa/unit/ucalc_formula.cxx               |   47 +++++
 sc/source/core/inc/interpre.hxx            |    9 +
 sc/source/core/inc/jumpmatrix.hxx          |    3 
 sc/source/core/tool/interpr1.cxx           |  230 ++++++++++++++++++++++++++---
 sc/source/core/tool/interpr3.cxx           |   30 +--
 sc/source/core/tool/interpr6.cxx           |  181 +++++++++++++++++++---
 sc/source/core/tool/jumpmatrix.cxx         |    5 
 sc/source/core/tool/token.cxx              |    5 
 11 files changed, 463 insertions(+), 71 deletions(-)

New commits:
commit f6cdba8a801ba296bd3f7ca6334fc3671b0bbe58
Author: Eike Rathke <erack at redhat.com>
Date:   Sun May 21 00:20:46 2017 +0200

    Factor out ScInterpreter::SwitchToArrayRefList(), tdf#58874
    
    Change-Id: I7a672b8d0bd6dae9baa1289a3b00b0789a0d4d6d

diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 3586d21c317f..9948392ea622 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -571,6 +571,10 @@ void ScMax( bool bTextAsZero = false );
 /** Check for array of references to determine the maximum size of a return
     column vector if in array context. */
 size_t GetRefListArrayMaxSize( short nParamCount );
+/** Switch to array reference list if current TOS is one and create/init or
+    update matrix and return true. Else return false. */
+bool SwitchToArrayRefList( ScMatrixRef& xResMat, SCSIZE nMatRows, double fCurrent,
+        const std::function<bool( double& fVectorResult, const double& fCurrent )>& AssignFunc );
 void IterateParameters( ScIterFunc, bool bTextAsZero = false );
 void ScSumSQ();
 void ScSum();
diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index bf8b9dc77c00..675e9c8165bf 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3456,6 +3456,34 @@ void ScInterpreter::ScUnichar()
     }
 }
 
+bool ScInterpreter::SwitchToArrayRefList( ScMatrixRef& xResMat, SCSIZE nMatRows, double fCurrent,
+        const std::function<bool( double& fVectorResult, const double& fCurrent )>& AssignFunc )
+{
+    const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+    if (!p || !p->IsArrayResult())
+        return false;
+
+    if (!xResMat)
+    {
+        // Create and init all elements with current value.
+        assert(nMatRows > 0);
+        xResMat = GetNewMat( 1, nMatRows, true);
+        xResMat->FillDouble( fCurrent, 0,0, 0,nMatRows-1);
+    }
+    else
+    {
+        // Current value and values from vector are operands
+        // for each vector position.
+        for (SCSIZE i=0; i < nMatRows; ++i)
+        {
+            double fVecRes = xResMat->GetDouble(0,i);
+            if (AssignFunc( fVecRes, fCurrent))
+                xResMat->PutDouble( fVecRes, 0,i);
+        }
+    }
+    return true;
+}
+
 void ScInterpreter::ScMin( bool bTextAsZero )
 {
     short nParamCount = GetByte();
@@ -3499,29 +3527,17 @@ void ScInterpreter::ScMin( bool bTextAsZero )
             break;
             case svRefList :
             {
-                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
-                if (p && p->IsArrayResult())
+                auto AssignFunc = []( double& fVecRes, double fMin )
                 {
-                    nRefArrayPos = nRefInList;
-                    if (!xResMat)
-                    {
-                        // Create and init all elements with current value.
-                        assert(nMatRows > 0);
-                        xResMat = GetNewMat( 1, nMatRows, true);
-                        xResMat->FillDouble( nMin, 0,0, 0,nMatRows-1);
-                    }
-                    else
+                    if (fVecRes > fMin)
                     {
-                        // Current value and values from vector are operands
-                        // for each vector position.
-                        for (SCSIZE i=0; i < nMatRows; ++i)
-                        {
-                            double fVecRes = xResMat->GetDouble(0,i);
-                            if (fVecRes > nMin)
-                                xResMat->PutDouble( nMin, 0,i);
-                        }
+                        fVecRes = fMin;
+                        return true;
                     }
-                }
+                    return false;
+                };
+                if (SwitchToArrayRefList( xResMat, nMatRows, nMin, AssignFunc))
+                    nRefArrayPos = nRefInList;
             }
             SAL_FALLTHROUGH;
             case svDoubleRef :
@@ -3666,29 +3682,17 @@ void ScInterpreter::ScMax( bool bTextAsZero )
             break;
             case svRefList :
             {
-                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
-                if (p && p->IsArrayResult())
+                auto AssignFunc = []( double& fVecRes, double fMax )
                 {
-                    nRefArrayPos = nRefInList;
-                    if (!xResMat)
+                    if (fVecRes < fMax)
                     {
-                        // Create and init all elements with current value.
-                        assert(nMatRows > 0);
-                        xResMat = GetNewMat( 1, nMatRows, true);
-                        xResMat->FillDouble( nMax, 0,0, 0,nMatRows-1);
+                        fVecRes = fMax;
+                        return true;
                     }
-                    else
-                    {
-                        // Current value and values from vector are operands
-                        // for each vector position.
-                        for (SCSIZE i=0; i < nMatRows; ++i)
-                        {
-                            double fVecRes = xResMat->GetDouble(0,i);
-                            if (fVecRes < nMax)
-                                xResMat->PutDouble( nMax, 0,i);
-                        }
-                    }
-                }
+                    return false;
+                };
+                if (SwitchToArrayRefList( xResMat, nMatRows, nMax, AssignFunc))
+                    nRefArrayPos = nRefInList;
             }
             SAL_FALLTHROUGH;
             case svDoubleRef :
commit 667e0625090f084b8d9ae5a885b6b4624766ed6c
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 23:06:38 2017 +0200

    Unit test for SUBTOTAL MIN,MAX with array of references, tdf#58874
    
    Change-Id: I116b236066f28e3442f644544e789e1dbc2ff88a

diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index c2b46cec85ae..92f93722c531 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7922,11 +7922,29 @@ void Test::testFuncRefListArraySUBTOTAL()
     aMark.SelectOneTable(0);
     m_pDoc->InsertMatrixFormula(1, 6, 1, 8, aMark, "=SUBTOTAL(9;OFFSET(A1;ROW(1:3);0;2))");
     ScAddress aPos(1,6,0);
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A2:A3 failed",  6.0, m_pDoc->GetValue(aPos));
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL SUM for A2:A3 failed",  6.0, m_pDoc->GetValue(aPos));
     aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A3:A4 failed", 12.0, m_pDoc->GetValue(aPos));
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL SUM for A3:A4 failed", 12.0, m_pDoc->GetValue(aPos));
     aPos.IncRow();
-    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A4:A5 failed", 24.0, m_pDoc->GetValue(aPos));
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL SUM for A4:A5 failed", 24.0, m_pDoc->GetValue(aPos));
+
+    // Matrix in C7:C9, individual MIN of A2:A3, A3:A4 and A4:A5
+    m_pDoc->InsertMatrixFormula(2, 6, 2, 8, aMark, "=SUBTOTAL(5;OFFSET(A1;ROW(1:3);0;2))");
+    aPos.Set(2,6,0);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MIN for A2:A3 failed",  2.0, m_pDoc->GetValue(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MIN for A3:A4 failed",  4.0, m_pDoc->GetValue(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MIN for A4:A5 failed",  8.0, m_pDoc->GetValue(aPos));
+
+    // Matrix in D7:D9, individual MAX of A2:A3, A3:A4 and A4:A5
+    m_pDoc->InsertMatrixFormula(3, 6, 3, 8, aMark, "=SUBTOTAL(4;OFFSET(A1;ROW(1:3);0;2))");
+    aPos.Set(3,6,0);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A2:A3 failed",  4.0, m_pDoc->GetValue(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A3:A4 failed",  8.0, m_pDoc->GetValue(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL MAX for A4:A5 failed", 16.0, m_pDoc->GetValue(aPos));
 
     m_pDoc->DeleteTab(0);
 }
commit c41b82203ef54a74bd0693e29f65617d0e158a06
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 23:05:33 2017 +0200

    Handle MIN and MAX with arrays of references, tdf#58874
    
    Change-Id: I24c9f3078f60e14e64f1e1e3910963dfe0a38d77

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 7417e54b8ca3..bf8b9dc77c00 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -3461,6 +3461,9 @@ void ScInterpreter::ScMin( bool bTextAsZero )
     short nParamCount = GetByte();
     if (!MustHaveParamCountMin( nParamCount, 1))
         return;
+    const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+    ScMatrixRef xResMat;
+    size_t nRefArrayPos = std::numeric_limits<size_t>::max();
     double nMin = ::std::numeric_limits<double>::max();
     double nVal = 0.0;
     ScAddress aAdr;
@@ -3494,9 +3497,35 @@ void ScInterpreter::ScMin( bool bTextAsZero )
                 }
             }
             break;
-            case svDoubleRef :
             case svRefList :
             {
+                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+                if (p && p->IsArrayResult())
+                {
+                    nRefArrayPos = nRefInList;
+                    if (!xResMat)
+                    {
+                        // Create and init all elements with current value.
+                        assert(nMatRows > 0);
+                        xResMat = GetNewMat( 1, nMatRows, true);
+                        xResMat->FillDouble( nMin, 0,0, 0,nMatRows-1);
+                    }
+                    else
+                    {
+                        // Current value and values from vector are operands
+                        // for each vector position.
+                        for (SCSIZE i=0; i < nMatRows; ++i)
+                        {
+                            double fVecRes = xResMat->GetDouble(0,i);
+                            if (fVecRes > nMin)
+                                xResMat->PutDouble( nMin, 0,i);
+                        }
+                    }
+                }
+            }
+            SAL_FALLTHROUGH;
+            case svDoubleRef :
+            {
                 FormulaError nErr = FormulaError::NONE;
                 PopDoubleRef( aRange, nParamCount, nRefInList);
                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
@@ -3512,6 +3541,18 @@ void ScInterpreter::ScMin( bool bTextAsZero )
                     }
                     SetError(nErr);
                 }
+                if (nRefArrayPos != std::numeric_limits<size_t>::max())
+                {
+                    // Update vector element with current value.
+                    double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
+                    if (fVecRes > nMin)
+                        xResMat->PutDouble( nMin, 0,nRefArrayPos);
+
+                    // Reset.
+                    nMin = std::numeric_limits<double>::max();
+                    nVal = 0.0;
+                    nRefArrayPos = std::numeric_limits<size_t>::max();
+                }
             }
             break;
             case svMatrix :
@@ -3545,10 +3586,41 @@ void ScInterpreter::ScMin( bool bTextAsZero )
                 SetError(FormulaError::IllegalParameter);
         }
     }
-    if ( nVal < nMin  )
-        PushDouble(0.0);
+
+    if (xResMat)
+    {
+        // Include value of last non-references-array type and calculate final result.
+        if (nMin < std::numeric_limits<double>::max())
+        {
+            for (SCSIZE i=0; i < nMatRows; ++i)
+            {
+                double fVecRes = xResMat->GetDouble(0,i);
+                if (fVecRes > nMin)
+                    xResMat->PutDouble( nMin, 0,i);
+            }
+        }
+        else
+        {
+            /* TODO: the awkward "no value is minimum 0.0" is likely the case
+             * if a value is numeric_limits::max. Still, that could be a valid
+             * minimum value as well, but nVal and nMin had been reset after
+             * the last svRefList.. so we may lie here. */
+            for (SCSIZE i=0; i < nMatRows; ++i)
+            {
+                double fVecRes = xResMat->GetDouble(0,i);
+                if (fVecRes == std::numeric_limits<double>::max())
+                    xResMat->PutDouble( 0.0, 0,i);
+            }
+        }
+        PushMatrix( xResMat);
+    }
     else
-        PushDouble(nMin);
+    {
+        if ( nVal < nMin  )
+            PushDouble(0.0);    // zero or only empty arguments
+        else
+            PushDouble(nMin);
+    }
 }
 
 void ScInterpreter::ScMax( bool bTextAsZero )
@@ -3556,7 +3628,10 @@ void ScInterpreter::ScMax( bool bTextAsZero )
     short nParamCount = GetByte();
     if (!MustHaveParamCountMin( nParamCount, 1))
         return;
-    double nMax = -(::std::numeric_limits<double>::max());
+    const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+    ScMatrixRef xResMat;
+    size_t nRefArrayPos = std::numeric_limits<size_t>::max();
+    double nMax = std::numeric_limits<double>::lowest();
     double nVal = 0.0;
     ScAddress aAdr;
     ScRange aRange;
@@ -3589,9 +3664,35 @@ void ScInterpreter::ScMax( bool bTextAsZero )
                 }
             }
             break;
-            case svDoubleRef :
             case svRefList :
             {
+                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+                if (p && p->IsArrayResult())
+                {
+                    nRefArrayPos = nRefInList;
+                    if (!xResMat)
+                    {
+                        // Create and init all elements with current value.
+                        assert(nMatRows > 0);
+                        xResMat = GetNewMat( 1, nMatRows, true);
+                        xResMat->FillDouble( nMax, 0,0, 0,nMatRows-1);
+                    }
+                    else
+                    {
+                        // Current value and values from vector are operands
+                        // for each vector position.
+                        for (SCSIZE i=0; i < nMatRows; ++i)
+                        {
+                            double fVecRes = xResMat->GetDouble(0,i);
+                            if (fVecRes < nMax)
+                                xResMat->PutDouble( nMax, 0,i);
+                        }
+                    }
+                }
+            }
+            SAL_FALLTHROUGH;
+            case svDoubleRef :
+            {
                 FormulaError nErr = FormulaError::NONE;
                 PopDoubleRef( aRange, nParamCount, nRefInList);
                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
@@ -3607,6 +3708,18 @@ void ScInterpreter::ScMax( bool bTextAsZero )
                     }
                     SetError(nErr);
                 }
+                if (nRefArrayPos != std::numeric_limits<size_t>::max())
+                {
+                    // Update vector element with current value.
+                    double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
+                    if (fVecRes < nMax)
+                        xResMat->PutDouble( nMax, 0,nRefArrayPos);
+
+                    // Reset.
+                    nMax = std::numeric_limits<double>::lowest();
+                    nVal = 0.0;
+                    nRefArrayPos = std::numeric_limits<size_t>::max();
+                }
             }
             break;
             case svMatrix :
@@ -3640,10 +3753,41 @@ void ScInterpreter::ScMax( bool bTextAsZero )
                 SetError(FormulaError::IllegalParameter);
         }
     }
-    if ( nVal > nMax  )
-        PushDouble(0.0);
+
+    if (xResMat)
+    {
+        // Include value of last non-references-array type and calculate final result.
+        if (nMax > std::numeric_limits<double>::lowest())
+        {
+            for (SCSIZE i=0; i < nMatRows; ++i)
+            {
+                double fVecRes = xResMat->GetDouble(0,i);
+                if (fVecRes < nMax)
+                    xResMat->PutDouble( nMax, 0,i);
+            }
+        }
+        else
+        {
+            /* TODO: the awkward "no value is maximum 0.0" is likely the case
+             * if a value is numeric_limits::lowest. Still, that could be a
+             * valid maximum value as well, but nVal and nMax had been reset
+             * after the last svRefList.. so we may lie here. */
+            for (SCSIZE i=0; i < nMatRows; ++i)
+            {
+                double fVecRes = xResMat->GetDouble(0,i);
+                if (fVecRes == -std::numeric_limits<double>::max())
+                    xResMat->PutDouble( 0.0, 0,i);
+            }
+        }
+        PushMatrix( xResMat);
+    }
     else
-        PushDouble(nMax);
+    {
+        if ( nVal > nMax  )
+            PushDouble(0.0);    // zero or only empty arguments
+        else
+            PushDouble(nMax);
+    }
 }
 
 void ScInterpreter::GetStVarParams( double& rVal, double& rValCount, bool bTextAsZero )
commit 5236e847191bbc3fb47a630bec5dbe8ed65679d7
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 22:08:12 2017 +0200

    const nMatRows, tdf#58874
    
    Change-Id: Ic9e11ed6b8890fe9d3db4b3a9b4d1d8d50838b2e

diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index d0cb8a14b82f..35004f2846bc 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -504,7 +504,7 @@ static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uL
 void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
 {
     short nParamCount = GetByte();
-    SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
+    const SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
     ScMatrixRef xResMat, xResCount;
     double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
     double fVal = 0.0;
commit 17dd13922c01a864e5124afc97c9b19f0e29b44c
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 21:30:41 2017 +0200

    Factor out to ScInterpreter::GetRefListArrayMaxSize(), tdf#58874
    
    Change-Id: Ie08c37ff66faaaba8f8945503e3d212943d324d7

diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 9ddf9e2c1900..3586d21c317f 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -568,6 +568,9 @@ void ScUnicode();
 void ScUnichar();
 void ScMin( bool bTextAsZero = false );
 void ScMax( bool bTextAsZero = false );
+/** Check for array of references to determine the maximum size of a return
+    column vector if in array context. */
+size_t GetRefListArrayMaxSize( short nParamCount );
 void IterateParameters( ScIterFunc, bool bTextAsZero = false );
 void ScSumSQ();
 void ScSum();
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 0b36b129b48f..d0cb8a14b82f 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -459,6 +459,24 @@ void IterateMatrix(
     }
 }
 
+size_t ScInterpreter::GetRefListArrayMaxSize( short nParamCount )
+{
+    size_t nSize = 0;
+    if (bMatrixFormula || pCur->IsInForceArray())
+    {
+        for (short i=1; i <= nParamCount; ++i)
+        {
+            if (GetStackType(i) == svRefList)
+            {
+                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
+                if (p && p->IsArrayResult() && p->GetRefList()->size() > nSize)
+                    nSize = p->GetRefList()->size();
+            }
+        }
+    }
+    return nSize;
+}
+
 static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount )
 {
     switch( eFunc )
@@ -486,21 +504,7 @@ static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uL
 void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
 {
     short nParamCount = GetByte();
-    SCSIZE nMatRows = 0;
-    if (bMatrixFormula || pCur->IsInForceArray())
-    {
-        // Check for arrays of references to determine the maximum size of a
-        // return column vector.
-        for (short i=1; i <= nParamCount; ++i)
-        {
-            if (GetStackType(i) == svRefList)
-            {
-                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
-                if (p && p->IsArrayResult() && p->GetRefList()->size() > nMatRows)
-                    nMatRows = p->GetRefList()->size();
-            }
-        }
-    }
+    SCSIZE nMatRows = GetRefListArrayMaxSize( nParamCount);
     ScMatrixRef xResMat, xResCount;
     double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
     double fVal = 0.0;
commit 1e70dedee1c7be912e4aaa2ff12b046dbd364a86
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 21:29:30 2017 +0200

    Add unit test for SUBTOTAL over reference list in array context, tdf#58874
    
    Change-Id: I82752c035f6551d3136dc06331ff8745ba959463

diff --git a/sc/qa/unit/ucalc.hxx b/sc/qa/unit/ucalc.hxx
index 5d1def66c7c7..d36ed7ddd2a5 100644
--- a/sc/qa/unit/ucalc.hxx
+++ b/sc/qa/unit/ucalc.hxx
@@ -212,6 +212,7 @@ public:
     void testFuncLCM();
     void testFuncSUMSQ();
     void testFuncMDETERM();
+    void testFuncRefListArraySUBTOTAL();
     void testMatConcat();
     void testMatConcatReplication();
     void testRefR1C1WholeCol();
@@ -620,6 +621,7 @@ public:
     CPPUNIT_TEST(testFuncLCM);
     CPPUNIT_TEST(testFuncSUMSQ);
     CPPUNIT_TEST(testFuncMDETERM);
+    CPPUNIT_TEST(testFuncRefListArraySUBTOTAL);
     CPPUNIT_TEST(testMatConcat);
     CPPUNIT_TEST(testMatConcatReplication);
     CPPUNIT_TEST(testExternalRef);
diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 7c58bcb51522..c2b46cec85ae 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7904,4 +7904,31 @@ void Test::testFuncRowsHidden()
     m_pDoc->DeleteTab(0);
 }
 
+// Test SUBTOTAL with reference lists in array context.
+void Test::testFuncRefListArraySUBTOTAL()
+{
+    sc::AutoCalcSwitch aACSwitch(*m_pDoc, true); // turn auto calc on.
+    m_pDoc->InsertTab(0, "Test");
+
+    m_pDoc->SetValue(0,0,0,  1.0);  // A1
+    m_pDoc->SetValue(0,1,0,  2.0);  // A2
+    m_pDoc->SetValue(0,2,0,  4.0);  // A3
+    m_pDoc->SetValue(0,3,0,  8.0);  // A4
+    m_pDoc->SetValue(0,4,0, 16.0);  // A5
+    m_pDoc->SetValue(0,5,0, 32.0);  // A6
+
+    // Matrix in B7:B9, individual SUM of A2:A3, A3:A4 and A4:A5
+    ScMarkData aMark;
+    aMark.SelectOneTable(0);
+    m_pDoc->InsertMatrixFormula(1, 6, 1, 8, aMark, "=SUBTOTAL(9;OFFSET(A1;ROW(1:3);0;2))");
+    ScAddress aPos(1,6,0);
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A2:A3 failed",  6.0, m_pDoc->GetValue(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A3:A4 failed", 12.0, m_pDoc->GetValue(aPos));
+    aPos.IncRow();
+    CPPUNIT_ASSERT_EQUAL_MESSAGE("SUBTOTAL for A4:A5 failed", 24.0, m_pDoc->GetValue(aPos));
+
+    m_pDoc->DeleteTab(0);
+}
+
 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
commit d9ba325bf1fd4e8f5557f34e5af6502107be5207
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 21:14:31 2017 +0200

    Use SetValue() instead of SetString()
    
    Change-Id: I9d1f9be14d69006126a2c72b7c4cfbfb24b3cfe8

diff --git a/sc/qa/unit/ucalc_formula.cxx b/sc/qa/unit/ucalc_formula.cxx
index 223b88dd1f2f..7c58bcb51522 100644
--- a/sc/qa/unit/ucalc_formula.cxx
+++ b/sc/qa/unit/ucalc_formula.cxx
@@ -7837,7 +7837,7 @@ void Test::testIntersectionOpExcel()
     // Vertical cell range covering C2.
     pGlobalNames->insert( new ScRangeData( m_pDoc, "vert", "$C$1:$C$3"));
     // Data in C2.
-    m_pDoc->SetString(2,1,0,"1");
+    m_pDoc->SetValue(2,1,0, 1.0);
 
     m_pDoc->SetGrammar(FormulaGrammar::GRAM_ENGLISH_XL_A1);
 
commit 91bdd41bb0092e7ed9ef4e5b782650be3cfd9440
Author: Eike Rathke <erack at redhat.com>
Date:   Sat May 20 20:09:01 2017 +0200

    Handle reference list as array in IterateParameters(), tdf#58874
    
    This in array context now returns the expexted array for an expression like
    =SUBTOTAL(9,OFFSET(A1,ROW(1:3),0,2))
    where OFFSET returns an array (svRefList) of references, here
    A2:A3
    A3:A4
    A4:A5
    and SUBTOTAL(9,...) sums each of the references independently to return an
    array of three sums.
    
    Currently works with SUM, COUNT, COUNT2, AVERAGE, PRODUCT and SUMSQ.
    MAX and MIN are not handle in IterateParameters() and need an extra
    implementation, or rather move them into IterateParameters() as well?
    
    Change-Id: I03b7d1cccf78c1a831348106432126aec8d1f519

diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 72c82e9474a7..0b36b129b48f 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -459,9 +459,49 @@ void IterateMatrix(
     }
 }
 
+static double lcl_IterResult( ScIterFunc eFunc, double fRes, double fMem, sal_uLong nCount )
+{
+    switch( eFunc )
+    {
+        case ifSUM:
+            fRes = ::rtl::math::approxAdd( fRes, fMem );
+        break;
+        case ifAVERAGE:
+            fRes = sc::div( ::rtl::math::approxAdd( fRes, fMem ), nCount);
+        break;
+        case ifCOUNT2:
+        case ifCOUNT:
+            fRes = nCount;
+        break;
+        case ifPRODUCT:
+            if ( !nCount )
+                fRes = 0.0;
+        break;
+        default:
+            ; // nothing
+    }
+    return fRes;
+}
+
 void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
 {
     short nParamCount = GetByte();
+    SCSIZE nMatRows = 0;
+    if (bMatrixFormula || pCur->IsInForceArray())
+    {
+        // Check for arrays of references to determine the maximum size of a
+        // return column vector.
+        for (short i=1; i <= nParamCount; ++i)
+        {
+            if (GetStackType(i) == svRefList)
+            {
+                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp - i]);
+                if (p && p->IsArrayResult() && p->GetRefList()->size() > nMatRows)
+                    nMatRows = p->GetRefList()->size();
+            }
+        }
+    }
+    ScMatrixRef xResMat, xResCount;
     double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
     double fVal = 0.0;
     double fMem = 0.0;  // first numeric value != 0.0
@@ -469,6 +509,7 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
     ScAddress aAdr;
     ScRange aRange;
     size_t nRefInList = 0;
+    size_t nRefArrayPos = std::numeric_limits<size_t>::max();
     if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
          ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
         nGlobalError = FormulaError::NONE;
@@ -678,9 +719,55 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                 }
             }
             break;
-            case svDoubleRef :
             case svRefList :
             {
+                const ScRefListToken* p = dynamic_cast<const ScRefListToken*>(pStack[sp-1]);
+                if (p && p->IsArrayResult())
+                {
+                    nRefArrayPos = nRefInList;
+                    if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
+                    {
+                        fRes = rtl::math::approxAdd( fRes, fMem);
+                        fMem = 0.0;
+                    }
+                    // The "one value to all references of an array" seems to
+                    // be what Excel does if there are other types than just
+                    // arrays of references.
+                    if (!xResMat)
+                    {
+                        // Create and init all elements with current value.
+                        assert(nMatRows > 0);
+                        xResMat = GetNewMat( 1, nMatRows, true);
+                        xResMat->FillDouble( fRes, 0,0, 0,nMatRows-1);
+                        if (eFunc != ifSUM)
+                        {
+                            xResCount = GetNewMat( 1, nMatRows, true);
+                            xResCount->FillDouble( nCount, 0,0, 0,nMatRows-1);
+                        }
+                    }
+                    else
+                    {
+                        // Current value and values from vector are operands
+                        // for each vector position.
+                        for (SCSIZE i=0; i < nMatRows; ++i)
+                        {
+                            if (xResCount)
+                                xResCount->PutDouble( xResCount->GetDouble(0,i) + nCount, 0,i);
+                            double fVecRes = xResMat->GetDouble(0,i);
+                            if (eFunc == ifPRODUCT)
+                                fVecRes *= fRes;
+                            else
+                                fVecRes += fRes;
+                            xResMat->PutDouble( fVecRes, 0,i);
+                        }
+                    }
+                    fRes = ((eFunc == ifPRODUCT) ? 1.0 : 0.0);
+                    nCount = 0;
+                }
+            }
+            SAL_FALLTHROUGH;
+            case svDoubleRef :
+            {
                 PopDoubleRef( aRange, nParamCount, nRefInList);
                 if (nGlobalError == FormulaError::NoRef)
                 {
@@ -835,6 +922,27 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                         SetError( nErr );
                     }
                 }
+                if (nRefArrayPos != std::numeric_limits<size_t>::max())
+                {
+                    // Update vector element with current value.
+                    if ((eFunc == ifSUM || eFunc == ifAVERAGE) && fMem != 0.0)
+                    {
+                        fRes = rtl::math::approxAdd( fRes, fMem);
+                        fMem = 0.0;
+                    }
+                    if (xResCount)
+                        xResCount->PutDouble( xResCount->GetDouble(0,nRefArrayPos) + nCount, 0,nRefArrayPos);
+                    double fVecRes = xResMat->GetDouble(0,nRefArrayPos);
+                    if (eFunc == ifPRODUCT)
+                        fVecRes *= fRes;
+                    else
+                        fVecRes += fRes;
+                    xResMat->PutDouble( fVecRes, 0,nRefArrayPos);
+                    // Reset.
+                    fRes = ((eFunc == ifPRODUCT) ? 1.0 : 0.0);
+                    nCount = 0;
+                    nRefArrayPos = std::numeric_limits<size_t>::max();
+                }
             }
             break;
             case svExternalDoubleRef:
@@ -874,21 +982,33 @@ void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                 SetError(FormulaError::IllegalParameter);
         }
     }
-    switch( eFunc )
-    {
-        case ifSUM:     fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
-        case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
-        case ifCOUNT2:
-        case ifCOUNT:   fRes  = nCount; break;
-        case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
-        default: ; // nothing
-    }
+
     // A boolean return type makes no sense on sums et al.
     // Counts are always numbers.
     if( nFuncFmtType == css::util::NumberFormat::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
         nFuncFmtType = css::util::NumberFormat::NUMBER;
 
-    PushDouble( fRes);
+    if (xResMat)
+    {
+        // Include value of last non-references-array type and calculate final result.
+        for (SCSIZE i=0; i < nMatRows; ++i)
+        {
+            if (xResCount)
+                nCount += xResCount->GetDouble(0,i);
+            double fVecRes = xResMat->GetDouble(0,i);
+            if (eFunc == ifPRODUCT)
+                fVecRes *= fRes;
+            else
+                fVecRes += fRes;
+            fVecRes = lcl_IterResult( eFunc, fVecRes, fMem, nCount);
+            xResMat->PutDouble( fVecRes, 0,i);
+        }
+        PushMatrix( xResMat);
+    }
+    else
+    {
+        PushDouble( lcl_IterResult( eFunc, fRes, fMem, nCount));
+    }
 }
 
 void ScInterpreter::ScSumSQ()
commit f6703ce85f9399b94958601ed6623865b205c5fb
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 22:48:24 2017 +0200

    Change IterateParameters to push token instead of returning double, tdf#58874
    
    Change-Id: Ib256d99126116379b27fc246dedf0fac2efb8c02

diff --git a/sc/source/core/inc/interpre.hxx b/sc/source/core/inc/interpre.hxx
index 902fde9e1376..9ddf9e2c1900 100644
--- a/sc/source/core/inc/interpre.hxx
+++ b/sc/source/core/inc/interpre.hxx
@@ -568,7 +568,7 @@ void ScUnicode();
 void ScUnichar();
 void ScMin( bool bTextAsZero = false );
 void ScMax( bool bTextAsZero = false );
-double IterateParameters( ScIterFunc, bool bTextAsZero = false );
+void IterateParameters( ScIterFunc, bool bTextAsZero = false );
 void ScSumSQ();
 void ScSum();
 void ScProduct();
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index 31448ee48f6e..72c82e9474a7 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -459,7 +459,7 @@ void IterateMatrix(
     }
 }
 
-double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
+void ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
 {
     short nParamCount = GetByte();
     double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
@@ -614,7 +614,10 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
             {
                 PopSingleRef( aAdr );
                 if (nGlobalError == FormulaError::NoRef)
-                    return 0.0;
+                {
+                    PushError( FormulaError::NoRef);
+                    return;
+                }
 
                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
@@ -680,7 +683,10 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
             {
                 PopDoubleRef( aRange, nParamCount, nRefInList);
                 if (nGlobalError == FormulaError::NoRef)
-                    return 0.0;
+                {
+                    PushError( FormulaError::NoRef);
+                    return;
+                }
 
                 if ( nGlobalError != FormulaError::NONE && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ||
                      ( mnSubTotalFlags & SubtotalFlags::IgnoreErrVal ) ) )
@@ -717,8 +723,8 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                         FormulaError nErr = aAction.getError();
                         if ( nErr != FormulaError::NONE )
                         {
-                            SetError( nErr );
-                            return fRes;
+                            PushError( nErr );
+                            return;
                         }
                         fRes += aAction.getSum();
 
@@ -881,37 +887,38 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
     // Counts are always numbers.
     if( nFuncFmtType == css::util::NumberFormat::LOGICAL || eFunc == ifCOUNT || eFunc == ifCOUNT2 )
         nFuncFmtType = css::util::NumberFormat::NUMBER;
-    return fRes;
+
+    PushDouble( fRes);
 }
 
 void ScInterpreter::ScSumSQ()
 {
-    PushDouble( IterateParameters( ifSUMSQ ) );
+    IterateParameters( ifSUMSQ );
 }
 
 void ScInterpreter::ScSum()
 {
-    PushDouble( IterateParameters( ifSUM ) );
+    IterateParameters( ifSUM );
 }
 
 void ScInterpreter::ScProduct()
 {
-    PushDouble( IterateParameters( ifPRODUCT ) );
+    IterateParameters( ifPRODUCT );
 }
 
 void ScInterpreter::ScAverage( bool bTextAsZero )
 {
-    PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
+    IterateParameters( ifAVERAGE, bTextAsZero );
 }
 
 void ScInterpreter::ScCount()
 {
-    PushDouble( IterateParameters( ifCOUNT ) );
+    IterateParameters( ifCOUNT );
 }
 
 void ScInterpreter::ScCount2()
 {
-    PushDouble( IterateParameters( ifCOUNT2 ) );
+    IterateParameters( ifCOUNT2 );
 }
 
 void ScInterpreter::ScRawSubtract()
commit c9bff2c2e64823504baa8a4b5e20a88866ba0a71
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 22:28:37 2017 +0200

    Get rid of some unneccessary formula:: namespace
    
    Change-Id: Icd30167589b507c3f83a31dbb5c0eb473ab6580e

diff --git a/sc/source/core/tool/interpr3.cxx b/sc/source/core/tool/interpr3.cxx
index 8937e666c865..ea3145b3a5c0 100644
--- a/sc/source/core/tool/interpr3.cxx
+++ b/sc/source/core/tool/interpr3.cxx
@@ -2471,7 +2471,7 @@ void ScInterpreter::ScZTest()
     double rValCount = 0.0;
     switch (GetStackType())
     {
-        case formula::svDouble :
+        case svDouble :
         {
             fVal = GetDouble();
             fSum    += fVal;
@@ -2494,7 +2494,7 @@ void ScInterpreter::ScZTest()
         }
         break;
         case svRefList :
-        case formula::svDoubleRef :
+        case svDoubleRef :
         {
             short nParam = 1;
             size_t nRefInList = 0;
@@ -2912,7 +2912,7 @@ void ScInterpreter::ScHarMean()
     {
         switch (GetStackType())
         {
-            case formula::svDouble    :
+            case svDouble    :
             {
                 double x = GetDouble();
                 if (x > 0.0)
@@ -2941,7 +2941,7 @@ void ScInterpreter::ScHarMean()
                 }
                 break;
             }
-            case formula::svDoubleRef :
+            case svDoubleRef :
             case svRefList :
             {
                 FormulaError nErr = FormulaError::NONE;
@@ -3034,7 +3034,7 @@ void ScInterpreter::ScGeoMean()
     {
         switch (GetStackType())
         {
-            case formula::svDouble    :
+            case svDouble    :
             {
                 double x = GetDouble();
                 if (x > 0.0)
@@ -3063,7 +3063,7 @@ void ScInterpreter::ScGeoMean()
                 }
                 break;
             }
-            case formula::svDoubleRef :
+            case svDoubleRef :
             case svRefList :
             {
                 FormulaError nErr = FormulaError::NONE;
@@ -3175,7 +3175,7 @@ bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::
     {
         switch (GetStackType())
         {
-            case formula::svDouble :
+            case svDouble :
             {
                 fVal = GetDouble();
                 fSum += fVal;
@@ -3196,7 +3196,7 @@ bool ScInterpreter::CalculateSkew(double& fSum,double& fCount,double& vSum,std::
                 }
             }
             break;
-            case formula::svDoubleRef :
+            case svDoubleRef :
             case svRefList :
             {
                 PopDoubleRef( aRange, nParamCount, nRefInList);
@@ -3663,7 +3663,7 @@ void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double
         const StackVar eStackType = GetStackType();
         switch (eStackType)
         {
-            case formula::svDouble :
+            case svDouble :
                 rArray.push_back( PopDouble());
             break;
             case svSingleRef :
@@ -3674,7 +3674,7 @@ void ScInterpreter::GetNumberSequenceArray( sal_uInt8 nParamCount, vector<double
                     rArray.push_back(GetCellValue(aAdr, aCell));
             }
             break;
-            case formula::svDoubleRef :
+            case svDoubleRef :
             case svRefList :
             {
                 PopDoubleRef( aRange, nParam, nRefInList);
@@ -3946,7 +3946,7 @@ void ScInterpreter::ScAveDev()
     {
         switch (GetStackType())
         {
-            case formula::svDouble :
+            case svDouble :
                 rVal += GetDouble();
                 rValCount++;
                 break;
@@ -3961,7 +3961,7 @@ void ScInterpreter::ScAveDev()
                 }
             }
             break;
-            case formula::svDoubleRef :
+            case svDoubleRef :
             case svRefList :
             {
                 FormulaError nErr = FormulaError::NONE;
@@ -4029,7 +4029,7 @@ void ScInterpreter::ScAveDev()
     {
         switch (GetStackType())
         {
-            case formula::svDouble :
+            case svDouble :
                 rVal += fabs(GetDouble() - nMiddle);
                 break;
             case svSingleRef :
@@ -4040,7 +4040,7 @@ void ScInterpreter::ScAveDev()
                     rVal += fabs(GetCellValue(aAdr, aCell) - nMiddle);
             }
             break;
-            case formula::svDoubleRef :
+            case svDoubleRef :
             case svRefList :
             {
                 FormulaError nErr = FormulaError::NONE;
@@ -4278,7 +4278,7 @@ void ScInterpreter::ScRSQ()
     {
         switch (GetStackType())
         {
-            case formula::svDouble:
+            case svDouble:
                 {
                     double fVal = PopDouble();
                     PushDouble( fVal * fVal);
diff --git a/sc/source/core/tool/interpr6.cxx b/sc/source/core/tool/interpr6.cxx
index c42f0f4545d3..31448ee48f6e 100644
--- a/sc/source/core/tool/interpr6.cxx
+++ b/sc/source/core/tool/interpr6.cxx
@@ -564,7 +564,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                 StackVar eType = pToken->GetType();
                 if (eFunc == ifCOUNT2)
                 {
-                    if ( eType != formula::svEmptyCell &&
+                    if ( eType != svEmptyCell &&
                          ( ( pToken->GetOpCode() != ocSubTotal &&
                              pToken->GetOpCode() != ocAggregate ) ||
                            ( mnSubTotalFlags & SubtotalFlags::IgnoreNestedStAg ) ) )
@@ -572,7 +572,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                     if (nGlobalError != FormulaError::NONE)
                         nGlobalError = FormulaError::NONE;
                 }
-                else if (eType == formula::svDouble)
+                else if (eType == svDouble)
                 {
                     nCount++;
                     fVal = pToken->GetDouble();
@@ -602,7 +602,7 @@ double ScInterpreter::IterateParameters( ScIterFunc eFunc, bool bTextAsZero )
                         default: ; // nothing
                     }
                 }
-                else if (bTextAsZero && eType == formula::svString)
+                else if (bTextAsZero && eType == svString)
                 {
                     nCount++;
                     if ( eFunc == ifPRODUCT )
commit b45a7ed1e687f7c54f16f6ab65b85ab3d945af68
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 22:13:28 2017 +0200

    Do not force return value to double in SUBTOTAL and AGGREGATE, tdf#58874
    
    Change-Id: I305adfb97022f353dde6aab4e234faff0fdfb904

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 3cca0b101f15..7417e54b8ca3 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -6725,9 +6725,9 @@ void ScInterpreter::ScSubTotal()
         }
         mnSubTotalFlags = SubtotalFlags::NONE;
         // Get rid of the 1st (fished) parameter.
-        double nVal = GetDouble();
+        FormulaConstTokenRef xRef( PopToken());
         Pop();
-        PushDouble( nVal );
+        PushTokenRef( xRef);
     }
 }
 
@@ -6806,11 +6806,11 @@ void ScInterpreter::ScAggregate()
             }
             mnSubTotalFlags = SubtotalFlags::NONE;
         }
-        double nVal = GetDouble();
+        FormulaConstTokenRef xRef( PopToken());
         // Get rid of the 1st and 2nd (fished) parameters.
         Pop();
         Pop();
-        PushDouble( nVal );
+        PushTokenRef( xRef);
     }
 }
 
commit 27caf863d4dc06dd8cc09f5e4836d40f59ee9faf
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 22:11:15 2017 +0200

    Mention validation with xmllint
    
    Change-Id: I03af05e51084a438109c2e200faa8d5e5b4f2c74

diff --git a/i18npool/source/localedata/data/locale.dtd b/i18npool/source/localedata/data/locale.dtd
index 2898ee4bb04e..377df12b9bb8 100644
--- a/i18npool/source/localedata/data/locale.dtd
+++ b/i18npool/source/localedata/data/locale.dtd
@@ -26,15 +26,23 @@
     ATTENTION! PLEASE! HEADS UP! IMPORTANT!
     ===========================================================================
 
-    Please validate your locale data contribution using a validating parser. A
-    validating parser, for example, may be found at
+    Please validate your locale data contribution.
+
+    A quick validation check can be done if you have xmllint installed and the
+    current locale.dtd file at hand, you can download the locale.dtd file from
+    https://cgit.freedesktop.org/libreoffice/core/plain/i18npool/source/localedata/data/locale.dtd
+
+    xmllint --dtdvalid locale.dtd --noout your_data.xml
+
+
+    Second, using a validating parser. A validating parser, for example, may be found at
     http://unicode.org/cldr/data/tools/java/org/unicode/cldr/util/XMLValidator.java
     Compile it into a class-jar and call it in the
     i18npool/source/localedata/data/ directory:
     java -cp <your_path>/XMLValidator.jar org.unicode.cldr.util.XMLValidator your_data.xml
 
 
-    A second possibility is:
+    A third possibility is:
 
     - temporarily (!) change the DOCTYPE of your file to read (all on one line)
       <!DOCTYPE Locale SYSTEM "http://cgit.freedesktop.org/libreoffice/core/plain/i18npool/source/localedata/data/locale.dtd">
commit b086633566cbcc5e73add5d195ce0ab207ea8f7c
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 21:44:17 2017 +0200

    Create RefList at JumpMatrix if current function returns Reference, tdf#58874
    
    Change-Id: I8fcdbc743c614857ee298b3d9c730ab64477dd8c

diff --git a/sc/source/core/tool/interpr1.cxx b/sc/source/core/tool/interpr1.cxx
index 29f51d6326a1..3cca0b101f15 100644
--- a/sc/source/core/tool/interpr1.cxx
+++ b/sc/source/core/tool/interpr1.cxx
@@ -581,6 +581,7 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
                 break;
                 case svSingleRef:
                 {
+                    FormulaConstTokenRef xRef = pStack[sp-1];
                     ScAddress aAdr;
                     PopSingleRef( aAdr );
                     if ( nGlobalError != FormulaError::NONE )
@@ -619,10 +620,21 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
                                 pJumpMatrix->PutResultString(aStr, nC, nR);
                         }
                     }
+
+                    formula::ParamClass eReturnType = ScParameterClassification::GetParameterType( pCur, SAL_MAX_UINT16);
+                    if (eReturnType == ParamClass::Reference)
+                    {
+                        /* TODO: What about error handling and do we actually
+                         * need the result matrix above at all in this case? */
+                        ScComplexRefData aRef;
+                        aRef.Ref1 = aRef.Ref2 = *(xRef->GetSingleRef());
+                        pJumpMatrix->GetRefList().push_back( aRef);
+                    }
                 }
                 break;
                 case svDoubleRef:
                 {   // upper left plus offset within matrix
+                    FormulaConstTokenRef xRef = pStack[sp-1];
                     double fVal;
                     ScRange aRange;
                     PopDoubleRef( aRange );
@@ -690,6 +702,14 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
                         SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
                         lcl_AdjustJumpMatrix( pJumpMatrix, nParmCols, nParmRows );
                     }
+
+                    formula::ParamClass eReturnType = ScParameterClassification::GetParameterType( pCur, SAL_MAX_UINT16);
+                    if (eReturnType == ParamClass::Reference)
+                    {
+                        /* TODO: What about error handling and do we actually
+                         * need the result matrix above at all in this case? */
+                        pJumpMatrix->GetRefList().push_back( *(xRef->GetDoubleRef()));
+                    }
                 }
                 break;
                 case svMatrix:
@@ -780,17 +800,33 @@ bool ScInterpreter::JumpMatrix( short nStackLevel )
     }
     if ( !bCont )
     {   // we're done with it, throw away jump matrix, keep result
-        ScMatrix* pResMat = pJumpMatrix->GetResultMatrix();
-        pJumpMatrix = nullptr;
-        Pop();
-        PushMatrix( pResMat );
-        // Remove jump matrix from map and remember result matrix in case it
-        // could be reused in another path of the same condition.
-        if (pTokenMatrixMap)
-        {
-            pTokenMatrixMap->erase( pCur);
-            pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
-                        pStack[sp-1]));
+        formula::ParamClass eReturnType = ScParameterClassification::GetParameterType( pCur, SAL_MAX_UINT16);
+        if (eReturnType == ParamClass::Reference)
+        {
+            FormulaTokenRef xRef = new ScRefListToken(true);
+            *(xRef->GetRefList()) = pJumpMatrix->GetRefList();
+            pJumpMatrix = nullptr;
+            Pop();
+            PushTokenRef( xRef);
+            if (pTokenMatrixMap)
+            {
+                pTokenMatrixMap->erase( pCur);
+                // There's no result matrix to remember in this case.
+            }
+        }
+        else
+        {
+            ScMatrix* pResMat = pJumpMatrix->GetResultMatrix();
+            pJumpMatrix = nullptr;
+            Pop();
+            PushMatrix( pResMat );
+            // Remove jump matrix from map and remember result matrix in case it
+            // could be reused in another path of the same condition.
+            if (pTokenMatrixMap)
+            {
+                pTokenMatrixMap->erase( pCur);
+                pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur, pStack[sp-1]));
+            }
         }
         return true;
     }
commit 3a3064fcb4778b050398d98598d6ed61e8298134
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 20:21:03 2017 +0200

    Introduce ScRefListToken::mbArrayResult for reference results, tdf#58874
    
    Change-Id: Icd077a82ab0c951667a6566d5c5d47084c46d20d

diff --git a/sc/inc/token.hxx b/sc/inc/token.hxx
index 7c082010ea93..8d561af85760 100644
--- a/sc/inc/token.hxx
+++ b/sc/inc/token.hxx
@@ -265,11 +265,15 @@ class ScRefListToken : public formula::FormulaToken
 {
 private:
             ScRefList           aRefList;
+            bool                mbArrayResult;  // whether RefList is an array result
 public:
                                 ScRefListToken() :
-                                    FormulaToken( formula::svRefList ) {}
+                                    FormulaToken( formula::svRefList ), mbArrayResult(false) {}
+            explicit            ScRefListToken( bool bArrayResult ) :
+                                    FormulaToken( formula::svRefList ), mbArrayResult( bArrayResult ) {}
                                 ScRefListToken( const ScRefListToken & r ) :
-                                    FormulaToken( r ), aRefList( r.aRefList ) {}
+                                    FormulaToken( r ), aRefList( r.aRefList ), mbArrayResult( r.mbArrayResult ) {}
+            bool                IsArrayResult() const;
     virtual const ScRefList*    GetRefList() const override;
     virtual       ScRefList*    GetRefList() override;
     virtual bool                operator==( const formula::FormulaToken& rToken ) const override;
diff --git a/sc/source/core/tool/token.cxx b/sc/source/core/tool/token.cxx
index 512fecc7f83f..ea2060d8c7a2 100644
--- a/sc/source/core/tool/token.cxx
+++ b/sc/source/core/tool/token.cxx
@@ -683,9 +683,12 @@ bool ScDoubleRefToken::operator==( const FormulaToken& r ) const
 
 const ScRefList*        ScRefListToken::GetRefList() const  { return &aRefList; }
       ScRefList*        ScRefListToken::GetRefList()        { return &aRefList; }
+      bool              ScRefListToken::IsArrayResult() const { return mbArrayResult; }
 bool ScRefListToken::operator==( const FormulaToken& r ) const
 {
-    return FormulaToken::operator==( r ) && &aRefList == r.GetRefList();
+    const ScRefListToken* p;
+    return FormulaToken::operator==( r ) && &aRefList == r.GetRefList() &&
+        ((p = dynamic_cast<const ScRefListToken*>(&r)) != nullptr) && mbArrayResult == p->IsArrayResult();
 }
 
 ScMatrixToken::ScMatrixToken( const ScMatrixRef& p ) :
commit 6a569fd47e3665b0aaec397ace0346938bb3b4bf
Author: Eike Rathke <erack at redhat.com>
Date:   Fri May 19 19:20:27 2017 +0200

    Introduce ScJumpMatrix::mvRefList for array of reference results, tdf#58874
    
    Change-Id: I478ddbcd951b386b8d4cbb38059b904af7c79703

diff --git a/sc/source/core/inc/jumpmatrix.hxx b/sc/source/core/inc/jumpmatrix.hxx
index 94b8dc1737aa..1c61b330108d 100644
--- a/sc/source/core/inc/jumpmatrix.hxx
+++ b/sc/source/core/inc/jumpmatrix.hxx
@@ -26,6 +26,7 @@
 #include <vector>
 #include "types.hxx"
 #include "address.hxx"
+#include "token.hxx"
 
 typedef ::std::vector< const formula::FormulaToken*> ScTokenVec;
 
@@ -58,6 +59,7 @@ class ScJumpMatrix
 {
     std::vector<ScJumpMatrixEntry> mvJump;      // the jumps
     ScMatrixRef         pMat;       // the results
+    ScRefList           mvRefList;  // array of references result, if any
     ScTokenVec*         pParams;    // parameter stack
     SCSIZE              nCols;
     SCSIZE              nRows;
@@ -108,6 +110,7 @@ public:
     bool Next( SCSIZE& rCol, SCSIZE& rRow );
     void GetResMatDimensions( SCSIZE& rCols, SCSIZE& rRows );
     void SetNewResMat( SCSIZE nNewCols, SCSIZE nNewRows );
+    ScRefList& GetRefList();
 
     void PutResultDouble( double fVal, SCSIZE nC, SCSIZE nR );
     void PutResultString( const svl::SharedString& rStr, SCSIZE nC, SCSIZE nR );
diff --git a/sc/source/core/tool/jumpmatrix.cxx b/sc/source/core/tool/jumpmatrix.cxx
index 760f89735db6..cc7455f42a5d 100644
--- a/sc/source/core/tool/jumpmatrix.cxx
+++ b/sc/source/core/tool/jumpmatrix.cxx
@@ -176,6 +176,11 @@ bool ScJumpMatrix::HasResultMatrix() const
     return pMat.get() != nullptr;
 }
 
+ScRefList& ScJumpMatrix::GetRefList()
+{
+    return mvRefList;
+}
+
 void ScJumpMatrix::FlushBufferOtherThan( ScJumpMatrix::BufferType eType, SCSIZE nC, SCSIZE nR )
 {
     if (!mvBufferDoubles.empty() &&


More information about the Libreoffice-commits mailing list