LCOV - code coverage report
Current view: top level - sc/source/core/tool - interpr1.cxx (source / functions) Hit Total Coverage
Test: commit 10e77ab3ff6f4314137acd6e2702a6e5c1ce1fae Lines: 2100 4630 45.4 %
Date: 2014-11-03 Functions: 127 183 69.4 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
       2             : /*
       3             :  * This file is part of the LibreOffice project.
       4             :  *
       5             :  * This Source Code Form is subject to the terms of the Mozilla Public
       6             :  * License, v. 2.0. If a copy of the MPL was not distributed with this
       7             :  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
       8             :  *
       9             :  * This file incorporates work covered by the following license notice:
      10             :  *
      11             :  *   Licensed to the Apache Software Foundation (ASF) under one or more
      12             :  *   contributor license agreements. See the NOTICE file distributed
      13             :  *   with this work for additional information regarding copyright
      14             :  *   ownership. The ASF licenses this file to you under the Apache
      15             :  *   License, Version 2.0 (the "License"); you may not use this file
      16             :  *   except in compliance with the License. You may obtain a copy of
      17             :  *   the License at http://www.apache.org/licenses/LICENSE-2.0 .
      18             :  */
      19             : 
      20             : #include "interpre.hxx"
      21             : 
      22             : #include "scitems.hxx"
      23             : #include <editeng/langitem.hxx>
      24             : #include <editeng/justifyitem.hxx>
      25             : #include <osl/thread.h>
      26             : #include <svx/algitem.hxx>
      27             : #include <unotools/textsearch.hxx>
      28             : #include <svl/zforlist.hxx>
      29             : #include <svl/zformat.hxx>
      30             : #include <tools/urlobj.hxx>
      31             : #include <unotools/charclass.hxx>
      32             : #include <sfx2/docfile.hxx>
      33             : #include <sfx2/printer.hxx>
      34             : #include <unotools/collatorwrapper.hxx>
      35             : #include <unotools/transliterationwrapper.hxx>
      36             : #include <rtl/ustring.hxx>
      37             : #include <unicode/uchar.h>
      38             : 
      39             : #include "patattr.hxx"
      40             : #include "global.hxx"
      41             : #include "document.hxx"
      42             : #include "dociter.hxx"
      43             : #include "formulacell.hxx"
      44             : #include "scmatrix.hxx"
      45             : #include "docoptio.hxx"
      46             : #include "globstr.hrc"
      47             : #include "attrib.hxx"
      48             : #include "jumpmatrix.hxx"
      49             : #include "cellkeytranslator.hxx"
      50             : #include "lookupcache.hxx"
      51             : #include "rangenam.hxx"
      52             : #include "rangeutl.hxx"
      53             : #include "compiler.hxx"
      54             : #include "externalrefmgr.hxx"
      55             : #include <basic/sbstar.hxx>
      56             : #include "doubleref.hxx"
      57             : #include "queryparam.hxx"
      58             : #include "queryentry.hxx"
      59             : #include "tokenarray.hxx"
      60             : #include "compare.hxx"
      61             : 
      62             : #include <comphelper/processfactory.hxx>
      63             : #include <comphelper/random.hxx>
      64             : #include <comphelper/string.hxx>
      65             : #include <svl/sharedstringpool.hxx>
      66             : 
      67             : #include <stdlib.h>
      68             : #include <string.h>
      69             : #include <math.h>
      70             : #include <vector>
      71             : #include <memory>
      72             : #include <limits>
      73             : 
      74             : static const sal_uInt64 n2power48 = SAL_CONST_UINT64( 281474976710656); // 2^48
      75             : 
      76          76 : IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack )
      77          76 : IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter )
      78             : 
      79          76 : ScCalcConfig ScInterpreter::maGlobalConfig;
      80             : ScTokenStack* ScInterpreter::pGlobalStack = NULL;
      81             : bool ScInterpreter::bGlobalStackInUse = false;
      82             : 
      83             : using namespace formula;
      84             : using ::std::unique_ptr;
      85             : 
      86          50 : void ScInterpreter::ScIfJump()
      87             : {
      88          50 :     const short* pJump = pCur->GetJump();
      89          50 :     short nJumpCount = pJump[ 0 ];
      90          50 :     MatrixDoubleRefToMatrix();
      91          50 :     switch ( GetStackType() )
      92             :     {
      93             :         case svMatrix:
      94             :         {
      95           2 :             ScMatrixRef pMat = PopMatrix();
      96           2 :             if ( !pMat )
      97           0 :                 PushIllegalParameter();
      98             :             else
      99             :             {
     100           2 :                 FormulaTokenRef xNew;
     101           2 :                 ScTokenMatrixMap::const_iterator aMapIter;
     102             :                 // DoubleError handled by JumpMatrix
     103           2 :                 pMat->SetErrorInterpreter( NULL);
     104             :                 SCSIZE nCols, nRows;
     105           2 :                 pMat->GetDimensions( nCols, nRows );
     106           2 :                 if ( nCols == 0 || nRows == 0 )
     107             :                 {
     108           0 :                     PushIllegalArgument();
     109          50 :                     return;
     110             :                 }
     111           8 :                 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
     112           8 :                                     pCur)) != pTokenMatrixMap->end()))
     113           0 :                     xNew = (*aMapIter).second;
     114             :                 else
     115             :                 {
     116           2 :                     ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
     117           4 :                     for ( SCSIZE nC=0; nC < nCols; ++nC )
     118             :                     {
     119           6 :                         for ( SCSIZE nR=0; nR < nRows; ++nR )
     120             :                         {
     121             :                             double fVal;
     122             :                             bool bTrue;
     123           4 :                             bool bIsValue = pMat->IsValue(nC, nR);
     124           4 :                             if (bIsValue)
     125             :                             {
     126           4 :                                 fVal = pMat->GetDouble(nC, nR);
     127           4 :                                 bIsValue = ::rtl::math::isFinite(fVal);
     128           4 :                                 bTrue = bIsValue && (fVal != 0.0);
     129           4 :                                 if (bTrue)
     130           0 :                                     fVal = 1.0;
     131             :                             }
     132             :                             else
     133             :                             {
     134             :                                 // Treat empty and empty path as 0, but string
     135             :                                 // as error.
     136           0 :                                 bIsValue = (!pMat->IsString(nC, nR) || pMat->IsEmpty(nC, nR));
     137           0 :                                 bTrue = false;
     138           0 :                                 fVal = (bIsValue ? 0.0 : CreateDoubleError( errNoValue));
     139             :                             }
     140           4 :                             if ( bTrue )
     141             :                             {   // TRUE
     142           0 :                                 if( nJumpCount >= 2 )
     143             :                                 {   // THEN path
     144             :                                     pJumpMat->SetJump( nC, nR, fVal,
     145           0 :                                             pJump[ 1 ],
     146           0 :                                             pJump[ nJumpCount ]);
     147             :                                 }
     148             :                                 else
     149             :                                 {   // no parameter given for THEN
     150             :                                     pJumpMat->SetJump( nC, nR, fVal,
     151           0 :                                             pJump[ nJumpCount ],
     152           0 :                                             pJump[ nJumpCount ]);
     153             :                                 }
     154             :                             }
     155             :                             else
     156             :                             {   // FALSE
     157           4 :                                 if( nJumpCount == 3 && bIsValue )
     158             :                                 {   // ELSE path
     159             :                                     pJumpMat->SetJump( nC, nR, fVal,
     160           0 :                                             pJump[ 2 ],
     161           0 :                                             pJump[ nJumpCount ]);
     162             :                                 }
     163             :                                 else
     164             :                                 {   // no parameter given for ELSE,
     165             :                                     // or DoubleError
     166             :                                     pJumpMat->SetJump( nC, nR, fVal,
     167           4 :                                             pJump[ nJumpCount ],
     168           8 :                                             pJump[ nJumpCount ]);
     169             :                                 }
     170             :                             }
     171             :                         }
     172             :                     }
     173           2 :                     xNew = new ScJumpMatrixToken( pJumpMat );
     174           2 :                     GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur, xNew));
     175             :                 }
     176           2 :                 PushTempToken( xNew.get());
     177             :                 // set endpoint of path for main code line
     178           2 :                 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     179           2 :             }
     180             :         }
     181           2 :         break;
     182             :         default:
     183             :         {
     184          48 :             if ( GetBool() )
     185             :             {   // TRUE
     186          28 :                 if( nJumpCount >= 2 )
     187             :                 {   // THEN path
     188          22 :                     aCode.Jump( pJump[ 1 ], pJump[ nJumpCount ] );
     189             :                 }
     190             :                 else
     191             :                 {   // no parameter given for THEN
     192           6 :                     nFuncFmtType = NUMBERFORMAT_LOGICAL;
     193           6 :                     PushInt(1);
     194           6 :                     aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     195             :                 }
     196             :             }
     197             :             else
     198             :             {   // FALSE
     199          20 :                 if( nJumpCount == 3 )
     200             :                 {   // ELSE path
     201          16 :                     aCode.Jump( pJump[ 2 ], pJump[ nJumpCount ] );
     202             :                 }
     203             :                 else
     204             :                 {   // no parameter given for ELSE
     205           4 :                     nFuncFmtType = NUMBERFORMAT_LOGICAL;
     206           4 :                     PushInt(0);
     207           4 :                     aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     208             :                 }
     209             :             }
     210             :         }
     211             :     }
     212             : }
     213             : 
     214             : /** Store a matrix value in another matrix in the context of that other matrix
     215             :     is the result matrix of a jump matrix. All arguments must be valid and are
     216             :     not checked. */
     217           2 : static void lcl_storeJumpMatResult(
     218             :     const ScMatrix* pMat, ScJumpMatrix* pJumpMat, SCSIZE nC, SCSIZE nR )
     219             : {
     220           2 :     if ( pMat->IsValue( nC, nR ) )
     221             :     {
     222           2 :         double fVal = pMat->GetDouble( nC, nR );
     223           2 :         pJumpMat->PutResultDouble( fVal, nC, nR );
     224             :     }
     225           0 :     else if ( pMat->IsEmpty( nC, nR ) )
     226             :     {
     227           0 :         pJumpMat->PutResultEmpty( nC, nR );
     228             :     }
     229             :     else
     230             :     {
     231           0 :         pJumpMat->PutResultString(pMat->GetString(nC, nR), nC, nR);
     232             :     }
     233           2 : }
     234             : 
     235          24 : void ScInterpreter::ScIfError( bool bNAonly )
     236             : {
     237          24 :     const short* pJump = pCur->GetJump();
     238          24 :     short nJumpCount = pJump[ 0 ];
     239          24 :     if (!sp)
     240             :     {
     241           0 :         PushError( errUnknownStackVariable);
     242           0 :         aCode.Jump( pJump[ nJumpCount  ], pJump[ nJumpCount ] );
     243           2 :         return;
     244             :     }
     245             : 
     246          24 :     FormulaTokenRef xToken( pStack[ sp - 1 ] );
     247          24 :     bool bError = false;
     248          24 :     sal_uInt16 nOldGlobalError = nGlobalError;
     249          24 :     nGlobalError = 0;
     250             : 
     251          24 :     MatrixDoubleRefToMatrix();
     252          24 :     switch (GetStackType())
     253             :     {
     254             :         default:
     255           2 :             Pop();
     256             :             // Act on implicitly propagated error, if any.
     257           2 :             if (nOldGlobalError)
     258           0 :                 nGlobalError = nOldGlobalError;
     259           2 :             if (nGlobalError)
     260           0 :                 bError = true;
     261           2 :             break;
     262             :         case svError:
     263           2 :             PopError();
     264           2 :             bError = true;
     265           2 :             break;
     266             :         case svDoubleRef:
     267             :         case svSingleRef:
     268             :             {
     269          18 :                 ScAddress aAdr;
     270          18 :                 if (!PopDoubleRefOrSingleRef( aAdr))
     271           0 :                     bError = true;
     272             :                 else
     273             :                 {
     274             : 
     275          18 :                     ScRefCellValue aCell;
     276          18 :                     aCell.assign(*pDok, aAdr);
     277          18 :                     nGlobalError = GetCellErrCode(aCell);
     278          18 :                     if (nGlobalError)
     279          12 :                         bError = true;
     280             :                 }
     281             :             }
     282          18 :             break;
     283             :         case svExternalSingleRef:
     284             :         case svExternalDoubleRef:
     285             :         {
     286             :             double fVal;
     287           0 :             svl::SharedString aStr;
     288             :             // Handles also existing jump matrix case and sets error on
     289             :             // elements.
     290           0 :             GetDoubleOrStringFromMatrix( fVal, aStr);
     291           0 :             if (nGlobalError)
     292           0 :                 bError = true;
     293             :         }
     294           0 :         break;
     295             :         case svMatrix:
     296             :             {
     297           2 :                 const ScMatrixRef pMat = PopMatrix();
     298           2 :                 if (!pMat || (nGlobalError && (!bNAonly || nGlobalError == NOTAVAILABLE)))
     299             :                 {
     300           0 :                     bError = true;
     301           0 :                     break;  // switch
     302             :                 }
     303             :                 // If the matrix has no queried error at all we can simply use
     304             :                 // it as result and don't need to bother with jump matrix.
     305           2 :                 SCSIZE nErrorCol = ::std::numeric_limits<SCSIZE>::max(),
     306           2 :                        nErrorRow = ::std::numeric_limits<SCSIZE>::max();
     307             :                 SCSIZE nCols, nRows;
     308           2 :                 pMat->GetDimensions( nCols, nRows );
     309           2 :                 if (nCols == 0 || nRows == 0)
     310             :                 {
     311           0 :                     bError = true;
     312           0 :                     break;  // switch
     313             :                 }
     314           4 :                 for (SCSIZE nC=0; nC < nCols && !bError; ++nC)
     315             :                 {
     316           4 :                     for (SCSIZE nR=0; nR < nRows && !bError; ++nR)
     317             :                     {
     318           2 :                         sal_uInt16 nErr = pMat->GetError( nC, nR );
     319           2 :                         if (nErr && (!bNAonly || nErr == NOTAVAILABLE))
     320             :                         {
     321           2 :                             bError = true;
     322           2 :                             nErrorCol = nC;
     323           2 :                             nErrorRow = nR;
     324             :                         }
     325             :                     }
     326             :                 }
     327           2 :                 if (!bError)
     328           0 :                     break;  // switch, we're done and have the result
     329             : 
     330           4 :                 FormulaTokenRef xNew;
     331           2 :                 ScTokenMatrixMap::const_iterator aMapIter;
     332           2 :                 if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find( pCur)) != pTokenMatrixMap->end()))
     333             :                 {
     334           0 :                     xNew = (*aMapIter).second;
     335             :                 }
     336             :                 else
     337             :                 {
     338           2 :                     const ScMatrix* pMatPtr = pMat.get();
     339           2 :                     ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
     340             :                     // Init all jumps to no error to save single calls. Error
     341             :                     // is the exceptional condition.
     342           2 :                     const double fFlagResult = CreateDoubleError( errJumpMatHasResult);
     343           2 :                     pJumpMat->SetAllJumps( fFlagResult, pJump[ nJumpCount ], pJump[ nJumpCount ] );
     344             :                     // Up to first error position simply store results, no need
     345             :                     // to evaluate error conditions again.
     346           2 :                     SCSIZE nC = 0, nR = 0;
     347           4 :                     for ( ; nC < nCols && (nC != nErrorCol || nR != nErrorRow); /*nop*/ )
     348             :                     {
     349           0 :                         for ( ; nR < nRows && (nC != nErrorCol || nR != nErrorRow); ++nR)
     350             :                         {
     351           0 :                             lcl_storeJumpMatResult(pMatPtr, pJumpMat, nC, nR);
     352             :                         }
     353           0 :                         if (nC != nErrorCol || nR != nErrorRow)
     354           0 :                             ++nC;
     355             :                     }
     356             :                     // Now the mixed cases.
     357           4 :                     for ( ; nC < nCols; ++nC)
     358             :                     {
     359           6 :                         for ( ; nR < nRows; ++nR)
     360             :                         {
     361           4 :                             sal_uInt16 nErr = pMat->GetError( nC, nR );
     362           4 :                             if (nErr && (!bNAonly || nErr == NOTAVAILABLE))
     363             :                             {   // TRUE, THEN path
     364           2 :                                 pJumpMat->SetJump( nC, nR, 1.0, pJump[ 1 ], pJump[ nJumpCount ] );
     365             :                             }
     366             :                             else
     367             :                             {   // FALSE, EMPTY path, store result instead
     368           2 :                                 lcl_storeJumpMatResult(pMatPtr, pJumpMat, nC, nR);
     369             :                             }
     370             :                         }
     371             :                     }
     372           2 :                     xNew = new ScJumpMatrixToken( pJumpMat );
     373           2 :                     GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type( pCur, xNew ));
     374             :                 }
     375           2 :                 nGlobalError = nOldGlobalError;
     376           2 :                 PushTempToken( xNew.get() );
     377             :                 // set endpoint of path for main code line
     378           2 :                 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     379           2 :                 return;
     380             :             }
     381             :             break;
     382             :     }
     383             : 
     384          22 :     if (bError && (!bNAonly || nGlobalError == NOTAVAILABLE))
     385             :     {
     386             :         // error, calculate 2nd argument
     387          12 :         nGlobalError = 0;
     388          12 :         aCode.Jump( pJump[ 1 ], pJump[ nJumpCount ] );
     389             :     }
     390             :     else
     391             :     {
     392             :         // no error, push 1st argument and continue
     393          10 :         nGlobalError = nOldGlobalError;
     394          10 :         PushTempToken( xToken.get());
     395          10 :         aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     396          22 :     }
     397             : }
     398             : 
     399          10 : void ScInterpreter::ScChoseJump()
     400             : {
     401             :     // We have to set a jump, if there was none chosen because of an error set
     402             :     // it to endpoint.
     403          10 :     bool bHaveJump = false;
     404          10 :     const short* pJump = pCur->GetJump();
     405          10 :     short nJumpCount = pJump[ 0 ];
     406          10 :     MatrixDoubleRefToMatrix();
     407          10 :     switch ( GetStackType() )
     408             :     {
     409             :         case svMatrix:
     410             :         {
     411           0 :             ScMatrixRef pMat = PopMatrix();
     412           0 :             if ( !pMat )
     413           0 :                 PushIllegalParameter();
     414             :             else
     415             :             {
     416           0 :                 FormulaTokenRef xNew;
     417           0 :                 ScTokenMatrixMap::const_iterator aMapIter;
     418             :                 // DoubleError handled by JumpMatrix
     419           0 :                 pMat->SetErrorInterpreter( NULL);
     420             :                 SCSIZE nCols, nRows;
     421           0 :                 pMat->GetDimensions( nCols, nRows );
     422           0 :                 if ( nCols == 0 || nRows == 0 )
     423           0 :                     PushIllegalParameter();
     424           0 :                 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
     425           0 :                                     pCur)) != pTokenMatrixMap->end()))
     426           0 :                     xNew = (*aMapIter).second;
     427             :                 else
     428             :                 {
     429           0 :                     ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
     430           0 :                     for ( SCSIZE nC=0; nC < nCols; ++nC )
     431             :                     {
     432           0 :                         for ( SCSIZE nR=0; nR < nRows; ++nR )
     433             :                         {
     434             :                             double fVal;
     435           0 :                             bool bIsValue = pMat->IsValue(nC, nR);
     436           0 :                             if ( bIsValue )
     437             :                             {
     438           0 :                                 fVal = pMat->GetDouble(nC, nR);
     439           0 :                                 bIsValue = ::rtl::math::isFinite( fVal );
     440           0 :                                 if ( bIsValue )
     441             :                                 {
     442           0 :                                     fVal = ::rtl::math::approxFloor( fVal);
     443           0 :                                     if ( (fVal < 1) || (fVal >= nJumpCount))
     444             :                                     {
     445           0 :                                         bIsValue = false;
     446             :                                         fVal = CreateDoubleError(
     447           0 :                                                 errIllegalArgument);
     448             :                                     }
     449             :                                 }
     450             :                             }
     451             :                             else
     452             :                             {
     453           0 :                                 fVal = CreateDoubleError( errNoValue);
     454             :                             }
     455           0 :                             if ( bIsValue )
     456             :                             {
     457             :                                 pJumpMat->SetJump( nC, nR, fVal,
     458           0 :                                         pJump[ (short)fVal ],
     459           0 :                                         pJump[ nJumpCount ]);
     460             :                             }
     461             :                             else
     462             :                             {
     463             :                                 pJumpMat->SetJump( nC, nR, fVal,
     464           0 :                                         pJump[ nJumpCount ],
     465           0 :                                         pJump[ nJumpCount ]);
     466             :                             }
     467             :                         }
     468             :                     }
     469           0 :                     xNew = new ScJumpMatrixToken( pJumpMat );
     470           0 :                     GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
     471           0 :                                 pCur, xNew));
     472             :                 }
     473           0 :                 PushTempToken( xNew.get());
     474             :                 // set endpoint of path for main code line
     475           0 :                 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     476           0 :                 bHaveJump = true;
     477           0 :             }
     478             :         }
     479           0 :         break;
     480             :         default:
     481             :         {
     482          10 :             double nJumpIndex = ::rtl::math::approxFloor( GetDouble() );
     483          10 :             if (!nGlobalError && (nJumpIndex >= 1) && (nJumpIndex < nJumpCount))
     484             :             {
     485           6 :                 aCode.Jump( pJump[ (short) nJumpIndex ], pJump[ nJumpCount ] );
     486           6 :                 bHaveJump = true;
     487             :             }
     488             :             else
     489           4 :                 PushIllegalArgument();
     490             :         }
     491             :     }
     492          10 :     if (!bHaveJump)
     493           4 :         aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
     494          10 : }
     495             : 
     496           0 : static void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, SCSIZE nParmCols, SCSIZE nParmRows )
     497             : {
     498             :     SCSIZE nJumpCols, nJumpRows;
     499             :     SCSIZE nResCols, nResRows;
     500             :     SCSIZE nAdjustCols, nAdjustRows;
     501           0 :     pJumpM->GetDimensions( nJumpCols, nJumpRows );
     502           0 :     pJumpM->GetResMatDimensions( nResCols, nResRows );
     503           0 :     if (( nJumpCols == 1 && nParmCols > nResCols ) ||
     504           0 :         ( nJumpRows == 1 && nParmRows > nResRows ))
     505             :     {
     506           0 :         if ( nJumpCols == 1 && nJumpRows == 1 )
     507             :         {
     508           0 :             nAdjustCols = nParmCols > nResCols ? nParmCols : nResCols;
     509           0 :             nAdjustRows = nParmRows > nResRows ? nParmRows : nResRows;
     510             :         }
     511           0 :         else if ( nJumpCols == 1 )
     512             :         {
     513           0 :             nAdjustCols = nParmCols;
     514           0 :             nAdjustRows = nResRows;
     515             :         }
     516             :         else
     517             :         {
     518           0 :             nAdjustCols = nResCols;
     519           0 :             nAdjustRows = nParmRows;
     520             :         }
     521           0 :         pJumpM->SetNewResMat( nAdjustCols, nAdjustRows );
     522             :     }
     523           0 : }
     524             : 
     525          14 : bool ScInterpreter::JumpMatrix( short nStackLevel )
     526             : {
     527          14 :     pJumpMatrix = pStack[sp-nStackLevel]->GetJumpMatrix();
     528          14 :     bool bHasResMat = pJumpMatrix->HasResultMatrix();
     529             :     SCSIZE nC, nR;
     530          14 :     if ( nStackLevel == 2 )
     531             :     {
     532           8 :         if ( aCode.HasStacked() )
     533           8 :             aCode.Pop();    // pop what Jump() pushed
     534             :         else
     535             :         {
     536             :             OSL_FAIL( "ScInterpreter::JumpMatrix: pop goes the weasel" );
     537             :         }
     538             : 
     539           8 :         if ( !bHasResMat )
     540             :         {
     541           0 :             Pop();
     542           0 :             SetError( errUnknownStackVariable );
     543             :         }
     544             :         else
     545             :         {
     546           8 :             pJumpMatrix->GetPos( nC, nR );
     547           8 :             switch ( GetStackType() )
     548             :             {
     549             :                 case svDouble:
     550             :                 {
     551           8 :                     double fVal = GetDouble();
     552           8 :                     if ( nGlobalError )
     553             :                     {
     554           0 :                         fVal = CreateDoubleError( nGlobalError );
     555           0 :                         nGlobalError = 0;
     556             :                     }
     557           8 :                     pJumpMatrix->PutResultDouble( fVal, nC, nR );
     558             :                 }
     559           8 :                 break;
     560             :                 case svString:
     561             :                 {
     562           0 :                     svl::SharedString aStr = GetString();
     563           0 :                     if ( nGlobalError )
     564             :                     {
     565             :                         pJumpMatrix->PutResultDouble( CreateDoubleError( nGlobalError),
     566           0 :                                 nC, nR);
     567           0 :                         nGlobalError = 0;
     568             :                     }
     569             :                     else
     570           0 :                         pJumpMatrix->PutResultString(aStr, nC, nR);
     571             :                 }
     572           0 :                 break;
     573             :                 case svSingleRef:
     574             :                 {
     575           0 :                     ScAddress aAdr;
     576           0 :                     PopSingleRef( aAdr );
     577           0 :                     if ( nGlobalError )
     578             :                     {
     579             :                         pJumpMatrix->PutResultDouble( CreateDoubleError( nGlobalError),
     580           0 :                                 nC, nR);
     581           0 :                         nGlobalError = 0;
     582             :                     }
     583             :                     else
     584             :                     {
     585           0 :                         ScRefCellValue aCell;
     586           0 :                         aCell.assign(*pDok, aAdr);
     587           0 :                         if (aCell.hasEmptyValue())
     588           0 :                             pJumpMatrix->PutResultEmpty( nC, nR );
     589           0 :                         else if (aCell.hasNumeric())
     590             :                         {
     591           0 :                             double fVal = GetCellValue(aAdr, aCell);
     592           0 :                             if ( nGlobalError )
     593             :                             {
     594             :                                 fVal = CreateDoubleError(
     595           0 :                                         nGlobalError);
     596           0 :                                 nGlobalError = 0;
     597             :                             }
     598           0 :                             pJumpMatrix->PutResultDouble( fVal, nC, nR );
     599             :                         }
     600             :                         else
     601             :                         {
     602           0 :                             svl::SharedString aStr;
     603           0 :                             GetCellString(aStr, aCell);
     604           0 :                             if ( nGlobalError )
     605             :                             {
     606             :                                 pJumpMatrix->PutResultDouble( CreateDoubleError(
     607           0 :                                             nGlobalError), nC, nR);
     608           0 :                                 nGlobalError = 0;
     609             :                             }
     610             :                             else
     611           0 :                                 pJumpMatrix->PutResultString(aStr, nC, nR);
     612           0 :                         }
     613             :                     }
     614             :                 }
     615           0 :                 break;
     616             :                 case svDoubleRef:
     617             :                 {   // upper left plus offset within matrix
     618             :                     double fVal;
     619           0 :                     ScRange aRange;
     620           0 :                     PopDoubleRef( aRange );
     621           0 :                     if ( nGlobalError )
     622             :                     {
     623           0 :                         fVal = CreateDoubleError( nGlobalError );
     624           0 :                         nGlobalError = 0;
     625           0 :                         pJumpMatrix->PutResultDouble( fVal, nC, nR );
     626             :                     }
     627             :                     else
     628             :                     {
     629             :                         // Do not modify the original range because we use it
     630             :                         // to adjust the size of the result matrix if necessary.
     631           0 :                         ScAddress aAdr( aRange.aStart);
     632           0 :                         sal_uLong nCol = (sal_uLong)aAdr.Col() + nC;
     633           0 :                         sal_uLong nRow = (sal_uLong)aAdr.Row() + nR;
     634           0 :                         if ((nCol > static_cast<sal_uLong>(aRange.aEnd.Col()) &&
     635           0 :                                     aRange.aEnd.Col() != aRange.aStart.Col())
     636           0 :                                 || (nRow > static_cast<sal_uLong>(aRange.aEnd.Row()) &&
     637           0 :                                     aRange.aEnd.Row() != aRange.aStart.Row()))
     638             :                           {
     639           0 :                             fVal = CreateDoubleError( NOTAVAILABLE );
     640           0 :                             pJumpMatrix->PutResultDouble( fVal, nC, nR );
     641             :                           }
     642             :                           else
     643             :                           {
     644             :                             // Replicate column and/or row of a vector if it is
     645             :                             // one. Note that this could be a range reference
     646             :                             // that in fact consists of only one cell, e.g. A1:A1
     647           0 :                             if (aRange.aEnd.Col() == aRange.aStart.Col())
     648           0 :                                 nCol = aRange.aStart.Col();
     649           0 :                             if (aRange.aEnd.Row() == aRange.aStart.Row())
     650           0 :                                 nRow = aRange.aStart.Row();
     651           0 :                             aAdr.SetCol( static_cast<SCCOL>(nCol) );
     652           0 :                             aAdr.SetRow( static_cast<SCROW>(nRow) );
     653           0 :                             ScRefCellValue aCell;
     654           0 :                             aCell.assign(*pDok, aAdr);
     655           0 :                             if (aCell.hasEmptyValue())
     656           0 :                                 pJumpMatrix->PutResultEmpty( nC, nR );
     657           0 :                             else if (aCell.hasNumeric())
     658             :                               {
     659           0 :                                 double fCellVal = GetCellValue(aAdr, aCell);
     660           0 :                                 if ( nGlobalError )
     661             :                                 {
     662             :                                     fCellVal = CreateDoubleError(
     663           0 :                                             nGlobalError);
     664           0 :                                     nGlobalError = 0;
     665             :                                 }
     666           0 :                                 pJumpMatrix->PutResultDouble( fCellVal, nC, nR );
     667             :                               }
     668             :                               else
     669             :                               {
     670           0 :                                 svl::SharedString aStr;
     671           0 :                                 GetCellString(aStr, aCell);
     672           0 :                                 if ( nGlobalError )
     673             :                                 {
     674             :                                     pJumpMatrix->PutResultDouble( CreateDoubleError(
     675           0 :                                                 nGlobalError), nC, nR);
     676           0 :                                     nGlobalError = 0;
     677             :                                 }
     678             :                                 else
     679           0 :                                     pJumpMatrix->PutResultString(aStr, nC, nR);
     680           0 :                             }
     681             :                           }
     682           0 :                         SCSIZE nParmCols = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
     683           0 :                         SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
     684           0 :                         lcl_AdjustJumpMatrix( pJumpMatrix, nParmCols, nParmRows );
     685             :                     }
     686             :                 }
     687           0 :                 break;
     688             :                 case svMatrix:
     689             :                 {   // match matrix offsets
     690             :                     double fVal;
     691           0 :                     ScMatrixRef pMat = PopMatrix();
     692           0 :                     if ( nGlobalError )
     693             :                     {
     694           0 :                         fVal = CreateDoubleError( nGlobalError );
     695           0 :                         nGlobalError = 0;
     696           0 :                         pJumpMatrix->PutResultDouble( fVal, nC, nR );
     697             :                     }
     698           0 :                     else if ( !pMat )
     699             :                     {
     700           0 :                         fVal = CreateDoubleError( errUnknownVariable );
     701           0 :                         pJumpMatrix->PutResultDouble( fVal, nC, nR );
     702             :                     }
     703             :                     else
     704             :                     {
     705             :                         SCSIZE nCols, nRows;
     706           0 :                         pMat->GetDimensions( nCols, nRows );
     707           0 :                         if ((nCols <= nC && nCols != 1) ||
     708           0 :                             (nRows <= nR && nRows != 1))
     709             :                         {
     710           0 :                             fVal = CreateDoubleError( NOTAVAILABLE );
     711           0 :                             pJumpMatrix->PutResultDouble( fVal, nC, nR );
     712             :                         }
     713             :                         else
     714             :                         {
     715           0 :                             lcl_storeJumpMatResult(pMat.get(), pJumpMatrix, nC, nR);
     716             :                         }
     717           0 :                         lcl_AdjustJumpMatrix( pJumpMatrix, nCols, nRows );
     718           0 :                     }
     719             :                 }
     720           0 :                 break;
     721             :                 case svError:
     722             :                 {
     723           0 :                     PopError();
     724           0 :                     double fVal = CreateDoubleError( nGlobalError);
     725           0 :                     nGlobalError = 0;
     726           0 :                     pJumpMatrix->PutResultDouble( fVal, nC, nR );
     727             :                 }
     728           0 :                 break;
     729             :                 default:
     730             :                 {
     731           0 :                     Pop();
     732           0 :                     double fVal = CreateDoubleError( errIllegalArgument);
     733           0 :                     pJumpMatrix->PutResultDouble( fVal, nC, nR );
     734             :                 }
     735             :             }
     736             :         }
     737             :     }
     738          14 :     bool bCont = pJumpMatrix->Next( nC, nR );
     739          14 :     if ( bCont )
     740             :     {
     741             :         double fBool;
     742             :         short nStart, nNext, nStop;
     743          12 :         pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
     744          30 :         while ( bCont && nStart == nNext )
     745             :         {   // push all results that have no jump path
     746           6 :             if ( bHasResMat && (GetDoubleErrorValue( fBool) != errJumpMatHasResult) )
     747             :             {
     748             :                 // a false without path results in an empty path value
     749           4 :                 if ( fBool == 0.0 )
     750           4 :                     pJumpMatrix->PutResultEmptyPath( nC, nR );
     751             :                 else
     752           0 :                     pJumpMatrix->PutResultDouble( fBool, nC, nR );
     753             :             }
     754           6 :             bCont = pJumpMatrix->Next( nC, nR );
     755           6 :             if ( bCont )
     756           2 :                 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
     757             :         }
     758          12 :         if ( bCont && nStart != nNext )
     759             :         {
     760           8 :             const ScTokenVec* pParams = pJumpMatrix->GetJumpParameters();
     761           8 :             if ( pParams )
     762             :             {
     763          36 :                 for ( ScTokenVec::const_iterator i = pParams->begin();
     764          24 :                         i != pParams->end(); ++i )
     765             :                 {
     766             :                     // This is not the current state of the interpreter, so
     767             :                     // push without error, and elements' errors are coded into
     768             :                     // double.
     769           6 :                     PushWithoutError( *(*i));
     770             :                 }
     771             :             }
     772           8 :             aCode.Jump( nStart, nNext, nStop );
     773             :         }
     774             :     }
     775          14 :     if ( !bCont )
     776             :     {   // we're done with it, throw away jump matrix, keep result
     777           6 :         ScMatrix* pResMat = pJumpMatrix->GetResultMatrix();
     778           6 :         pJumpMatrix = NULL;
     779           6 :         Pop();
     780           6 :         PushMatrix( pResMat );
     781             :         // Remove jump matrix from map and remember result matrix in case it
     782             :         // could be reused in another path of the same condition.
     783           6 :         if (pTokenMatrixMap)
     784             :         {
     785           6 :             pTokenMatrixMap->erase( pCur);
     786             :             pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
     787           6 :                         pStack[sp-1]));
     788             :         }
     789           6 :         return true;
     790             :     }
     791           8 :     return false;
     792             : }
     793             : 
     794        3058 : double ScInterpreter::Compare()
     795             : {
     796        3058 :     sc::Compare aComp;
     797        3058 :     aComp.mbIgnoreCase = pDok->GetDocOptions().IsIgnoreCase();
     798        9174 :     for( short i = 1; i >= 0; i-- )
     799             :     {
     800        6116 :         sc::Compare::Cell& rCell = aComp.maCells[i];
     801             : 
     802        6116 :         switch ( GetRawStackType() )
     803             :         {
     804             :             case svEmptyCell:
     805           0 :                 Pop();
     806           0 :                 rCell.mbEmpty = true;
     807           0 :                 break;
     808             :             case svMissing:
     809             :             case svDouble:
     810        6064 :                 rCell.mfValue = GetDouble();
     811        6064 :                 rCell.mbValue = true;
     812        6064 :                 break;
     813             :             case svString:
     814           8 :                 rCell.maStr = GetString();
     815           8 :                 rCell.mbValue = false;
     816           8 :                 break;
     817             :             case svDoubleRef :
     818             :             case svSingleRef :
     819             :             {
     820          44 :                 ScAddress aAdr;
     821          44 :                 if ( !PopDoubleRefOrSingleRef( aAdr ) )
     822           0 :                     break;
     823          44 :                 ScRefCellValue aCell;
     824          44 :                 aCell.assign(*pDok, aAdr);
     825          44 :                 if (aCell.hasEmptyValue())
     826          16 :                     rCell.mbEmpty = true;
     827          28 :                 else if (aCell.hasString())
     828             :                 {
     829           2 :                     svl::SharedString aStr;
     830           2 :                     GetCellString(aStr, aCell);
     831           2 :                     rCell.maStr = aStr;
     832           2 :                     rCell.mbValue = false;
     833             :                 }
     834             :                 else
     835             :                 {
     836          26 :                     rCell.mfValue = GetCellValue(aAdr, aCell);
     837          26 :                     rCell.mbValue = true;
     838          44 :                 }
     839             :             }
     840          44 :             break;
     841             :             case svExternalSingleRef:
     842             :             {
     843           0 :                 ScMatrixRef pMat = GetMatrix();
     844           0 :                 if (!pMat)
     845             :                 {
     846           0 :                     SetError( errIllegalParameter);
     847           0 :                     break;
     848             :                 }
     849             : 
     850             :                 SCSIZE nC, nR;
     851           0 :                 pMat->GetDimensions(nC, nR);
     852           0 :                 if (!nC || !nR)
     853             :                 {
     854           0 :                     SetError( errIllegalParameter);
     855           0 :                     break;
     856             :                 }
     857           0 :                 if (pMat->IsEmpty(0, 0))
     858           0 :                     rCell.mbEmpty = true;
     859           0 :                 else if (pMat->IsString(0, 0))
     860             :                 {
     861           0 :                     rCell.maStr = pMat->GetString(0, 0);
     862           0 :                     rCell.mbValue = false;
     863             :                 }
     864             :                 else
     865             :                 {
     866           0 :                     rCell.mfValue = pMat->GetDouble(0, 0);
     867           0 :                     rCell.mbValue = true;
     868           0 :                 }
     869             :             }
     870           0 :             break;
     871             :             case svExternalDoubleRef:
     872             :                 // TODO: Find out how to handle this...
     873             :             default:
     874           0 :                 SetError( errIllegalParameter);
     875           0 :             break;
     876             :         }
     877             :     }
     878        3058 :     if( nGlobalError )
     879           0 :         return 0;
     880        3058 :     nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
     881        3058 :     return sc::CompareFunc(aComp.maCells[0], aComp.maCells[1], aComp.mbIgnoreCase);
     882             : }
     883             : 
     884          26 : sc::RangeMatrix ScInterpreter::CompareMat( ScQueryOp eOp, sc::CompareOptions* pOptions )
     885             : {
     886          26 :     sc::Compare aComp;
     887          26 :     aComp.meOp = eOp;
     888          26 :     aComp.mbIgnoreCase = pDok->GetDocOptions().IsIgnoreCase();
     889          52 :     sc::RangeMatrix aMat[2];
     890          26 :     ScAddress aAdr;
     891          78 :     for( short i = 1; i >= 0; i-- )
     892             :     {
     893          52 :         sc::Compare::Cell& rCell = aComp.maCells[i];
     894             : 
     895          52 :         switch (GetRawStackType())
     896             :         {
     897             :             case svEmptyCell:
     898           0 :                 Pop();
     899           0 :                 rCell.mbEmpty = true;
     900           0 :                 break;
     901             :             case svMissing:
     902             :             case svDouble:
     903           0 :                 rCell.mfValue = GetDouble();
     904           0 :                 rCell.mbValue = true;
     905           0 :                 break;
     906             :             case svString:
     907           2 :                 rCell.maStr = GetString();
     908           2 :                 rCell.mbValue = false;
     909           2 :                 break;
     910             :             case svSingleRef:
     911             :             {
     912          24 :                 PopSingleRef( aAdr );
     913          24 :                 ScRefCellValue aCell;
     914          24 :                 aCell.assign(*pDok, aAdr);
     915          24 :                 if (aCell.hasEmptyValue())
     916           0 :                     rCell.mbEmpty = true;
     917          24 :                 else if (aCell.hasString())
     918             :                 {
     919          12 :                     svl::SharedString aStr;
     920          12 :                     GetCellString(aStr, aCell);
     921          12 :                     rCell.maStr = aStr;
     922          12 :                     rCell.mbValue = false;
     923             :                 }
     924             :                 else
     925             :                 {
     926          12 :                     rCell.mfValue = GetCellValue(aAdr, aCell);
     927          12 :                     rCell.mbValue = true;
     928          24 :                 }
     929             :             }
     930          24 :             break;
     931             :             case svDoubleRef:
     932             :             case svMatrix:
     933          26 :                 aMat[i] = GetRangeMatrix();
     934          26 :                 if (!aMat[i].mpMat)
     935           0 :                     SetError( errIllegalParameter);
     936             :                 else
     937          26 :                     aMat[i].mpMat->SetErrorInterpreter(NULL);
     938             :                     // errors are transported as DoubleError inside matrix
     939          26 :                 break;
     940             :             default:
     941           0 :                 SetError( errIllegalParameter);
     942           0 :             break;
     943             :         }
     944             :     }
     945             : 
     946          26 :     sc::RangeMatrix aRes;
     947             : 
     948          26 :     if (nGlobalError)
     949             :     {
     950           0 :         nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
     951           0 :         return aRes;
     952             :     }
     953             : 
     954          26 :     if (aMat[0].mpMat && aMat[1].mpMat)
     955             :     {
     956             :         SCSIZE nC0, nC1;
     957             :         SCSIZE nR0, nR1;
     958           0 :         aMat[0].mpMat->GetDimensions(nC0, nR0);
     959           0 :         aMat[1].mpMat->GetDimensions(nC1, nR1);
     960           0 :         SCSIZE nC = std::max( nC0, nC1 );
     961           0 :         SCSIZE nR = std::max( nR0, nR1 );
     962           0 :         aRes.mpMat = GetNewMat( nC, nR);
     963           0 :         if (!aRes.mpMat)
     964           0 :             return aRes;
     965           0 :         for ( SCSIZE j=0; j<nC; j++ )
     966             :         {
     967           0 :             for ( SCSIZE k=0; k<nR; k++ )
     968             :             {
     969           0 :                 SCSIZE nCol = j, nRow = k;
     970           0 :                 if (aMat[0].mpMat->ValidColRowOrReplicated(nCol, nRow) &&
     971           0 :                     aMat[1].mpMat->ValidColRowOrReplicated(nCol, nRow))
     972             :                 {
     973           0 :                     for ( short i=1; i>=0; i-- )
     974             :                     {
     975           0 :                         sc::Compare::Cell& rCell = aComp.maCells[i];
     976             : 
     977           0 :                         if (aMat[i].mpMat->IsString(j, k))
     978             :                         {
     979           0 :                             rCell.mbValue = false;
     980           0 :                             rCell.maStr = aMat[i].mpMat->GetString(j, k);
     981           0 :                             rCell.mbEmpty = aMat[i].mpMat->IsEmpty(j, k);
     982             :                         }
     983             :                         else
     984             :                         {
     985           0 :                             rCell.mbValue = true;
     986           0 :                             rCell.mfValue = aMat[i].mpMat->GetDouble(j, k);
     987           0 :                             rCell.mbEmpty = false;
     988             :                         }
     989             :                     }
     990             :                     aRes.mpMat->PutDouble(
     991           0 :                         sc::CompareFunc(aComp.maCells[0], aComp.maCells[1], aComp.mbIgnoreCase, pOptions), j, k);
     992             :                 }
     993             :                 else
     994           0 :                     aRes.mpMat->PutString(mrStrPool.intern(ScGlobal::GetRscString(STR_NO_VALUE)), j, k);
     995             :             }
     996             :         }
     997             : 
     998           0 :         switch (eOp)
     999             :         {
    1000             :             case SC_EQUAL:
    1001           0 :                 aRes.mpMat->CompareEqual();
    1002           0 :                 break;
    1003             :             case SC_LESS:
    1004           0 :                 aRes.mpMat->CompareLess();
    1005           0 :                 break;
    1006             :             case SC_GREATER:
    1007           0 :                 aRes.mpMat->CompareGreater();
    1008           0 :                 break;
    1009             :             case SC_LESS_EQUAL:
    1010           0 :                 aRes.mpMat->CompareLessEqual();
    1011           0 :                 break;
    1012             :             case SC_GREATER_EQUAL:
    1013           0 :                 aRes.mpMat->CompareGreaterEqual();
    1014           0 :                 break;
    1015             :             case SC_NOT_EQUAL:
    1016           0 :                 aRes.mpMat->CompareNotEqual();
    1017           0 :                 break;
    1018             :             default:
    1019             :                 OSL_TRACE( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)eOp);
    1020           0 :                 aRes.mpMat.reset();
    1021           0 :                 return aRes;
    1022             :         }
    1023             :     }
    1024          26 :     else if (aMat[0].mpMat || aMat[1].mpMat)
    1025             :     {
    1026          26 :         size_t i = ( aMat[0].mpMat ? 0 : 1);
    1027             : 
    1028          26 :         aRes.mnCol1 = aMat[i].mnCol1;
    1029          26 :         aRes.mnRow1 = aMat[i].mnRow1;
    1030          26 :         aRes.mnTab1 = aMat[i].mnTab1;
    1031          26 :         aRes.mnCol2 = aMat[i].mnCol2;
    1032          26 :         aRes.mnRow2 = aMat[i].mnRow2;
    1033          26 :         aRes.mnTab2 = aMat[i].mnTab2;
    1034             : 
    1035          26 :         ScMatrix& rMat = *aMat[i].mpMat;
    1036          26 :         aRes.mpMat = rMat.CompareMatrix(aComp, i, pOptions);
    1037          26 :         if (!aRes.mpMat)
    1038           0 :             return aRes;
    1039             :     }
    1040             : 
    1041          26 :     nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1042          52 :     return aRes;
    1043             : }
    1044             : 
    1045           0 : ScMatrixRef ScInterpreter::QueryMat( const ScMatrixRef& pMat, sc::CompareOptions& rOptions )
    1046             : {
    1047           0 :     short nSaveCurFmtType = nCurFmtType;
    1048           0 :     short nSaveFuncFmtType = nFuncFmtType;
    1049           0 :     PushMatrix( pMat);
    1050           0 :     const ScQueryEntry::Item& rItem = rOptions.aQueryEntry.GetQueryItem();
    1051           0 :     if (rItem.meType == ScQueryEntry::ByString)
    1052           0 :         PushString(rItem.maString.getString());
    1053             :     else
    1054           0 :         PushDouble(rItem.mfVal);
    1055           0 :     ScMatrixRef pResultMatrix = CompareMat(rOptions.aQueryEntry.eOp, &rOptions).mpMat;
    1056           0 :     nCurFmtType = nSaveCurFmtType;
    1057           0 :     nFuncFmtType = nSaveFuncFmtType;
    1058           0 :     if (nGlobalError || !pResultMatrix)
    1059             :     {
    1060           0 :         SetError( errIllegalParameter);
    1061           0 :         return pResultMatrix;
    1062             :     }
    1063             : 
    1064           0 :     return pResultMatrix;
    1065             : }
    1066             : 
    1067        3068 : void ScInterpreter::ScEqual()
    1068             : {
    1069        3068 :     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
    1070             :     {
    1071          26 :         sc::RangeMatrix aMat = CompareMat(SC_EQUAL);
    1072          26 :         if (!aMat.mpMat)
    1073             :         {
    1074           0 :             PushIllegalParameter();
    1075        3068 :             return;
    1076             :         }
    1077             : 
    1078          26 :         PushMatrix(aMat);
    1079             :     }
    1080             :     else
    1081        3042 :         PushInt( int(Compare() == 0) );
    1082             : }
    1083             : 
    1084          10 : void ScInterpreter::ScNotEqual()
    1085             : {
    1086          10 :     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
    1087             :     {
    1088           0 :         sc::RangeMatrix aMat = CompareMat(SC_NOT_EQUAL);
    1089           0 :         if (!aMat.mpMat)
    1090             :         {
    1091           0 :             PushIllegalParameter();
    1092          10 :             return;
    1093             :         }
    1094             : 
    1095           0 :         PushMatrix(aMat);
    1096             :     }
    1097             :     else
    1098          10 :         PushInt( int(Compare() != 0) );
    1099             : }
    1100             : 
    1101           0 : void ScInterpreter::ScLess()
    1102             : {
    1103           0 :     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
    1104             :     {
    1105           0 :         sc::RangeMatrix aMat = CompareMat(SC_LESS);
    1106           0 :         if (!aMat.mpMat)
    1107             :         {
    1108           0 :             PushIllegalParameter();
    1109           0 :             return;
    1110             :         }
    1111             : 
    1112           0 :         PushMatrix(aMat);
    1113             :     }
    1114             :     else
    1115           0 :         PushInt( int(Compare() < 0) );
    1116             : }
    1117             : 
    1118           6 : void ScInterpreter::ScGreater()
    1119             : {
    1120           6 :     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
    1121             :     {
    1122           0 :         sc::RangeMatrix aMat = CompareMat(SC_GREATER);
    1123           0 :         if (!aMat.mpMat)
    1124             :         {
    1125           0 :             PushIllegalParameter();
    1126           6 :             return;
    1127             :         }
    1128             : 
    1129           0 :         PushMatrix(aMat);
    1130             :     }
    1131             :     else
    1132           6 :         PushInt( int(Compare() > 0) );
    1133             : }
    1134             : 
    1135           0 : void ScInterpreter::ScLessEqual()
    1136             : {
    1137           0 :     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
    1138             :     {
    1139           0 :         sc::RangeMatrix aMat = CompareMat(SC_LESS_EQUAL);
    1140           0 :         if (!aMat.mpMat)
    1141             :         {
    1142           0 :             PushIllegalParameter();
    1143           0 :             return;
    1144             :         }
    1145             : 
    1146           0 :         PushMatrix(aMat);
    1147             :     }
    1148             :     else
    1149           0 :         PushInt( int(Compare() <= 0) );
    1150             : }
    1151             : 
    1152           0 : void ScInterpreter::ScGreaterEqual()
    1153             : {
    1154           0 :     if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
    1155             :     {
    1156           0 :         sc::RangeMatrix aMat = CompareMat(SC_GREATER_EQUAL);
    1157           0 :         if (!aMat.mpMat)
    1158             :         {
    1159           0 :             PushIllegalParameter();
    1160           0 :             return;
    1161             :         }
    1162             : 
    1163           0 :         PushMatrix(aMat);
    1164             :     }
    1165             :     else
    1166           0 :         PushInt( int(Compare() >= 0) );
    1167             : }
    1168             : 
    1169          36 : void ScInterpreter::ScAnd()
    1170             : {
    1171          36 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1172          36 :     short nParamCount = GetByte();
    1173          36 :     if ( MustHaveParamCountMin( nParamCount, 1 ) )
    1174             :     {
    1175          36 :         bool bHaveValue = false;
    1176          36 :         bool nRes = true;
    1177          36 :         size_t nRefInList = 0;
    1178         128 :         while( nParamCount-- > 0)
    1179             :         {
    1180          56 :             if ( !nGlobalError )
    1181             :             {
    1182          56 :                 switch ( GetStackType() )
    1183             :                 {
    1184             :                     case svDouble :
    1185          26 :                         bHaveValue = true;
    1186          26 :                         nRes &= ( PopDouble() != 0.0 );
    1187          26 :                     break;
    1188             :                     case svString :
    1189           0 :                         Pop();
    1190           0 :                         SetError( errNoValue );
    1191           0 :                     break;
    1192             :                     case svSingleRef :
    1193             :                     {
    1194           0 :                         ScAddress aAdr;
    1195           0 :                         PopSingleRef( aAdr );
    1196           0 :                         if ( !nGlobalError )
    1197             :                         {
    1198           0 :                             ScRefCellValue aCell;
    1199           0 :                             aCell.assign(*pDok, aAdr);
    1200           0 :                             if (aCell.hasNumeric())
    1201             :                             {
    1202           0 :                                 bHaveValue = true;
    1203           0 :                                 nRes &= ( GetCellValue(aAdr, aCell) != 0.0 );
    1204           0 :                             }
    1205             :                             // else: Xcl raises no error here
    1206             :                         }
    1207             :                     }
    1208           0 :                     break;
    1209             :                     case svDoubleRef:
    1210             :                     case svRefList:
    1211             :                     {
    1212          22 :                         ScRange aRange;
    1213          22 :                         PopDoubleRef( aRange, nParamCount, nRefInList);
    1214          22 :                         if ( !nGlobalError )
    1215             :                         {
    1216             :                             double fVal;
    1217          22 :                             sal_uInt16 nErr = 0;
    1218          22 :                             ScValueIterator aValIter( pDok, aRange );
    1219          22 :                             if ( aValIter.GetFirst( fVal, nErr ) && nErr == 0 )
    1220             :                             {
    1221          22 :                                 bHaveValue = true;
    1222        2842 :                                 do
    1223             :                                 {
    1224        2842 :                                     nRes &= ( fVal != 0.0 );
    1225        5684 :                                 } while ( (nErr == 0) &&
    1226        2842 :                                     aValIter.GetNext( fVal, nErr ) );
    1227             :                             }
    1228          22 :                             SetError( nErr );
    1229             :                         }
    1230             :                     }
    1231          22 :                     break;
    1232             :                     case svExternalSingleRef:
    1233             :                     case svExternalDoubleRef:
    1234             :                     case svMatrix:
    1235             :                     {
    1236           8 :                         ScMatrixRef pMat = GetMatrix();
    1237           8 :                         if ( pMat )
    1238             :                         {
    1239           8 :                             bHaveValue = true;
    1240           8 :                             double fVal = pMat->And();
    1241           8 :                             sal_uInt16 nErr = GetDoubleErrorValue( fVal );
    1242           8 :                             if ( nErr )
    1243             :                             {
    1244           0 :                                 SetError( nErr );
    1245           0 :                                 nRes = false;
    1246             :                             }
    1247             :                             else
    1248           8 :                                 nRes &= (fVal != 0.0);
    1249           8 :                         }
    1250             :                         // else: GetMatrix did set errIllegalParameter
    1251             :                     }
    1252           8 :                     break;
    1253             :                     default:
    1254           0 :                         Pop();
    1255           0 :                         SetError( errIllegalParameter);
    1256             :                 }
    1257             :             }
    1258             :             else
    1259           0 :                 Pop();
    1260             :         }
    1261          36 :         if ( bHaveValue )
    1262          36 :             PushInt( int(nRes) );
    1263             :         else
    1264           0 :             PushNoValue();
    1265             :     }
    1266          36 : }
    1267             : 
    1268          26 : void ScInterpreter::ScOr()
    1269             : {
    1270          26 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1271          26 :     short nParamCount = GetByte();
    1272          26 :     if ( MustHaveParamCountMin( nParamCount, 1 ) )
    1273             :     {
    1274          26 :         bool bHaveValue = false;
    1275          26 :         bool nRes = false;
    1276          26 :         size_t nRefInList = 0;
    1277         108 :         while( nParamCount-- > 0)
    1278             :         {
    1279          56 :             if ( !nGlobalError )
    1280             :             {
    1281          56 :                 switch ( GetStackType() )
    1282             :                 {
    1283             :                     case svDouble :
    1284          40 :                         bHaveValue = true;
    1285          40 :                         nRes |= ( PopDouble() != 0.0 );
    1286          40 :                     break;
    1287             :                     case svString :
    1288           0 :                         Pop();
    1289           0 :                         SetError( errNoValue );
    1290           0 :                     break;
    1291             :                     case svSingleRef :
    1292             :                     {
    1293           0 :                         ScAddress aAdr;
    1294           0 :                         PopSingleRef( aAdr );
    1295           0 :                         if ( !nGlobalError )
    1296             :                         {
    1297           0 :                             ScRefCellValue aCell;
    1298           0 :                             aCell.assign(*pDok, aAdr);
    1299           0 :                             if (aCell.hasNumeric())
    1300             :                             {
    1301           0 :                                 bHaveValue = true;
    1302           0 :                                 nRes |= ( GetCellValue(aAdr, aCell) != 0.0 );
    1303           0 :                             }
    1304             :                             // else: Xcl raises no error here
    1305             :                         }
    1306             :                     }
    1307           0 :                     break;
    1308             :                     case svDoubleRef:
    1309             :                     case svRefList:
    1310             :                     {
    1311           0 :                         ScRange aRange;
    1312           0 :                         PopDoubleRef( aRange, nParamCount, nRefInList);
    1313           0 :                         if ( !nGlobalError )
    1314             :                         {
    1315             :                             double fVal;
    1316           0 :                             sal_uInt16 nErr = 0;
    1317           0 :                             ScValueIterator aValIter( pDok, aRange );
    1318           0 :                             if ( aValIter.GetFirst( fVal, nErr ) )
    1319             :                             {
    1320           0 :                                 bHaveValue = true;
    1321           0 :                                 do
    1322             :                                 {
    1323           0 :                                     nRes |= ( fVal != 0.0 );
    1324           0 :                                 } while ( (nErr == 0) &&
    1325           0 :                                     aValIter.GetNext( fVal, nErr ) );
    1326             :                             }
    1327           0 :                             SetError( nErr );
    1328             :                         }
    1329             :                     }
    1330           0 :                     break;
    1331             :                     case svExternalSingleRef:
    1332             :                     case svExternalDoubleRef:
    1333             :                     case svMatrix:
    1334             :                     {
    1335          16 :                         bHaveValue = true;
    1336          16 :                         ScMatrixRef pMat = GetMatrix();
    1337          16 :                         if ( pMat )
    1338             :                         {
    1339          16 :                             bHaveValue = true;
    1340          16 :                             double fVal = pMat->Or();
    1341          16 :                             sal_uInt16 nErr = GetDoubleErrorValue( fVal );
    1342          16 :                             if ( nErr )
    1343             :                             {
    1344           0 :                                 SetError( nErr );
    1345           0 :                                 nRes = false;
    1346             :                             }
    1347             :                             else
    1348          16 :                                 nRes |= (fVal != 0.0);
    1349          16 :                         }
    1350             :                         // else: GetMatrix did set errIllegalParameter
    1351             :                     }
    1352          16 :                     break;
    1353             :                     default:
    1354           0 :                         Pop();
    1355           0 :                         SetError( errIllegalParameter);
    1356             :                 }
    1357             :             }
    1358             :             else
    1359           0 :                 Pop();
    1360             :         }
    1361          26 :         if ( bHaveValue )
    1362          26 :             PushInt( int(nRes) );
    1363             :         else
    1364           0 :             PushNoValue();
    1365             :     }
    1366          26 : }
    1367             : 
    1368           0 : void ScInterpreter::ScXor()
    1369             : {
    1370             : 
    1371           0 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1372           0 :     short nParamCount = GetByte();
    1373           0 :     if ( MustHaveParamCountMin( nParamCount, 1 ) )
    1374             :     {
    1375           0 :         bool bHaveValue = false;
    1376           0 :         bool nRes = false;
    1377           0 :         size_t nRefInList = 0;
    1378           0 :         while( nParamCount-- > 0)
    1379             :         {
    1380           0 :             if ( !nGlobalError )
    1381             :             {
    1382           0 :                 switch ( GetStackType() )
    1383             :                 {
    1384             :                     case svDouble :
    1385           0 :                         bHaveValue = true;
    1386           0 :                         nRes ^= ( PopDouble() != 0.0 );
    1387           0 :                     break;
    1388             :                     case svString :
    1389           0 :                         Pop();
    1390           0 :                         SetError( errNoValue );
    1391           0 :                     break;
    1392             :                     case svSingleRef :
    1393             :                     {
    1394           0 :                         ScAddress aAdr;
    1395           0 :                         PopSingleRef( aAdr );
    1396           0 :                         if ( !nGlobalError )
    1397             :                         {
    1398           0 :                             ScRefCellValue aCell;
    1399           0 :                             aCell.assign(*pDok, aAdr);
    1400           0 :                             if (aCell.hasNumeric())
    1401             :                             {
    1402           0 :                                 bHaveValue = true;
    1403           0 :                                 nRes ^= ( GetCellValue(aAdr, aCell) != 0.0 );
    1404           0 :                             }
    1405             :                             /* TODO: set error? Excel doesn't have XOR, but
    1406             :                              * doesn't set an error in this case for AND and
    1407             :                              * OR. */
    1408             :                         }
    1409             :                     }
    1410           0 :                     break;
    1411             :                     case svDoubleRef:
    1412             :                     case svRefList:
    1413             :                     {
    1414           0 :                         ScRange aRange;
    1415           0 :                         PopDoubleRef( aRange, nParamCount, nRefInList);
    1416           0 :                         if ( !nGlobalError )
    1417             :                         {
    1418             :                             double fVal;
    1419           0 :                             sal_uInt16 nErr = 0;
    1420           0 :                             ScValueIterator aValIter( pDok, aRange );
    1421           0 :                             if ( aValIter.GetFirst( fVal, nErr ) )
    1422             :                             {
    1423           0 :                                 bHaveValue = true;
    1424           0 :                                 do
    1425             :                                 {
    1426           0 :                                     nRes ^= ( fVal != 0.0 );
    1427           0 :                                 } while ( (nErr == 0) &&
    1428           0 :                                     aValIter.GetNext( fVal, nErr ) );
    1429             :                             }
    1430           0 :                             SetError( nErr );
    1431             :                         }
    1432             :                     }
    1433           0 :                     break;
    1434             :                     case svExternalSingleRef:
    1435             :                     case svExternalDoubleRef:
    1436             :                     case svMatrix:
    1437             :                     {
    1438           0 :                         bHaveValue = true;
    1439           0 :                         ScMatrixRef pMat = GetMatrix();
    1440           0 :                         if ( pMat )
    1441             :                         {
    1442           0 :                             bHaveValue = true;
    1443           0 :                             double fVal = pMat->Xor();
    1444           0 :                             sal_uInt16 nErr = GetDoubleErrorValue( fVal );
    1445           0 :                             if ( nErr )
    1446             :                             {
    1447           0 :                                 SetError( nErr );
    1448           0 :                                 nRes = false;
    1449             :                             }
    1450             :                             else
    1451           0 :                                 nRes ^= ( fVal != 0.0 );
    1452           0 :                         }
    1453             :                         // else: GetMatrix did set errIllegalParameter
    1454             :                     }
    1455           0 :                     break;
    1456             :                     default:
    1457           0 :                         Pop();
    1458           0 :                         SetError( errIllegalParameter);
    1459             :                 }
    1460             :             }
    1461             :             else
    1462           0 :                 Pop();
    1463             :         }
    1464           0 :         if ( bHaveValue )
    1465           0 :             PushInt( int(nRes) );
    1466             :         else
    1467           0 :             PushNoValue();
    1468             :     }
    1469           0 : }
    1470             : 
    1471         152 : void ScInterpreter::ScNeg()
    1472             : {
    1473             :     // Simple negation doesn't change current format type to number, keep
    1474             :     // current type.
    1475         152 :     nFuncFmtType = nCurFmtType;
    1476         152 :     switch ( GetStackType() )
    1477             :     {
    1478             :         case svMatrix :
    1479             :         {
    1480           0 :             ScMatrixRef pMat = GetMatrix();
    1481           0 :             if ( !pMat )
    1482           0 :                 PushIllegalParameter();
    1483             :             else
    1484             :             {
    1485             :                 SCSIZE nC, nR;
    1486           0 :                 pMat->GetDimensions( nC, nR );
    1487           0 :                 ScMatrixRef pResMat = GetNewMat( nC, nR);
    1488           0 :                 if ( !pResMat )
    1489           0 :                     PushIllegalArgument();
    1490             :                 else
    1491             :                 {
    1492           0 :                     for (SCSIZE i = 0; i < nC; ++i)
    1493             :                     {
    1494           0 :                         for (SCSIZE j = 0; j < nR; ++j)
    1495             :                         {
    1496           0 :                             if ( pMat->IsValueOrEmpty(i,j) )
    1497           0 :                                 pResMat->PutDouble( -pMat->GetDouble(i,j), i, j );
    1498             :                             else
    1499             :                                 pResMat->PutString(
    1500           0 :                                     mrStrPool.intern(ScGlobal::GetRscString(STR_NO_VALUE)), i, j);
    1501             :                         }
    1502             :                     }
    1503           0 :                     PushMatrix( pResMat );
    1504           0 :                 }
    1505           0 :             }
    1506             :         }
    1507           0 :         break;
    1508             :         default:
    1509         152 :             PushDouble( -GetDouble() );
    1510             :     }
    1511         152 : }
    1512             : 
    1513           0 : void ScInterpreter::ScPercentSign()
    1514             : {
    1515           0 :     nFuncFmtType = NUMBERFORMAT_PERCENT;
    1516           0 :     const FormulaToken* pSaveCur = pCur;
    1517           0 :     sal_uInt8 nSavePar = cPar;
    1518           0 :     PushInt( 100 );
    1519           0 :     cPar = 2;
    1520           0 :     FormulaByteToken aDivOp( ocDiv, cPar );
    1521           0 :     pCur = &aDivOp;
    1522           0 :     ScDiv();
    1523           0 :     pCur = pSaveCur;
    1524           0 :     cPar = nSavePar;
    1525           0 : }
    1526             : 
    1527           8 : void ScInterpreter::ScNot()
    1528             : {
    1529           8 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1530           8 :     switch ( GetStackType() )
    1531             :     {
    1532             :         case svMatrix :
    1533             :         {
    1534           0 :             ScMatrixRef pMat = GetMatrix();
    1535           0 :             if ( !pMat )
    1536           0 :                 PushIllegalParameter();
    1537             :             else
    1538             :             {
    1539             :                 SCSIZE nC, nR;
    1540           0 :                 pMat->GetDimensions( nC, nR );
    1541           0 :                 ScMatrixRef pResMat = GetNewMat( nC, nR);
    1542           0 :                 if ( !pResMat )
    1543           0 :                     PushIllegalArgument();
    1544             :                 else
    1545             :                 {
    1546           0 :                     for (SCSIZE i = 0; i < nC; ++i)
    1547             :                     {
    1548           0 :                         for (SCSIZE j = 0; j < nR; ++j)
    1549             :                         {
    1550           0 :                             if ( pMat->IsValueOrEmpty(i,j) )
    1551           0 :                                 pResMat->PutDouble( double(pMat->GetDouble(i,j) == 0.0), i, j );
    1552             :                             else
    1553             :                                 pResMat->PutString(
    1554           0 :                                     mrStrPool.intern(ScGlobal::GetRscString(STR_NO_VALUE)), i, j);
    1555             :                         }
    1556             :                     }
    1557           0 :                     PushMatrix( pResMat );
    1558           0 :                 }
    1559           0 :             }
    1560             :         }
    1561           0 :         break;
    1562             :         default:
    1563           8 :             PushInt( int(GetDouble() == 0.0) );
    1564             :     }
    1565           8 : }
    1566             : 
    1567          12 : void ScInterpreter::ScBitAnd()
    1568             : {
    1569             : 
    1570          12 :     if ( !MustHaveParamCount( GetByte(), 2 ) )
    1571          12 :         return;
    1572             : 
    1573          12 :     double num1 = ::rtl::math::approxFloor( GetDouble());
    1574          12 :     double num2 = ::rtl::math::approxFloor( GetDouble());
    1575          12 :     if (    (num1 >= n2power48) || (num1 < 0) ||
    1576           8 :             (num2 >= n2power48) || (num2 < 0))
    1577           8 :         PushIllegalArgument();
    1578             :     else
    1579           4 :         PushDouble ((sal_uInt64) num1 & (sal_uInt64) num2);
    1580             : }
    1581             : 
    1582           8 : void ScInterpreter::ScBitOr()
    1583             : {
    1584             : 
    1585           8 :     if ( !MustHaveParamCount( GetByte(), 2 ) )
    1586           8 :         return;
    1587             : 
    1588           8 :     double num1 = ::rtl::math::approxFloor( GetDouble());
    1589           8 :     double num2 = ::rtl::math::approxFloor( GetDouble());
    1590           8 :     if (    (num1 >= n2power48) || (num1 < 0) ||
    1591           8 :             (num2 >= n2power48) || (num2 < 0))
    1592           4 :         PushIllegalArgument();
    1593             :     else
    1594           4 :         PushDouble ((sal_uInt64) num1 | (sal_uInt64) num2);
    1595             : }
    1596             : 
    1597           8 : void ScInterpreter::ScBitXor()
    1598             : {
    1599             : 
    1600           8 :     if ( !MustHaveParamCount( GetByte(), 2 ) )
    1601           8 :         return;
    1602             : 
    1603           8 :     double num1 = ::rtl::math::approxFloor( GetDouble());
    1604           8 :     double num2 = ::rtl::math::approxFloor( GetDouble());
    1605           8 :     if (    (num1 >= n2power48) || (num1 < 0) ||
    1606           8 :             (num2 >= n2power48) || (num2 < 0))
    1607           4 :         PushIllegalArgument();
    1608             :     else
    1609           4 :         PushDouble ((sal_uInt64) num1 ^ (sal_uInt64) num2);
    1610             : }
    1611             : 
    1612           8 : void ScInterpreter::ScBitLshift()
    1613             : {
    1614             : 
    1615           8 :     if ( !MustHaveParamCount( GetByte(), 2 ) )
    1616           8 :         return;
    1617             : 
    1618           8 :     double fShift = ::rtl::math::approxFloor( GetDouble());
    1619           8 :     double num = ::rtl::math::approxFloor( GetDouble());
    1620           8 :     if ((num >= n2power48) || (num < 0))
    1621           0 :         PushIllegalArgument();
    1622             :     else
    1623             :     {
    1624             :         double fRes;
    1625           8 :         if (fShift < 0)
    1626           4 :             fRes = ::rtl::math::approxFloor( num / pow( 2.0, -fShift));
    1627           4 :         else if (fShift == 0)
    1628           0 :             fRes = num;
    1629             :         else
    1630           4 :             fRes = num * pow( 2.0, fShift);
    1631           8 :         PushDouble( fRes);
    1632             :     }
    1633             : }
    1634             : 
    1635           8 : void ScInterpreter::ScBitRshift()
    1636             : {
    1637             : 
    1638           8 :     if ( !MustHaveParamCount( GetByte(), 2 ) )
    1639           8 :         return;
    1640             : 
    1641           8 :     double fShift = ::rtl::math::approxFloor( GetDouble());
    1642           8 :     double num = ::rtl::math::approxFloor( GetDouble());
    1643           8 :     if ((num >= n2power48) || (num < 0))
    1644           0 :         PushIllegalArgument();
    1645             :     else
    1646             :     {
    1647             :         double fRes;
    1648           8 :         if (fShift < 0)
    1649           4 :             fRes = num * pow( 2.0, -fShift);
    1650           4 :         else if (fShift == 0)
    1651           0 :             fRes = num;
    1652             :         else
    1653           4 :             fRes = ::rtl::math::approxFloor( num / pow( 2.0, fShift));
    1654           8 :         PushDouble( fRes);
    1655             :     }
    1656             : }
    1657             : 
    1658          34 : void ScInterpreter::ScPi()
    1659             : {
    1660          34 :     PushDouble(F_PI);
    1661          34 : }
    1662             : 
    1663           0 : void ScInterpreter::ScRandom()
    1664             : {
    1665           0 :     PushDouble(::comphelper::rng::uniform_real_distribution());
    1666           0 : }
    1667             : 
    1668          12 : void ScInterpreter::ScTrue()
    1669             : {
    1670          12 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1671          12 :     PushInt(1);
    1672          12 : }
    1673             : 
    1674           4 : void ScInterpreter::ScFalse()
    1675             : {
    1676           4 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1677           4 :     PushInt(0);
    1678           4 : }
    1679             : 
    1680           0 : void ScInterpreter::ScDeg()
    1681             : {
    1682           0 :     PushDouble((GetDouble() / F_PI) * 180.0);
    1683           0 : }
    1684             : 
    1685           0 : void ScInterpreter::ScRad()
    1686             : {
    1687           0 :     PushDouble(GetDouble() * (F_PI / 180));
    1688           0 : }
    1689             : 
    1690          30 : void ScInterpreter::ScSin()
    1691             : {
    1692          30 :     PushDouble(::rtl::math::sin(GetDouble()));
    1693          30 : }
    1694             : 
    1695           8 : void ScInterpreter::ScCos()
    1696             : {
    1697           8 :     PushDouble(::rtl::math::cos(GetDouble()));
    1698           8 : }
    1699             : 
    1700           0 : void ScInterpreter::ScTan()
    1701             : {
    1702           0 :     PushDouble(::rtl::math::tan(GetDouble()));
    1703           0 : }
    1704             : 
    1705           0 : void ScInterpreter::ScCot()
    1706             : {
    1707           0 :     PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
    1708           0 : }
    1709             : 
    1710           0 : void ScInterpreter::ScArcSin()
    1711             : {
    1712           0 :     PushDouble(asin(GetDouble()));
    1713           0 : }
    1714             : 
    1715          10 : void ScInterpreter::ScArcCos()
    1716             : {
    1717          10 :     PushDouble(acos(GetDouble()));
    1718          10 : }
    1719             : 
    1720           0 : void ScInterpreter::ScArcTan()
    1721             : {
    1722           0 :     PushDouble(atan(GetDouble()));
    1723           0 : }
    1724             : 
    1725          10 : void ScInterpreter::ScArcCot()
    1726             : {
    1727          10 :     PushDouble((F_PI2) - atan(GetDouble()));
    1728          10 : }
    1729             : 
    1730           0 : void ScInterpreter::ScSinHyp()
    1731             : {
    1732           0 :     PushDouble(sinh(GetDouble()));
    1733           0 : }
    1734             : 
    1735           0 : void ScInterpreter::ScCosHyp()
    1736             : {
    1737           0 :     PushDouble(cosh(GetDouble()));
    1738           0 : }
    1739             : 
    1740           0 : void ScInterpreter::ScTanHyp()
    1741             : {
    1742           0 :     PushDouble(tanh(GetDouble()));
    1743           0 : }
    1744             : 
    1745           0 : void ScInterpreter::ScCotHyp()
    1746             : {
    1747           0 :     PushDouble(1.0 / tanh(GetDouble()));
    1748           0 : }
    1749             : 
    1750           0 : void ScInterpreter::ScArcSinHyp()
    1751             : {
    1752           0 :     PushDouble( ::rtl::math::asinh( GetDouble()));
    1753           0 : }
    1754             : 
    1755           8 : void ScInterpreter::ScArcCosHyp()
    1756             : {
    1757           8 :     double fVal = GetDouble();
    1758           8 :     if (fVal < 1.0)
    1759           4 :         PushIllegalArgument();
    1760             :     else
    1761           4 :         PushDouble( ::rtl::math::acosh( fVal));
    1762           8 : }
    1763             : 
    1764           0 : void ScInterpreter::ScArcTanHyp()
    1765             : {
    1766           0 :     double fVal = GetDouble();
    1767           0 :     if (fabs(fVal) >= 1.0)
    1768           0 :         PushIllegalArgument();
    1769             :     else
    1770           0 :         PushDouble( ::rtl::math::atanh( fVal));
    1771           0 : }
    1772             : 
    1773           0 : void ScInterpreter::ScArcCotHyp()
    1774             : {
    1775           0 :     double nVal = GetDouble();
    1776           0 :     if (fabs(nVal) <= 1.0)
    1777           0 :         PushIllegalArgument();
    1778             :     else
    1779           0 :         PushDouble(0.5 * log((nVal + 1.0) / (nVal - 1.0)));
    1780           0 : }
    1781             : 
    1782           0 : void ScInterpreter::ScCosecant()
    1783             : {
    1784           0 :     PushDouble(1.0 / ::rtl::math::sin(GetDouble()));
    1785           0 : }
    1786             : 
    1787           0 : void ScInterpreter::ScSecant()
    1788             : {
    1789           0 :     PushDouble(1.0 / ::rtl::math::cos(GetDouble()));
    1790           0 : }
    1791             : 
    1792           0 : void ScInterpreter::ScCosecantHyp()
    1793             : {
    1794           0 :     PushDouble(1.0 / sinh(GetDouble()));
    1795           0 : }
    1796             : 
    1797           0 : void ScInterpreter::ScSecantHyp()
    1798             : {
    1799           0 :     PushDouble(1.0 / cosh(GetDouble()));
    1800           0 : }
    1801             : 
    1802           0 : void ScInterpreter::ScExp()
    1803             : {
    1804           0 :     PushDouble(exp(GetDouble()));
    1805           0 : }
    1806             : 
    1807         288 : void ScInterpreter::ScSqrt()
    1808             : {
    1809         288 :     double fVal = GetDouble();
    1810         288 :     if (fVal >= 0.0)
    1811          90 :         PushDouble(sqrt(fVal));
    1812             :     else
    1813         198 :         PushIllegalArgument();
    1814         288 : }
    1815             : 
    1816           8 : void ScInterpreter::ScIsEmpty()
    1817             : {
    1818           8 :     short nRes = 0;
    1819           8 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1820           8 :     switch ( GetRawStackType() )
    1821             :     {
    1822             :         case svEmptyCell:
    1823             :         {
    1824           0 :             FormulaTokenRef p = PopToken();
    1825           0 :             if (!static_cast<const ScEmptyCellToken*>(p.get())->IsInherited())
    1826           0 :                 nRes = 1;
    1827             :         }
    1828           0 :         break;
    1829             :         case svDoubleRef :
    1830             :         case svSingleRef :
    1831             :         {
    1832           8 :             ScAddress aAdr;
    1833           8 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    1834           0 :                 break;
    1835             :             // NOTE: this could test also on inherited emptiness, but then the
    1836             :             // cell tested wouldn't be empty. Must correspond with
    1837             :             // ScCountEmptyCells().
    1838           8 :             ScRefCellValue aCell;
    1839           8 :             aCell.assign(*pDok, aAdr);
    1840           8 :             if (aCell.meType == CELLTYPE_NONE)
    1841           2 :                 nRes = 1;
    1842             :         }
    1843           8 :         break;
    1844             :         case svExternalSingleRef:
    1845             :         case svExternalDoubleRef:
    1846             :         case svMatrix:
    1847             :         {
    1848           0 :             ScMatrixRef pMat = GetMatrix();
    1849           0 :             if ( !pMat )
    1850             :                 ;   // nothing
    1851           0 :             else if ( !pJumpMatrix )
    1852           0 :                 nRes = pMat->IsEmpty( 0, 0) ? 1 : 0;
    1853             :             else
    1854             :             {
    1855             :                 SCSIZE nCols, nRows, nC, nR;
    1856           0 :                 pMat->GetDimensions( nCols, nRows);
    1857           0 :                 pJumpMatrix->GetPos( nC, nR);
    1858           0 :                 if ( nC < nCols && nR < nRows )
    1859           0 :                     nRes = pMat->IsEmpty( nC, nR) ? 1 : 0;
    1860             :                 // else: false, not empty (which is what Xcl does)
    1861           0 :             }
    1862             :         }
    1863           0 :         break;
    1864             :         default:
    1865           0 :             Pop();
    1866             :     }
    1867           8 :     nGlobalError = 0;
    1868           8 :     PushInt( nRes );
    1869           8 : }
    1870             : 
    1871          32 : bool ScInterpreter::IsString()
    1872             : {
    1873          32 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1874          32 :     bool nRes = false;
    1875          32 :     switch ( GetRawStackType() )
    1876             :     {
    1877             :         case svString:
    1878           2 :             Pop();
    1879           2 :             nRes = true;
    1880           2 :         break;
    1881             :         case svDoubleRef :
    1882             :         case svSingleRef :
    1883             :         {
    1884          20 :             ScAddress aAdr;
    1885          20 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    1886           0 :                 break;
    1887             : 
    1888          20 :             ScRefCellValue aCell;
    1889          20 :             aCell.assign(*pDok, aAdr);
    1890          20 :             if (GetCellErrCode(aCell) == 0)
    1891             :             {
    1892          12 :                 switch (aCell.meType)
    1893             :                 {
    1894             :                     case CELLTYPE_STRING :
    1895             :                     case CELLTYPE_EDIT :
    1896           0 :                         nRes = true;
    1897           0 :                         break;
    1898             :                     case CELLTYPE_FORMULA :
    1899          12 :                         nRes = (!aCell.mpFormula->IsValue() && !aCell.mpFormula->IsEmpty());
    1900          12 :                         break;
    1901             :                     default:
    1902             :                         ; // nothing
    1903             :                 }
    1904          20 :             }
    1905             :         }
    1906          20 :         break;
    1907             :         case svMatrix:
    1908             :         {
    1909           0 :             ScMatrixRef pMat = PopMatrix();
    1910           0 :             if ( !pMat )
    1911             :                 ;   // nothing
    1912           0 :             else if ( !pJumpMatrix )
    1913           0 :                 nRes = pMat->IsString(0, 0) && !pMat->IsEmpty(0, 0);
    1914             :             else
    1915             :             {
    1916             :                 SCSIZE nCols, nRows, nC, nR;
    1917           0 :                 pMat->GetDimensions( nCols, nRows);
    1918           0 :                 pJumpMatrix->GetPos( nC, nR);
    1919           0 :                 if ( nC < nCols && nR < nRows )
    1920           0 :                     nRes = pMat->IsString( nC, nR) && !pMat->IsEmpty( nC, nR);
    1921           0 :             }
    1922             :         }
    1923           0 :         break;
    1924             :         default:
    1925          10 :             Pop();
    1926             :     }
    1927          32 :     nGlobalError = 0;
    1928          32 :     return nRes;
    1929             : }
    1930             : 
    1931          26 : void ScInterpreter::ScIsString()
    1932             : {
    1933          26 :     PushInt( int(IsString()) );
    1934          26 : }
    1935             : 
    1936           6 : void ScInterpreter::ScIsNonString()
    1937             : {
    1938           6 :     PushInt( int(!IsString()) );
    1939           6 : }
    1940             : 
    1941           8 : void ScInterpreter::ScIsLogical()
    1942             : {
    1943           8 :     bool nRes = false;
    1944           8 :     switch ( GetStackType() )
    1945             :     {
    1946             :         case svDoubleRef :
    1947             :         case svSingleRef :
    1948             :         {
    1949           2 :             ScAddress aAdr;
    1950           2 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    1951           0 :                 break;
    1952             : 
    1953           2 :             ScRefCellValue aCell;
    1954           2 :             aCell.assign(*pDok, aAdr);
    1955           2 :             if (GetCellErrCode(aCell) == 0)
    1956             :             {
    1957           2 :                 if (aCell.hasNumeric())
    1958             :                 {
    1959           2 :                     sal_uLong nFormat = GetCellNumberFormat(aAdr, aCell);
    1960           2 :                     nRes = (pFormatter->GetType(nFormat) == NUMBERFORMAT_LOGICAL);
    1961             :                 }
    1962           2 :             }
    1963             :         }
    1964           2 :         break;
    1965             :         case svMatrix:
    1966             :             // TODO: we don't have type information for arrays except
    1967             :             // numerical/string.
    1968             :         // Fall thru
    1969             :         default:
    1970           6 :             PopError();
    1971           6 :             if ( !nGlobalError )
    1972           6 :                 nRes = ( nCurFmtType == NUMBERFORMAT_LOGICAL );
    1973             :     }
    1974           8 :     nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
    1975           8 :     nGlobalError = 0;
    1976           8 :     PushInt( int(nRes) );
    1977           8 : }
    1978             : 
    1979          10 : void ScInterpreter::ScType()
    1980             : {
    1981          10 :     short nType = 0;
    1982          10 :     switch ( GetStackType() )
    1983             :     {
    1984             :         case svDoubleRef :
    1985             :         case svSingleRef :
    1986             :         {
    1987           2 :             ScAddress aAdr;
    1988           2 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    1989           0 :                 break;
    1990             : 
    1991           2 :             ScRefCellValue aCell;
    1992           2 :             aCell.assign(*pDok, aAdr);
    1993           2 :             if (GetCellErrCode(aCell) == 0)
    1994             :             {
    1995           2 :                 switch (aCell.meType)
    1996             :                 {
    1997             :                     // NOTE: this is Xcl nonsense!
    1998             :                     case CELLTYPE_STRING :
    1999             :                     case CELLTYPE_EDIT :
    2000           0 :                         nType = 2;
    2001           0 :                         break;
    2002             :                     case CELLTYPE_VALUE :
    2003             :                     {
    2004           0 :                         sal_uLong nFormat = GetCellNumberFormat(aAdr, aCell);
    2005           0 :                         if (pFormatter->GetType(nFormat) == NUMBERFORMAT_LOGICAL)
    2006           0 :                             nType = 4;
    2007             :                         else
    2008           0 :                             nType = 1;
    2009             :                     }
    2010           0 :                     break;
    2011             :                     case CELLTYPE_FORMULA :
    2012           2 :                         nType = 8;
    2013           2 :                         break;
    2014             :                     default:
    2015           0 :                         PushIllegalArgument();
    2016             :                 }
    2017             :             }
    2018             :             else
    2019           0 :                 nType = 16;
    2020             :         }
    2021           2 :         break;
    2022             :         case svString:
    2023           2 :             PopError();
    2024           2 :             if ( nGlobalError )
    2025             :             {
    2026           0 :                 nType = 16;
    2027           0 :                 nGlobalError = 0;
    2028             :             }
    2029             :             else
    2030           2 :                 nType = 2;
    2031           2 :         break;
    2032             :         case svMatrix:
    2033           2 :             PopMatrix();
    2034           2 :             if ( nGlobalError )
    2035             :             {
    2036           0 :                 nType = 16;
    2037           0 :                 nGlobalError = 0;
    2038             :             }
    2039             :             else
    2040           2 :                 nType = 64;
    2041             :                 // we could return the type of one element if in JumpMatrix or
    2042             :                 // ForceArray mode, but Xcl doesn't ...
    2043           2 :         break;
    2044             :         default:
    2045           4 :             PopError();
    2046           4 :             if ( nGlobalError )
    2047             :             {
    2048           2 :                 nType = 16;
    2049           2 :                 nGlobalError = 0;
    2050             :             }
    2051             :             else
    2052           2 :                 nType = 1;
    2053             :     }
    2054          10 :     PushInt( nType );
    2055          10 : }
    2056             : 
    2057           2 : static inline bool lcl_FormatHasNegColor( const SvNumberformat* pFormat )
    2058             : {
    2059           2 :     return pFormat && pFormat->GetColor( 1 );
    2060             : }
    2061             : 
    2062           2 : static inline bool lcl_FormatHasOpenPar( const SvNumberformat* pFormat )
    2063             : {
    2064           2 :     return pFormat && (pFormat->GetFormatstring().indexOf('(') != -1);
    2065             : }
    2066             : 
    2067             : namespace {
    2068             : 
    2069           0 : void getFormatString(SvNumberFormatter* pFormatter, sal_uLong nFormat, OUString& rFmtStr)
    2070             : {
    2071           0 :     bool        bAppendPrec = true;
    2072             :     sal_uInt16  nPrec, nLeading;
    2073             :     bool        bThousand, bIsRed;
    2074           0 :     pFormatter->GetFormatSpecialInfo( nFormat, bThousand, bIsRed, nPrec, nLeading );
    2075             : 
    2076           0 :     switch( pFormatter->GetType( nFormat ) )
    2077             :     {
    2078           0 :         case NUMBERFORMAT_NUMBER:       if(bThousand) rFmtStr = ","; else rFmtStr = "F"; break;
    2079           0 :         case NUMBERFORMAT_CURRENCY:     rFmtStr = "C";                                   break;
    2080           0 :         case NUMBERFORMAT_SCIENTIFIC:   rFmtStr = "S";                                   break;
    2081           0 :         case NUMBERFORMAT_PERCENT:      rFmtStr = "P";                                   break;
    2082             :         default:
    2083             :         {
    2084           0 :             bAppendPrec = false;
    2085           0 :             switch( pFormatter->GetIndexTableOffset( nFormat ) )
    2086             :             {
    2087             :                 case NF_DATE_SYSTEM_SHORT:
    2088             :                 case NF_DATE_SYS_DMMMYY:
    2089             :                 case NF_DATE_SYS_DDMMYY:
    2090             :                 case NF_DATE_SYS_DDMMYYYY:
    2091             :                 case NF_DATE_SYS_DMMMYYYY:
    2092             :                 case NF_DATE_DIN_DMMMYYYY:
    2093             :                 case NF_DATE_SYS_DMMMMYYYY:
    2094           0 :                 case NF_DATE_DIN_DMMMMYYYY: rFmtStr = "D1"; break;
    2095           0 :                 case NF_DATE_SYS_DDMMM:     rFmtStr = "D2"; break;
    2096           0 :                 case NF_DATE_SYS_MMYY:      rFmtStr = "D3"; break;
    2097             :                 case NF_DATETIME_SYSTEM_SHORT_HHMM:
    2098             :                 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
    2099           0 :                                             rFmtStr = "D4"; break;
    2100           0 :                 case NF_DATE_DIN_MMDD:      rFmtStr = "D5"; break;
    2101           0 :                 case NF_TIME_HHMMSSAMPM:    rFmtStr = "D6"; break;
    2102           0 :                 case NF_TIME_HHMMAMPM:      rFmtStr = "D7"; break;
    2103           0 :                 case NF_TIME_HHMMSS:        rFmtStr = "D8"; break;
    2104           0 :                 case NF_TIME_HHMM:          rFmtStr = "D9"; break;
    2105           0 :                 default:                    rFmtStr = "G";
    2106             :             }
    2107             :         }
    2108             :     }
    2109           0 :     if( bAppendPrec )
    2110           0 :         rFmtStr += OUString::number(nPrec);
    2111           0 :     const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
    2112           0 :     if( lcl_FormatHasNegColor( pFormat ) )
    2113           0 :         rFmtStr += "-";
    2114           0 :     if( lcl_FormatHasOpenPar( pFormat ) )
    2115           0 :         rFmtStr += "()";
    2116           0 : }
    2117             : 
    2118             : }
    2119             : 
    2120          56 : void ScInterpreter::ScCell()
    2121             : {   // ATTRIBUTE ; [REF]
    2122          56 :     sal_uInt8 nParamCount = GetByte();
    2123          56 :     if( MustHaveParamCount( nParamCount, 1, 2 ) )
    2124             :     {
    2125          56 :         ScAddress aCellPos( aPos );
    2126          56 :         bool bError = false;
    2127          56 :         if( nParamCount == 2 )
    2128             :         {
    2129          56 :             switch (GetStackType())
    2130             :             {
    2131             :                 case svExternalSingleRef:
    2132             :                 case svExternalDoubleRef:
    2133             :                 {
    2134             :                     // Let's handle external reference separately...
    2135           0 :                     ScCellExternal();
    2136          56 :                     return;
    2137             :                 }
    2138             :                 default:
    2139             :                     ;
    2140             :             }
    2141          56 :             bError = !PopDoubleRefOrSingleRef( aCellPos );
    2142             :         }
    2143          56 :         OUString aInfoType = GetString().getString();
    2144          56 :         if( bError || nGlobalError )
    2145           0 :             PushIllegalParameter();
    2146             :         else
    2147             :         {
    2148          56 :             ScRefCellValue aCell;
    2149          56 :             aCell.assign(*pDok, aCellPos);
    2150             : 
    2151          56 :             ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::GetLocale(), ocCell);
    2152             : 
    2153             : // *** ADDRESS INFO ***
    2154          56 :             if( aInfoType.equalsAscii( "COL" ) )
    2155             :             {   // column number (1-based)
    2156           6 :                 PushInt( aCellPos.Col() + 1 );
    2157             :             }
    2158          50 :             else if( aInfoType.equalsAscii( "ROW" ) )
    2159             :             {   // row number (1-based)
    2160           6 :                 PushInt( aCellPos.Row() + 1 );
    2161             :             }
    2162          44 :             else if( aInfoType.equalsAscii( "SHEET" ) )
    2163             :             {   // table number (1-based)
    2164           6 :                 PushInt( aCellPos.Tab() + 1 );
    2165             :             }
    2166          38 :             else if( aInfoType.equalsAscii( "ADDRESS" ) )
    2167             :             {   // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
    2168          10 :                 sal_uInt16 nFlags = (aCellPos.Tab() == aPos.Tab()) ? (SCA_ABS) : (SCA_ABS_3D);
    2169          10 :                 OUString aStr(aCellPos.Format(nFlags, pDok, pDok->GetAddressConvention()));
    2170          10 :                 PushString(aStr);
    2171             :             }
    2172          28 :             else if( aInfoType.equalsAscii( "FILENAME" ) )
    2173             :             {   // file name and table name: 'FILENAME'#$TABLE
    2174           0 :                 SCTAB nTab = aCellPos.Tab();
    2175           0 :                 OUString aFuncResult;
    2176           0 :                 if( nTab < pDok->GetTableCount() )
    2177             :                 {
    2178           0 :                     if( pDok->GetLinkMode( nTab ) == SC_LINK_VALUE )
    2179           0 :                         pDok->GetName( nTab, aFuncResult );
    2180             :                     else
    2181             :                     {
    2182           0 :                         SfxObjectShell* pShell = pDok->GetDocumentShell();
    2183           0 :                         if( pShell && pShell->GetMedium() )
    2184             :                         {
    2185           0 :                             OUStringBuffer aBuf;
    2186           0 :                             aBuf.append('\'');
    2187           0 :                             const INetURLObject& rURLObj = pShell->GetMedium()->GetURLObject();
    2188           0 :                             aBuf.append(rURLObj.GetMainURL(INetURLObject::DECODE_UNAMBIGUOUS));
    2189           0 :                             aBuf.appendAscii("'#$");
    2190           0 :                             OUString aTabName;
    2191           0 :                             pDok->GetName( nTab, aTabName );
    2192           0 :                             aBuf.append(aTabName);
    2193           0 :                             aFuncResult = aBuf.makeStringAndClear();
    2194             :                         }
    2195             :                     }
    2196             :                 }
    2197           0 :                 PushString( aFuncResult );
    2198             :             }
    2199          28 :             else if( aInfoType.equalsAscii( "COORD" ) )
    2200             :             {   // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
    2201             :                 // Yes, passing tab as col is intentional!
    2202           0 :                 OUStringBuffer aFuncResult;
    2203             :                 OUString aCellStr =
    2204           0 :                 ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format(
    2205           0 :                     (SCA_COL_ABSOLUTE|SCA_VALID_COL), NULL, pDok->GetAddressConvention() );
    2206           0 :                 aFuncResult.append(aCellStr);
    2207           0 :                 aFuncResult.append(':');
    2208           0 :                 aCellStr = aCellPos.Format((SCA_COL_ABSOLUTE|SCA_VALID_COL|SCA_ROW_ABSOLUTE|SCA_VALID_ROW),
    2209           0 :                                  NULL, pDok->GetAddressConvention());
    2210           0 :                 aFuncResult.append(aCellStr);
    2211           0 :                 PushString( aFuncResult.makeStringAndClear() );
    2212             :             }
    2213             : 
    2214             : // *** CELL PROPERTIES ***
    2215          28 :             else if( aInfoType.equalsAscii( "CONTENTS" ) )
    2216             :             {   // contents of the cell, no formatting
    2217           6 :                 if (aCell.hasString())
    2218             :                 {
    2219           2 :                     svl::SharedString aStr;
    2220           2 :                     GetCellString(aStr, aCell);
    2221           2 :                     PushString( aStr );
    2222             :                 }
    2223             :                 else
    2224           4 :                     PushDouble(GetCellValue(aCellPos, aCell));
    2225             :             }
    2226          22 :             else if( aInfoType.equalsAscii( "TYPE" ) )
    2227             :             {   // b = blank; l = string (label); v = otherwise (value)
    2228             :                 sal_Unicode c;
    2229          18 :                 if (aCell.hasString())
    2230           6 :                     c = 'l';
    2231             :                 else
    2232          12 :                     c = aCell.hasNumeric() ? 'v' : 'b';
    2233          18 :                 PushString( OUString(c) );
    2234             :             }
    2235           4 :             else if( aInfoType.equalsAscii( "WIDTH" ) )
    2236             :             {   // column width (rounded off as count of zero characters in standard font and size)
    2237           0 :                 Printer*    pPrinter = pDok->GetPrinter();
    2238           0 :                 MapMode     aOldMode( pPrinter->GetMapMode() );
    2239           0 :                 vcl::Font   aOldFont( pPrinter->GetFont() );
    2240           0 :                 vcl::Font   aDefFont;
    2241             : 
    2242           0 :                 pPrinter->SetMapMode( MAP_TWIP );
    2243             :                 // font color doesn't matter here
    2244           0 :                 pDok->GetDefPattern()->GetFont( aDefFont, SC_AUTOCOL_BLACK, pPrinter );
    2245           0 :                 pPrinter->SetFont( aDefFont );
    2246           0 :                 long nZeroWidth = pPrinter->GetTextWidth( OUString( '0' ) );
    2247           0 :                 pPrinter->SetFont( aOldFont );
    2248           0 :                 pPrinter->SetMapMode( aOldMode );
    2249           0 :                 int nZeroCount = (int)(pDok->GetColWidth( aCellPos.Col(), aCellPos.Tab() ) / nZeroWidth);
    2250           0 :                 PushInt( nZeroCount );
    2251             :             }
    2252           4 :             else if( aInfoType.equalsAscii( "PREFIX" ) )
    2253             :             {   // ' = left; " = right; ^ = centered
    2254           0 :                 sal_Unicode c = 0;
    2255           0 :                 if (aCell.hasString())
    2256             :                 {
    2257             :                     const SvxHorJustifyItem* pJustAttr = static_cast<const SvxHorJustifyItem*>(
    2258           0 :                         pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_HOR_JUSTIFY ));
    2259           0 :                     switch( pJustAttr->GetValue() )
    2260             :                     {
    2261             :                         case SVX_HOR_JUSTIFY_STANDARD:
    2262             :                         case SVX_HOR_JUSTIFY_LEFT:
    2263           0 :                         case SVX_HOR_JUSTIFY_BLOCK:     c = '\''; break;
    2264           0 :                         case SVX_HOR_JUSTIFY_CENTER:    c = '^';  break;
    2265           0 :                         case SVX_HOR_JUSTIFY_RIGHT:     c = '"';  break;
    2266           0 :                         case SVX_HOR_JUSTIFY_REPEAT:    c = '\\'; break;
    2267             :                     }
    2268             :                 }
    2269           0 :                 PushString( OUString(c) );
    2270             :             }
    2271           4 :             else if( aInfoType.equalsAscii( "PROTECT" ) )
    2272             :             {   // 1 = cell locked
    2273             :                 const ScProtectionAttr* pProtAttr = static_cast<const ScProtectionAttr*>(
    2274           0 :                     pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION ));
    2275           0 :                 PushInt( pProtAttr->GetProtection() ? 1 : 0 );
    2276             :             }
    2277             : 
    2278             : // *** FORMATTING ***
    2279           4 :             else if( aInfoType.equalsAscii( "FORMAT" ) )
    2280             :             {   // specific format code for standard formats
    2281           0 :                 OUString aFuncResult;
    2282           0 :                 sal_uLong   nFormat = pDok->GetNumberFormat( aCellPos );
    2283           0 :                 getFormatString(pFormatter, nFormat, aFuncResult);
    2284           0 :                 PushString( aFuncResult );
    2285             :             }
    2286           4 :             else if( aInfoType.equalsAscii( "COLOR" ) )
    2287             :             {   // 1 = negative values are colored, otherwise 0
    2288           2 :                 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
    2289           2 :                 PushInt( lcl_FormatHasNegColor( pFormat ) ? 1 : 0 );
    2290             :             }
    2291           2 :             else if( aInfoType.equalsAscii( "PARENTHESES" ) )
    2292             :             {   // 1 = format string contains a '(' character, otherwise 0
    2293           2 :                 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
    2294           2 :                 PushInt( lcl_FormatHasOpenPar( pFormat ) ? 1 : 0 );
    2295             :             }
    2296             :             else
    2297           0 :                 PushIllegalArgument();
    2298          56 :         }
    2299             :     }
    2300             : }
    2301             : 
    2302           0 : void ScInterpreter::ScCellExternal()
    2303             : {
    2304             :     sal_uInt16 nFileId;
    2305           0 :     OUString aTabName;
    2306             :     ScSingleRefData aRef;
    2307           0 :     ScExternalRefCache::TokenRef pToken;
    2308           0 :     ScExternalRefCache::CellFormat aFmt;
    2309           0 :     PopExternalSingleRef(nFileId, aTabName, aRef, pToken, &aFmt);
    2310           0 :     if (nGlobalError)
    2311             :     {
    2312           0 :         PushIllegalParameter();
    2313           0 :         return;
    2314             :     }
    2315             : 
    2316           0 :     OUString aInfoType = GetString().getString();
    2317           0 :     if (nGlobalError)
    2318             :     {
    2319           0 :         PushIllegalParameter();
    2320           0 :         return;
    2321             :     }
    2322             : 
    2323             :     SCCOL nCol;
    2324             :     SCROW nRow;
    2325             :     SCTAB nTab;
    2326           0 :     aRef.SetAbsTab(0); // external ref has a tab index of -1, which SingleRefToVars() don't like.
    2327           0 :     SingleRefToVars(aRef, nCol, nRow, nTab);
    2328           0 :     if (nGlobalError)
    2329             :     {
    2330           0 :         PushIllegalParameter();
    2331           0 :         return;
    2332             :     }
    2333           0 :     aRef.SetAbsTab(-1); // revert the value.
    2334             : 
    2335           0 :     ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::GetLocale(), ocCell);
    2336           0 :     ScExternalRefManager* pRefMgr = pDok->GetExternalRefManager();
    2337             : 
    2338           0 :     if ( aInfoType == "COL" )
    2339           0 :         PushInt(nCol + 1);
    2340           0 :     else if ( aInfoType == "ROW" )
    2341           0 :         PushInt(nRow + 1);
    2342           0 :     else if ( aInfoType == "SHEET" )
    2343             :     {
    2344             :         // For SHEET, No idea what number we should set, but let's always set
    2345             :         // 1 if the external sheet exists, no matter what sheet.  Excel does
    2346             :         // the same.
    2347           0 :         if (pRefMgr->getCacheTable(nFileId, aTabName, false, NULL).get())
    2348           0 :             PushInt(1);
    2349             :         else
    2350           0 :             SetError(errNoName);
    2351             :     }
    2352           0 :     else if ( aInfoType == "ADDRESS" )
    2353             :     {
    2354             :         // ODF 1.2 says we need to always display address using the ODF A1 grammar.
    2355           0 :         ScTokenArray aArray;
    2356           0 :         aArray.AddExternalSingleReference(nFileId, aTabName, aRef);
    2357           0 :         ScCompiler aComp(pDok, aPos, aArray);
    2358           0 :         aComp.SetGrammar(formula::FormulaGrammar::GRAM_ODFF_A1);
    2359           0 :         OUString aStr;
    2360           0 :         aComp.CreateStringFromTokenArray(aStr);
    2361           0 :         PushString(aStr);
    2362             :     }
    2363           0 :     else if ( aInfoType == "FILENAME" )
    2364             :     {
    2365             :         // 'file URI'#$SheetName
    2366             : 
    2367           0 :         const OUString* p = pRefMgr->getExternalFileName(nFileId);
    2368           0 :         if (!p)
    2369             :         {
    2370             :             // In theory this should never happen...
    2371           0 :             SetError(errNoName);
    2372           0 :             return;
    2373             :         }
    2374             : 
    2375           0 :         OUStringBuffer aBuf;
    2376           0 :         aBuf.append('\'');
    2377           0 :         aBuf.append(*p);
    2378           0 :         aBuf.appendAscii("'#$");
    2379           0 :         aBuf.append(aTabName);
    2380           0 :         PushString(aBuf.makeStringAndClear());
    2381             :     }
    2382           0 :     else if ( aInfoType == "CONTENTS" )
    2383             :     {
    2384           0 :         switch (pToken->GetType())
    2385             :         {
    2386             :             case svString:
    2387           0 :                 PushString(pToken->GetString());
    2388           0 :             break;
    2389             :             case svDouble:
    2390           0 :                 PushString(OUString::number(pToken->GetDouble()));
    2391           0 :             break;
    2392             :             case svError:
    2393           0 :                 PushString(ScGlobal::GetErrorString(pToken->GetError()));
    2394           0 :             break;
    2395             :             default:
    2396           0 :                 PushString(ScGlobal::GetEmptyOUString());
    2397             :         }
    2398             :     }
    2399           0 :     else if ( aInfoType == "TYPE" )
    2400             :     {
    2401           0 :         sal_Unicode c = 'v';
    2402           0 :         switch (pToken->GetType())
    2403             :         {
    2404             :             case svString:
    2405           0 :                 c = 'l';
    2406           0 :             break;
    2407             :             case svEmptyCell:
    2408           0 :                 c = 'b';
    2409           0 :             break;
    2410             :             default:
    2411             :                 ;
    2412             :         }
    2413           0 :         PushString(OUString(c));
    2414             :     }
    2415           0 :     else if ( aInfoType == "FORMAT" )
    2416             :     {
    2417           0 :         OUString aFmtStr;
    2418           0 :         sal_uLong nFmt = aFmt.mbIsSet ? aFmt.mnIndex : 0;
    2419           0 :         getFormatString(pFormatter, nFmt, aFmtStr);
    2420           0 :         PushString(aFmtStr);
    2421             :     }
    2422           0 :     else if ( aInfoType == "COLOR" )
    2423             :     {
    2424             :         // 1 = negative values are colored, otherwise 0
    2425           0 :         int nVal = 0;
    2426           0 :         if (aFmt.mbIsSet)
    2427             :         {
    2428           0 :             const SvNumberformat* pFormat = pFormatter->GetEntry(aFmt.mnIndex);
    2429           0 :             nVal = lcl_FormatHasNegColor(pFormat) ? 1 : 0;
    2430             :         }
    2431           0 :         PushInt(nVal);
    2432             :     }
    2433           0 :     else if ( aInfoType == "PARENTHESES" )
    2434             :     {
    2435             :         // 1 = format string contains a '(' character, otherwise 0
    2436           0 :         int nVal = 0;
    2437           0 :         if (aFmt.mbIsSet)
    2438             :         {
    2439           0 :             const SvNumberformat* pFormat = pFormatter->GetEntry(aFmt.mnIndex);
    2440           0 :             nVal = lcl_FormatHasOpenPar(pFormat) ? 1 : 0;
    2441             :         }
    2442           0 :         PushInt(nVal);
    2443             :     }
    2444             :     else
    2445           0 :         PushIllegalParameter();
    2446             : }
    2447             : 
    2448          14 : void ScInterpreter::ScIsRef()
    2449             : {
    2450          14 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2451          14 :     bool nRes = false;
    2452          14 :     switch ( GetStackType() )
    2453             :     {
    2454             :         case svSingleRef :
    2455             :         {
    2456           2 :             ScAddress aAdr;
    2457           2 :             PopSingleRef( aAdr );
    2458           2 :             if ( !nGlobalError )
    2459           2 :                 nRes = true;
    2460             :         }
    2461           2 :         break;
    2462             :         case svDoubleRef :
    2463             :         {
    2464           4 :             ScRange aRange;
    2465           4 :             PopDoubleRef( aRange );
    2466           4 :             if ( !nGlobalError )
    2467           4 :                 nRes = true;
    2468             :         }
    2469           4 :         break;
    2470             :         case svRefList :
    2471             :         {
    2472           0 :             FormulaTokenRef x = PopToken();
    2473           0 :             if ( !nGlobalError )
    2474           0 :                 nRes = !x.get()->GetRefList()->empty();
    2475             :         }
    2476           0 :         break;
    2477             :         default:
    2478           8 :             Pop();
    2479             :     }
    2480          14 :     nGlobalError = 0;
    2481          14 :     PushInt( int(nRes) );
    2482          14 : }
    2483             : 
    2484           8 : void ScInterpreter::ScIsValue()
    2485             : {
    2486           8 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2487           8 :     bool nRes = false;
    2488           8 :     switch ( GetRawStackType() )
    2489             :     {
    2490             :         case svDouble:
    2491           0 :             Pop();
    2492           0 :             nRes = true;
    2493           0 :         break;
    2494             :         case svDoubleRef :
    2495             :         case svSingleRef :
    2496             :         {
    2497           8 :             ScAddress aAdr;
    2498           8 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    2499           0 :                 break;
    2500             : 
    2501           8 :             ScRefCellValue aCell;
    2502           8 :             aCell.assign(*pDok, aAdr);
    2503           8 :             if (GetCellErrCode(aCell) == 0)
    2504             :             {
    2505           8 :                 switch (aCell.meType)
    2506             :                 {
    2507             :                     case CELLTYPE_VALUE :
    2508           0 :                         nRes = true;
    2509           0 :                         break;
    2510             :                     case CELLTYPE_FORMULA :
    2511           8 :                         nRes = (aCell.mpFormula->IsValue() && !aCell.mpFormula->IsEmpty());
    2512           8 :                         break;
    2513             :                     default:
    2514             :                         ; // nothing
    2515             :                 }
    2516           8 :             }
    2517             :         }
    2518           8 :         break;
    2519             :         case svMatrix:
    2520             :         {
    2521           0 :             ScMatrixRef pMat = PopMatrix();
    2522           0 :             if ( !pMat )
    2523             :                 ;   // nothing
    2524           0 :             else if ( !pJumpMatrix )
    2525             :             {
    2526           0 :                 if (pMat->GetErrorIfNotString( 0, 0) == 0)
    2527           0 :                     nRes = pMat->IsValue( 0, 0);
    2528             :             }
    2529             :             else
    2530             :             {
    2531             :                 SCSIZE nCols, nRows, nC, nR;
    2532           0 :                 pMat->GetDimensions( nCols, nRows);
    2533           0 :                 pJumpMatrix->GetPos( nC, nR);
    2534           0 :                 if ( nC < nCols && nR < nRows )
    2535           0 :                     if (pMat->GetErrorIfNotString( nC, nR) == 0)
    2536           0 :                         nRes = pMat->IsValue( nC, nR);
    2537           0 :             }
    2538             :         }
    2539           0 :         break;
    2540             :         default:
    2541           0 :             Pop();
    2542             :     }
    2543           8 :     nGlobalError = 0;
    2544           8 :     PushInt( int(nRes) );
    2545           8 : }
    2546             : 
    2547          52 : void ScInterpreter::ScIsFormula()
    2548             : {
    2549          52 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2550          52 :     bool nRes = false;
    2551          52 :     switch ( GetStackType() )
    2552             :     {
    2553             :         case svDoubleRef :
    2554             :         case svSingleRef :
    2555             :         {
    2556          52 :             ScAddress aAdr;
    2557          52 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    2558           0 :                 break;
    2559             : 
    2560          52 :             nRes = (pDok->GetCellType(aAdr) == CELLTYPE_FORMULA);
    2561             :         }
    2562          52 :         break;
    2563             :         default:
    2564           0 :             Pop();
    2565             :     }
    2566          52 :     nGlobalError = 0;
    2567          52 :     PushInt( int(nRes) );
    2568          52 : }
    2569             : 
    2570           8 : void ScInterpreter::ScFormula()
    2571             : {
    2572           8 :     OUString aFormula;
    2573           8 :     switch ( GetStackType() )
    2574             :     {
    2575             :         case svDoubleRef :
    2576             :         case svSingleRef :
    2577             :         {
    2578           8 :             ScAddress aAdr;
    2579           8 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    2580           0 :                 break;
    2581             : 
    2582           8 :             ScRefCellValue aCell;
    2583           8 :             aCell.assign(*pDok, aAdr);
    2584           8 :             switch (aCell.meType)
    2585             :             {
    2586             :                 case CELLTYPE_FORMULA :
    2587           8 :                     aCell.mpFormula->GetFormula(aFormula);
    2588           8 :                 break;
    2589             :                 default:
    2590           0 :                     SetError( NOTAVAILABLE );
    2591           8 :             }
    2592             :         }
    2593           8 :         break;
    2594             :         default:
    2595           0 :             Pop();
    2596           0 :             SetError( NOTAVAILABLE );
    2597             :     }
    2598           8 :     PushString( aFormula );
    2599           8 : }
    2600             : 
    2601          10 : void ScInterpreter::ScIsNV()
    2602             : {
    2603          10 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2604          10 :     bool nRes = false;
    2605          10 :     switch ( GetStackType() )
    2606             :     {
    2607             :         case svDoubleRef :
    2608             :         case svSingleRef :
    2609             :         {
    2610           6 :             ScAddress aAdr;
    2611           6 :             bool bOk = PopDoubleRefOrSingleRef( aAdr );
    2612           6 :             if ( nGlobalError == NOTAVAILABLE )
    2613           0 :                 nRes = true;
    2614           6 :             else if (bOk)
    2615             :             {
    2616           6 :                 ScRefCellValue aCell;
    2617           6 :                 aCell.assign(*pDok, aAdr);
    2618           6 :                 sal_uInt16 nErr = GetCellErrCode(aCell);
    2619           6 :                 nRes = (nErr == NOTAVAILABLE);
    2620             :             }
    2621             :         }
    2622           6 :         break;
    2623             :         case svMatrix:
    2624             :         {
    2625           0 :             ScMatrixRef pMat = PopMatrix();
    2626           0 :             if ( !pMat )
    2627             :                 ;   // nothing
    2628           0 :             else if ( !pJumpMatrix )
    2629           0 :                 nRes = (pMat->GetErrorIfNotString( 0, 0) == NOTAVAILABLE);
    2630             :             else
    2631             :             {
    2632             :                 SCSIZE nCols, nRows, nC, nR;
    2633           0 :                 pMat->GetDimensions( nCols, nRows);
    2634           0 :                 pJumpMatrix->GetPos( nC, nR);
    2635           0 :                 if ( nC < nCols && nR < nRows )
    2636           0 :                     nRes = (pMat->GetErrorIfNotString( nC, nR) == NOTAVAILABLE);
    2637           0 :             }
    2638             :         }
    2639           0 :         break;
    2640             :         default:
    2641           4 :             PopError();
    2642           4 :             if ( nGlobalError == NOTAVAILABLE )
    2643           2 :                 nRes = true;
    2644             :     }
    2645          10 :     nGlobalError = 0;
    2646          10 :     PushInt( int(nRes) );
    2647          10 : }
    2648             : 
    2649           8 : void ScInterpreter::ScIsErr()
    2650             : {
    2651           8 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2652           8 :     bool nRes = false;
    2653           8 :     switch ( GetStackType() )
    2654             :     {
    2655             :         case svDoubleRef :
    2656             :         case svSingleRef :
    2657             :         {
    2658           4 :             ScAddress aAdr;
    2659           4 :             bool bOk = PopDoubleRefOrSingleRef( aAdr );
    2660           4 :             if ( !bOk || (nGlobalError && nGlobalError != NOTAVAILABLE) )
    2661           0 :                 nRes = true;
    2662             :             else
    2663             :             {
    2664           4 :                 ScRefCellValue aCell;
    2665           4 :                 aCell.assign(*pDok, aAdr);
    2666           4 :                 sal_uInt16 nErr = GetCellErrCode(aCell);
    2667           4 :                 nRes = (nErr && nErr != NOTAVAILABLE);
    2668             :             }
    2669             :         }
    2670           4 :         break;
    2671             :         case svMatrix:
    2672             :         {
    2673           0 :             ScMatrixRef pMat = PopMatrix();
    2674           0 :             if ( nGlobalError || !pMat )
    2675           0 :                 nRes = ((nGlobalError && nGlobalError != NOTAVAILABLE) || !pMat);
    2676           0 :             else if ( !pJumpMatrix )
    2677             :             {
    2678           0 :                 sal_uInt16 nErr = pMat->GetErrorIfNotString( 0, 0);
    2679           0 :                 nRes = (nErr && nErr != NOTAVAILABLE);
    2680             :             }
    2681             :             else
    2682             :             {
    2683             :                 SCSIZE nCols, nRows, nC, nR;
    2684           0 :                 pMat->GetDimensions( nCols, nRows);
    2685           0 :                 pJumpMatrix->GetPos( nC, nR);
    2686           0 :                 if ( nC < nCols && nR < nRows )
    2687             :                 {
    2688           0 :                     sal_uInt16 nErr = pMat->GetErrorIfNotString( nC, nR);
    2689           0 :                     nRes = (nErr && nErr != NOTAVAILABLE);
    2690             :                 }
    2691           0 :             }
    2692             :         }
    2693           0 :         break;
    2694             :         default:
    2695           4 :             PopError();
    2696           4 :             if ( nGlobalError && nGlobalError != NOTAVAILABLE )
    2697           2 :                 nRes = true;
    2698             :     }
    2699           8 :     nGlobalError = 0;
    2700           8 :     PushInt( int(nRes) );
    2701           8 : }
    2702             : 
    2703          28 : void ScInterpreter::ScIsError()
    2704             : {
    2705          28 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2706          28 :     bool nRes = false;
    2707          28 :     switch ( GetStackType() )
    2708             :     {
    2709             :         case svDoubleRef :
    2710             :         case svSingleRef :
    2711             :         {
    2712          16 :             ScAddress aAdr;
    2713          16 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    2714             :             {
    2715           0 :                 nRes = true;
    2716           0 :                 break;
    2717             :             }
    2718          16 :             if ( nGlobalError )
    2719           0 :                 nRes = true;
    2720             :             else
    2721             :             {
    2722          16 :                 ScRefCellValue aCell;
    2723          16 :                 aCell.assign(*pDok, aAdr);
    2724          16 :                 nRes = (GetCellErrCode(aCell) != 0);
    2725             :             }
    2726             :         }
    2727          16 :         break;
    2728             :         case svMatrix:
    2729             :         {
    2730           0 :             ScMatrixRef pMat = PopMatrix();
    2731           0 :             if ( nGlobalError || !pMat )
    2732           0 :                 nRes = true;
    2733           0 :             else if ( !pJumpMatrix )
    2734           0 :                 nRes = (pMat->GetErrorIfNotString( 0, 0) != 0);
    2735             :             else
    2736             :             {
    2737             :                 SCSIZE nCols, nRows, nC, nR;
    2738           0 :                 pMat->GetDimensions( nCols, nRows);
    2739           0 :                 pJumpMatrix->GetPos( nC, nR);
    2740           0 :                 if ( nC < nCols && nR < nRows )
    2741           0 :                     nRes = (pMat->GetErrorIfNotString( nC, nR) != 0);
    2742           0 :             }
    2743             :         }
    2744           0 :         break;
    2745             :         default:
    2746          12 :             PopError();
    2747          12 :             if ( nGlobalError )
    2748          12 :                 nRes = true;
    2749             :     }
    2750          28 :     nGlobalError = 0;
    2751          28 :     PushInt( int(nRes) );
    2752          28 : }
    2753             : 
    2754          18 : bool ScInterpreter::IsEven()
    2755             : {
    2756          18 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    2757          18 :     bool nRes = false;
    2758          18 :     double fVal = 0.0;
    2759          18 :     switch ( GetStackType() )
    2760             :     {
    2761             :         case svDoubleRef :
    2762             :         case svSingleRef :
    2763             :         {
    2764           0 :             ScAddress aAdr;
    2765           0 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    2766           0 :                 break;
    2767             : 
    2768           0 :             ScRefCellValue aCell;
    2769           0 :             aCell.assign(*pDok, aAdr);
    2770           0 :             sal_uInt16 nErr = GetCellErrCode(aCell);
    2771           0 :             if (nErr != 0)
    2772           0 :                 SetError(nErr);
    2773             :             else
    2774             :             {
    2775           0 :                 switch (aCell.meType)
    2776             :                 {
    2777             :                     case CELLTYPE_VALUE :
    2778           0 :                         fVal = GetCellValue(aAdr, aCell);
    2779           0 :                         nRes = true;
    2780           0 :                     break;
    2781             :                     case CELLTYPE_FORMULA :
    2782           0 :                         if (aCell.mpFormula->IsValue())
    2783             :                         {
    2784           0 :                             fVal = GetCellValue(aAdr, aCell);
    2785           0 :                             nRes = true;
    2786             :                         }
    2787           0 :                     break;
    2788             :                     default:
    2789             :                         ; // nothing
    2790             :                 }
    2791           0 :             }
    2792             :         }
    2793           0 :         break;
    2794             :         case svDouble:
    2795             :         {
    2796          18 :             fVal = PopDouble();
    2797          18 :             nRes = true;
    2798             :         }
    2799          18 :         break;
    2800             :         case svMatrix:
    2801             :         {
    2802           0 :             ScMatrixRef pMat = PopMatrix();
    2803           0 :             if ( !pMat )
    2804             :                 ;   // nothing
    2805           0 :             else if ( !pJumpMatrix )
    2806             :             {
    2807           0 :                 nRes = pMat->IsValue( 0, 0);
    2808           0 :                 if ( nRes )
    2809           0 :                     fVal = pMat->GetDouble( 0, 0);
    2810             :             }
    2811             :             else
    2812             :             {
    2813             :                 SCSIZE nCols, nRows, nC, nR;
    2814           0 :                 pMat->GetDimensions( nCols, nRows);
    2815           0 :                 pJumpMatrix->GetPos( nC, nR);
    2816           0 :                 if ( nC < nCols && nR < nRows )
    2817             :                 {
    2818           0 :                     nRes = pMat->IsValue( nC, nR);
    2819           0 :                     if ( nRes )
    2820           0 :                         fVal = pMat->GetDouble( nC, nR);
    2821             :                 }
    2822             :                 else
    2823           0 :                     SetError( errNoValue);
    2824           0 :             }
    2825             :         }
    2826           0 :         break;
    2827             :         default:
    2828             :             ; // nothing
    2829             :     }
    2830          18 :     if ( !nRes )
    2831           0 :         SetError( errIllegalParameter);
    2832             :     else
    2833          18 :         nRes = ( fmod( ::rtl::math::approxFloor( fabs( fVal ) ), 2.0 ) < 0.5 );
    2834          18 :     return nRes;
    2835             : }
    2836             : 
    2837           8 : void ScInterpreter::ScIsEven()
    2838             : {
    2839           8 :     PushInt( int(IsEven()) );
    2840           8 : }
    2841             : 
    2842          10 : void ScInterpreter::ScIsOdd()
    2843             : {
    2844          10 :     PushInt( int(!IsEven()) );
    2845          10 : }
    2846             : 
    2847          46 : void ScInterpreter::ScN()
    2848             : {
    2849          46 :     sal_uInt16 nErr = nGlobalError;
    2850          46 :     nGlobalError = 0;
    2851             :     // Temporarily override the ConvertStringToValue() error for
    2852             :     // GetCellValue() / GetCellValueOrZero()
    2853          46 :     sal_uInt16 nSErr = mnStringNoValueError;
    2854          46 :     mnStringNoValueError = errCellNoValue;
    2855          46 :     double fVal = GetDouble();
    2856          46 :     mnStringNoValueError = nSErr;
    2857          46 :     if (nErr)
    2858           0 :         nGlobalError = nErr;    // preserve previous error if any
    2859          46 :     else if (nGlobalError == errCellNoValue)
    2860           8 :         nGlobalError = 0;       // reset temporary detection error
    2861          46 :     PushDouble(fVal);
    2862          46 : }
    2863             : 
    2864           2 : void ScInterpreter::ScTrim()
    2865             : {
    2866             :     // Doesn't only trim but also removes duplicated blanks within!
    2867           2 :     OUString aVal = comphelper::string::strip(GetString().getString(), ' ');
    2868           4 :     OUStringBuffer aStr;
    2869           2 :     const sal_Unicode* p = aVal.getStr();
    2870           2 :     const sal_Unicode* const pEnd = p + aVal.getLength();
    2871          58 :     while ( p < pEnd )
    2872             :     {
    2873          54 :         if ( *p != ' ' || p[-1] != ' ' )    // first can't be ' ', so -1 is fine
    2874          22 :             aStr.append(*p);
    2875          54 :         p++;
    2876             :     }
    2877           4 :     PushString(aStr.makeStringAndClear());
    2878           2 : }
    2879             : 
    2880           2 : void ScInterpreter::ScUpper()
    2881             : {
    2882           2 :     OUString aString = ScGlobal::pCharClass->uppercase(GetString().getString());
    2883           2 :     PushString(aString);
    2884           2 : }
    2885             : 
    2886           4 : void ScInterpreter::ScPropper()
    2887             : {
    2888             : //2do: what to do with I18N-CJK ?!?
    2889           4 :     OUStringBuffer aStr(GetString().getString());
    2890           4 :     const sal_Int32 nLen = aStr.getLength();
    2891           4 :     if ( nLen > 0 )
    2892             :     {
    2893           4 :         OUString aUpr(ScGlobal::pCharClass->uppercase(aStr.toString()));
    2894           8 :         OUString aLwr(ScGlobal::pCharClass->lowercase(aStr.toString()));
    2895           4 :         aStr[0] = aUpr[0];
    2896           4 :         sal_Int32 nPos = 1;
    2897          22 :         while( nPos < nLen )
    2898             :         {
    2899          14 :             OUString aTmpStr( aStr[nPos-1] );
    2900          14 :             if ( !ScGlobal::pCharClass->isLetter( aTmpStr, 0 ) )
    2901           0 :                 aStr[nPos] = aUpr[nPos];
    2902             :             else
    2903          14 :                 aStr[nPos] = aLwr[nPos];
    2904          14 :             ++nPos;
    2905          18 :         }
    2906             :     }
    2907           4 :     PushString(aStr.makeStringAndClear());
    2908           4 : }
    2909             : 
    2910           4 : void ScInterpreter::ScLower()
    2911             : {
    2912           4 :     OUString aString = ScGlobal::pCharClass->lowercase(GetString().getString());
    2913           4 :     PushString(aString);
    2914           4 : }
    2915             : 
    2916           8 : void ScInterpreter::ScLen()
    2917             : {
    2918           8 :     PushDouble(GetString().getLength());
    2919           8 : }
    2920             : 
    2921          12 : void ScInterpreter::ScT()
    2922             : {
    2923          12 :     switch ( GetStackType() )
    2924             :     {
    2925             :         case svDoubleRef :
    2926             :         case svSingleRef :
    2927             :         {
    2928           0 :             ScAddress aAdr;
    2929           0 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    2930             :             {
    2931           0 :                 PushInt(0);
    2932          12 :                 return ;
    2933             :             }
    2934           0 :             bool bValue = false;
    2935           0 :             ScRefCellValue aCell;
    2936           0 :             aCell.assign(*pDok, aAdr);
    2937           0 :             if (GetCellErrCode(aCell) == 0)
    2938             :             {
    2939           0 :                 switch (aCell.meType)
    2940             :                 {
    2941             :                     case CELLTYPE_VALUE :
    2942           0 :                         bValue = true;
    2943           0 :                         break;
    2944             :                     case CELLTYPE_FORMULA :
    2945           0 :                         bValue = aCell.mpFormula->IsValue();
    2946           0 :                         break;
    2947             :                     default:
    2948             :                         ; // nothing
    2949             :                 }
    2950             :             }
    2951           0 :             if ( bValue )
    2952           0 :                 PushString(EMPTY_OUSTRING);
    2953             :             else
    2954             :             {
    2955             :                 // like GetString()
    2956           0 :                 svl::SharedString aStr;
    2957           0 :                 GetCellString(aStr, aCell);
    2958           0 :                 PushString(aStr);
    2959           0 :             }
    2960             :         }
    2961           0 :         break;
    2962             :         case svMatrix:
    2963             :         case svExternalSingleRef:
    2964             :         case svExternalDoubleRef:
    2965             :         {
    2966             :             double fVal;
    2967           6 :             svl::SharedString aStr;
    2968           6 :             ScMatValType nMatValType = GetDoubleOrStringFromMatrix( fVal, aStr);
    2969           6 :             if (ScMatrix::IsValueType( nMatValType))
    2970           2 :                 PushString(svl::SharedString::getEmptyString());
    2971             :             else
    2972           4 :                 PushString( aStr);
    2973             :         }
    2974           6 :         break;
    2975             :         case svDouble :
    2976             :         {
    2977           4 :             PopError();
    2978           4 :             PushString( EMPTY_OUSTRING );
    2979             :         }
    2980           4 :         break;
    2981             :         case svString :
    2982             :             ;   // leave on stack
    2983           2 :         break;
    2984             :         default :
    2985           0 :             PushError( errUnknownOpCode);
    2986             :     }
    2987             : }
    2988             : 
    2989           2 : void ScInterpreter::ScValue()
    2990             : {
    2991           2 :     OUString aInputString;
    2992             :     double fVal;
    2993             : 
    2994           2 :     switch ( GetRawStackType() )
    2995             :     {
    2996             :         case svMissing:
    2997             :         case svEmptyCell:
    2998           0 :             Pop();
    2999           0 :             PushInt(0);
    3000           0 :             return;
    3001             :         case svDouble:
    3002           0 :             return;     // leave on stack
    3003             :             //break;
    3004             : 
    3005             :         case svSingleRef:
    3006             :         case svDoubleRef:
    3007             :         {
    3008           0 :             ScAddress aAdr;
    3009           0 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    3010             :             {
    3011           0 :                 PushInt(0);
    3012           0 :                 return;
    3013             :             }
    3014           0 :             ScRefCellValue aCell;
    3015           0 :             aCell.assign(*pDok, aAdr);
    3016           0 :             if (aCell.hasString())
    3017             :             {
    3018           0 :                 svl::SharedString aSS;
    3019           0 :                 GetCellString(aSS, aCell);
    3020           0 :                 aInputString = aSS.getString();
    3021             :             }
    3022           0 :             else if (aCell.hasNumeric())
    3023             :             {
    3024           0 :                 PushDouble( GetCellValue(aAdr, aCell) );
    3025           0 :                 return;
    3026             :             }
    3027             :             else
    3028             :             {
    3029           0 :                 PushDouble(0.0);
    3030           0 :                 return;
    3031           0 :             }
    3032             :         }
    3033           0 :         break;
    3034             :         case svMatrix:
    3035             :             {
    3036           0 :                 svl::SharedString aSS;
    3037             :                 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
    3038           0 :                         aSS);
    3039           0 :                 aInputString = aSS.getString();
    3040           0 :                 switch (nType)
    3041             :                 {
    3042             :                     case SC_MATVAL_EMPTY:
    3043           0 :                         fVal = 0.0;
    3044             :                         // fallthru
    3045             :                     case SC_MATVAL_VALUE:
    3046             :                     case SC_MATVAL_BOOLEAN:
    3047           0 :                         PushDouble( fVal);
    3048           0 :                         return;
    3049             :                         //break;
    3050             :                     case SC_MATVAL_STRING:
    3051             :                         // evaluated below
    3052           0 :                         break;
    3053             :                     default:
    3054           0 :                         PushIllegalArgument();
    3055           0 :                 }
    3056             :             }
    3057           0 :             break;
    3058             :         default:
    3059           2 :             aInputString = GetString().getString();
    3060           2 :             break;
    3061             :     }
    3062             : 
    3063           2 :     sal_uInt32 nFIndex = 0;     // 0 for default locale
    3064           2 :     if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
    3065           2 :         PushDouble(fVal);
    3066             :     else
    3067           0 :         PushIllegalArgument();
    3068             : }
    3069             : 
    3070             : // fdo#57180
    3071          20 : void ScInterpreter::ScNumberValue()
    3072             : {
    3073             : 
    3074          20 :     sal_uInt8 nParamCount = GetByte();
    3075          20 :     if ( !MustHaveParamCount( nParamCount, 1, 3 ) )
    3076          18 :         return;
    3077             : 
    3078          20 :     OUString aInputString;
    3079          22 :     OUString aDecimalSeparator, aGroupSeparator;
    3080          20 :     sal_Unicode cDecimalSeparator = 0;
    3081             : 
    3082          20 :     if ( nParamCount == 3 )
    3083          14 :         aGroupSeparator = GetString().getString();
    3084             : 
    3085          20 :     if ( nParamCount >= 2 )
    3086             :     {
    3087          20 :         aDecimalSeparator = GetString().getString();
    3088          20 :         if ( aDecimalSeparator.getLength() == 1  )
    3089          16 :             cDecimalSeparator = aDecimalSeparator[ 0 ];
    3090             :         else
    3091             :         {
    3092           4 :             PushIllegalArgument();  //if given, separator length must be 1
    3093           4 :             return;
    3094             :         }
    3095             :     }
    3096             : 
    3097          16 :     if ( cDecimalSeparator && aGroupSeparator.indexOf( cDecimalSeparator ) != -1 )
    3098             :     {
    3099           0 :         PushIllegalArgument(); //decimal separator cannot appear in group separator
    3100           0 :         return;
    3101             :     }
    3102             : 
    3103          16 :     switch (GetStackType())
    3104             :     {
    3105             :         case svDouble:
    3106           0 :         return; // leave on stack
    3107             :         default:
    3108          16 :         aInputString = GetString().getString();
    3109             :     }
    3110          16 :     if ( nGlobalError )
    3111             :     {
    3112           0 :         PushError( nGlobalError );
    3113           0 :         return;
    3114             :     }
    3115          16 :     if ( aInputString.isEmpty() )
    3116             :     {
    3117           0 :         if ( maCalcConfig.mbEmptyStringAsZero )
    3118           0 :             PushDouble( 0.0 );
    3119             :         else
    3120           0 :             PushNoValue();
    3121           0 :         return;
    3122             :     }
    3123             : 
    3124          16 :     sal_Int32 nDecSep = aInputString.indexOf( cDecimalSeparator );
    3125          16 :     if ( nDecSep != 0 )
    3126             :     {
    3127          14 :         OUString aTemporary( nDecSep >= 0 ? aInputString.copy( 0, nDecSep ) : aInputString );
    3128          14 :         sal_Int32 nIndex = 0;
    3129          44 :         while (nIndex < aGroupSeparator.getLength())
    3130             :         {
    3131          16 :             sal_uInt32 nChar = aGroupSeparator.iterateCodePoints( &nIndex );
    3132          16 :             aTemporary = aTemporary.replaceAll( OUString( &nChar, 1 ), "" );
    3133             :         }
    3134          14 :         if ( nDecSep >= 0 )
    3135          14 :             aInputString = aTemporary + aInputString.copy( nDecSep );
    3136             :         else
    3137           0 :             aInputString = aTemporary;
    3138             :     }
    3139             : 
    3140         178 :     for ( sal_Int32 i = aInputString.getLength(); --i >= 0; )
    3141             :     {
    3142         146 :         sal_Unicode c = aInputString[ i ];
    3143         146 :         if ( c == 0x0020 || c == 0x0009 || c == 0x000A || c == 0x000D )
    3144          18 :             aInputString = aInputString.replaceAt( i, 1, "" ); // remove spaces etc.
    3145             :     }
    3146          16 :     sal_Int32 nPercentCount = 0;
    3147          26 :     for ( sal_Int32 i = aInputString.getLength() - 1; i >= 0 && aInputString[ i ] == 0x0025; i-- )
    3148             :     {
    3149          10 :         aInputString = aInputString.replaceAt( i, 1, "" );  // remove and count trailing '%'
    3150          10 :         nPercentCount++;
    3151             :     }
    3152             : 
    3153             :     rtl_math_ConversionStatus eStatus;
    3154             :     sal_Int32 nParseEnd;
    3155          16 :     double fVal = ::rtl::math::stringToDouble( aInputString, cDecimalSeparator, 0, &eStatus, &nParseEnd );
    3156          16 :     if ( eStatus == rtl_math_ConversionStatus_Ok && nParseEnd == aInputString.getLength() )
    3157             :     {
    3158          14 :         if (nPercentCount)
    3159           4 :             fVal *= pow( 10.0, -(nPercentCount * 2));    // process '%' from input string
    3160          14 :         PushDouble(fVal);
    3161          14 :         return;
    3162             :     }
    3163           4 :     PushNoValue();
    3164             : }
    3165             : 
    3166             : //2do: this should be a proper unicode string method
    3167           6 : static inline bool lcl_ScInterpreter_IsPrintable( sal_Unicode c )
    3168             : {
    3169           6 :     return 0x20 <= c && c != 0x7f;
    3170             : }
    3171             : 
    3172           2 : void ScInterpreter::ScClean()
    3173             : {
    3174           2 :     OUString aStr = GetString().getString();
    3175           8 :     for ( sal_Int32 i = 0; i < aStr.getLength(); i++ )
    3176             :     {
    3177           6 :         if ( !lcl_ScInterpreter_IsPrintable( aStr[i] ) )
    3178           4 :             aStr = aStr.replaceAt(i,1,"");
    3179             :     }
    3180           2 :     PushString(aStr);
    3181           2 : }
    3182             : 
    3183           6 : void ScInterpreter::ScCode()
    3184             : {
    3185             : //2do: make it full range unicode?
    3186           6 :     OUString aStr = GetString().getString();
    3187             :     //"classic" ByteString conversion flags
    3188             :     const sal_uInt32 convertFlags =
    3189             :         RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE |
    3190             :         RTL_UNICODETOTEXT_FLAGS_CONTROL_IGNORE |
    3191             :         RTL_UNICODETOTEXT_FLAGS_FLUSH |
    3192             :         RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT |
    3193             :         RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT |
    3194           6 :         RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE;
    3195           6 :     PushInt( (unsigned char) OUStringToOString(OUString(aStr[0]), osl_getThreadTextEncoding(), convertFlags).toChar() );
    3196           6 : }
    3197             : 
    3198          10 : void ScInterpreter::ScChar()
    3199             : {
    3200             : //2do: make it full range unicode?
    3201          10 :     double fVal = GetDouble();
    3202          10 :     if (fVal < 0.0 || fVal >= 256.0)
    3203           0 :         PushIllegalArgument();
    3204             :     else
    3205             :     {
    3206             :         //"classic" ByteString conversion flags
    3207             :         const sal_uInt32 convertFlags =
    3208             :             RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT |
    3209             :             RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT |
    3210          10 :             RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT;
    3211             : 
    3212          10 :         sal_Char cEncodedChar = static_cast<sal_Char>(fVal);
    3213          10 :         OUString aStr(&cEncodedChar, 1,  osl_getThreadTextEncoding(), convertFlags);
    3214          10 :         PushString(aStr);
    3215             :     }
    3216          10 : }
    3217             : 
    3218             : /* #i70213# fullwidth/halfwidth conversion provided by
    3219             :  * Takashi Nakamoto <bluedwarf@ooo>
    3220             :  * erAck: added Excel compatibility conversions as seen in issue's test case. */
    3221             : 
    3222           2 : static OUString lcl_convertIntoHalfWidth( const OUString & rStr )
    3223             : {
    3224             :     static bool bFirstASCCall = true;
    3225           2 :     static utl::TransliterationWrapper aTrans( ::comphelper::getProcessComponentContext(), 0 );
    3226             : 
    3227           2 :     if( bFirstASCCall )
    3228             :     {
    3229           2 :         aTrans.loadModuleByImplName( OUString( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM );
    3230           2 :         bFirstASCCall = false;
    3231             :     }
    3232             : 
    3233           2 :     return aTrans.transliterate( rStr, 0, sal_uInt16( rStr.getLength() ), NULL );
    3234             : }
    3235             : 
    3236           2 : static OUString lcl_convertIntoFullWidth( const OUString & rStr )
    3237             : {
    3238             :     static bool bFirstJISCall = true;
    3239           2 :     static utl::TransliterationWrapper aTrans( ::comphelper::getProcessComponentContext(), 0 );
    3240             : 
    3241           2 :     if( bFirstJISCall )
    3242             :     {
    3243           2 :         aTrans.loadModuleByImplName( OUString( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM );
    3244           2 :         bFirstJISCall = false;
    3245             :     }
    3246             : 
    3247           2 :     return aTrans.transliterate( rStr, 0, sal_uInt16( rStr.getLength() ), NULL );
    3248             : }
    3249             : 
    3250             : /* ODFF:
    3251             :  * Summary: Converts half-width to full-width ASCII and katakana characters.
    3252             :  * Semantics: Conversion is done for half-width ASCII and katakana characters,
    3253             :  * other characters are simply copied from T to the result. This is the
    3254             :  * complementary function to ASC.
    3255             :  * For references regarding halfwidth and fullwidth characters see
    3256             :  * http://www.unicode.org/reports/tr11/
    3257             :  * http://www.unicode.org/charts/charindex2.html#H
    3258             :  * http://www.unicode.org/charts/charindex2.html#F
    3259             :  */
    3260           2 : void ScInterpreter::ScJis()
    3261             : {
    3262           2 :     if (MustHaveParamCount( GetByte(), 1))
    3263           2 :         PushString( lcl_convertIntoFullWidth( GetString().getString()));
    3264           2 : }
    3265             : 
    3266             : /* ODFF:
    3267             :  * Summary: Converts full-width to half-width ASCII and katakana characters.
    3268             :  * Semantics: Conversion is done for full-width ASCII and katakana characters,
    3269             :  * other characters are simply copied from T to the result. This is the
    3270             :  * complementary function to JIS.
    3271             :  */
    3272           2 : void ScInterpreter::ScAsc()
    3273             : {
    3274           2 :     if (MustHaveParamCount( GetByte(), 1))
    3275           2 :         PushString( lcl_convertIntoHalfWidth( GetString().getString()));
    3276           2 : }
    3277             : 
    3278           2 : void ScInterpreter::ScUnicode()
    3279             : {
    3280           2 :     if ( MustHaveParamCount( GetByte(), 1 ) )
    3281             :     {
    3282           2 :         OUString aStr = GetString().getString();
    3283           2 :         if (aStr.isEmpty())
    3284           0 :             PushIllegalParameter();
    3285             :         else
    3286             :         {
    3287           2 :             sal_Int32 i = 0;
    3288           2 :             PushDouble(aStr.iterateCodePoints(&i));
    3289           2 :         }
    3290             :     }
    3291           2 : }
    3292             : 
    3293           0 : void ScInterpreter::ScUnichar()
    3294             : {
    3295           0 :     if ( MustHaveParamCount( GetByte(), 1 ) )
    3296             :     {
    3297           0 :         double dVal = ::rtl::math::approxFloor( GetDouble() );
    3298           0 :         if ((dVal < 0x000000) || (dVal > 0x10FFFF))
    3299           0 :             PushIllegalArgument();
    3300             :         else
    3301             :         {
    3302           0 :             sal_uInt32 nCodePoint = static_cast<sal_uInt32>( dVal );
    3303           0 :             OUString aStr( &nCodePoint, 1 );
    3304           0 :             PushString( aStr );
    3305             :         }
    3306             :     }
    3307           0 : }
    3308             : 
    3309          92 : void ScInterpreter::ScMin( bool bTextAsZero )
    3310             : {
    3311          92 :     short nParamCount = GetByte();
    3312          92 :     if (!MustHaveParamCountMin( nParamCount, 1))
    3313          92 :         return;
    3314          92 :     double nMin = ::std::numeric_limits<double>::max();
    3315          92 :     double nVal = 0.0;
    3316          92 :     ScAddress aAdr;
    3317          92 :     ScRange aRange;
    3318          92 :     size_t nRefInList = 0;
    3319         276 :     while (nParamCount-- > 0)
    3320             :     {
    3321          92 :         switch (GetStackType())
    3322             :         {
    3323             :             case svDouble :
    3324             :             {
    3325           0 :                 nVal = GetDouble();
    3326           0 :                 if (nMin > nVal) nMin = nVal;
    3327           0 :                 nFuncFmtType = NUMBERFORMAT_NUMBER;
    3328             :             }
    3329           0 :             break;
    3330             :             case svSingleRef :
    3331             :             {
    3332           0 :                 PopSingleRef( aAdr );
    3333           0 :                 ScRefCellValue aCell;
    3334           0 :                 aCell.assign(*pDok, aAdr);
    3335           0 :                 if (aCell.hasNumeric())
    3336             :                 {
    3337           0 :                     nVal = GetCellValue(aAdr, aCell);
    3338           0 :                     CurFmtToFuncFmt();
    3339           0 :                     if (nMin > nVal) nMin = nVal;
    3340             :                 }
    3341           0 :                 else if (bTextAsZero && aCell.hasString())
    3342             :                 {
    3343           0 :                     if ( nMin > 0.0 )
    3344           0 :                         nMin = 0.0;
    3345           0 :                 }
    3346             :             }
    3347           0 :             break;
    3348             :             case svDoubleRef :
    3349             :             case svRefList :
    3350             :             {
    3351          88 :                 sal_uInt16 nErr = 0;
    3352          88 :                 PopDoubleRef( aRange, nParamCount, nRefInList);
    3353          88 :                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
    3354          88 :                 if (aValIter.GetFirst(nVal, nErr))
    3355             :                 {
    3356          88 :                     if (nMin > nVal)
    3357          88 :                         nMin = nVal;
    3358          88 :                     aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
    3359         852 :                     while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
    3360             :                     {
    3361         676 :                         if (nMin > nVal)
    3362          44 :                             nMin = nVal;
    3363             :                     }
    3364          88 :                     SetError(nErr);
    3365             :                 }
    3366             :             }
    3367          88 :             break;
    3368             :             case svMatrix :
    3369             :             case svExternalSingleRef:
    3370             :             case svExternalDoubleRef:
    3371             :             {
    3372           4 :                 ScMatrixRef pMat = GetMatrix();
    3373           4 :                 if (pMat)
    3374             :                 {
    3375           4 :                     nFuncFmtType = NUMBERFORMAT_NUMBER;
    3376           4 :                     nVal = pMat->GetMinValue(bTextAsZero);
    3377           4 :                     if (nMin > nVal)
    3378           4 :                         nMin = nVal;
    3379           4 :                 }
    3380             :             }
    3381           4 :             break;
    3382             :             case svString :
    3383             :             {
    3384           0 :                 Pop();
    3385           0 :                 if ( bTextAsZero )
    3386             :                 {
    3387           0 :                     if ( nMin > 0.0 )
    3388           0 :                         nMin = 0.0;
    3389             :                 }
    3390             :                 else
    3391           0 :                     SetError(errIllegalParameter);
    3392             :             }
    3393           0 :             break;
    3394             :             default :
    3395           0 :                 Pop();
    3396           0 :                 SetError(errIllegalParameter);
    3397             :         }
    3398             :     }
    3399          92 :     if ( nVal < nMin  )
    3400           0 :         PushDouble(0.0);
    3401             :     else
    3402          92 :         PushDouble(nMin);
    3403             : }
    3404             : 
    3405         124 : void ScInterpreter::ScMax( bool bTextAsZero )
    3406             : {
    3407         124 :     short nParamCount = GetByte();
    3408         124 :     if (!MustHaveParamCountMin( nParamCount, 1))
    3409         124 :         return;
    3410         124 :     double nMax = -(::std::numeric_limits<double>::max());
    3411         124 :     double nVal = 0.0;
    3412         124 :     ScAddress aAdr;
    3413         124 :     ScRange aRange;
    3414         124 :     size_t nRefInList = 0;
    3415         372 :     while (nParamCount-- > 0)
    3416             :     {
    3417         124 :         switch (GetStackType())
    3418             :         {
    3419             :             case svDouble :
    3420             :             {
    3421           0 :                 nVal = GetDouble();
    3422           0 :                 if (nMax < nVal) nMax = nVal;
    3423           0 :                 nFuncFmtType = NUMBERFORMAT_NUMBER;
    3424             :             }
    3425           0 :             break;
    3426             :             case svSingleRef :
    3427             :             {
    3428           0 :                 PopSingleRef( aAdr );
    3429           0 :                 ScRefCellValue aCell;
    3430           0 :                 aCell.assign(*pDok, aAdr);
    3431           0 :                 if (aCell.hasNumeric())
    3432             :                 {
    3433           0 :                     nVal = GetCellValue(aAdr, aCell);
    3434           0 :                     CurFmtToFuncFmt();
    3435           0 :                     if (nMax < nVal) nMax = nVal;
    3436             :                 }
    3437           0 :                 else if (bTextAsZero && aCell.hasString())
    3438             :                 {
    3439           0 :                     if ( nMax < 0.0 )
    3440           0 :                         nMax = 0.0;
    3441           0 :                 }
    3442             :             }
    3443           0 :             break;
    3444             :             case svDoubleRef :
    3445             :             case svRefList :
    3446             :             {
    3447         124 :                 sal_uInt16 nErr = 0;
    3448         124 :                 PopDoubleRef( aRange, nParamCount, nRefInList);
    3449         124 :                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
    3450         124 :                 if (aValIter.GetFirst(nVal, nErr))
    3451             :                 {
    3452         124 :                     if (nMax < nVal)
    3453         124 :                         nMax = nVal;
    3454         124 :                     aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
    3455        1270 :                     while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
    3456             :                     {
    3457        1022 :                         if (nMax < nVal)
    3458         248 :                             nMax = nVal;
    3459             :                     }
    3460         124 :                     SetError(nErr);
    3461             :                 }
    3462             :             }
    3463         124 :             break;
    3464             :             case svMatrix :
    3465             :             case svExternalSingleRef:
    3466             :             case svExternalDoubleRef:
    3467             :             {
    3468           0 :                 ScMatrixRef pMat = GetMatrix();
    3469           0 :                 if (pMat)
    3470             :                 {
    3471           0 :                     nFuncFmtType = NUMBERFORMAT_NUMBER;
    3472           0 :                     nVal = pMat->GetMaxValue(bTextAsZero);
    3473           0 :                     if (nMax < nVal)
    3474           0 :                         nMax = nVal;
    3475           0 :                 }
    3476             :             }
    3477           0 :             break;
    3478             :             case svString :
    3479             :             {
    3480           0 :                 Pop();
    3481           0 :                 if ( bTextAsZero )
    3482             :                 {
    3483           0 :                     if ( nMax < 0.0 )
    3484           0 :                         nMax = 0.0;
    3485             :                 }
    3486             :                 else
    3487           0 :                     SetError(errIllegalParameter);
    3488             :             }
    3489           0 :             break;
    3490             :             default :
    3491           0 :                 Pop();
    3492           0 :                 SetError(errIllegalParameter);
    3493             :         }
    3494             :     }
    3495         124 :     if ( nVal > nMax  )
    3496           0 :         PushDouble(0.0);
    3497             :     else
    3498         124 :         PushDouble(nMax);
    3499             : }
    3500             : 
    3501         456 : void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
    3502             :                 bool bTextAsZero )
    3503             : {
    3504         456 :     short nParamCount = GetByte();
    3505             : 
    3506         456 :     std::vector<double> values;
    3507         456 :     double fSum    = 0.0;
    3508         456 :     double vSum    = 0.0;
    3509         456 :     double vMean    = 0.0;
    3510         456 :     double fVal = 0.0;
    3511         456 :     rValCount = 0.0;
    3512         456 :     ScAddress aAdr;
    3513         456 :     ScRange aRange;
    3514         456 :     size_t nRefInList = 0;
    3515        1368 :     while (nParamCount-- > 0)
    3516             :     {
    3517         456 :         switch (GetStackType())
    3518             :         {
    3519             :             case svDouble :
    3520             :             {
    3521           0 :                 fVal = GetDouble();
    3522           0 :                 values.push_back(fVal);
    3523           0 :                 fSum    += fVal;
    3524           0 :                 rValCount++;
    3525             :             }
    3526           0 :             break;
    3527             :             case svSingleRef :
    3528             :             {
    3529           0 :                 PopSingleRef( aAdr );
    3530           0 :                 ScRefCellValue aCell;
    3531           0 :                 aCell.assign(*pDok, aAdr);
    3532           0 :                 if (aCell.hasNumeric())
    3533             :                 {
    3534           0 :                     fVal = GetCellValue(aAdr, aCell);
    3535           0 :                     values.push_back(fVal);
    3536           0 :                     fSum += fVal;
    3537           0 :                     rValCount++;
    3538             :                 }
    3539           0 :                 else if (bTextAsZero && aCell.hasString())
    3540             :                 {
    3541           0 :                     values.push_back(0.0);
    3542           0 :                     rValCount++;
    3543           0 :                 }
    3544             :             }
    3545           0 :             break;
    3546             :             case svDoubleRef :
    3547             :             case svRefList :
    3548             :             {
    3549         456 :                 sal_uInt16 nErr = 0;
    3550         456 :                 PopDoubleRef( aRange, nParamCount, nRefInList);
    3551         456 :                 ScValueIterator aValIter( pDok, aRange, mnSubTotalFlags, bTextAsZero );
    3552         456 :                 if (aValIter.GetFirst(fVal, nErr))
    3553             :                 {
    3554        4164 :                     do
    3555             :                     {
    3556        4164 :                         values.push_back(fVal);
    3557        4164 :                         fSum += fVal;
    3558        4164 :                         rValCount++;
    3559             :                     }
    3560        4164 :                     while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
    3561             :                 }
    3562             :             }
    3563         456 :             break;
    3564             :             case svMatrix :
    3565             :             {
    3566           0 :                 ScMatrixRef pMat = PopMatrix();
    3567           0 :                 if (pMat)
    3568             :                 {
    3569             :                     SCSIZE nC, nR;
    3570           0 :                     pMat->GetDimensions(nC, nR);
    3571           0 :                     for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
    3572             :                     {
    3573           0 :                         for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
    3574             :                         {
    3575           0 :                             if (!pMat->IsString(nMatCol,nMatRow))
    3576             :                             {
    3577           0 :                                 fVal= pMat->GetDouble(nMatCol,nMatRow);
    3578           0 :                                 values.push_back(fVal);
    3579           0 :                                 fSum += fVal;
    3580           0 :                                 rValCount++;
    3581             :                             }
    3582           0 :                             else if ( bTextAsZero )
    3583             :                             {
    3584           0 :                                 values.push_back(0.0);
    3585           0 :                                 rValCount++;
    3586             :                             }
    3587             :                         }
    3588             :                     }
    3589           0 :                 }
    3590             :             }
    3591           0 :             break;
    3592             :             case svString :
    3593             :             {
    3594           0 :                 Pop();
    3595           0 :                 if ( bTextAsZero )
    3596             :                 {
    3597           0 :                     values.push_back(0.0);
    3598           0 :                     rValCount++;
    3599             :                 }
    3600             :                 else
    3601           0 :                     SetError(errIllegalParameter);
    3602             :             }
    3603           0 :             break;
    3604             :             default :
    3605           0 :                 Pop();
    3606           0 :                 SetError(errIllegalParameter);
    3607             :         }
    3608             :     }
    3609             : 
    3610         456 :     ::std::vector<double>::size_type n = values.size();
    3611         456 :     vMean = fSum / n;
    3612        4620 :     for (::std::vector<double>::size_type i = 0; i < n; i++)
    3613        4164 :         vSum += ::rtl::math::approxSub( values[i], vMean) * ::rtl::math::approxSub( values[i], vMean);
    3614         456 :     rVal = vSum;
    3615         456 : }
    3616             : 
    3617         114 : void ScInterpreter::ScVar( bool bTextAsZero )
    3618             : {
    3619             :     double nVal;
    3620             :     double nValCount;
    3621         114 :     GetStVarParams( nVal, nValCount, bTextAsZero );
    3622             : 
    3623         114 :     if (nValCount <= 1.0)
    3624           0 :         PushError( errDivisionByZero );
    3625             :     else
    3626         114 :         PushDouble( nVal / (nValCount - 1.0));
    3627         114 : }
    3628             : 
    3629         114 : void ScInterpreter::ScVarP( bool bTextAsZero )
    3630             : {
    3631             :     double nVal;
    3632             :     double nValCount;
    3633         114 :     GetStVarParams( nVal, nValCount, bTextAsZero );
    3634             : 
    3635         114 :     PushDouble( div( nVal, nValCount));
    3636         114 : }
    3637             : 
    3638         114 : void ScInterpreter::ScStDev( bool bTextAsZero )
    3639             : {
    3640             :     double nVal;
    3641             :     double nValCount;
    3642         114 :     GetStVarParams( nVal, nValCount, bTextAsZero );
    3643         114 :     if (nValCount <= 1.0)
    3644           0 :         PushError( errDivisionByZero );
    3645             :     else
    3646         114 :         PushDouble( sqrt( nVal / (nValCount - 1.0)));
    3647         114 : }
    3648             : 
    3649         114 : void ScInterpreter::ScStDevP( bool bTextAsZero )
    3650             : {
    3651             :     double nVal;
    3652             :     double nValCount;
    3653         114 :     GetStVarParams( nVal, nValCount, bTextAsZero );
    3654         114 :     if (nValCount == 0.0)
    3655           0 :         PushError( errDivisionByZero );
    3656             :     else
    3657         114 :         PushDouble( sqrt( nVal / nValCount));
    3658             : 
    3659             :     /* this was: PushDouble( sqrt( div( nVal, nValCount)));
    3660             :      *
    3661             :      * Besides that the special NAN gets lost in the call through sqrt(),
    3662             :      * unxlngi6.pro then looped back and forth somewhere between div() and
    3663             :      * ::rtl::math::setNan(). Tests showed that
    3664             :      *
    3665             :      *      sqrt( div( 1, 0));
    3666             :      *
    3667             :      * produced a loop, but
    3668             :      *
    3669             :      *      double f1 = div( 1, 0);
    3670             :      *      sqrt( f1 );
    3671             :      *
    3672             :      * was fine. There seems to be some compiler optimization problem. It does
    3673             :      * not occur when compiled with debug=t.
    3674             :      */
    3675         114 : }
    3676             : 
    3677           0 : void ScInterpreter::ScColumns()
    3678             : {
    3679           0 :     sal_uInt8 nParamCount = GetByte();
    3680           0 :     sal_uLong nVal = 0;
    3681             :     SCCOL nCol1;
    3682             :     SCROW nRow1;
    3683             :     SCTAB nTab1;
    3684             :     SCCOL nCol2;
    3685             :     SCROW nRow2;
    3686             :     SCTAB nTab2;
    3687           0 :     while (nParamCount-- > 0)
    3688             :     {
    3689           0 :         switch ( GetStackType() )
    3690             :         {
    3691             :             case svSingleRef:
    3692           0 :                 PopError();
    3693           0 :                 nVal++;
    3694           0 :                 break;
    3695             :             case svDoubleRef:
    3696           0 :                 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    3697           0 :                 nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1) *
    3698           0 :                     static_cast<sal_uLong>(nCol2 - nCol1 + 1);
    3699           0 :                 break;
    3700             :             case svMatrix:
    3701             :             {
    3702           0 :                 ScMatrixRef pMat = PopMatrix();
    3703           0 :                 if (pMat)
    3704             :                 {
    3705             :                     SCSIZE nC, nR;
    3706           0 :                     pMat->GetDimensions(nC, nR);
    3707           0 :                     nVal += nC;
    3708           0 :                 }
    3709             :             }
    3710           0 :             break;
    3711             :             case svExternalSingleRef:
    3712           0 :                 PopError();
    3713           0 :                 nVal++;
    3714           0 :             break;
    3715             :             case svExternalDoubleRef:
    3716             :             {
    3717             :                 sal_uInt16 nFileId;
    3718           0 :                 OUString aTabName;
    3719             :                 ScComplexRefData aRef;
    3720           0 :                 PopExternalDoubleRef( nFileId, aTabName, aRef);
    3721           0 :                 ScRange aAbs = aRef.toAbs(aPos);
    3722           0 :                 nVal += static_cast<sal_uLong>(aAbs.aEnd.Tab() - aAbs.aStart.Tab() + 1) *
    3723           0 :                     static_cast<sal_uLong>(aAbs.aEnd.Col() - aAbs.aStart.Col() + 1);
    3724             :             }
    3725           0 :             break;
    3726             :             default:
    3727           0 :                 PopError();
    3728           0 :                 SetError(errIllegalParameter);
    3729             :         }
    3730             :     }
    3731           0 :     PushDouble((double)nVal);
    3732           0 : }
    3733             : 
    3734           0 : void ScInterpreter::ScRows()
    3735             : {
    3736           0 :     sal_uInt8 nParamCount = GetByte();
    3737           0 :     sal_uLong nVal = 0;
    3738             :     SCCOL nCol1;
    3739             :     SCROW nRow1;
    3740             :     SCTAB nTab1;
    3741             :     SCCOL nCol2;
    3742             :     SCROW nRow2;
    3743             :     SCTAB nTab2;
    3744           0 :     while (nParamCount-- > 0)
    3745             :     {
    3746           0 :         switch ( GetStackType() )
    3747             :         {
    3748             :             case svSingleRef:
    3749           0 :                 PopError();
    3750           0 :                 nVal++;
    3751           0 :                 break;
    3752             :             case svDoubleRef:
    3753           0 :                 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    3754           0 :                 nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1) *
    3755           0 :                     static_cast<sal_uLong>(nRow2 - nRow1 + 1);
    3756           0 :                 break;
    3757             :             case svMatrix:
    3758             :             {
    3759           0 :                 ScMatrixRef pMat = PopMatrix();
    3760           0 :                 if (pMat)
    3761             :                 {
    3762             :                     SCSIZE nC, nR;
    3763           0 :                     pMat->GetDimensions(nC, nR);
    3764           0 :                     nVal += nR;
    3765           0 :                 }
    3766             :             }
    3767           0 :             break;
    3768             :             case svExternalSingleRef:
    3769           0 :                 PopError();
    3770           0 :                 nVal++;
    3771           0 :             break;
    3772             :             case svExternalDoubleRef:
    3773             :             {
    3774             :                 sal_uInt16 nFileId;
    3775           0 :                 OUString aTabName;
    3776             :                 ScComplexRefData aRef;
    3777           0 :                 PopExternalDoubleRef( nFileId, aTabName, aRef);
    3778           0 :                 ScRange aAbs = aRef.toAbs(aPos);
    3779           0 :                 nVal += static_cast<sal_uLong>(aAbs.aEnd.Tab() - aAbs.aStart.Tab() + 1) *
    3780           0 :                     static_cast<sal_uLong>(aAbs.aEnd.Row() - aAbs.aStart.Row() + 1);
    3781             :             }
    3782           0 :             break;
    3783             :             default:
    3784           0 :                 PopError();
    3785           0 :                 SetError(errIllegalParameter);
    3786             :         }
    3787             :     }
    3788           0 :     PushDouble((double)nVal);
    3789           0 : }
    3790             : 
    3791           6 : void ScInterpreter::ScTables()
    3792             : {
    3793           6 :     sal_uInt8 nParamCount = GetByte();
    3794             :     sal_uLong nVal;
    3795           6 :     if ( nParamCount == 0 )
    3796           6 :         nVal = pDok->GetTableCount();
    3797             :     else
    3798             :     {
    3799           0 :         nVal = 0;
    3800             :         SCCOL nCol1;
    3801             :         SCROW nRow1;
    3802             :         SCTAB nTab1;
    3803             :         SCCOL nCol2;
    3804             :         SCROW nRow2;
    3805             :         SCTAB nTab2;
    3806           0 :         while (nParamCount-- > 0)
    3807             :         {
    3808           0 :             switch ( GetStackType() )
    3809             :             {
    3810             :                 case svSingleRef:
    3811           0 :                     PopError();
    3812           0 :                     nVal++;
    3813           0 :                 break;
    3814             :                 case svDoubleRef:
    3815           0 :                     PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    3816           0 :                     nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1);
    3817           0 :                 break;
    3818             :                 case svMatrix:
    3819           0 :                     PopError();
    3820           0 :                     nVal++;
    3821           0 :                 break;
    3822             :                 case svExternalSingleRef:
    3823           0 :                     PopError();
    3824           0 :                     nVal++;
    3825           0 :                 break;
    3826             :                 case svExternalDoubleRef:
    3827             :                 {
    3828             :                     sal_uInt16 nFileId;
    3829           0 :                     OUString aTabName;
    3830             :                     ScComplexRefData aRef;
    3831           0 :                     PopExternalDoubleRef( nFileId, aTabName, aRef);
    3832           0 :                     ScRange aAbs = aRef.toAbs(aPos);
    3833           0 :                     nVal += static_cast<sal_uLong>(aAbs.aEnd.Tab() - aAbs.aStart.Tab() + 1);
    3834             :                 }
    3835           0 :                 break;
    3836             :                 default:
    3837           0 :                     PopError();
    3838           0 :                     SetError( errIllegalParameter );
    3839             :             }
    3840             :         }
    3841             :     }
    3842           6 :     PushDouble( (double) nVal );
    3843           6 : }
    3844             : 
    3845          34 : void ScInterpreter::ScColumn()
    3846             : {
    3847          34 :     sal_uInt8 nParamCount = GetByte();
    3848          34 :     if ( MustHaveParamCount( nParamCount, 0, 1 ) )
    3849             :     {
    3850          34 :         double nVal = 0;
    3851          34 :         if (nParamCount == 0)
    3852             :         {
    3853          10 :             nVal = aPos.Col() + 1;
    3854          10 :             if (bMatrixFormula)
    3855             :             {
    3856             :                 SCCOL nCols;
    3857             :                 SCROW nRows;
    3858           4 :                 pMyFormulaCell->GetMatColsRows( nCols, nRows);
    3859           4 :                 if (nCols == 0)
    3860             :                 {
    3861             :                     // Happens if called via ScViewFunc::EnterMatrix()
    3862             :                     // ScFormulaCell::GetResultDimensions() as of course a
    3863             :                     // matrix result is not available yet.
    3864           0 :                     nCols = 1;
    3865             :                 }
    3866           4 :                 ScMatrixRef pResMat = GetNewMat( static_cast<SCSIZE>(nCols), 1);
    3867           4 :                 if (pResMat)
    3868             :                 {
    3869           8 :                     for (SCCOL i=0; i < nCols; ++i)
    3870           4 :                         pResMat->PutDouble( nVal + i, static_cast<SCSIZE>(i), 0);
    3871           4 :                     PushMatrix( pResMat);
    3872           4 :                     return;
    3873           0 :                 }
    3874             :             }
    3875             :         }
    3876             :         else
    3877             :         {
    3878          24 :             switch ( GetStackType() )
    3879             :             {
    3880             :                 case svSingleRef :
    3881             :                 {
    3882             :                     SCCOL nCol1;
    3883             :                     SCROW nRow1;
    3884             :                     SCTAB nTab1;
    3885          16 :                     PopSingleRef( nCol1, nRow1, nTab1 );
    3886          16 :                     nVal = (double) (nCol1 + 1);
    3887             :                 }
    3888          16 :                 break;
    3889             :                 case svDoubleRef :
    3890             :                 {
    3891             :                     SCCOL nCol1;
    3892             :                     SCROW nRow1;
    3893             :                     SCTAB nTab1;
    3894             :                     SCCOL nCol2;
    3895             :                     SCROW nRow2;
    3896             :                     SCTAB nTab2;
    3897           8 :                     PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    3898           8 :                     if (nCol2 > nCol1)
    3899             :                     {
    3900             :                         ScMatrixRef pResMat = GetNewMat(
    3901           8 :                                 static_cast<SCSIZE>(nCol2-nCol1+1), 1);
    3902           8 :                         if (pResMat)
    3903             :                         {
    3904          32 :                             for (SCCOL i = nCol1; i <= nCol2; i++)
    3905          24 :                                 pResMat->PutDouble((double)(i+1),
    3906          48 :                                         static_cast<SCSIZE>(i-nCol1), 0);
    3907           8 :                             PushMatrix(pResMat);
    3908           8 :                             return;
    3909             :                         }
    3910             :                         else
    3911           0 :                             nVal = 0.0;
    3912             :                     }
    3913             :                     else
    3914           0 :                         nVal = (double) (nCol1 + 1);
    3915             :                 }
    3916           0 :                 break;
    3917             :                 default:
    3918           0 :                     SetError( errIllegalParameter );
    3919           0 :                     nVal = 0.0;
    3920             :             }
    3921             :         }
    3922          22 :         PushDouble( nVal );
    3923             :     }
    3924             : }
    3925             : 
    3926         114 : void ScInterpreter::ScRow()
    3927             : {
    3928         114 :     sal_uInt8 nParamCount = GetByte();
    3929         114 :     if ( MustHaveParamCount( nParamCount, 0, 1 ) )
    3930             :     {
    3931         114 :         double nVal = 0;
    3932         114 :         if (nParamCount == 0)
    3933             :         {
    3934          92 :             nVal = aPos.Row() + 1;
    3935          92 :             if (bMatrixFormula)
    3936             :             {
    3937             :                 SCCOL nCols;
    3938             :                 SCROW nRows;
    3939           4 :                 pMyFormulaCell->GetMatColsRows( nCols, nRows);
    3940           4 :                 if (nRows == 0)
    3941             :                 {
    3942             :                     // Happens if called via ScViewFunc::EnterMatrix()
    3943             :                     // ScFormulaCell::GetResultDimensions() as of course a
    3944             :                     // matrix result is not available yet.
    3945           0 :                     nRows = 1;
    3946             :                 }
    3947           4 :                 ScMatrixRef pResMat = GetNewMat( 1, static_cast<SCSIZE>(nRows));
    3948           4 :                 if (pResMat)
    3949             :                 {
    3950           8 :                     for (SCROW i=0; i < nRows; i++)
    3951           4 :                         pResMat->PutDouble( nVal + i, 0, static_cast<SCSIZE>(i));
    3952           4 :                     PushMatrix( pResMat);
    3953           4 :                     return;
    3954           0 :                 }
    3955             :             }
    3956             :         }
    3957             :         else
    3958             :         {
    3959          22 :             switch ( GetStackType() )
    3960             :             {
    3961             :                 case svSingleRef :
    3962             :                 {
    3963             :                     SCCOL nCol1;
    3964             :                     SCROW nRow1;
    3965             :                     SCTAB nTab1;
    3966          20 :                     PopSingleRef( nCol1, nRow1, nTab1 );
    3967          20 :                     nVal = (double) (nRow1 + 1);
    3968             :                 }
    3969          20 :                 break;
    3970             :                 case svDoubleRef :
    3971             :                 {
    3972             :                     SCCOL nCol1;
    3973             :                     SCROW nRow1;
    3974             :                     SCTAB nTab1;
    3975             :                     SCCOL nCol2;
    3976             :                     SCROW nRow2;
    3977             :                     SCTAB nTab2;
    3978           2 :                     PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    3979           2 :                     if (nRow2 > nRow1)
    3980             :                     {
    3981             :                         ScMatrixRef pResMat = GetNewMat( 1,
    3982           2 :                                 static_cast<SCSIZE>(nRow2-nRow1+1));
    3983           2 :                         if (pResMat)
    3984             :                         {
    3985           6 :                             for (SCROW i = nRow1; i <= nRow2; i++)
    3986           4 :                                 pResMat->PutDouble((double)(i+1), 0,
    3987           8 :                                         static_cast<SCSIZE>(i-nRow1));
    3988           2 :                             PushMatrix(pResMat);
    3989           2 :                             return;
    3990             :                         }
    3991             :                         else
    3992           0 :                             nVal = 0.0;
    3993             :                     }
    3994             :                     else
    3995           0 :                         nVal = (double) (nRow1 + 1);
    3996             :                 }
    3997           0 :                 break;
    3998             :                 default:
    3999           0 :                     SetError( errIllegalParameter );
    4000           0 :                     nVal = 0.0;
    4001             :             }
    4002             :         }
    4003         108 :         PushDouble( nVal );
    4004             :     }
    4005             : }
    4006             : 
    4007           0 : void ScInterpreter::ScTable()
    4008             : {
    4009           0 :     sal_uInt8 nParamCount = GetByte();
    4010           0 :     if ( MustHaveParamCount( nParamCount, 0, 1 ) )
    4011             :     {
    4012           0 :         SCTAB nVal = 0;
    4013           0 :         if ( nParamCount == 0 )
    4014           0 :             nVal = aPos.Tab() + 1;
    4015             :         else
    4016             :         {
    4017           0 :             switch ( GetStackType() )
    4018             :             {
    4019             :                 case svString :
    4020             :                 {
    4021           0 :                     svl::SharedString aStr = PopString();
    4022           0 :                     if ( pDok->GetTable(aStr.getString(), nVal))
    4023           0 :                         ++nVal;
    4024             :                     else
    4025           0 :                         SetError( errIllegalArgument );
    4026             :                 }
    4027           0 :                 break;
    4028             :                 case svSingleRef :
    4029             :                 {
    4030             :                     SCCOL nCol1;
    4031             :                     SCROW nRow1;
    4032             :                     SCTAB nTab1;
    4033           0 :                     PopSingleRef( nCol1, nRow1, nTab1 );
    4034           0 :                     nVal = nTab1 + 1;
    4035             :                 }
    4036           0 :                 break;
    4037             :                 case svDoubleRef :
    4038             :                 {
    4039             :                     SCCOL nCol1;
    4040             :                     SCROW nRow1;
    4041             :                     SCTAB nTab1;
    4042             :                     SCCOL nCol2;
    4043             :                     SCROW nRow2;
    4044             :                     SCTAB nTab2;
    4045           0 :                     PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    4046           0 :                     nVal = nTab1 + 1;
    4047             :                 }
    4048           0 :                 break;
    4049             :                 default:
    4050           0 :                     SetError( errIllegalParameter );
    4051             :             }
    4052           0 :             if ( nGlobalError )
    4053           0 :                 nVal = 0;
    4054             :         }
    4055           0 :         PushDouble( (double) nVal );
    4056             :     }
    4057           0 : }
    4058             : 
    4059             : namespace {
    4060             : 
    4061             : class VectorMatrixAccessor
    4062             : {
    4063             : public:
    4064           0 :     VectorMatrixAccessor(const ScMatrix& rMat, bool bColVec) :
    4065           0 :         mrMat(rMat), mbColVec(bColVec) {}
    4066             : 
    4067           0 :     bool IsEmpty(SCSIZE i) const
    4068             :     {
    4069           0 :         return mbColVec ? mrMat.IsEmpty(0, i) : mrMat.IsEmpty(i, 0);
    4070             :     }
    4071             : 
    4072           0 :     bool IsEmptyPath(SCSIZE i) const
    4073             :     {
    4074           0 :         return mbColVec ? mrMat.IsEmptyPath(0, i) : mrMat.IsEmptyPath(i, 0);
    4075             :     }
    4076             : 
    4077           0 :     bool IsValue(SCSIZE i) const
    4078             :     {
    4079           0 :         return mbColVec ? mrMat.IsValue(0, i) : mrMat.IsValue(i, 0);
    4080             :     }
    4081             : 
    4082           0 :     bool IsString(SCSIZE i) const
    4083             :     {
    4084           0 :         return mbColVec ? mrMat.IsString(0, i) : mrMat.IsString(i, 0);
    4085             :     }
    4086             : 
    4087           0 :     double GetDouble(SCSIZE i) const
    4088             :     {
    4089           0 :         return mbColVec ? mrMat.GetDouble(0, i) : mrMat.GetDouble(i, 0);
    4090             :     }
    4091             : 
    4092           0 :     OUString GetString(SCSIZE i) const
    4093             :     {
    4094           0 :         return mbColVec ? mrMat.GetString(0, i).getString() : mrMat.GetString(i, 0).getString();
    4095             :     }
    4096             : 
    4097           0 :     SCSIZE GetElementCount() const
    4098             :     {
    4099             :         SCSIZE nC, nR;
    4100           0 :         mrMat.GetDimensions(nC, nR);
    4101           0 :         return mbColVec ? nR : nC;
    4102             :     }
    4103             : 
    4104             : private:
    4105             :     const ScMatrix& mrMat;
    4106             :     bool mbColVec;
    4107             : };
    4108             : 
    4109             : /** returns -1 when the matrix value is smaller than the query value, 0 when
    4110             :     they are equal, and 1 when the matrix value is larger than the query
    4111             :     value. */
    4112           0 : static sal_Int32 lcl_CompareMatrix2Query(
    4113             :     SCSIZE i, const VectorMatrixAccessor& rMat, const ScQueryEntry& rEntry)
    4114             : {
    4115           0 :     if (rMat.IsEmpty(i))
    4116             :     {
    4117             :         /* TODO: in case we introduced query for real empty this would have to
    4118             :          * be changed! */
    4119           0 :         return -1;      // empty always less than anything else
    4120             :     }
    4121             : 
    4122             :     /* FIXME: what is an empty path (result of IF(false;true_path) in
    4123             :      * comparisons? */
    4124             : 
    4125           0 :     bool bByString = rEntry.GetQueryItem().meType == ScQueryEntry::ByString;
    4126           0 :     if (rMat.IsValue(i))
    4127             :     {
    4128           0 :         if (bByString)
    4129           0 :             return -1;  // numeric always less than string
    4130             : 
    4131           0 :         const double nVal1 = rMat.GetDouble(i);
    4132           0 :         const double nVal2 = rEntry.GetQueryItem().mfVal;
    4133           0 :         if (nVal1 == nVal2)
    4134           0 :             return 0;
    4135             : 
    4136           0 :         return nVal1 < nVal2 ? -1 : 1;
    4137             :     }
    4138             : 
    4139           0 :     if (!bByString)
    4140           0 :         return 1;       // string always greater than numeric
    4141             : 
    4142           0 :     OUString aStr1 = rMat.GetString(i);
    4143           0 :     OUString aStr2 = rEntry.GetQueryItem().maString.getString();
    4144             : 
    4145           0 :     return ScGlobal::GetCollator()->compareString(aStr1, aStr2); // case-insensitive
    4146             : }
    4147             : 
    4148             : /** returns the last item with the identical value as the original item
    4149             :     value. */
    4150           0 : static void lcl_GetLastMatch( SCSIZE& rIndex, const VectorMatrixAccessor& rMat,
    4151             :         SCSIZE nMatCount, bool bReverse)
    4152             : {
    4153           0 :     if (rMat.IsValue(rIndex))
    4154             :     {
    4155           0 :         double nVal = rMat.GetDouble(rIndex);
    4156           0 :         if (bReverse)
    4157           0 :             while (rIndex > 0 && rMat.IsValue(rIndex-1) &&
    4158           0 :                     nVal == rMat.GetDouble(rIndex-1))
    4159           0 :                 --rIndex;
    4160             :         else
    4161           0 :             while (rIndex < nMatCount-1 && rMat.IsValue(rIndex+1) &&
    4162           0 :                     nVal == rMat.GetDouble(rIndex+1))
    4163           0 :                 ++rIndex;
    4164             :     }
    4165             :     //! Order of IsEmptyPath, IsEmpty, IsString is significant!
    4166           0 :     else if (rMat.IsEmptyPath(rIndex))
    4167             :     {
    4168           0 :         if (bReverse)
    4169           0 :             while (rIndex > 0 && rMat.IsEmptyPath(rIndex-1))
    4170           0 :                 --rIndex;
    4171             :         else
    4172           0 :             while (rIndex < nMatCount-1 && rMat.IsEmptyPath(rIndex+1))
    4173           0 :                 ++rIndex;
    4174             :     }
    4175           0 :     else if (rMat.IsEmpty(rIndex))
    4176             :     {
    4177           0 :         if (bReverse)
    4178           0 :             while (rIndex > 0 && rMat.IsEmpty(rIndex-1))
    4179           0 :                 --rIndex;
    4180             :         else
    4181           0 :             while (rIndex < nMatCount-1 && rMat.IsEmpty(rIndex+1))
    4182           0 :                 ++rIndex;
    4183             :     }
    4184           0 :     else if (rMat.IsString(rIndex))
    4185             :     {
    4186           0 :         OUString aStr( rMat.GetString(rIndex));
    4187           0 :         if (bReverse)
    4188           0 :             while (rIndex > 0 && rMat.IsString(rIndex-1) &&
    4189           0 :                     aStr == rMat.GetString(rIndex-1))
    4190           0 :                 --rIndex;
    4191             :         else
    4192           0 :             while (rIndex < nMatCount-1 && rMat.IsString(rIndex+1) &&
    4193           0 :                     aStr == rMat.GetString(rIndex+1))
    4194           0 :                 ++rIndex;
    4195             :     }
    4196             :     else
    4197             :     {
    4198             :         OSL_FAIL("lcl_GetLastMatch: unhandled matrix type");
    4199             :     }
    4200           0 : }
    4201             : 
    4202             : }
    4203             : 
    4204         138 : void ScInterpreter::ScMatch()
    4205             : {
    4206             : 
    4207         138 :     sal_uInt8 nParamCount = GetByte();
    4208         138 :     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
    4209             :     {
    4210             :         double fTyp;
    4211         138 :         if (nParamCount == 3)
    4212         136 :             fTyp = GetDouble();
    4213             :         else
    4214           2 :             fTyp = 1.0;
    4215         138 :         SCCOL nCol1 = 0;
    4216         138 :         SCROW nRow1 = 0;
    4217         138 :         SCTAB nTab1 = 0;
    4218         138 :         SCCOL nCol2 = 0;
    4219         138 :         SCROW nRow2 = 0;
    4220         138 :         SCTAB nTab2 = 0;
    4221         138 :         ScMatrixRef pMatSrc = NULL;
    4222             : 
    4223         138 :         switch (GetStackType())
    4224             :         {
    4225             :             case svSingleRef:
    4226           0 :                 PopSingleRef( nCol1, nRow1, nTab1);
    4227           0 :                 nCol2 = nCol1;
    4228           0 :                 nRow2 = nRow1;
    4229           0 :                 nTab2 = nTab1;
    4230           0 :             break;
    4231             :             case svDoubleRef:
    4232             :             {
    4233         138 :                 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    4234         138 :                 if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
    4235             :                 {
    4236           0 :                     PushIllegalParameter();
    4237           0 :                     return;
    4238             :                 }
    4239             :             }
    4240         138 :             break;
    4241             :             case svMatrix:
    4242             :             case svExternalDoubleRef:
    4243             :             {
    4244           0 :                 if (GetStackType() == svMatrix)
    4245           0 :                     pMatSrc = PopMatrix();
    4246             :                 else
    4247           0 :                     PopExternalDoubleRef(pMatSrc);
    4248             : 
    4249           0 :                 if (!pMatSrc)
    4250             :                 {
    4251           0 :                     PushIllegalParameter();
    4252           0 :                     return;
    4253             :                 }
    4254             :             }
    4255           0 :             break;
    4256             :             default:
    4257           0 :                 PushIllegalParameter();
    4258           0 :                 return;
    4259             :         }
    4260             : 
    4261         138 :         if (nGlobalError == 0)
    4262             :         {
    4263             :             double fVal;
    4264         138 :             ScQueryParam rParam;
    4265         138 :             rParam.nCol1       = nCol1;
    4266         138 :             rParam.nRow1       = nRow1;
    4267         138 :             rParam.nCol2       = nCol2;
    4268         138 :             rParam.nTab        = nTab1;
    4269             : 
    4270         138 :             ScQueryEntry& rEntry = rParam.GetEntry(0);
    4271         138 :             ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    4272         138 :             rEntry.bDoQuery = true;
    4273         138 :             if (fTyp < 0.0)
    4274          66 :                 rEntry.eOp = SC_GREATER_EQUAL;
    4275          72 :             else if (fTyp > 0.0)
    4276          62 :                 rEntry.eOp = SC_LESS_EQUAL;
    4277         138 :             switch ( GetStackType() )
    4278             :             {
    4279             :                 case svDouble:
    4280             :                 {
    4281           2 :                     fVal = GetDouble();
    4282           2 :                     rItem.mfVal = fVal;
    4283           2 :                     rItem.meType = ScQueryEntry::ByValue;
    4284             :                 }
    4285           2 :                 break;
    4286             :                 case svString:
    4287             :                 {
    4288          10 :                     rItem.meType = ScQueryEntry::ByString;
    4289          10 :                     rItem.maString = GetString();
    4290             :                 }
    4291          10 :                 break;
    4292             :                 case svDoubleRef :
    4293             :                 case svSingleRef :
    4294             :                 {
    4295         126 :                     ScAddress aAdr;
    4296         126 :                     if ( !PopDoubleRefOrSingleRef( aAdr ) )
    4297             :                     {
    4298           0 :                         PushInt(0);
    4299           0 :                         return ;
    4300             :                     }
    4301         126 :                     ScRefCellValue aCell;
    4302         126 :                     aCell.assign(*pDok, aAdr);
    4303         126 :                     if (aCell.hasNumeric())
    4304             :                     {
    4305          96 :                         fVal = GetCellValue(aAdr, aCell);
    4306          96 :                         rItem.meType = ScQueryEntry::ByValue;
    4307          96 :                         rItem.mfVal = fVal;
    4308             :                     }
    4309             :                     else
    4310             :                     {
    4311          30 :                         GetCellString(rItem.maString, aCell);
    4312          30 :                         rItem.meType = ScQueryEntry::ByString;
    4313         126 :                     }
    4314             :                 }
    4315         126 :                 break;
    4316             :                 case svExternalSingleRef:
    4317             :                 {
    4318           0 :                     ScExternalRefCache::TokenRef pToken;
    4319           0 :                     PopExternalSingleRef(pToken);
    4320           0 :                     if (!pToken)
    4321             :                     {
    4322           0 :                         PushInt(0);
    4323           0 :                         return;
    4324             :                     }
    4325           0 :                     if (pToken->GetType() == svDouble)
    4326             :                     {
    4327           0 :                         rItem.meType = ScQueryEntry::ByValue;
    4328           0 :                         rItem.mfVal = pToken->GetDouble();
    4329             :                     }
    4330             :                     else
    4331             :                     {
    4332           0 :                         rItem.meType = ScQueryEntry::ByString;
    4333           0 :                         rItem.maString = pToken->GetString();
    4334           0 :                     }
    4335             :                 }
    4336           0 :                 break;
    4337             :                 case svExternalDoubleRef:
    4338             :                     // TODO: Implement this.
    4339           0 :                     PushIllegalParameter();
    4340           0 :                     return;
    4341             :                 break;
    4342             :                 case svMatrix :
    4343             :                 {
    4344           0 :                     svl::SharedString aStr;
    4345             :                     ScMatValType nType = GetDoubleOrStringFromMatrix(
    4346           0 :                             rItem.mfVal, aStr);
    4347           0 :                     rItem.maString = aStr;
    4348           0 :                     rItem.meType = ScMatrix::IsNonValueType(nType) ?
    4349           0 :                         ScQueryEntry::ByString : ScQueryEntry::ByValue;
    4350             :                 }
    4351           0 :                 break;
    4352             :                 default:
    4353             :                 {
    4354           0 :                     PushIllegalParameter();
    4355           0 :                     return;
    4356             :                 }
    4357             :             }
    4358         138 :             if (rItem.meType == ScQueryEntry::ByString)
    4359             :             {
    4360          40 :                 bool bIsVBAMode = pDok->IsInVBAMode();
    4361             : 
    4362             :                 // #TODO handle MSO wildcards
    4363          40 :                 if ( bIsVBAMode )
    4364           0 :                     rParam.bRegExp = false;
    4365             :                 else
    4366          40 :                     rParam.bRegExp = MayBeRegExp(rEntry.GetQueryItem().maString.getString(), pDok);
    4367             :             }
    4368             : 
    4369         138 :             if (pMatSrc) // The source data is matrix array.
    4370             :             {
    4371             :                 SCSIZE nC, nR;
    4372           0 :                 pMatSrc->GetDimensions( nC, nR);
    4373           0 :                 if (nC > 1 && nR > 1)
    4374             :                 {
    4375             :                     // The source matrix must be a vector.
    4376           0 :                     PushIllegalParameter();
    4377           0 :                     return;
    4378             :                 }
    4379           0 :                 SCSIZE nMatCount = (nC == 1) ? nR : nC;
    4380           0 :                 VectorMatrixAccessor aMatAcc(*pMatSrc, nC == 1);
    4381             : 
    4382             :                 // simple serial search for equality mode (source data doesn't
    4383             :                 // need to be sorted).
    4384             : 
    4385           0 :                 if (rEntry.eOp == SC_EQUAL)
    4386             :                 {
    4387           0 :                     for (SCSIZE i = 0; i < nMatCount; ++i)
    4388             :                     {
    4389           0 :                         if (lcl_CompareMatrix2Query( i, aMatAcc, rEntry) == 0)
    4390             :                         {
    4391           0 :                             PushDouble(i+1); // found !
    4392           0 :                             return;
    4393             :                         }
    4394             :                     }
    4395           0 :                     PushNA(); // not found
    4396           0 :                     return;
    4397             :                 }
    4398             : 
    4399             :                 // binary search for non-equality mode (the source data is
    4400             :                 // assumed to be sorted).
    4401             : 
    4402           0 :                 bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL);
    4403           0 :                 SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0;
    4404           0 :                 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
    4405             :                 {
    4406           0 :                     SCSIZE nMid = nFirst + nLen/2;
    4407           0 :                     sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, aMatAcc, rEntry);
    4408           0 :                     if (nCmp == 0)
    4409             :                     {
    4410             :                         // exact match.  find the last item with the same value.
    4411           0 :                         lcl_GetLastMatch( nMid, aMatAcc, nMatCount, !bAscOrder);
    4412           0 :                         PushDouble( nMid+1);
    4413           0 :                         return;
    4414             :                     }
    4415             : 
    4416           0 :                     if (nLen == 1) // first and last items are next to each other.
    4417             :                     {
    4418           0 :                         if (nCmp < 0)
    4419           0 :                             nHitIndex = bAscOrder ? nLast : nFirst;
    4420             :                         else
    4421           0 :                             nHitIndex = bAscOrder ? nFirst : nLast;
    4422           0 :                         break;
    4423             :                     }
    4424             : 
    4425           0 :                     if (nCmp < 0)
    4426             :                     {
    4427           0 :                         if (bAscOrder)
    4428           0 :                             nFirst = nMid;
    4429             :                         else
    4430           0 :                             nLast = nMid;
    4431             :                     }
    4432             :                     else
    4433             :                     {
    4434           0 :                         if (bAscOrder)
    4435           0 :                             nLast = nMid;
    4436             :                         else
    4437           0 :                             nFirst = nMid;
    4438             :                     }
    4439             :                 }
    4440             : 
    4441           0 :                 if (nHitIndex == nMatCount-1) // last item
    4442             :                 {
    4443           0 :                     sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex, aMatAcc, rEntry);
    4444           0 :                     if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
    4445             :                     {
    4446             :                         // either the last item is an exact match or the real
    4447             :                         // hit is beyond the last item.
    4448           0 :                         PushDouble( nHitIndex+1);
    4449           0 :                         return;
    4450             :                     }
    4451             :                 }
    4452             : 
    4453           0 :                 if (nHitIndex > 0) // valid hit must be 2nd item or higher
    4454             :                 {
    4455           0 :                     PushDouble( nHitIndex); // non-exact match
    4456           0 :                     return;
    4457             :                 }
    4458             : 
    4459           0 :                 PushNA();
    4460           0 :                 return;
    4461             :             }
    4462             : 
    4463         138 :             SCCOLROW nDelta = 0;
    4464         138 :             if (nCol1 == nCol2)
    4465             :             {                                           // search row in column
    4466          76 :                 rParam.nRow2 = nRow2;
    4467          76 :                 rEntry.nField = nCol1;
    4468          76 :                 ScAddress aResultPos( nCol1, nRow1, nTab1);
    4469          76 :                 if (!LookupQueryWithCache( aResultPos, rParam))
    4470             :                 {
    4471          12 :                     PushNA();
    4472          12 :                     return;
    4473             :                 }
    4474          64 :                 nDelta = aResultPos.Row() - nRow1;
    4475             :             }
    4476             :             else
    4477             :             {                                           // search column in row
    4478             :                 SCCOL nC;
    4479          62 :                 rParam.bByRow = false;
    4480          62 :                 rParam.nRow2 = nRow1;
    4481          62 :                 rEntry.nField = nCol1;
    4482          62 :                 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
    4483             :                 // Advance Entry.nField in Iterator if column changed
    4484          62 :                 aCellIter.SetAdvanceQueryParamEntryField( true );
    4485          62 :                 if (fTyp == 0.0)
    4486             :                 {                                       // EQUAL
    4487           0 :                     if ( aCellIter.GetFirst() )
    4488           0 :                         nC = aCellIter.GetCol();
    4489             :                     else
    4490             :                     {
    4491           0 :                         PushNA();
    4492           0 :                         return;
    4493             :                     }
    4494             :                 }
    4495             :                 else
    4496             :                 {                                       // <= or >=
    4497             :                     SCROW nR;
    4498          62 :                     if ( !aCellIter.FindEqualOrSortedLastInRange( nC, nR ) )
    4499             :                     {
    4500           8 :                         PushNA();
    4501           8 :                         return;
    4502             :                     }
    4503             :                 }
    4504          54 :                 nDelta = nC - nCol1;
    4505             :             }
    4506         118 :             PushDouble((double) (nDelta + 1));
    4507             :         }
    4508             :         else
    4509           0 :             PushIllegalParameter();
    4510             :     }
    4511             : }
    4512             : 
    4513             : namespace {
    4514             : 
    4515         162 : bool isCellContentEmpty( const ScRefCellValue& rCell )
    4516             : {
    4517         162 :     switch (rCell.meType)
    4518             :     {
    4519             :         case CELLTYPE_VALUE:
    4520             :         case CELLTYPE_STRING:
    4521             :         case CELLTYPE_EDIT:
    4522          12 :             return false;
    4523             :         case CELLTYPE_FORMULA:
    4524             :         {
    4525         148 :             sc::FormulaResultValue aRes = rCell.mpFormula->GetResult();
    4526         148 :             if (aRes.meType != sc::FormulaResultValue::String)
    4527         134 :                 return false;
    4528          14 :             if (!aRes.maString.isEmpty())
    4529           0 :                 return false;
    4530             :         }
    4531          14 :         break;
    4532             :         default:
    4533             :             ;
    4534             :     }
    4535             : 
    4536          16 :     return true;
    4537             : }
    4538             : 
    4539             : }
    4540             : 
    4541          22 : void ScInterpreter::ScCountEmptyCells()
    4542             : {
    4543          22 :     if ( MustHaveParamCount( GetByte(), 1 ) )
    4544             :     {
    4545          22 :         sal_uLong nMaxCount = 0, nCount = 0;
    4546          22 :         switch (GetStackType())
    4547             :         {
    4548             :             case svSingleRef :
    4549             :             {
    4550          10 :                 nMaxCount = 1;
    4551          10 :                 ScAddress aAdr;
    4552          10 :                 PopSingleRef( aAdr );
    4553          10 :                 ScRefCellValue aCell;
    4554          10 :                 aCell.assign(*pDok, aAdr);
    4555          10 :                 if (!isCellContentEmpty(aCell))
    4556           4 :                     nCount = 1;
    4557             :             }
    4558          10 :             break;
    4559             :             case svDoubleRef :
    4560             :             case svRefList :
    4561             :             {
    4562          12 :                 ScRange aRange;
    4563          12 :                 short nParam = 1;
    4564          12 :                 size_t nRefInList = 0;
    4565          36 :                 while (nParam-- > 0)
    4566             :                 {
    4567          12 :                     PopDoubleRef( aRange, nParam, nRefInList);
    4568             :                     nMaxCount +=
    4569          24 :                         static_cast<sal_uLong>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) *
    4570          24 :                         static_cast<sal_uLong>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) *
    4571          24 :                         static_cast<sal_uLong>(aRange.aEnd.Tab() - aRange.aStart.Tab() + 1);
    4572             : 
    4573          12 :                     ScCellIterator aIter( pDok, aRange, mnSubTotalFlags);
    4574         164 :                     for (bool bHas = aIter.first(); bHas; bHas = aIter.next())
    4575             :                     {
    4576         152 :                         const ScRefCellValue& rCell = aIter.getRefCellValue();
    4577         152 :                         if (!isCellContentEmpty(rCell))
    4578         142 :                             ++nCount;
    4579             :                     }
    4580          12 :                 }
    4581             :             }
    4582          12 :             break;
    4583           0 :             default : SetError(errIllegalParameter); break;
    4584             :         }
    4585          22 :         PushDouble(nMaxCount - nCount);
    4586             :     }
    4587          22 : }
    4588             : 
    4589           8 : double ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc )
    4590             : {
    4591           8 :     sal_uInt8 nParamCount = GetByte();
    4592           8 :     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
    4593           2 :         return 0;
    4594             : 
    4595           6 :     SCCOL nCol3 = 0;
    4596           6 :     SCROW nRow3 = 0;
    4597           6 :     SCTAB nTab3 = 0;
    4598             : 
    4599           6 :     ScMatrixRef pSumExtraMatrix;
    4600           6 :     bool bSumExtraRange = (nParamCount == 3);
    4601           6 :     if (bSumExtraRange)
    4602             :     {
    4603             :         // Save only the upperleft cell in case of cell range.  The geometry
    4604             :         // of the 3rd parameter is taken from the 1st parameter.
    4605             : 
    4606           6 :         switch ( GetStackType() )
    4607             :         {
    4608             :             case svDoubleRef :
    4609             :                 {
    4610           6 :                     SCCOL nColJunk = 0;
    4611           6 :                     SCROW nRowJunk = 0;
    4612           6 :                     SCTAB nTabJunk = 0;
    4613           6 :                     PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
    4614           6 :                     if ( nTabJunk != nTab3 )
    4615             :                     {
    4616           0 :                         SetError( errIllegalParameter);
    4617           0 :                         return 0;
    4618             :                     }
    4619             :                 }
    4620           6 :                 break;
    4621             :             case svSingleRef :
    4622           0 :                 PopSingleRef( nCol3, nRow3, nTab3 );
    4623           0 :                 break;
    4624             :             case svMatrix:
    4625           0 :                 pSumExtraMatrix = PopMatrix();
    4626             :                 //! nCol3, nRow3, nTab3 remain 0
    4627           0 :                 break;
    4628             :             case svExternalSingleRef:
    4629             :                 {
    4630           0 :                     pSumExtraMatrix = new ScMatrix(1, 1, 0.0);
    4631           0 :                     ScExternalRefCache::TokenRef pToken;
    4632           0 :                     PopExternalSingleRef(pToken);
    4633           0 :                     if (!pToken)
    4634             :                     {
    4635           0 :                         SetError( errIllegalParameter);
    4636           0 :                         return 0;
    4637             :                     }
    4638             : 
    4639           0 :                     if (pToken->GetType() == svDouble)
    4640           0 :                         pSumExtraMatrix->PutDouble(pToken->GetDouble(), 0, 0);
    4641             :                     else
    4642           0 :                         pSumExtraMatrix->PutString(pToken->GetString(), 0, 0);
    4643             :                 }
    4644           0 :                 break;
    4645             :             case svExternalDoubleRef:
    4646           0 :                 PopExternalDoubleRef(pSumExtraMatrix);
    4647           0 :                 break;
    4648             :             default:
    4649           0 :                 SetError( errIllegalParameter);
    4650           0 :                 return 0;
    4651             :         }
    4652             :     }
    4653             : 
    4654           6 :     svl::SharedString aString;
    4655           6 :     double fVal = 0.0;
    4656           6 :     bool bIsString = true;
    4657           6 :     switch ( GetStackType() )
    4658             :     {
    4659             :         case svDoubleRef :
    4660             :         case svSingleRef :
    4661             :             {
    4662           0 :                 ScAddress aAdr;
    4663           0 :                 if ( !PopDoubleRefOrSingleRef( aAdr ) )
    4664           0 :                     return 0;
    4665             : 
    4666           0 :                 ScRefCellValue aCell;
    4667           0 :                 aCell.assign(*pDok, aAdr);
    4668           0 :                 switch (aCell.meType)
    4669             :                 {
    4670             :                     case CELLTYPE_VALUE :
    4671           0 :                         fVal = GetCellValue(aAdr, aCell);
    4672           0 :                         bIsString = false;
    4673           0 :                         break;
    4674             :                     case CELLTYPE_FORMULA :
    4675           0 :                         if (aCell.mpFormula->IsValue())
    4676             :                         {
    4677           0 :                             fVal = GetCellValue(aAdr, aCell);
    4678           0 :                             bIsString = false;
    4679             :                         }
    4680             :                         else
    4681           0 :                             GetCellString(aString, aCell);
    4682           0 :                         break;
    4683             :                     case CELLTYPE_STRING :
    4684             :                     case CELLTYPE_EDIT :
    4685           0 :                         GetCellString(aString, aCell);
    4686           0 :                         break;
    4687             :                     default:
    4688           0 :                         fVal = 0.0;
    4689           0 :                         bIsString = false;
    4690           0 :                 }
    4691             :             }
    4692           0 :             break;
    4693             :         case svString:
    4694           6 :             aString = GetString();
    4695           6 :             break;
    4696             :         case svMatrix :
    4697             :         case svExternalDoubleRef:
    4698             :             {
    4699           0 :                 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, aString);
    4700           0 :                 bIsString = ScMatrix::IsNonValueType( nType);
    4701             :             }
    4702           0 :             break;
    4703             :         case svExternalSingleRef:
    4704             :             {
    4705           0 :                 ScExternalRefCache::TokenRef pToken;
    4706           0 :                 PopExternalSingleRef(pToken);
    4707           0 :                 if (pToken)
    4708             :                 {
    4709           0 :                     if (pToken->GetType() == svDouble)
    4710             :                     {
    4711           0 :                         fVal = pToken->GetDouble();
    4712           0 :                         bIsString = false;
    4713             :                     }
    4714             :                     else
    4715           0 :                         aString = pToken->GetString();
    4716           0 :                 }
    4717             :             }
    4718           0 :             break;
    4719             :         default:
    4720             :             {
    4721           0 :                 fVal = GetDouble();
    4722           0 :                 bIsString = false;
    4723             :             }
    4724             :     }
    4725             : 
    4726           6 :     double fSum = 0.0;
    4727           6 :     double fMem = 0.0;
    4728           6 :     double fRes = 0.0;
    4729           6 :     double fCount = 0.0;
    4730           6 :     bool bNull = true;
    4731           6 :     short nParam = 1;
    4732           6 :     size_t nRefInList = 0;
    4733          18 :     while (nParam-- > 0)
    4734             :     {
    4735           6 :         SCCOL nCol1 = 0;
    4736           6 :         SCROW nRow1 = 0;
    4737           6 :         SCTAB nTab1 = 0;
    4738           6 :         SCCOL nCol2 = 0;
    4739           6 :         SCROW nRow2 = 0;
    4740           6 :         SCTAB nTab2 = 0;
    4741           6 :         ScMatrixRef pQueryMatrix;
    4742           6 :         switch ( GetStackType() )
    4743             :         {
    4744             :             case svRefList :
    4745           0 :                 if (bSumExtraRange)
    4746             :                 {
    4747           0 :                     SetError( errIllegalParameter);
    4748             :                 }
    4749             :                 else
    4750             :                 {
    4751           0 :                     ScRange aRange;
    4752           0 :                     PopDoubleRef( aRange, nParam, nRefInList);
    4753           0 :                     aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    4754             :                 }
    4755           0 :                 break;
    4756             :             case svDoubleRef :
    4757           6 :                 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    4758           6 :                 break;
    4759             :             case svSingleRef :
    4760           0 :                 PopSingleRef( nCol1, nRow1, nTab1 );
    4761           0 :                 nCol2 = nCol1;
    4762           0 :                 nRow2 = nRow1;
    4763           0 :                 nTab2 = nTab1;
    4764           0 :                 break;
    4765             :             case svMatrix:
    4766             :             case svExternalSingleRef:
    4767             :             case svExternalDoubleRef:
    4768             :                 {
    4769           0 :                     pQueryMatrix = GetMatrix();
    4770           0 :                     if (!pQueryMatrix)
    4771             :                     {
    4772           0 :                         SetError( errIllegalParameter);
    4773           0 :                         return 0;
    4774             :                     }
    4775           0 :                     nCol1 = 0;
    4776           0 :                     nRow1 = 0;
    4777           0 :                     nTab1 = 0;
    4778             :                     SCSIZE nC, nR;
    4779           0 :                     pQueryMatrix->GetDimensions( nC, nR);
    4780           0 :                     nCol2 = static_cast<SCCOL>(nC - 1);
    4781           0 :                     nRow2 = static_cast<SCROW>(nR - 1);
    4782           0 :                     nTab2 = 0;
    4783             :                 }
    4784           0 :                 break;
    4785             :             default:
    4786           0 :                 SetError( errIllegalParameter);
    4787             :         }
    4788           6 :         if ( nTab1 != nTab2 )
    4789             :         {
    4790           0 :             SetError( errIllegalParameter);
    4791             :         }
    4792             : 
    4793           6 :         if (bSumExtraRange)
    4794             :         {
    4795             :             // Take the range geometry of the 1st parameter and apply it to
    4796             :             // the 3rd. If parts of the resulting range would point outside
    4797             :             // the sheet, don't complain but silently ignore and simply cut
    4798             :             // them away, this is what Xcl does :-/
    4799             : 
    4800             :             // For the cut-away part we also don't need to determine the
    4801             :             // criteria match, so shrink the source range accordingly,
    4802             :             // instead of the result range.
    4803           6 :             SCCOL nColDelta = nCol2 - nCol1;
    4804           6 :             SCROW nRowDelta = nRow2 - nRow1;
    4805             :             SCCOL nMaxCol;
    4806             :             SCROW nMaxRow;
    4807           6 :             if (pSumExtraMatrix)
    4808             :             {
    4809             :                 SCSIZE nC, nR;
    4810           0 :                 pSumExtraMatrix->GetDimensions( nC, nR);
    4811           0 :                 nMaxCol = static_cast<SCCOL>(nC - 1);
    4812           0 :                 nMaxRow = static_cast<SCROW>(nR - 1);
    4813             :             }
    4814             :             else
    4815             :             {
    4816           6 :                 nMaxCol = MAXCOL;
    4817           6 :                 nMaxRow = MAXROW;
    4818             :             }
    4819           6 :             if (nCol3 + nColDelta > nMaxCol)
    4820             :             {
    4821           0 :                 SCCOL nNewDelta = nMaxCol - nCol3;
    4822           0 :                 nCol2 = nCol1 + nNewDelta;
    4823             :             }
    4824             : 
    4825           6 :             if (nRow3 + nRowDelta > nMaxRow)
    4826             :             {
    4827           0 :                 SCROW nNewDelta = nMaxRow - nRow3;
    4828           0 :                 nRow2 = nRow1 + nNewDelta;
    4829             :             }
    4830             :         }
    4831             :         else
    4832             :         {
    4833           0 :             nCol3 = nCol1;
    4834           0 :             nRow3 = nRow1;
    4835           0 :             nTab3 = nTab1;
    4836             :         }
    4837             : 
    4838           6 :         if (nGlobalError == 0)
    4839             :         {
    4840           6 :             ScQueryParam rParam;
    4841           6 :             rParam.nRow1       = nRow1;
    4842           6 :             rParam.nRow2       = nRow2;
    4843             : 
    4844           6 :             ScQueryEntry& rEntry = rParam.GetEntry(0);
    4845           6 :             ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    4846           6 :             rEntry.bDoQuery = true;
    4847           6 :             if (!bIsString)
    4848             :             {
    4849           0 :                 rItem.meType = ScQueryEntry::ByValue;
    4850           0 :                 rItem.mfVal = fVal;
    4851           0 :                 rEntry.eOp = SC_EQUAL;
    4852             :             }
    4853             :             else
    4854             :             {
    4855           6 :                 rParam.FillInExcelSyntax(pDok->GetSharedStringPool(), aString.getString(), 0);
    4856           6 :                 sal_uInt32 nIndex = 0;
    4857             :                 bool bNumber = pFormatter->IsNumberFormat(
    4858           6 :                         rItem.maString.getString(), nIndex, rItem.mfVal);
    4859           6 :                 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
    4860           6 :                 if (rItem.meType == ScQueryEntry::ByString)
    4861           6 :                     rParam.bRegExp = MayBeRegExp(rItem.maString.getString(), pDok);
    4862             :             }
    4863           6 :             ScAddress aAdr;
    4864           6 :             aAdr.SetTab( nTab3 );
    4865           6 :             rParam.nCol1  = nCol1;
    4866           6 :             rParam.nCol2  = nCol2;
    4867           6 :             rEntry.nField = nCol1;
    4868           6 :             SCsCOL nColDiff = nCol3 - nCol1;
    4869           6 :             SCsROW nRowDiff = nRow3 - nRow1;
    4870           6 :             if (pQueryMatrix)
    4871             :             {
    4872             :                 // Never case-sensitive.
    4873           0 :                 sc::CompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
    4874           0 :                 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
    4875           0 :                 if (nGlobalError || !pResultMatrix)
    4876             :                 {
    4877           0 :                     SetError( errIllegalParameter);
    4878             :                 }
    4879             : 
    4880           0 :                 if (pSumExtraMatrix)
    4881             :                 {
    4882           0 :                     for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
    4883             :                     {
    4884           0 :                         for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
    4885             :                         {
    4886           0 :                             if (pResultMatrix->IsValue( nCol, nRow) &&
    4887           0 :                                     pResultMatrix->GetDouble( nCol, nRow))
    4888             :                             {
    4889           0 :                                 SCSIZE nC = nCol + nColDiff;
    4890           0 :                                 SCSIZE nR = nRow + nRowDiff;
    4891           0 :                                 if (pSumExtraMatrix->IsValue( nC, nR))
    4892             :                                 {
    4893           0 :                                     fVal = pSumExtraMatrix->GetDouble( nC, nR);
    4894           0 :                                     ++fCount;
    4895           0 :                                     if ( bNull && fVal != 0.0 )
    4896             :                                     {
    4897           0 :                                         bNull = false;
    4898           0 :                                         fMem = fVal;
    4899             :                                     }
    4900             :                                     else
    4901           0 :                                         fSum += fVal;
    4902             :                                 }
    4903             :                             }
    4904             :                         }
    4905             :                     }
    4906             :                 }
    4907             :                 else
    4908             :                 {
    4909           0 :                     for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
    4910             :                     {
    4911           0 :                         for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
    4912             :                         {
    4913           0 :                             if (pResultMatrix->GetDouble( nCol, nRow))
    4914             :                             {
    4915           0 :                                 aAdr.SetCol( nCol + nColDiff);
    4916           0 :                                 aAdr.SetRow( nRow + nRowDiff);
    4917           0 :                                 ScRefCellValue aCell;
    4918           0 :                                 aCell.assign(*pDok, aAdr);
    4919           0 :                                 if (aCell.hasNumeric())
    4920             :                                 {
    4921           0 :                                     fVal = GetCellValue(aAdr, aCell);
    4922           0 :                                     ++fCount;
    4923           0 :                                     if ( bNull && fVal != 0.0 )
    4924             :                                     {
    4925           0 :                                         bNull = false;
    4926           0 :                                         fMem = fVal;
    4927             :                                     }
    4928             :                                     else
    4929           0 :                                         fSum += fVal;
    4930           0 :                                 }
    4931             :                             }
    4932             :                         }
    4933             :                     }
    4934           0 :                 }
    4935             :             }
    4936             :             else
    4937             :             {
    4938           6 :                 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
    4939             :                 // Increment Entry.nField in iterator when switching to next column.
    4940           6 :                 aCellIter.SetAdvanceQueryParamEntryField( true );
    4941           6 :                 if ( aCellIter.GetFirst() )
    4942             :                 {
    4943           6 :                     if (pSumExtraMatrix)
    4944             :                     {
    4945           0 :                         do
    4946             :                         {
    4947           0 :                             SCSIZE nC = aCellIter.GetCol() + nColDiff;
    4948           0 :                             SCSIZE nR = aCellIter.GetRow() + nRowDiff;
    4949           0 :                             if (pSumExtraMatrix->IsValue( nC, nR))
    4950             :                             {
    4951           0 :                                 fVal = pSumExtraMatrix->GetDouble( nC, nR);
    4952           0 :                                 ++fCount;
    4953           0 :                                 if ( bNull && fVal != 0.0 )
    4954             :                                 {
    4955           0 :                                     bNull = false;
    4956           0 :                                     fMem = fVal;
    4957             :                                 }
    4958             :                                 else
    4959           0 :                                     fSum += fVal;
    4960             :                             }
    4961             :                         } while ( aCellIter.GetNext() );
    4962             :                     }
    4963             :                     else
    4964             :                     {
    4965          46 :                         do
    4966             :                         {
    4967          46 :                             aAdr.SetCol( aCellIter.GetCol() + nColDiff);
    4968          46 :                             aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
    4969          46 :                             ScRefCellValue aCell;
    4970          46 :                             aCell.assign(*pDok, aAdr);
    4971          46 :                             if (aCell.hasNumeric())
    4972             :                             {
    4973          46 :                                 fVal = GetCellValue(aAdr, aCell);
    4974          46 :                                 ++fCount;
    4975          46 :                                 if ( bNull && fVal != 0.0 )
    4976             :                                 {
    4977           6 :                                     bNull = false;
    4978           6 :                                     fMem = fVal;
    4979             :                                 }
    4980             :                                 else
    4981          40 :                                     fSum += fVal;
    4982          46 :                             }
    4983             :                         } while ( aCellIter.GetNext() );
    4984             :                     }
    4985           6 :                 }
    4986           6 :             }
    4987             :         }
    4988             :         else
    4989             :         {
    4990           0 :             SetError( errIllegalParameter);
    4991           0 :             return 0;
    4992             :         }
    4993           6 :     }
    4994             : 
    4995           6 :     switch( eFunc )
    4996             :     {
    4997           6 :         case ifSUMIF:     fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
    4998           0 :         case ifAVERAGEIF: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
    4999             :     }
    5000           6 :     return fRes;
    5001             : }
    5002             : 
    5003           6 : void ScInterpreter::ScSumIf()
    5004             : {
    5005           6 :     PushDouble( IterateParametersIf( ifSUMIF));
    5006           6 : }
    5007             : 
    5008           2 : void ScInterpreter::ScAverageIf()
    5009             : {
    5010           2 :     PushDouble( IterateParametersIf( ifAVERAGEIF));
    5011           2 : }
    5012             : 
    5013          26 : void ScInterpreter::ScCountIf()
    5014             : {
    5015          26 :     if ( MustHaveParamCount( GetByte(), 2 ) )
    5016             :     {
    5017          26 :         svl::SharedString aString;
    5018          26 :         double fVal = 0.0;
    5019          26 :         bool bIsString = true;
    5020          26 :         switch ( GetStackType() )
    5021             :         {
    5022             :             case svDoubleRef :
    5023             :             case svSingleRef :
    5024             :             {
    5025           0 :                 ScAddress aAdr;
    5026           0 :                 if ( !PopDoubleRefOrSingleRef( aAdr ) )
    5027             :                 {
    5028           0 :                     PushInt(0);
    5029           0 :                     return ;
    5030             :                 }
    5031           0 :                 ScRefCellValue aCell;
    5032           0 :                 aCell.assign(*pDok, aAdr);
    5033           0 :                 switch (aCell.meType)
    5034             :                 {
    5035             :                     case CELLTYPE_VALUE :
    5036           0 :                         fVal = GetCellValue(aAdr, aCell);
    5037           0 :                         bIsString = false;
    5038           0 :                         break;
    5039             :                     case CELLTYPE_FORMULA :
    5040           0 :                         if (aCell.mpFormula->IsValue())
    5041             :                         {
    5042           0 :                             fVal = GetCellValue(aAdr, aCell);
    5043           0 :                             bIsString = false;
    5044             :                         }
    5045             :                         else
    5046           0 :                             GetCellString(aString, aCell);
    5047           0 :                         break;
    5048             :                     case CELLTYPE_STRING :
    5049             :                     case CELLTYPE_EDIT :
    5050           0 :                         GetCellString(aString, aCell);
    5051           0 :                         break;
    5052             :                     default:
    5053           0 :                         fVal = 0.0;
    5054           0 :                         bIsString = false;
    5055           0 :                 }
    5056             :             }
    5057           0 :             break;
    5058             :             case svMatrix:
    5059             :             case svExternalSingleRef:
    5060             :             case svExternalDoubleRef:
    5061             :             {
    5062           0 :                 ScMatValType nType = GetDoubleOrStringFromMatrix(fVal, aString);
    5063           0 :                 bIsString = ScMatrix::IsNonValueType( nType);
    5064             :             }
    5065           0 :             break;
    5066             :             case svString:
    5067          14 :                 aString = GetString();
    5068          14 :             break;
    5069             :             default:
    5070             :             {
    5071          12 :                 fVal = GetDouble();
    5072          12 :                 bIsString = false;
    5073             :             }
    5074             :         }
    5075          26 :         double fCount = 0.0;
    5076          26 :         short nParam = 1;
    5077          26 :         size_t nRefInList = 0;
    5078          78 :         while (nParam-- > 0)
    5079             :         {
    5080          26 :             SCCOL nCol1 = 0;
    5081          26 :             SCROW nRow1 = 0;
    5082          26 :             SCTAB nTab1 = 0;
    5083          26 :             SCCOL nCol2 = 0;
    5084          26 :             SCROW nRow2 = 0;
    5085          26 :             SCTAB nTab2 = 0;
    5086          26 :             ScMatrixRef pQueryMatrix;
    5087          26 :             switch ( GetStackType() )
    5088             :             {
    5089             :                 case svDoubleRef :
    5090             :                 case svRefList :
    5091             :                     {
    5092          24 :                         ScRange aRange;
    5093          24 :                         PopDoubleRef( aRange, nParam, nRefInList);
    5094          24 :                         aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    5095             :                     }
    5096          24 :                     break;
    5097             :                 case svSingleRef :
    5098           2 :                     PopSingleRef( nCol1, nRow1, nTab1 );
    5099           2 :                     nCol2 = nCol1;
    5100           2 :                     nRow2 = nRow1;
    5101           2 :                     nTab2 = nTab1;
    5102           2 :                     break;
    5103             :                 case svMatrix:
    5104             :                 case svExternalSingleRef:
    5105             :                 case svExternalDoubleRef:
    5106             :                 {
    5107           0 :                     pQueryMatrix = GetMatrix();
    5108           0 :                     if (!pQueryMatrix)
    5109             :                     {
    5110           0 :                         PushIllegalParameter();
    5111           0 :                         return;
    5112             :                     }
    5113           0 :                     nCol1 = 0;
    5114           0 :                     nRow1 = 0;
    5115           0 :                     nTab1 = 0;
    5116             :                     SCSIZE nC, nR;
    5117           0 :                     pQueryMatrix->GetDimensions( nC, nR);
    5118           0 :                     nCol2 = static_cast<SCCOL>(nC - 1);
    5119           0 :                     nRow2 = static_cast<SCROW>(nR - 1);
    5120           0 :                     nTab2 = 0;
    5121             :                 }
    5122           0 :                 break;
    5123             :                 default:
    5124           0 :                     PushIllegalParameter();
    5125           0 :                     return ;
    5126             :             }
    5127          26 :             if ( nTab1 != nTab2 )
    5128             :             {
    5129           0 :                 PushIllegalParameter();
    5130           0 :                 return;
    5131             :             }
    5132          26 :             if (nCol1 > nCol2)
    5133             :             {
    5134           0 :                 PushIllegalParameter();
    5135           0 :                 return;
    5136             :             }
    5137          26 :             if (nGlobalError == 0)
    5138             :             {
    5139          26 :                 ScQueryParam rParam;
    5140          26 :                 rParam.nRow1       = nRow1;
    5141          26 :                 rParam.nRow2       = nRow2;
    5142             : 
    5143          26 :                 ScQueryEntry& rEntry = rParam.GetEntry(0);
    5144          26 :                 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    5145          26 :                 rEntry.bDoQuery = true;
    5146          26 :                 if (!bIsString)
    5147             :                 {
    5148          12 :                     rItem.meType = ScQueryEntry::ByValue;
    5149          12 :                     rItem.mfVal = fVal;
    5150          12 :                     rEntry.eOp = SC_EQUAL;
    5151             :                 }
    5152             :                 else
    5153             :                 {
    5154          14 :                     rParam.FillInExcelSyntax(pDok->GetSharedStringPool(), aString.getString(), 0);
    5155          14 :                     sal_uInt32 nIndex = 0;
    5156             :                     bool bNumber = pFormatter->IsNumberFormat(
    5157          14 :                             rItem.maString.getString(), nIndex, rItem.mfVal);
    5158          14 :                     rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
    5159          14 :                     if (rItem.meType == ScQueryEntry::ByString)
    5160           4 :                         rParam.bRegExp = MayBeRegExp(rItem.maString.getString(), pDok);
    5161             :                 }
    5162          26 :                 rParam.nCol1  = nCol1;
    5163          26 :                 rParam.nCol2  = nCol2;
    5164          26 :                 rEntry.nField = nCol1;
    5165          26 :                 if (pQueryMatrix)
    5166             :                 {
    5167             :                     // Never case-sensitive.
    5168           0 :                     sc::CompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
    5169           0 :                     ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
    5170           0 :                     if (nGlobalError || !pResultMatrix)
    5171             :                     {
    5172           0 :                         PushIllegalParameter();
    5173           0 :                         return;
    5174             :                     }
    5175             : 
    5176           0 :                     SCSIZE nSize = pResultMatrix->GetElementCount();
    5177           0 :                     for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
    5178             :                     {
    5179           0 :                         if (pResultMatrix->IsValue( nIndex) &&
    5180           0 :                                 pResultMatrix->GetDouble( nIndex))
    5181           0 :                             ++fCount;
    5182           0 :                     }
    5183             :                 }
    5184             :                 else
    5185             :                 {
    5186          26 :                     ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
    5187             :                     // Keep Entry.nField in iterator on column change
    5188          26 :                     aCellIter.SetAdvanceQueryParamEntryField( true );
    5189          26 :                     if ( aCellIter.GetFirst() )
    5190             :                     {
    5191          82 :                         do
    5192             :                         {
    5193          82 :                             fCount++;
    5194             :                         } while ( aCellIter.GetNext() );
    5195          26 :                     }
    5196          26 :                 }
    5197             :             }
    5198             :             else
    5199             :             {
    5200           0 :                 PushIllegalParameter();
    5201           0 :                 return;
    5202             :             }
    5203          26 :         }
    5204          26 :         PushDouble(fCount);
    5205             :     }
    5206             : }
    5207             : 
    5208           0 : double ScInterpreter::IterateParametersIfs( ScIterFuncIfs eFunc )
    5209             : {
    5210           0 :     sal_uInt8 nParamCount = GetByte();
    5211           0 :     sal_uInt8 nQueryCount = nParamCount / 2;
    5212             : 
    5213             :     bool bCheck;
    5214           0 :     if ( eFunc == ifCOUNTIFS )
    5215           0 :         bCheck = (nParamCount >= 2) && (nParamCount % 2 == 0);
    5216             :     else
    5217           0 :         bCheck = (nParamCount >= 3) && (nParamCount % 2 == 1);
    5218             : 
    5219           0 :     if ( !bCheck )
    5220             :     {
    5221           0 :         SetError( errParameterExpected);
    5222             :     }
    5223             :     else
    5224             :     {
    5225           0 :         std::vector<sal_uInt8> aResArray;
    5226           0 :         size_t nRowSize = 0;
    5227           0 :         size_t nColSize = 0;
    5228           0 :         double fVal = 0.0;
    5229           0 :         double fSum = 0.0;
    5230           0 :         double fMem = 0.0;
    5231           0 :         double fRes = 0.0;
    5232           0 :         double fCount = 0.0;
    5233           0 :         short nParam = 1;
    5234           0 :         size_t nRefInList = 0;
    5235           0 :         SCCOL nDimensionCols = 0;
    5236           0 :         SCROW nDimensionRows = 0;
    5237             : 
    5238           0 :         while (nParamCount > 1 && !nGlobalError)
    5239             :         {
    5240             :             // take criteria
    5241           0 :             svl::SharedString aString;
    5242           0 :             fVal = 0.0;
    5243           0 :             bool bIsString = true;
    5244           0 :             switch ( GetStackType() )
    5245             :             {
    5246             :                 case svDoubleRef :
    5247             :                 case svSingleRef :
    5248             :                     {
    5249           0 :                         ScAddress aAdr;
    5250           0 :                         if ( !PopDoubleRefOrSingleRef( aAdr ) )
    5251           0 :                             return 0;
    5252             : 
    5253           0 :                         ScRefCellValue aCell;
    5254           0 :                         aCell.assign(*pDok, aAdr);
    5255           0 :                         switch (aCell.meType)
    5256             :                         {
    5257             :                             case CELLTYPE_VALUE :
    5258           0 :                                 fVal = GetCellValue(aAdr, aCell);
    5259           0 :                                 bIsString = false;
    5260           0 :                                 break;
    5261             :                             case CELLTYPE_FORMULA :
    5262           0 :                                 if (aCell.mpFormula->IsValue())
    5263             :                                 {
    5264           0 :                                     fVal = GetCellValue(aAdr, aCell);
    5265           0 :                                     bIsString = false;
    5266             :                                 }
    5267             :                                 else
    5268           0 :                                     GetCellString(aString, aCell);
    5269           0 :                                 break;
    5270             :                             case CELLTYPE_STRING :
    5271             :                             case CELLTYPE_EDIT :
    5272           0 :                                 GetCellString(aString, aCell);
    5273           0 :                                 break;
    5274             :                             default:
    5275           0 :                                 fVal = 0.0;
    5276           0 :                                 bIsString = false;
    5277           0 :                         }
    5278             :                     }
    5279           0 :                     break;
    5280             :                 case svString:
    5281           0 :                     aString = GetString();
    5282           0 :                     break;
    5283             :                 case svMatrix :
    5284             :                 case svExternalDoubleRef:
    5285             :                     {
    5286           0 :                         ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, aString);
    5287           0 :                         bIsString = ScMatrix::IsNonValueType( nType);
    5288             :                     }
    5289           0 :                     break;
    5290             :                 case svExternalSingleRef:
    5291             :                     {
    5292           0 :                         ScExternalRefCache::TokenRef pToken;
    5293           0 :                         PopExternalSingleRef(pToken);
    5294           0 :                         if (pToken)
    5295             :                         {
    5296           0 :                             if (pToken->GetType() == svDouble)
    5297             :                             {
    5298           0 :                                 fVal = pToken->GetDouble();
    5299           0 :                                 bIsString = false;
    5300             :                             }
    5301             :                             else
    5302           0 :                                 aString = pToken->GetString();
    5303           0 :                         }
    5304             :                     }
    5305           0 :                     break;
    5306             :                 default:
    5307             :                     {
    5308           0 :                         fVal = GetDouble();
    5309           0 :                         bIsString = false;
    5310             :                     }
    5311             :             }
    5312             : 
    5313           0 :             if (nGlobalError)
    5314           0 :                 return 0;   // and bail out, no need to evaluate other arguments
    5315             : 
    5316             :             // take range
    5317           0 :             nParam = 1;
    5318           0 :             nRefInList = 0;
    5319           0 :             SCCOL nCol1 = 0;
    5320           0 :             SCROW nRow1 = 0;
    5321           0 :             SCTAB nTab1 = 0;
    5322           0 :             SCCOL nCol2 = 0;
    5323           0 :             SCROW nRow2 = 0;
    5324           0 :             SCTAB nTab2 = 0;
    5325           0 :             ScMatrixRef pQueryMatrix;
    5326           0 :             switch ( GetStackType() )
    5327             :             {
    5328             :                 case svRefList :
    5329             :                     {
    5330           0 :                         ScRange aRange;
    5331           0 :                         PopDoubleRef( aRange, nParam, nRefInList);
    5332           0 :                         aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    5333             :                     }
    5334           0 :                     break;
    5335             :                 case svDoubleRef :
    5336           0 :                     PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
    5337           0 :                     break;
    5338             :                 case svSingleRef :
    5339           0 :                     PopSingleRef( nCol1, nRow1, nTab1 );
    5340           0 :                     nCol2 = nCol1;
    5341           0 :                     nRow2 = nRow1;
    5342           0 :                     nTab2 = nTab1;
    5343           0 :                     break;
    5344             :                 case svMatrix:
    5345             :                 case svExternalSingleRef:
    5346             :                 case svExternalDoubleRef:
    5347             :                     {
    5348           0 :                         pQueryMatrix = PopMatrix();
    5349           0 :                         if (!pQueryMatrix)
    5350             :                         {
    5351           0 :                             SetError( errIllegalParameter);
    5352           0 :                             return 0;
    5353             :                         }
    5354           0 :                         nCol1 = 0;
    5355           0 :                         nRow1 = 0;
    5356           0 :                         nTab1 = 0;
    5357             :                         SCSIZE nC, nR;
    5358           0 :                         pQueryMatrix->GetDimensions( nC, nR);
    5359           0 :                         nCol2 = static_cast<SCCOL>(nC - 1);
    5360           0 :                         nRow2 = static_cast<SCROW>(nR - 1);
    5361           0 :                         nTab2 = 0;
    5362             :                     }
    5363           0 :                     break;
    5364             :                 default:
    5365           0 :                     SetError( errIllegalParameter);
    5366           0 :                     return 0;
    5367             :             }
    5368           0 :             if ( nTab1 != nTab2 )
    5369             :             {
    5370           0 :                 SetError( errIllegalArgument);
    5371           0 :                 return 0;
    5372             :             }
    5373             : 
    5374             :             // All reference ranges must be of same dimension and size.
    5375           0 :             if (!nDimensionCols)
    5376           0 :                 nDimensionCols = nCol2 - nCol1 + 1;
    5377           0 :             if (!nDimensionRows)
    5378           0 :                 nDimensionRows = nRow2 - nRow1 + 1;
    5379           0 :             if ((nDimensionCols != (nCol2 - nCol1 + 1)) || (nDimensionRows != (nRow2 - nRow1 + 1)))
    5380             :             {
    5381           0 :                 SetError ( errIllegalArgument);
    5382           0 :                 return 0;
    5383             :             }
    5384             : 
    5385             :             // recalculate matrix values
    5386           0 :             if (nGlobalError)
    5387           0 :                 return 0;
    5388             : 
    5389             :             // initialize temporary result matrix
    5390           0 :             if (aResArray.empty())
    5391             :             {
    5392           0 :                 nColSize = nCol2 - nCol1 + 1;
    5393           0 :                 nRowSize = nRow2 - nRow1 + 1;
    5394           0 :                 aResArray.resize(nColSize*nRowSize, 0);
    5395             :             }
    5396             : 
    5397           0 :             ScQueryParam rParam;
    5398           0 :             rParam.nRow1       = nRow1;
    5399           0 :             rParam.nRow2       = nRow2;
    5400             : 
    5401           0 :             ScQueryEntry& rEntry = rParam.GetEntry(0);
    5402           0 :             ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    5403           0 :             rEntry.bDoQuery = true;
    5404           0 :             if (!bIsString)
    5405             :             {
    5406           0 :                 rItem.meType = ScQueryEntry::ByValue;
    5407           0 :                 rItem.mfVal = fVal;
    5408           0 :                 rEntry.eOp = SC_EQUAL;
    5409             :             }
    5410             :             else
    5411             :             {
    5412           0 :                 rParam.FillInExcelSyntax(pDok->GetSharedStringPool(), aString.getString(), 0);
    5413           0 :                 sal_uInt32 nIndex = 0;
    5414             :                 bool bNumber = pFormatter->IsNumberFormat(
    5415           0 :                         rItem.maString.getString(), nIndex, rItem.mfVal);
    5416           0 :                 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
    5417           0 :                 if (rItem.meType == ScQueryEntry::ByString)
    5418           0 :                     rParam.bRegExp = MayBeRegExp(rItem.maString.getString(), pDok);
    5419             :             }
    5420           0 :             ScAddress aAdr;
    5421           0 :             aAdr.SetTab( nTab1 );
    5422           0 :             rParam.nCol1  = nCol1;
    5423           0 :             rParam.nCol2  = nCol2;
    5424           0 :             rEntry.nField = nCol1;
    5425           0 :             SCsCOL nColDiff = -nCol1;
    5426           0 :             SCsROW nRowDiff = -nRow1;
    5427           0 :             if (pQueryMatrix)
    5428             :             {
    5429             :                 // Never case-sensitive.
    5430           0 :                 sc::CompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
    5431           0 :                 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
    5432           0 :                 if (nGlobalError || !pResultMatrix)
    5433             :                 {
    5434           0 :                     SetError( errIllegalParameter);
    5435           0 :                     return 0;
    5436             :                 }
    5437             : 
    5438             :                 // result matrix is filled with boolean values.
    5439           0 :                 std::vector<double> aResValues;
    5440           0 :                 pResultMatrix->GetDoubleArray(aResValues, true);
    5441           0 :                 if (aResArray.size() != aResValues.size())
    5442             :                 {
    5443           0 :                     SetError( errIllegalParameter);
    5444           0 :                     return 0;
    5445             :                 }
    5446             : 
    5447           0 :                 std::vector<sal_uInt8>::iterator itRes = aResArray.begin(), itResEnd = aResArray.end();
    5448           0 :                 std::vector<double>::const_iterator itThisRes = aResValues.begin();
    5449           0 :                 for (; itRes != itResEnd; ++itRes, ++itThisRes)
    5450           0 :                     *itRes += *itThisRes;
    5451             :             }
    5452             :             else
    5453             :             {
    5454           0 :                 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
    5455             :                 // Increment Entry.nField in iterator when switching to next column.
    5456           0 :                 aCellIter.SetAdvanceQueryParamEntryField( true );
    5457           0 :                 if ( aCellIter.GetFirst() )
    5458             :                 {
    5459           0 :                     do
    5460             :                     {
    5461           0 :                         size_t nC = aCellIter.GetCol() + nColDiff;
    5462           0 :                         size_t nR = aCellIter.GetRow() + nRowDiff;
    5463           0 :                         ++aResArray[nC*nRowSize+nR];
    5464             :                     } while ( aCellIter.GetNext() );
    5465           0 :                 }
    5466             :             }
    5467           0 :             nParamCount -= 2;
    5468           0 :         }
    5469             : 
    5470           0 :         if (nGlobalError)
    5471           0 :             return 0;   // bail out
    5472             : 
    5473             :         // main range - only for AVERAGEIFS and SUMIFS
    5474           0 :         if (nParamCount == 1)
    5475             :         {
    5476           0 :             nParam = 1;
    5477           0 :             nRefInList = 0;
    5478           0 :             bool bNull = true;
    5479           0 :             SCCOL nMainCol1 = 0;
    5480           0 :             SCROW nMainRow1 = 0;
    5481           0 :             SCTAB nMainTab1 = 0;
    5482           0 :             SCCOL nMainCol2 = 0;
    5483           0 :             SCROW nMainRow2 = 0;
    5484           0 :             SCTAB nMainTab2 = 0;
    5485           0 :             ScMatrixRef pMainMatrix;
    5486           0 :             switch ( GetStackType() )
    5487             :             {
    5488             :                 case svRefList :
    5489             :                     {
    5490           0 :                         ScRange aRange;
    5491           0 :                         PopDoubleRef( aRange, nParam, nRefInList);
    5492           0 :                         aRange.GetVars( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2);
    5493             :                     }
    5494           0 :                     break;
    5495             :                 case svDoubleRef :
    5496           0 :                     PopDoubleRef( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2 );
    5497           0 :                     break;
    5498             :                 case svSingleRef :
    5499           0 :                     PopSingleRef( nMainCol1, nMainRow1, nMainTab1 );
    5500           0 :                     nMainCol2 = nMainCol1;
    5501           0 :                     nMainRow2 = nMainRow1;
    5502           0 :                     nMainTab2 = nMainTab1;
    5503           0 :                     break;
    5504             :                 case svMatrix:
    5505             :                 case svExternalSingleRef:
    5506             :                 case svExternalDoubleRef:
    5507             :                     {
    5508           0 :                         pMainMatrix = PopMatrix();
    5509           0 :                         if (!pMainMatrix)
    5510             :                         {
    5511           0 :                             SetError( errIllegalParameter);
    5512             :                         }
    5513           0 :                         nMainCol1 = 0;
    5514           0 :                         nMainRow1 = 0;
    5515           0 :                         nMainTab1 = 0;
    5516             :                         SCSIZE nC, nR;
    5517           0 :                         pMainMatrix->GetDimensions( nC, nR);
    5518           0 :                         nMainCol2 = static_cast<SCCOL>(nC - 1);
    5519           0 :                         nMainRow2 = static_cast<SCROW>(nR - 1);
    5520           0 :                         nMainTab2 = 0;
    5521             :                     }
    5522           0 :                     break;
    5523             :                 default:
    5524           0 :                     SetError( errIllegalParameter);
    5525           0 :                     return 0;
    5526             :             }
    5527           0 :             if ( nMainTab1 != nMainTab2 )
    5528             :             {
    5529           0 :                 SetError( errIllegalArgument);
    5530           0 :                 return 0;
    5531             :             }
    5532             : 
    5533             :             // All reference ranges must be of same dimension and size.
    5534           0 :             if ((nDimensionCols != (nMainCol2 - nMainCol1 + 1)) || (nDimensionRows != (nMainRow2 - nMainRow1 + 1)))
    5535             :             {
    5536           0 :                 SetError ( errIllegalArgument);
    5537           0 :                 return 0;
    5538             :             }
    5539             : 
    5540           0 :             if (nGlobalError)
    5541           0 :                 return 0;   // bail out
    5542             : 
    5543             :             // end-result calculation
    5544           0 :             ScAddress aAdr;
    5545           0 :             aAdr.SetTab( nMainTab1 );
    5546           0 :             if (pMainMatrix)
    5547             :             {
    5548           0 :                 std::vector<double> aMainValues;
    5549           0 :                 pMainMatrix->GetDoubleArray(aMainValues, false); // Map empty values to NaN's.
    5550           0 :                 if (aResArray.size() != aMainValues.size())
    5551             :                 {
    5552           0 :                     SetError( errIllegalArgument);
    5553           0 :                     return 0;
    5554             :                 }
    5555             : 
    5556           0 :                 std::vector<sal_uInt8>::const_iterator itRes = aResArray.begin(), itResEnd = aResArray.end();
    5557           0 :                 std::vector<double>::const_iterator itMain = aMainValues.begin();
    5558           0 :                 for (; itRes != itResEnd; ++itRes, ++itMain)
    5559             :                 {
    5560           0 :                     if (*itRes != nQueryCount)
    5561           0 :                         continue;
    5562             : 
    5563           0 :                     fVal = *itMain;
    5564           0 :                     if (GetDoubleErrorValue(fVal) == errElementNaN)
    5565           0 :                         continue;
    5566             : 
    5567           0 :                     ++fCount;
    5568           0 :                     if (bNull && fVal != 0.0)
    5569             :                     {
    5570           0 :                         bNull = false;
    5571           0 :                         fMem = fVal;
    5572             :                     }
    5573             :                     else
    5574           0 :                         fSum += fVal;
    5575           0 :                 }
    5576             :             }
    5577             :             else
    5578             :             {
    5579           0 :                 std::vector<sal_uInt8>::const_iterator itRes = aResArray.begin();
    5580           0 :                 for (size_t nCol = 0; nCol < nColSize; ++nCol)
    5581             :                 {
    5582           0 :                     for (size_t nRow = 0; nRow < nRowSize; ++nRow, ++itRes)
    5583             :                     {
    5584           0 :                         if (*itRes == nQueryCount)
    5585             :                         {
    5586           0 :                             aAdr.SetCol( static_cast<SCCOL>(nCol) + nMainCol1);
    5587           0 :                             aAdr.SetRow( static_cast<SCROW>(nRow) + nMainRow1);
    5588           0 :                             ScRefCellValue aCell;
    5589           0 :                             aCell.assign(*pDok, aAdr);
    5590           0 :                             if (aCell.hasNumeric())
    5591             :                             {
    5592           0 :                                 fVal = GetCellValue(aAdr, aCell);
    5593           0 :                                 ++fCount;
    5594           0 :                                 if ( bNull && fVal != 0.0 )
    5595             :                                 {
    5596           0 :                                     bNull = false;
    5597           0 :                                     fMem = fVal;
    5598             :                                 }
    5599             :                                 else
    5600           0 :                                     fSum += fVal;
    5601           0 :                             }
    5602             :                         }
    5603             :                     }
    5604             :                 }
    5605           0 :             }
    5606             :         }
    5607             :         else
    5608             :         {
    5609           0 :             std::vector<sal_uInt8>::const_iterator itRes = aResArray.begin(), itResEnd = aResArray.end();
    5610           0 :             for (; itRes != itResEnd; ++itRes)
    5611           0 :                 if (*itRes == nQueryCount)
    5612           0 :                     ++fCount;
    5613             :         }
    5614             : 
    5615           0 :         switch( eFunc )
    5616             :         {
    5617           0 :             case ifSUMIFS:     fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
    5618           0 :             case ifAVERAGEIFS: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
    5619           0 :             case ifCOUNTIFS:   fRes = fCount; break;
    5620             :             default: ; // nothing
    5621             :         }
    5622           0 :         return fRes;
    5623             :     }
    5624           0 :     return 0;
    5625             : }
    5626             : 
    5627           0 : void ScInterpreter::ScSumIfs()
    5628             : {
    5629           0 :     PushDouble( IterateParametersIfs( ifSUMIFS));
    5630           0 : }
    5631             : 
    5632           0 : void ScInterpreter::ScAverageIfs()
    5633             : {
    5634           0 :     PushDouble( IterateParametersIfs( ifAVERAGEIFS));
    5635           0 : }
    5636             : 
    5637           0 : void ScInterpreter::ScCountIfs()
    5638             : {
    5639           0 :     PushDouble( IterateParametersIfs( ifCOUNTIFS));
    5640           0 : }
    5641             : 
    5642           6 : void ScInterpreter::ScLookup()
    5643             : {
    5644           6 :     sal_uInt8 nParamCount = GetByte();
    5645           6 :     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
    5646           0 :         return ;
    5647             : 
    5648          12 :     ScMatrixRef pDataMat = NULL, pResMat = NULL;
    5649           6 :     SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
    5650           6 :     SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
    5651           6 :     SCTAB nTab1 = 0, nResTab = 0;
    5652           6 :     SCSIZE nLenMajor = 0;   // length of major direction
    5653           6 :     bool bVertical = true;  // whether to lookup vertically or horizontally
    5654             : 
    5655             :     // The third parameter, result array, for double, string and single reference.
    5656           6 :     double fResVal = 0.0;
    5657          12 :     svl::SharedString aResStr;
    5658           6 :     ScAddress aResAdr;
    5659           6 :     StackVar eResArrayType = svUnknown;
    5660             : 
    5661           6 :     if (nParamCount == 3)
    5662             :     {
    5663           6 :         eResArrayType = GetStackType();
    5664           6 :         switch (eResArrayType)
    5665             :         {
    5666             :             case svDoubleRef:
    5667             :             {
    5668             :                 SCTAB nTabJunk;
    5669             :                 PopDoubleRef(nResCol1, nResRow1, nResTab,
    5670           6 :                              nResCol2, nResRow2, nTabJunk);
    5671          12 :                 if (nResTab != nTabJunk ||
    5672          12 :                     ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
    5673             :                 {
    5674             :                     // The result array must be a vector.
    5675           0 :                     PushIllegalParameter();
    5676           0 :                     return;
    5677             :                 }
    5678             :             }
    5679           6 :             break;
    5680             :             case svMatrix:
    5681             :             case svExternalSingleRef:
    5682             :             case svExternalDoubleRef:
    5683             :             {
    5684           0 :                 pResMat = GetMatrix();
    5685           0 :                 if (!pResMat)
    5686             :                 {
    5687           0 :                     PushIllegalParameter();
    5688           0 :                     return;
    5689             :                 }
    5690             :                 SCSIZE nC, nR;
    5691           0 :                 pResMat->GetDimensions(nC, nR);
    5692           0 :                 if (nC != 1 && nR != 1)
    5693             :                 {
    5694             :                     // Result matrix must be a vector.
    5695           0 :                     PushIllegalParameter();
    5696           0 :                     return;
    5697             :                 }
    5698             :             }
    5699           0 :             break;
    5700             :             case svDouble:
    5701           0 :                 fResVal = GetDouble();
    5702           0 :             break;
    5703             :             case svString:
    5704           0 :                 aResStr = GetString();
    5705           0 :             break;
    5706             :             case svSingleRef:
    5707           0 :                 PopSingleRef( aResAdr );
    5708           0 :             break;
    5709             :             default:
    5710           0 :                 PushIllegalParameter();
    5711           0 :                 return;
    5712             :         }
    5713             :     }
    5714             : 
    5715             :     // For double, string and single reference.
    5716           6 :     double fDataVal = 0.0;
    5717           6 :     svl::SharedString aDataStr;
    5718           6 :     ScAddress aDataAdr;
    5719           6 :     bool bValueData = false;
    5720             : 
    5721             :     // Get the data-result range and also determine whether this is vertical
    5722             :     // lookup or horizontal lookup.
    5723             : 
    5724           6 :     StackVar eDataArrayType = GetStackType();
    5725           6 :     switch (eDataArrayType)
    5726             :     {
    5727             :         case svDoubleRef:
    5728             :         {
    5729             :             SCTAB nTabJunk;
    5730           6 :             PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
    5731           6 :             if (nTab1 != nTabJunk)
    5732             :             {
    5733           0 :                 PushIllegalParameter();
    5734           0 :                 return;
    5735             :             }
    5736           6 :             bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
    5737           6 :             nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
    5738             :         }
    5739           6 :         break;
    5740             :         case svMatrix:
    5741             :         case svExternalSingleRef:
    5742             :         case svExternalDoubleRef:
    5743             :         {
    5744           0 :             pDataMat = GetMatrix();
    5745           0 :             if (!pDataMat)
    5746             :             {
    5747           0 :                 PushIllegalParameter();
    5748           0 :                 return;
    5749             :             }
    5750             : 
    5751             :             SCSIZE nC, nR;
    5752           0 :             pDataMat->GetDimensions(nC, nR);
    5753           0 :             bVertical = (nR >= nC);
    5754           0 :             nLenMajor = bVertical ? nR : nC;
    5755             :         }
    5756           0 :         break;
    5757             :         case svDouble:
    5758             :         {
    5759           0 :             fDataVal = GetDouble();
    5760           0 :             bValueData = true;
    5761             :         }
    5762           0 :         break;
    5763             :         case svString:
    5764             :         {
    5765           0 :             aDataStr = GetString();
    5766             :         }
    5767           0 :         break;
    5768             :         case svSingleRef:
    5769             :         {
    5770           0 :             PopSingleRef( aDataAdr );
    5771           0 :             ScRefCellValue aCell;
    5772           0 :             aCell.assign(*pDok, aDataAdr);
    5773           0 :             if (aCell.hasEmptyValue())
    5774             :             {
    5775             :                 // Empty cells aren't found anywhere, bail out early.
    5776           0 :                 SetError( NOTAVAILABLE);
    5777             :             }
    5778           0 :             else if (aCell.hasNumeric())
    5779             :             {
    5780           0 :                 fDataVal = GetCellValue(aDataAdr, aCell);
    5781           0 :                 bValueData = true;
    5782             :             }
    5783             :             else
    5784           0 :                 GetCellString(aDataStr, aCell);
    5785             :         }
    5786           0 :         break;
    5787             :         default:
    5788           0 :             SetError( errIllegalParameter);
    5789             :     }
    5790             : 
    5791           6 :     if (nGlobalError)
    5792             :     {
    5793           0 :         PushError( nGlobalError);
    5794           0 :         return;
    5795             :     }
    5796             : 
    5797             :     // Get the lookup value.
    5798             : 
    5799           6 :     ScQueryParam aParam;
    5800           6 :     ScQueryEntry& rEntry = aParam.GetEntry(0);
    5801           6 :     if ( !FillEntry(rEntry) )
    5802           0 :         return;
    5803             : 
    5804           6 :     if ( eDataArrayType == svDouble || eDataArrayType == svString ||
    5805             :             eDataArrayType == svSingleRef )
    5806             :     {
    5807             :         // Delta position for a single value is always 0.
    5808             : 
    5809             :         // Found if data <= query, but not if query is string and found data is
    5810             :         // numeric or vice versa. This is how Excel does it but doesn't
    5811             :         // document it.
    5812             : 
    5813           0 :         bool bFound = false;
    5814           0 :         ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    5815             : 
    5816           0 :         if ( bValueData )
    5817             :         {
    5818           0 :             if (rItem.meType == ScQueryEntry::ByString)
    5819           0 :                 bFound = false;
    5820             :             else
    5821           0 :                 bFound = (fDataVal <= rItem.mfVal);
    5822             :         }
    5823             :         else
    5824             :         {
    5825           0 :             if (rItem.meType != ScQueryEntry::ByString)
    5826           0 :                 bFound = false;
    5827             :             else
    5828           0 :                 bFound = (ScGlobal::GetCollator()->compareString(aDataStr.getString(), rItem.maString.getString()) <= 0);
    5829             :         }
    5830             : 
    5831           0 :         if (!bFound)
    5832             :         {
    5833           0 :             PushNA();
    5834           0 :             return;
    5835             :         }
    5836             : 
    5837           0 :         if (pResMat)
    5838             :         {
    5839           0 :             if (pResMat->IsValue( 0, 0 ))
    5840           0 :                 PushDouble(pResMat->GetDouble( 0, 0 ));
    5841             :             else
    5842           0 :                 PushString(pResMat->GetString(0, 0));
    5843             :         }
    5844           0 :         else if (nParamCount == 3)
    5845             :         {
    5846           0 :             switch (eResArrayType)
    5847             :             {
    5848             :                 case svDouble:
    5849           0 :                     PushDouble( fResVal );
    5850           0 :                     break;
    5851             :                 case svString:
    5852           0 :                     PushString( aResStr );
    5853           0 :                     break;
    5854             :                 case svDoubleRef:
    5855           0 :                     aResAdr.Set( nResCol1, nResRow1, nResTab);
    5856             :                     // fallthru
    5857             :                 case svSingleRef:
    5858           0 :                     PushCellResultToken( true, aResAdr, NULL, NULL);
    5859           0 :                     break;
    5860             :                 default:
    5861             :                     OSL_FAIL( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
    5862             :             }
    5863             :         }
    5864             :         else
    5865             :         {
    5866           0 :             switch (eDataArrayType)
    5867             :             {
    5868             :                 case svDouble:
    5869           0 :                     PushDouble( fDataVal );
    5870           0 :                     break;
    5871             :                 case svString:
    5872           0 :                     PushString( aDataStr );
    5873           0 :                     break;
    5874             :                 case svSingleRef:
    5875           0 :                     PushCellResultToken( true, aDataAdr, NULL, NULL);
    5876           0 :                     break;
    5877             :                 default:
    5878             :                     OSL_FAIL( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
    5879             :             }
    5880             :         }
    5881           0 :         return;
    5882             :     }
    5883             : 
    5884             :     // Now, perform the search to compute the delta position (nDelta).
    5885             : 
    5886           6 :     if (pDataMat)
    5887             :     {
    5888             :         // Data array is given as a matrix.
    5889           0 :         rEntry.bDoQuery = true;
    5890           0 :         rEntry.eOp = SC_LESS_EQUAL;
    5891           0 :         bool bFound = false;
    5892             : 
    5893             :         SCSIZE nC, nR;
    5894           0 :         pDataMat->GetDimensions(nC, nR);
    5895             : 
    5896             :         // In case of non-vector matrix, only search the first row or column.
    5897           0 :         ScMatrixRef pDataMat2;
    5898           0 :         if (bVertical)
    5899             :         {
    5900           0 :             ScMatrixRef pTempMat(new ScMatrix(1, nR, 0.0));
    5901           0 :             for (SCSIZE i = 0; i < nR; ++i)
    5902           0 :                 if (pDataMat->IsValue(0, i))
    5903           0 :                     pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
    5904             :                 else
    5905           0 :                     pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
    5906           0 :             pDataMat2 = pTempMat;
    5907             :         }
    5908             :         else
    5909             :         {
    5910           0 :             ScMatrixRef pTempMat(new ScMatrix(nC, 1, 0.0));
    5911           0 :             for (SCSIZE i = 0; i < nC; ++i)
    5912           0 :                 if (pDataMat->IsValue(i, 0))
    5913           0 :                     pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
    5914             :                 else
    5915           0 :                     pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
    5916           0 :             pDataMat2 = pTempMat;
    5917             :         }
    5918             : 
    5919           0 :         VectorMatrixAccessor aMatAcc2(*pDataMat2, bVertical);
    5920             : 
    5921             :         // binary search for non-equality mode (the source data is
    5922             :         // assumed to be sorted in ascending order).
    5923             : 
    5924           0 :         SCCOLROW nDelta = -1;
    5925             : 
    5926           0 :         SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
    5927           0 :         for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
    5928             :         {
    5929           0 :             SCSIZE nMid = nFirst + nLen/2;
    5930           0 :             sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, aMatAcc2, rEntry);
    5931           0 :             if (nCmp == 0)
    5932             :             {
    5933             :                 // exact match.  find the last item with the same value.
    5934           0 :                 lcl_GetLastMatch( nMid, aMatAcc2, nLenMajor, false);
    5935           0 :                 nDelta = nMid;
    5936           0 :                 bFound = true;
    5937           0 :                 break;
    5938             :             }
    5939             : 
    5940           0 :             if (nLen == 1) // first and last items are next to each other.
    5941             :             {
    5942           0 :                 nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
    5943             :                 // If already the 1st item is greater there's nothing found.
    5944           0 :                 bFound = (nDelta >= 0);
    5945           0 :                 break;
    5946             :             }
    5947             : 
    5948           0 :             if (nCmp < 0)
    5949           0 :                 nFirst = nMid;
    5950             :             else
    5951           0 :                 nLast = nMid;
    5952             :         }
    5953             : 
    5954           0 :         if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
    5955             :         {
    5956           0 :             sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, aMatAcc2, rEntry);
    5957           0 :             if (nCmp <= 0)
    5958             :             {
    5959             :                 // either the last item is an exact match or the real
    5960             :                 // hit is beyond the last item.
    5961           0 :                 nDelta += 1;
    5962           0 :                 bFound = true;
    5963             :             }
    5964             :         }
    5965           0 :         else if (nDelta > 0) // valid hit must be 2nd item or higher
    5966             :         {
    5967             :             // non-exact match
    5968           0 :             bFound = true;
    5969             :         }
    5970             : 
    5971             :         // With 0-9 < A-Z, if query is numeric and data found is string, or
    5972             :         // vice versa, the (yet another undocumented) Excel behavior is to
    5973             :         // return #N/A instead.
    5974             : 
    5975           0 :         if (bFound)
    5976             :         {
    5977           0 :             VectorMatrixAccessor aMatAcc(*pDataMat, bVertical);
    5978           0 :             SCCOLROW i = nDelta;
    5979           0 :             SCSIZE n = aMatAcc.GetElementCount();
    5980           0 :             if (static_cast<SCSIZE>(i) >= n)
    5981           0 :                 i = static_cast<SCCOLROW>(n);
    5982           0 :             bool bByString = rEntry.GetQueryItem().meType == ScQueryEntry::ByString;
    5983           0 :             if (bByString == aMatAcc.IsValue(i))
    5984           0 :                 bFound = false;
    5985             :         }
    5986             : 
    5987           0 :         if (!bFound)
    5988             :         {
    5989           0 :             PushNA();
    5990           0 :             return;
    5991             :         }
    5992             : 
    5993             :         // Now that we've found the delta, push the result back to the cell.
    5994             : 
    5995           0 :         if (pResMat)
    5996             :         {
    5997           0 :             VectorMatrixAccessor aResMatAcc(*pResMat, bVertical);
    5998             :             // result array is matrix.
    5999           0 :             if (static_cast<SCSIZE>(nDelta) >= aResMatAcc.GetElementCount())
    6000             :             {
    6001           0 :                 PushNA();
    6002           0 :                 return;
    6003             :             }
    6004           0 :             if (aResMatAcc.IsValue(nDelta))
    6005           0 :                 PushDouble(aResMatAcc.GetDouble(nDelta));
    6006             :             else
    6007           0 :                 PushString(aResMatAcc.GetString(nDelta));
    6008             :         }
    6009           0 :         else if (nParamCount == 3)
    6010             :         {
    6011             :             // result array is cell range.
    6012           0 :             ScAddress aAdr;
    6013           0 :             aAdr.SetTab(nResTab);
    6014           0 :             bool bResVertical = (nResRow2 - nResRow1) > 0;
    6015           0 :             if (bResVertical)
    6016             :             {
    6017           0 :                 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
    6018           0 :                 if (nTempRow > MAXROW)
    6019             :                 {
    6020           0 :                     PushDouble(0);
    6021           0 :                     return;
    6022             :                 }
    6023           0 :                 aAdr.SetCol(nResCol1);
    6024           0 :                 aAdr.SetRow(nTempRow);
    6025             :             }
    6026             :             else
    6027             :             {
    6028           0 :                 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
    6029           0 :                 if (nTempCol > MAXCOL)
    6030             :                 {
    6031           0 :                     PushDouble(0);
    6032           0 :                     return;
    6033             :                 }
    6034           0 :                 aAdr.SetCol(nTempCol);
    6035           0 :                 aAdr.SetRow(nResRow1);
    6036             :             }
    6037           0 :             PushCellResultToken(true, aAdr, NULL, NULL);
    6038             :         }
    6039             :         else
    6040             :         {
    6041             :             // no result array.  Use the data array to get the final value from.
    6042           0 :             if (bVertical)
    6043             :             {
    6044           0 :                 if (pDataMat->IsValue(nC-1, nDelta))
    6045           0 :                     PushDouble(pDataMat->GetDouble(nC-1, nDelta));
    6046             :                 else
    6047           0 :                     PushString(pDataMat->GetString(nC-1, nDelta));
    6048             :             }
    6049             :             else
    6050             :             {
    6051           0 :                 if (pDataMat->IsValue(nDelta, nR-1))
    6052           0 :                     PushDouble(pDataMat->GetDouble(nDelta, nR-1));
    6053             :                 else
    6054           0 :                     PushString(pDataMat->GetString(nDelta, nR-1));
    6055             :             }
    6056             :         }
    6057             : 
    6058           0 :         return;
    6059             :     }
    6060             : 
    6061             :     // Perform cell range search.
    6062             : 
    6063           6 :     aParam.nCol1            = nCol1;
    6064           6 :     aParam.nRow1            = nRow1;
    6065           6 :     aParam.nCol2            = bVertical ? nCol1 : nCol2;
    6066           6 :     aParam.nRow2            = bVertical ? nRow2 : nRow1;
    6067           6 :     aParam.bByRow           = bVertical;
    6068             : 
    6069           6 :     rEntry.bDoQuery = true;
    6070           6 :     rEntry.eOp = SC_LESS_EQUAL;
    6071           6 :     rEntry.nField = nCol1;
    6072           6 :     ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    6073           6 :     if (rItem.meType == ScQueryEntry::ByString)
    6074           6 :         aParam.bRegExp = MayBeRegExp(rItem.maString.getString(), pDok);
    6075             : 
    6076           6 :     ScQueryCellIterator aCellIter(pDok, nTab1, aParam, false);
    6077             :     SCCOL nC;
    6078             :     SCROW nR;
    6079             :     // Advance Entry.nField in iterator upon switching columns if
    6080             :     // lookup in row.
    6081           6 :     aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
    6082           6 :     if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
    6083             :     {
    6084           0 :         PushNA();
    6085           0 :         return;
    6086             :     }
    6087             : 
    6088           6 :     SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
    6089             : 
    6090           6 :     if (pResMat)
    6091             :     {
    6092           0 :         VectorMatrixAccessor aResMatAcc(*pResMat, bVertical);
    6093             :         // Use the matrix result array.
    6094           0 :         if (aResMatAcc.IsValue(nDelta))
    6095           0 :             PushDouble(aResMatAcc.GetDouble(nDelta));
    6096             :         else
    6097           0 :             PushString(aResMatAcc.GetString(nDelta));
    6098             :     }
    6099           6 :     else if (nParamCount == 3)
    6100             :     {
    6101           6 :         switch (eResArrayType)
    6102             :         {
    6103             :             case svDoubleRef:
    6104             :             {
    6105             :                 // Use the result array vector.  Note that the result array is assumed
    6106             :                 // to be a vector (i.e. 1-dimensinoal array).
    6107             : 
    6108           6 :                 ScAddress aAdr;
    6109           6 :                 aAdr.SetTab(nResTab);
    6110           6 :                 bool bResVertical = (nResRow2 - nResRow1) > 0;
    6111           6 :                 if (bResVertical)
    6112             :                 {
    6113           6 :                     SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
    6114           6 :                     if (nTempRow > MAXROW)
    6115             :                     {
    6116           0 :                         PushDouble(0);
    6117           0 :                         return;
    6118             :                     }
    6119           6 :                     aAdr.SetCol(nResCol1);
    6120           6 :                     aAdr.SetRow(nTempRow);
    6121             :                 }
    6122             :                 else
    6123             :                 {
    6124           0 :                     SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
    6125           0 :                     if (nTempCol > MAXCOL)
    6126             :                     {
    6127           0 :                         PushDouble(0);
    6128           0 :                         return;
    6129             :                     }
    6130           0 :                     aAdr.SetCol(nTempCol);
    6131           0 :                     aAdr.SetRow(nResRow1);
    6132             :                 }
    6133           6 :                 PushCellResultToken( true, aAdr, NULL, NULL);
    6134             :             }
    6135           6 :             break;
    6136             :             case svDouble:
    6137             :             case svString:
    6138             :             case svSingleRef:
    6139             :             {
    6140           0 :                 if (nDelta != 0)
    6141           0 :                     PushNA();
    6142             :                 else
    6143             :                 {
    6144           0 :                     switch (eResArrayType)
    6145             :                     {
    6146             :                         case svDouble:
    6147           0 :                             PushDouble( fResVal );
    6148           0 :                             break;
    6149             :                         case svString:
    6150           0 :                             PushString( aResStr );
    6151           0 :                             break;
    6152             :                         case svSingleRef:
    6153           0 :                             PushCellResultToken( true, aResAdr, NULL, NULL);
    6154           0 :                             break;
    6155             :                         default:
    6156             :                             ;   // nothing
    6157             :                     }
    6158             :                 }
    6159             :             }
    6160           0 :             break;
    6161             :             default:
    6162             :                 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
    6163             :         }
    6164             :     }
    6165             :     else
    6166             :     {
    6167             :         // Regardless of whether or not the result array exists, the last
    6168             :         // array is always used as the "result" array.
    6169             : 
    6170           0 :         ScAddress aAdr;
    6171           0 :         aAdr.SetTab(nTab1);
    6172           0 :         if (bVertical)
    6173             :         {
    6174           0 :             SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
    6175           0 :             if (nTempRow > MAXROW)
    6176             :             {
    6177           0 :                 PushDouble(0);
    6178           0 :                 return;
    6179             :             }
    6180           0 :             aAdr.SetCol(nCol2);
    6181           0 :             aAdr.SetRow(nTempRow);
    6182             :         }
    6183             :         else
    6184             :         {
    6185           0 :             SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
    6186           0 :             if (nTempCol > MAXCOL)
    6187             :             {
    6188           0 :                 PushDouble(0);
    6189           0 :                 return;
    6190             :             }
    6191           0 :             aAdr.SetCol(nTempCol);
    6192           0 :             aAdr.SetRow(nRow2);
    6193             :         }
    6194           0 :         PushCellResultToken(true, aAdr, NULL, NULL);
    6195          12 :     }
    6196             : }
    6197             : 
    6198           0 : void ScInterpreter::ScHLookup()
    6199             : {
    6200           0 :     CalculateLookup(true);
    6201           0 : }
    6202             : 
    6203          60 : void ScInterpreter::CalculateLookup(bool bHLookup)
    6204             : {
    6205          60 :     sal_uInt8 nParamCount = GetByte();
    6206          60 :     if (!MustHaveParamCount(nParamCount, 3, 4))
    6207           0 :         return;
    6208             : 
    6209             :     // Optional 4th argument to declare whether or not the range is sorted.
    6210          60 :     bool bSorted = true;
    6211          60 :     if (nParamCount == 4)
    6212          46 :         bSorted = GetBool();
    6213             : 
    6214             :     // Index of column to search.
    6215          60 :     double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
    6216             : 
    6217          60 :     ScMatrixRef pMat = NULL;
    6218          60 :     SCSIZE nC = 0, nR = 0;
    6219          60 :     SCCOL nCol1 = 0;
    6220          60 :     SCROW nRow1 = 0;
    6221          60 :     SCTAB nTab1 = 0;
    6222          60 :     SCCOL nCol2 = 0;
    6223          60 :     SCROW nRow2 = 0;
    6224             :     SCTAB nTab2;
    6225          60 :     StackVar eType = GetStackType();
    6226          60 :     if (eType == svDoubleRef)
    6227             :     {
    6228          50 :         PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    6229          50 :         if (nTab1 != nTab2)
    6230             :         {
    6231           0 :             PushIllegalParameter();
    6232           0 :             return;
    6233             :         }
    6234             :     }
    6235          10 :     else if (eType == svSingleRef)
    6236             :     {
    6237           0 :         PopSingleRef(nCol1, nRow1, nTab1);
    6238           0 :         nCol2 = nCol1;
    6239           0 :         nRow2 = nRow1;
    6240             :     }
    6241          10 :     else if (eType == svMatrix || eType == svExternalDoubleRef || eType == svExternalSingleRef)
    6242             :     {
    6243          10 :         pMat = GetMatrix();
    6244             : 
    6245          20 :         if (pMat)
    6246          10 :             pMat->GetDimensions(nC, nR);
    6247             :         else
    6248             :         {
    6249           0 :             PushIllegalParameter();
    6250           0 :             return;
    6251             :         }
    6252             :     }
    6253             :     else
    6254             :     {
    6255           0 :         PushIllegalParameter();
    6256           0 :         return;
    6257             :     }
    6258             : 
    6259          60 :     if ( fIndex < 0.0 || (bHLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
    6260             :     {
    6261           0 :         PushIllegalArgument();
    6262           0 :         return;
    6263             :     }
    6264             : 
    6265          60 :     SCROW nZIndex = static_cast<SCROW>(fIndex);
    6266          60 :     SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
    6267             : 
    6268          60 :     if (!pMat)
    6269             :     {
    6270          50 :         nZIndex += nRow1;                       // Wertzeile
    6271          50 :         nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 );     // value column
    6272             :     }
    6273             : 
    6274          60 :     if (nGlobalError)
    6275             :     {
    6276           0 :         PushIllegalParameter();
    6277           0 :         return;
    6278             :     }
    6279             : 
    6280         120 :     ScQueryParam aParam;
    6281          60 :     aParam.nCol1 = nCol1;
    6282          60 :     aParam.nRow1 = nRow1;
    6283          60 :     if ( bHLookup )
    6284             :     {
    6285           0 :         aParam.nCol2 = nCol2;
    6286           0 :         aParam.nRow2 = nRow1;     // nur in der ersten Zeile suchen
    6287           0 :         aParam.bByRow = false;
    6288             :     }
    6289             :     else
    6290             :     {
    6291          60 :         aParam.nCol2 = nCol1;     // nur in der ersten Spalte suchen
    6292          60 :         aParam.nRow2 = nRow2;
    6293          60 :         aParam.nTab  = nTab1;
    6294             :     }
    6295             : 
    6296          60 :     ScQueryEntry& rEntry = aParam.GetEntry(0);
    6297          60 :     rEntry.bDoQuery = true;
    6298          60 :     if ( bSorted )
    6299          52 :         rEntry.eOp = SC_LESS_EQUAL;
    6300          60 :     if ( !FillEntry(rEntry) )
    6301           0 :         return;
    6302             : 
    6303          60 :     ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    6304          60 :     if (rItem.meType == ScQueryEntry::ByString)
    6305          32 :         aParam.bRegExp = MayBeRegExp(rItem.maString.getString(), pDok);
    6306          60 :     if (pMat)
    6307             :     {
    6308          10 :         SCSIZE nMatCount = bHLookup ? nC : nR;
    6309          10 :         SCSIZE nDelta = SCSIZE_MAX;
    6310          10 :         if (rItem.meType == ScQueryEntry::ByString)
    6311             :         {
    6312             : //!!!!!!!
    6313             : //! TODO: enable regex on matrix strings
    6314             : //!!!!!!!
    6315          10 :             svl::SharedString aParamStr = rItem.maString;
    6316          10 :             if ( bSorted )
    6317             :             {
    6318           6 :                 static CollatorWrapper* pCollator = ScGlobal::GetCollator();
    6319          22 :                 for (SCSIZE i = 0; i < nMatCount; i++)
    6320             :                 {
    6321          16 :                     if (bHLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
    6322             :                     {
    6323             :                         sal_Int32 nRes =
    6324             :                             pCollator->compareString(
    6325          16 :                                 bHLookup ? pMat->GetString(i,0).getString() : pMat->GetString(0,i).getString(), aParamStr.getString());
    6326          16 :                         if (nRes <= 0)
    6327           8 :                             nDelta = i;
    6328           8 :                         else if (i>0)   // #i2168# ignore first mismatch
    6329           6 :                             i = nMatCount+1;
    6330             :                     }
    6331             :                     else
    6332           0 :                         nDelta = i;
    6333             :                 }
    6334             :             }
    6335             :             else
    6336             :             {
    6337           4 :                 if (bHLookup)
    6338             :                 {
    6339           0 :                     for (SCSIZE i = 0; i < nMatCount; i++)
    6340             :                     {
    6341           0 :                         if (pMat->IsString(i, 0))
    6342             :                         {
    6343           0 :                             if (pMat->GetString(i,0).getDataIgnoreCase() == aParamStr.getDataIgnoreCase())
    6344             :                             {
    6345           0 :                                 nDelta = i;
    6346           0 :                                 i = nMatCount + 1;
    6347             :                             }
    6348             :                         }
    6349             :                     }
    6350             :                 }
    6351             :                 else
    6352             :                 {
    6353           4 :                     nDelta = pMat->MatchStringInColumns(aParamStr, 0, 0);
    6354             :                 }
    6355          10 :             }
    6356             :         }
    6357             :         else
    6358             :         {
    6359           0 :             if ( bSorted )
    6360             :             {
    6361             :                 // #i2168# ignore strings
    6362           0 :                 for (SCSIZE i = 0; i < nMatCount; i++)
    6363             :                 {
    6364           0 :                     if (!(bHLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
    6365             :                     {
    6366           0 :                         if ((bHLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rItem.mfVal)
    6367           0 :                             nDelta = i;
    6368             :                         else
    6369           0 :                             i = nMatCount+1;
    6370             :                     }
    6371             :                 }
    6372             :             }
    6373             :             else
    6374             :             {
    6375           0 :                 if (bHLookup)
    6376             :                 {
    6377           0 :                     for (SCSIZE i = 0; i < nMatCount; i++)
    6378             :                     {
    6379           0 :                         if (! pMat->IsString(i, 0) )
    6380             :                         {
    6381           0 :                             if ( pMat->GetDouble(i,0) == rItem.mfVal)
    6382             :                             {
    6383           0 :                                 nDelta = i;
    6384           0 :                                 i = nMatCount + 1;
    6385             :                             }
    6386             :                         }
    6387             :                     }
    6388             :                 }
    6389             :                 else
    6390             :                 {
    6391           0 :                     nDelta = pMat->MatchDoubleInColumns(rItem.mfVal, 0, 0);
    6392             :                 }
    6393             :             }
    6394             :         }
    6395          10 :         if ( nDelta != SCSIZE_MAX )
    6396             :         {
    6397          10 :             SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
    6398          10 :             SCSIZE nY = nDelta;
    6399          10 :             if ( bHLookup )
    6400             :             {
    6401           0 :                 nX = nDelta;
    6402           0 :                 nY = static_cast<SCSIZE>(nZIndex);
    6403             :             }
    6404          10 :             if ( pMat->IsString( nX, nY) )
    6405          10 :                 PushString(pMat->GetString( nX,nY).getString());
    6406             :             else
    6407           0 :                 PushDouble(pMat->GetDouble( nX,nY));
    6408             :         }
    6409             :         else
    6410           0 :             PushNA();
    6411             :     }
    6412             :     else
    6413             :     {
    6414          50 :         rEntry.nField = nCol1;
    6415          50 :         bool bFound = false;
    6416          50 :         SCCOL nCol = 0;
    6417          50 :         SCROW nRow = 0;
    6418          50 :         if ( bSorted )
    6419          46 :             rEntry.eOp = SC_LESS_EQUAL;
    6420          50 :         if ( bHLookup )
    6421             :         {
    6422           0 :             ScQueryCellIterator aCellIter(pDok, nTab1, aParam, false);
    6423             :             // advance Entry.nField in Iterator upon switching columns
    6424           0 :             aCellIter.SetAdvanceQueryParamEntryField( true );
    6425           0 :             if ( bSorted )
    6426             :             {
    6427             :                 SCROW nRow1_temp;
    6428           0 :                 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
    6429             :             }
    6430           0 :             else if ( aCellIter.GetFirst() )
    6431             :             {
    6432           0 :                 bFound = true;
    6433           0 :                 nCol = aCellIter.GetCol();
    6434             :             }
    6435           0 :             nRow = nZIndex;
    6436             :         }
    6437             :         else
    6438             :         {
    6439          50 :             ScAddress aResultPos( nCol1, nRow1, nTab1);
    6440          50 :             bFound = LookupQueryWithCache( aResultPos, aParam);
    6441          50 :             nRow = aResultPos.Row();
    6442          50 :             nCol = nSpIndex;
    6443             :         }
    6444             : 
    6445          50 :         if ( bFound )
    6446             :         {
    6447          46 :             ScAddress aAdr( nCol, nRow, nTab1 );
    6448          46 :             PushCellResultToken( true, aAdr, NULL, NULL);
    6449             :         }
    6450             :         else
    6451           4 :             PushNA();
    6452          60 :     }
    6453             : }
    6454             : 
    6455          66 : bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
    6456             : {
    6457          66 :     ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    6458          66 :     switch ( GetStackType() )
    6459             :     {
    6460             :         case svDouble:
    6461             :         {
    6462           0 :             rItem.meType = ScQueryEntry::ByValue;
    6463           0 :             rItem.mfVal = GetDouble();
    6464             :         }
    6465           0 :         break;
    6466             :         case svString:
    6467             :         {
    6468           6 :             rItem.meType = ScQueryEntry::ByString;
    6469           6 :             rItem.maString = GetString();
    6470             :         }
    6471           6 :         break;
    6472             :         case svDoubleRef :
    6473             :         case svSingleRef :
    6474             :         {
    6475          60 :             ScAddress aAdr;
    6476          60 :             if ( !PopDoubleRefOrSingleRef( aAdr ) )
    6477             :             {
    6478           0 :                 PushInt(0);
    6479           0 :                 return false;
    6480             :             }
    6481          60 :             ScRefCellValue aCell;
    6482          60 :             aCell.assign(*pDok, aAdr);
    6483          60 :             if (aCell.hasNumeric())
    6484             :             {
    6485          28 :                 rItem.meType = ScQueryEntry::ByValue;
    6486          28 :                 rItem.mfVal = GetCellValue(aAdr, aCell);
    6487             :             }
    6488             :             else
    6489             :             {
    6490          32 :                 GetCellString(rItem.maString, aCell);
    6491          32 :                 rItem.meType = ScQueryEntry::ByString;
    6492          60 :             }
    6493             :         }
    6494          60 :         break;
    6495             :         case svMatrix :
    6496             :         {
    6497           0 :             svl::SharedString aStr;
    6498           0 :             const ScMatValType nType = GetDoubleOrStringFromMatrix(rItem.mfVal, aStr);
    6499           0 :             rItem.maString = aStr;
    6500           0 :             rItem.meType = ScMatrix::IsNonValueType(nType) ?
    6501           0 :                 ScQueryEntry::ByString : ScQueryEntry::ByValue;
    6502             :         }
    6503           0 :         break;
    6504             :         default:
    6505             :         {
    6506           0 :             PushIllegalParameter();
    6507           0 :             return false;
    6508             :         }
    6509             :     } // switch ( GetStackType() )
    6510          66 :     return true;
    6511             : }
    6512          60 : void ScInterpreter::ScVLookup()
    6513             : {
    6514          60 :     CalculateLookup(false);
    6515          60 : }
    6516             : 
    6517          28 : void ScInterpreter::ScSubTotal()
    6518             : {
    6519          28 :     sal_uInt8 nParamCount = GetByte();
    6520          28 :     if ( MustHaveParamCountMin( nParamCount, 2 ) )
    6521             :     {
    6522             :         // We must fish the 1st parameter deep from the stack! And push it on top.
    6523          28 :         const FormulaToken* p = pStack[ sp - nParamCount ];
    6524          28 :         PushTempToken( *p );
    6525          28 :         int nFunc = (int) ::rtl::math::approxFloor( GetDouble() );
    6526          28 :         mnSubTotalFlags |= SUBTOTAL_IGN_NESTED_ST_AG | SUBTOTAL_IGN_FILTERED;
    6527          28 :         if (nFunc > 100)
    6528             :         {
    6529             :             // For opcodes 101 through 111, we need to skip hidden cells.
    6530             :             // Other than that these opcodes are identical to 1 through 11.
    6531           0 :             mnSubTotalFlags |= SUBTOTAL_IGN_HIDDEN;
    6532           0 :             nFunc -= 100;
    6533             :         }
    6534             : 
    6535          28 :         if ( nFunc < 1 || nFunc > 11 )
    6536           0 :             PushIllegalArgument();  // simulate return on stack, not SetError(...)
    6537             :         else
    6538             :         {
    6539          28 :             cPar = nParamCount - 1;
    6540          28 :             switch( nFunc )
    6541             :             {
    6542           0 :                 case SUBTOTAL_FUNC_AVE  : ScAverage(); break;
    6543           0 :                 case SUBTOTAL_FUNC_CNT  : ScCount();   break;
    6544           0 :                 case SUBTOTAL_FUNC_CNT2 : ScCount2();  break;
    6545          18 :                 case SUBTOTAL_FUNC_MAX  : ScMax();     break;
    6546           0 :                 case SUBTOTAL_FUNC_MIN  : ScMin();     break;
    6547           0 :                 case SUBTOTAL_FUNC_PROD : ScProduct(); break;
    6548           0 :                 case SUBTOTAL_FUNC_STD  : ScStDev();   break;
    6549           0 :                 case SUBTOTAL_FUNC_STDP : ScStDevP();  break;
    6550          10 :                 case SUBTOTAL_FUNC_SUM  : ScSum();     break;
    6551           0 :                 case SUBTOTAL_FUNC_VAR  : ScVar();     break;
    6552           0 :                 case SUBTOTAL_FUNC_VARP : ScVarP();    break;
    6553           0 :                 default : PushIllegalArgument();       break;
    6554             :             }
    6555             :         }
    6556          28 :         mnSubTotalFlags = 0x00;
    6557             :         // Get rid of the 1st (fished) parameter.
    6558          28 :         double nVal = GetDouble();
    6559          28 :         Pop();
    6560          28 :         PushDouble( nVal );
    6561             :     }
    6562          28 : }
    6563             : 
    6564        1728 : void ScInterpreter::ScAggregate()
    6565             : {
    6566        1728 :     sal_uInt8 nParamCount = GetByte();
    6567        1728 :     if ( MustHaveParamCountMin( nParamCount, 3 ) )
    6568             :     {
    6569             :         // fish the 1st parameter from the stack and push it on top.
    6570        1728 :         const FormulaToken* p = pStack[ sp - nParamCount ];
    6571        1728 :         PushTempToken( *p );
    6572        1728 :         int nFunc = ( int ) ::rtl::math::approxFloor( GetDouble() );
    6573             :         // fish the 2nd parameter from the stack and push it on top.
    6574        1728 :         const FormulaToken* p2 = pStack[ sp - ( nParamCount - 1 ) ];
    6575        1728 :         PushTempToken( *p2 );
    6576        1728 :         int nOption = ( int ) ::rtl::math::approxFloor( GetDouble() );
    6577             : 
    6578        1728 :         if ( nFunc < 1 || nFunc > 19 )
    6579           0 :             PushIllegalArgument();
    6580             :         else
    6581             :         {
    6582        1728 :             switch ( nOption)
    6583             :             {
    6584             :                 case 0 : // ignore nested SUBTOTAL and AGGREGATE functions
    6585         402 :                     mnSubTotalFlags = SUBTOTAL_IGN_NESTED_ST_AG;
    6586         402 :                     break;
    6587             :                 case 1 : // ignore hidden rows, nested SUBTOTAL and AGGREGATE functions
    6588         204 :                     mnSubTotalFlags = SUBTOTAL_IGN_HIDDEN | SUBTOTAL_IGN_NESTED_ST_AG;
    6589         204 :                     break;
    6590             :                 case 2 : // ignore error values, nested SUBTOTAL and AGGREGATE functions
    6591         192 :                     mnSubTotalFlags = SUBTOTAL_IGN_ERR_VAL | SUBTOTAL_IGN_NESTED_ST_AG;
    6592         192 :                     break;
    6593             :                 case 3 : // ignore hidden rows, error values, nested SUBTOTAL and AGGREGATE functions
    6594         186 :                     mnSubTotalFlags = SUBTOTAL_IGN_HIDDEN | SUBTOTAL_IGN_ERR_VAL | SUBTOTAL_IGN_NESTED_ST_AG;
    6595         186 :                     break;
    6596             :                 case 4 : // ignore nothing
    6597         204 :                     mnSubTotalFlags = 0x00;
    6598         204 :                     break;
    6599             :                 case 5 : // ignore hidden rows
    6600         186 :                     mnSubTotalFlags = SUBTOTAL_IGN_HIDDEN ;
    6601         186 :                     break;
    6602             :                 case 6 : // ignore error values
    6603         192 :                     mnSubTotalFlags = SUBTOTAL_IGN_ERR_VAL ;
    6604         192 :                     break;
    6605             :                 case 7 : // ignore hidden rows and error values
    6606         162 :                     mnSubTotalFlags = SUBTOTAL_IGN_HIDDEN | SUBTOTAL_IGN_ERR_VAL ;
    6607         162 :                     break;
    6608             :                 default :
    6609           0 :                     PushIllegalArgument();
    6610        1728 :                     return;
    6611             :             }
    6612             : 
    6613        1728 :             cPar = nParamCount - 2;
    6614        1728 :             switch ( nFunc )
    6615             :             {
    6616         114 :                 case SUBTOTAL_FUNC_AVE      : ScAverage(); break;
    6617         102 :                 case SUBTOTAL_FUNC_CNT      : ScCount();   break;
    6618         102 :                 case SUBTOTAL_FUNC_CNT2     : ScCount2();  break;
    6619         102 :                 case SUBTOTAL_FUNC_MAX      : ScMax();     break;
    6620          84 :                 case SUBTOTAL_FUNC_MIN      : ScMin();     break;
    6621         108 :                 case SUBTOTAL_FUNC_PROD     : ScProduct(); break;
    6622         108 :                 case SUBTOTAL_FUNC_STD      : ScStDev();   break;
    6623         108 :                 case SUBTOTAL_FUNC_STDP     : ScStDevP();  break;
    6624         108 :                 case SUBTOTAL_FUNC_SUM      : ScSum();     break;
    6625         108 :                 case SUBTOTAL_FUNC_VAR      : ScVar();     break;
    6626         108 :                 case SUBTOTAL_FUNC_VARP     : ScVarP();    break;
    6627         108 :                 case AGGREGATE_FUNC_MEDIAN  : ScMedian();            break;
    6628         108 :                 case AGGREGATE_FUNC_MODSNGL : ScModalValue();        break;
    6629          72 :                 case AGGREGATE_FUNC_LARGE   : ScLarge();             break;
    6630          72 :                 case AGGREGATE_FUNC_SMALL   : ScSmall();             break;
    6631          54 :                 case AGGREGATE_FUNC_PERCINC : ScPercentile( true );  break;
    6632          54 :                 case AGGREGATE_FUNC_QRTINC  : ScQuartile( true );    break;
    6633          54 :                 case AGGREGATE_FUNC_PERCEXC : ScPercentile( false ); break;
    6634          54 :                 case AGGREGATE_FUNC_QRTEXC  : ScQuartile( false );   break;
    6635           0 :                 default : PushIllegalArgument();       break;
    6636             :             }
    6637        1728 :             mnSubTotalFlags = 0x00;
    6638             :         }
    6639        1728 :         double nVal = GetDouble();
    6640             :         // Get rid of the 1st and 2nd (fished) parameters.
    6641        1728 :         Pop();
    6642        1728 :         Pop();
    6643        1728 :         PushDouble( nVal );
    6644             :     }
    6645             : }
    6646             : 
    6647          40 : ScDBQueryParamBase* ScInterpreter::GetDBParams( bool& rMissingField )
    6648             : {
    6649          40 :     bool bAllowMissingField = false;
    6650          40 :     if ( rMissingField )
    6651             :     {
    6652          20 :         bAllowMissingField = true;
    6653          20 :         rMissingField = false;
    6654             :     }
    6655          40 :     if ( GetByte() == 3 )
    6656             :     {
    6657             :         // First, get the query criteria range.
    6658          40 :         ::std::unique_ptr<ScDBRangeBase> pQueryRef( PopDBDoubleRef() );
    6659          40 :         if (!pQueryRef.get())
    6660           0 :             return NULL;
    6661             : 
    6662          40 :         bool    bByVal = true;
    6663          40 :         double  nVal = 0.0;
    6664          40 :         svl::SharedString  aStr;
    6665          40 :         ScRange aMissingRange;
    6666          40 :         bool bRangeFake = false;
    6667          40 :         switch (GetStackType())
    6668             :         {
    6669             :             case svDouble :
    6670          18 :                 nVal = ::rtl::math::approxFloor( GetDouble() );
    6671          18 :                 if ( bAllowMissingField && nVal == 0.0 )
    6672          10 :                     rMissingField = true;   // fake missing parameter
    6673          18 :                 break;
    6674             :             case svString :
    6675          22 :                 bByVal = false;
    6676          22 :                 aStr = GetString();
    6677          22 :                 break;
    6678             :             case svSingleRef :
    6679             :                 {
    6680           0 :                     ScAddress aAdr;
    6681           0 :                     PopSingleRef( aAdr );
    6682           0 :                     ScRefCellValue aCell;
    6683           0 :                     aCell.assign(*pDok, aAdr);
    6684           0 :                     if (aCell.hasNumeric())
    6685           0 :                         nVal = GetCellValue(aAdr, aCell);
    6686             :                     else
    6687             :                     {
    6688           0 :                         bByVal = false;
    6689           0 :                         GetCellString(aStr, aCell);
    6690           0 :                     }
    6691             :                 }
    6692           0 :                 break;
    6693             :             case svDoubleRef :
    6694           0 :                 if ( bAllowMissingField )
    6695             :                 {   // fake missing parameter for old SO compatibility
    6696           0 :                     bRangeFake = true;
    6697           0 :                     PopDoubleRef( aMissingRange );
    6698             :                 }
    6699             :                 else
    6700             :                 {
    6701           0 :                     PopError();
    6702           0 :                     SetError( errIllegalParameter );
    6703             :                 }
    6704           0 :                 break;
    6705             :             case svMissing :
    6706           0 :                 PopError();
    6707           0 :                 if ( bAllowMissingField )
    6708           0 :                     rMissingField = true;
    6709             :                 else
    6710           0 :                     SetError( errIllegalParameter );
    6711           0 :                 break;
    6712             :             default:
    6713           0 :                 PopError();
    6714           0 :                 SetError( errIllegalParameter );
    6715             :         }
    6716             : 
    6717          40 :         if (nGlobalError)
    6718           0 :             return NULL;
    6719             : 
    6720          40 :         unique_ptr<ScDBRangeBase> pDBRef( PopDBDoubleRef() );
    6721             : 
    6722          40 :         if (nGlobalError || !pDBRef.get())
    6723           0 :             return NULL;
    6724             : 
    6725          40 :         if ( bRangeFake )
    6726             :         {
    6727             :             // range parameter must match entire database range
    6728           0 :             if (pDBRef->isRangeEqual(aMissingRange))
    6729           0 :                 rMissingField = true;
    6730             :             else
    6731           0 :                 SetError( errIllegalParameter );
    6732             :         }
    6733             : 
    6734          40 :         if (nGlobalError)
    6735           0 :             return NULL;
    6736             : 
    6737          40 :         SCCOL nField = pDBRef->getFirstFieldColumn();
    6738          40 :         if (rMissingField)
    6739             :             ; // special case
    6740          30 :         else if (bByVal)
    6741           8 :             nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal));
    6742             :         else
    6743             :         {
    6744          22 :             sal_uInt16 nErr = 0;
    6745          22 :             nField = pDBRef->findFieldColumn(aStr.getString(), &nErr);
    6746          22 :             SetError(nErr);
    6747             :         }
    6748             : 
    6749          40 :         if (!ValidCol(nField))
    6750           0 :             return NULL;
    6751             : 
    6752          40 :         unique_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) );
    6753             : 
    6754          40 :         if (pParam.get())
    6755             :         {
    6756             :             // An allowed missing field parameter sets the result field
    6757             :             // to any of the query fields, just to be able to return
    6758             :             // some cell from the iterator.
    6759          40 :             if ( rMissingField )
    6760          10 :                 nField = static_cast<SCCOL>(pParam->GetEntry(0).nField);
    6761          40 :             pParam->mnField = nField;
    6762             : 
    6763          40 :             SCSIZE nCount = pParam->GetEntryCount();
    6764         104 :             for ( SCSIZE i=0; i < nCount; i++ )
    6765             :             {
    6766         104 :                 ScQueryEntry& rEntry = pParam->GetEntry(i);
    6767         104 :                 if (!rEntry.bDoQuery)
    6768          40 :                     break;
    6769             : 
    6770          64 :                 ScQueryEntry::Item& rItem = rEntry.GetQueryItem();
    6771          64 :                 sal_uInt32 nIndex = 0;
    6772          64 :                 OUString aQueryStr = rItem.maString.getString();
    6773             :                 bool bNumber = pFormatter->IsNumberFormat(
    6774          64 :                     aQueryStr, nIndex, rItem.mfVal);
    6775          64 :                 rItem.meType = bNumber ? ScQueryEntry::ByValue : ScQueryEntry::ByString;
    6776             : 
    6777          64 :                 if (!bNumber && !pParam->bRegExp)
    6778           4 :                     pParam->bRegExp = MayBeRegExp(aQueryStr, pDok);
    6779          64 :             }
    6780          40 :             return pParam.release();
    6781           0 :         }
    6782             :     }
    6783           0 :     return NULL;
    6784             : }
    6785             : 
    6786          10 : void ScInterpreter::DBIterator( ScIterFunc eFunc )
    6787             : {
    6788          10 :     double nErg = 0.0;
    6789          10 :     double fMem = 0.0;
    6790          10 :     bool bNull = true;
    6791          10 :     sal_uLong nCount = 0;
    6792          10 :     bool bMissingField = false;
    6793          10 :     unique_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
    6794          10 :     if (pQueryParam.get())
    6795             :     {
    6796          10 :         if (!pQueryParam->IsValidFieldIndex())
    6797             :         {
    6798           0 :             SetError(errNoValue);
    6799          10 :             return;
    6800             :         }
    6801          10 :         ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
    6802          20 :         ScDBQueryDataIterator::Value aValue;
    6803          10 :         if ( aValIter.GetFirst(aValue) && !aValue.mnError )
    6804             :         {
    6805          10 :             switch( eFunc )
    6806             :             {
    6807           2 :                 case ifPRODUCT: nErg = 1; break;
    6808           2 :                 case ifMAX:     nErg = -MAXDOUBLE; break;
    6809           2 :                 case ifMIN:     nErg = MAXDOUBLE; break;
    6810             :                 default: ; // nothing
    6811             :             }
    6812          50 :             do
    6813             :             {
    6814          50 :                 nCount++;
    6815          50 :                 switch( eFunc )
    6816             :                 {
    6817             :                     case ifAVERAGE:
    6818             :                     case ifSUM:
    6819          12 :                         if ( bNull && aValue.mfValue != 0.0 )
    6820             :                         {
    6821           4 :                             bNull = false;
    6822           4 :                             fMem = aValue.mfValue;
    6823             :                         }
    6824             :                         else
    6825           8 :                             nErg += aValue.mfValue;
    6826          12 :                         break;
    6827           0 :                     case ifSUMSQ:   nErg += aValue.mfValue * aValue.mfValue; break;
    6828           6 :                     case ifPRODUCT: nErg *= aValue.mfValue; break;
    6829          18 :                     case ifMAX:     if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break;
    6830          14 :                     case ifMIN:     if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break;
    6831             :                     default: ; // nothing
    6832             :                 }
    6833             :             }
    6834          50 :             while ( aValIter.GetNext(aValue) && !aValue.mnError );
    6835             :         }
    6836          20 :         SetError(aValue.mnError);
    6837             :     }
    6838             :     else
    6839           0 :         SetError( errIllegalParameter);
    6840          10 :     switch( eFunc )
    6841             :     {
    6842           0 :         case ifCOUNT:   nErg = nCount; break;
    6843           2 :         case ifSUM:     nErg = ::rtl::math::approxAdd( nErg, fMem ); break;
    6844           2 :         case ifAVERAGE: nErg = div(::rtl::math::approxAdd(nErg, fMem), nCount); break;
    6845             :         default: ; // nothing
    6846             :     }
    6847          10 :     PushDouble( nErg );
    6848             : }
    6849             : 
    6850           2 : void ScInterpreter::ScDBSum()
    6851             : {
    6852           2 :     DBIterator( ifSUM );
    6853           2 : }
    6854             : 
    6855          18 : void ScInterpreter::ScDBCount()
    6856             : {
    6857          18 :     bool bMissingField = true;
    6858          18 :     unique_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
    6859          18 :     if (pQueryParam.get())
    6860             :     {
    6861          18 :         sal_uLong nCount = 0;
    6862          18 :         if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL )
    6863             :         {   // count all matching records
    6864             :             // TODO: currently the QueryIterators only return cell pointers of
    6865             :             // existing cells, so if a query matches an empty cell there's
    6866             :             // nothing returned, and therefore not counted!
    6867             :             // Since this has ever been the case and this code here only came
    6868             :             // into existence to fix #i6899 and it never worked before we'll
    6869             :             // have to live with it until we reimplement the iterators to also
    6870             :             // return empty cells, which would mean to adapt all callers of
    6871             :             // iterators.
    6872          10 :             ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get());
    6873          10 :             p->nCol2 = p->nCol1; // Don't forget to select only one column.
    6874          10 :             SCTAB nTab = p->nTab;
    6875             :             // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField,
    6876             :             // so the source range has to be restricted, like before the introduction
    6877             :             // of ScDBQueryParamBase.
    6878          10 :             p->nCol1 = p->nCol2 = p->mnField;
    6879          10 :             ScQueryCellIterator aCellIter( pDok, nTab, *p);
    6880          10 :             if ( aCellIter.GetFirst() )
    6881             :             {
    6882          20 :                 do
    6883             :                 {
    6884          20 :                     nCount++;
    6885             :                 } while ( aCellIter.GetNext() );
    6886          10 :             }
    6887             :         }
    6888             :         else
    6889             :         {   // count only matching records with a value in the "result" field
    6890           8 :             if (!pQueryParam->IsValidFieldIndex())
    6891             :             {
    6892           0 :                 SetError(errNoValue);
    6893          18 :                 return;
    6894             :             }
    6895           8 :             ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
    6896          16 :             ScDBQueryDataIterator::Value aValue;
    6897           8 :             if ( aValIter.GetFirst(aValue) && !aValue.mnError )
    6898             :             {
    6899          32 :                 do
    6900             :                 {
    6901          32 :                     nCount++;
    6902             :                 }
    6903          32 :                 while ( aValIter.GetNext(aValue) && !aValue.mnError );
    6904             :             }
    6905          16 :             SetError(aValue.mnError);
    6906             :         }
    6907          18 :         PushDouble( nCount );
    6908             :     }
    6909             :     else
    6910           0 :         PushIllegalParameter();
    6911             : }
    6912             : 
    6913           2 : void ScInterpreter::ScDBCount2()
    6914             : {
    6915           2 :     bool bMissingField = true;
    6916           2 :     unique_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
    6917           2 :     if (pQueryParam.get())
    6918             :     {
    6919           2 :         if (!pQueryParam->IsValidFieldIndex())
    6920             :         {
    6921           0 :             SetError(errNoValue);
    6922           2 :             return;
    6923             :         }
    6924           2 :         sal_uLong nCount = 0;
    6925           2 :         pQueryParam->mbSkipString = false;
    6926           2 :         ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
    6927           4 :         ScDBQueryDataIterator::Value aValue;
    6928           2 :         if ( aValIter.GetFirst(aValue) && !aValue.mnError )
    6929             :         {
    6930          10 :             do
    6931             :             {
    6932          10 :                 nCount++;
    6933             :             }
    6934          10 :             while ( aValIter.GetNext(aValue) && !aValue.mnError );
    6935             :         }
    6936           2 :         SetError(aValue.mnError);
    6937           4 :         PushDouble( nCount );
    6938             :     }
    6939             :     else
    6940           0 :         PushIllegalParameter();
    6941             : }
    6942             : 
    6943           2 : void ScInterpreter::ScDBAverage()
    6944             : {
    6945           2 :     DBIterator( ifAVERAGE );
    6946           2 : }
    6947             : 
    6948           2 : void ScInterpreter::ScDBMax()
    6949             : {
    6950           2 :     DBIterator( ifMAX );
    6951           2 : }
    6952             : 
    6953           2 : void ScInterpreter::ScDBMin()
    6954             : {
    6955           2 :     DBIterator( ifMIN );
    6956           2 : }
    6957             : 
    6958           2 : void ScInterpreter::ScDBProduct()
    6959             : {
    6960           2 :     DBIterator( ifPRODUCT );
    6961           2 : }
    6962             : 
    6963           8 : void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
    6964             : {
    6965           8 :     std::vector<double> values;
    6966           8 :     double vSum    = 0.0;
    6967           8 :     double vMean    = 0.0;
    6968             : 
    6969           8 :     rValCount = 0.0;
    6970           8 :     double fSum    = 0.0;
    6971           8 :     bool bMissingField = false;
    6972          16 :     unique_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
    6973           8 :     if (pQueryParam.get())
    6974             :     {
    6975           8 :         if (!pQueryParam->IsValidFieldIndex())
    6976             :         {
    6977           0 :             SetError(errNoValue);
    6978           8 :             return;
    6979             :         }
    6980           8 :         ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
    6981          16 :         ScDBQueryDataIterator::Value aValue;
    6982           8 :         if (aValIter.GetFirst(aValue) && !aValue.mnError)
    6983             :         {
    6984          18 :             do
    6985             :             {
    6986          18 :                 rValCount++;
    6987          18 :                 values.push_back(aValue.mfValue);
    6988          18 :                 fSum += aValue.mfValue;
    6989             :             }
    6990          18 :             while ((aValue.mnError == 0) && aValIter.GetNext(aValue));
    6991             :         }
    6992          16 :         SetError(aValue.mnError);
    6993             :     }
    6994             :     else
    6995           0 :         SetError( errIllegalParameter);
    6996             : 
    6997           8 :     vMean = fSum / values.size();
    6998             : 
    6999          26 :     for (size_t i = 0; i < values.size(); i++)
    7000          18 :         vSum += (values[i] - vMean) * (values[i] - vMean);
    7001             : 
    7002          16 :     rVal = vSum;
    7003             : }
    7004             : 
    7005           2 : void ScInterpreter::ScDBStdDev()
    7006             : {
    7007             :     double fVal, fCount;
    7008           2 :     GetDBStVarParams( fVal, fCount );
    7009           2 :     PushDouble( sqrt(fVal/(fCount-1)));
    7010           2 : }
    7011             : 
    7012           2 : void ScInterpreter::ScDBStdDevP()
    7013             : {
    7014             :     double fVal, fCount;
    7015           2 :     GetDBStVarParams( fVal, fCount );
    7016           2 :     PushDouble( sqrt(fVal/fCount));
    7017           2 : }
    7018             : 
    7019           2 : void ScInterpreter::ScDBVar()
    7020             : {
    7021             :     double fVal, fCount;
    7022           2 :     GetDBStVarParams( fVal, fCount );
    7023           2 :     PushDouble(fVal/(fCount-1));
    7024           2 : }
    7025             : 
    7026           2 : void ScInterpreter::ScDBVarP()
    7027             : {
    7028             :     double fVal, fCount;
    7029           2 :     GetDBStVarParams( fVal, fCount );
    7030           2 :     PushDouble(fVal/fCount);
    7031           2 : }
    7032             : 
    7033          56 : void ScInterpreter::ScIndirect()
    7034             : {
    7035          56 :     sal_uInt8 nParamCount = GetByte();
    7036          56 :     if ( MustHaveParamCount( nParamCount, 1, 2 )  )
    7037             :     {
    7038             :         // Reference address syntax for INDIRECT is configurable.
    7039          56 :         FormulaGrammar::AddressConvention eConv = maCalcConfig.meStringRefAddressSyntax;
    7040          56 :         if (eConv == FormulaGrammar::CONV_UNSPECIFIED)
    7041             :             // Use the current address syntax if unspecified.
    7042          32 :             eConv = pDok->GetAddressConvention();
    7043             : 
    7044          56 :         if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
    7045             :         {
    7046             :             // Overwrite the config and try Excel R1C1.
    7047          16 :             eConv = FormulaGrammar::CONV_XL_R1C1;
    7048             :         }
    7049          56 :         const ScAddress::Details aDetails( eConv, aPos );
    7050          56 :         SCTAB nTab = aPos.Tab();
    7051          56 :         OUString sRefStr = GetString().getString();
    7052          56 :         ScRefAddress aRefAd, aRefAd2;
    7053         112 :         ScAddress::ExternalInfo aExtInfo;
    7054          56 :         if (ConvertDoubleRef(pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo))
    7055             :         {
    7056           0 :             if (aExtInfo.mbExternal)
    7057             :             {
    7058             :                 PushExternalDoubleRef(
    7059             :                     aExtInfo.mnFileId, aExtInfo.maTabName,
    7060           0 :                     aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
    7061           0 :                     aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab());
    7062             :             }
    7063             :             else
    7064           0 :                 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
    7065           0 :                         aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() );
    7066             :         }
    7067          56 :         else if (ConvertSingleRef(pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo))
    7068             :         {
    7069          40 :             if (aExtInfo.mbExternal)
    7070             :             {
    7071             :                 PushExternalSingleRef(
    7072           0 :                     aExtInfo.mnFileId, aExtInfo.maTabName, aRefAd.Col(), aRefAd.Row(), aRefAd.Tab());
    7073             :             }
    7074             :             else
    7075          40 :                 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
    7076             :         }
    7077             :         else
    7078             :         {
    7079             :             do
    7080             :             {
    7081          16 :                 ScRangeData* pData = ScRangeStringConverter::GetRangeDataFromString(sRefStr, nTab, pDok);
    7082          16 :                 if (!pData)
    7083          32 :                     break;
    7084             : 
    7085             :                 // We need this in order to obtain a good range.
    7086           0 :                 pData->ValidateTabRefs();
    7087             : 
    7088           0 :                 ScRange aRange;
    7089             : 
    7090             :                 // This is the usual way to treat named ranges containing
    7091             :                 // relative references.
    7092           0 :                 if (!pData->IsReference( aRange, aPos))
    7093           0 :                     break;
    7094             : 
    7095           0 :                 if (aRange.aStart == aRange.aEnd)
    7096           0 :                     PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
    7097           0 :                             aRange.aStart.Tab());
    7098             :                 else
    7099           0 :                     PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(),
    7100           0 :                             aRange.aStart.Tab(), aRange.aEnd.Col(),
    7101           0 :                             aRange.aEnd.Row(), aRange.aEnd.Tab());
    7102             : 
    7103             :                 // success!
    7104          56 :                 return;
    7105             :             }
    7106             :             while (false);
    7107             : 
    7108          16 :             PushError( errNoRef);
    7109          56 :         }
    7110             :     }
    7111             : }
    7112             : 
    7113           8 : void ScInterpreter::ScAddressFunc()
    7114             : {
    7115           8 :     OUString  sTabStr;
    7116             : 
    7117           8 :     sal_uInt8    nParamCount = GetByte();
    7118           8 :     if( !MustHaveParamCount( nParamCount, 2, 5 ) )
    7119           0 :         return;
    7120             : 
    7121           8 :     if( nParamCount >= 5 )
    7122           4 :         sTabStr = GetString().getString();
    7123             : 
    7124           8 :     FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;      // default
    7125           8 :     if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
    7126           2 :         eConv = FormulaGrammar::CONV_XL_R1C1;
    7127             : 
    7128           8 :     sal_uInt16  nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;   // default
    7129           8 :     if( nParamCount >= 3 )
    7130             :     {
    7131           4 :         sal_uInt16 n = (sal_uInt16) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
    7132           4 :         switch ( n )
    7133             :         {
    7134             :             default :
    7135           0 :                 PushNoValue();
    7136           0 :                 return;
    7137             : 
    7138             :             case 5:
    7139           2 :             case 1 : break; // default
    7140             :             case 6:
    7141           2 :             case 2 : nFlags = SCA_ROW_ABSOLUTE; break;
    7142             :             case 7:
    7143           0 :             case 3 : nFlags = SCA_COL_ABSOLUTE; break;
    7144             :             case 8:
    7145           0 :             case 4 : nFlags = 0; break; // both relative
    7146             :         }
    7147             :     }
    7148           8 :     nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL;
    7149             : 
    7150           8 :     SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
    7151           8 :     SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
    7152           8 :     if( eConv == FormulaGrammar::CONV_XL_R1C1 )
    7153             :     {
    7154             :         // YUCK!  The XL interface actually treats rel R1C1 refs differently
    7155             :         // than A1
    7156           2 :         if( !(nFlags & SCA_COL_ABSOLUTE) )
    7157           0 :             nCol += aPos.Col() + 1;
    7158           2 :         if( !(nFlags & SCA_ROW_ABSOLUTE) )
    7159           0 :             nRow += aPos.Row() + 1;
    7160             :     }
    7161             : 
    7162           8 :     --nCol;
    7163           8 :     --nRow;
    7164           8 :     if(!ValidCol( nCol) || !ValidRow( nRow))
    7165             :     {
    7166           0 :         PushIllegalArgument();
    7167           0 :         return;
    7168             :     }
    7169             : 
    7170           8 :     const ScAddress::Details aDetails( eConv, aPos );
    7171           8 :     const ScAddress aAdr( nCol, nRow, 0);
    7172           8 :     OUString aRefStr(aAdr.Format(nFlags, pDok, aDetails));
    7173             : 
    7174           8 :     if( nParamCount >= 5 && !sTabStr.isEmpty() )
    7175             :     {
    7176           4 :         OUString aDoc;
    7177           4 :         if (eConv == FormulaGrammar::CONV_OOO)
    7178             :         {
    7179             :             // Isolate Tab from 'Doc'#Tab
    7180           2 :             sal_Int32 nPos = ScCompiler::GetDocTabPos( sTabStr);
    7181           2 :             if (nPos != -1)
    7182             :             {
    7183           0 :                 if (sTabStr[nPos+1] == '$')
    7184           0 :                     ++nPos;     // also split 'Doc'#$Tab
    7185           0 :                 aDoc = sTabStr.copy( 0, nPos+1);
    7186           0 :                 sTabStr = sTabStr.copy( nPos+1);
    7187             :             }
    7188             :         }
    7189             :         /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may
    7190             :          * need some extra handling to isolate Tab from Doc. */
    7191           4 :         if (sTabStr[0] != '\'' || !sTabStr.endsWith("'"))
    7192           4 :             ScCompiler::CheckTabQuotes( sTabStr, eConv);
    7193           4 :         if (!aDoc.isEmpty())
    7194           0 :             sTabStr = aDoc + sTabStr;
    7195           4 :         sTabStr += eConv == FormulaGrammar::CONV_XL_R1C1 ? OUString("!") : OUString(".");
    7196           4 :         sTabStr += aRefStr;
    7197           4 :         PushString( sTabStr );
    7198             :     }
    7199             :     else
    7200           4 :         PushString( aRefStr );
    7201             : }
    7202             : 
    7203           2 : void ScInterpreter::ScOffset()
    7204             : {
    7205           2 :     sal_uInt8 nParamCount = GetByte();
    7206           2 :     if ( MustHaveParamCount( nParamCount, 3, 5 ) )
    7207             :     {
    7208           2 :         long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus;
    7209           2 :         if (nParamCount == 5)
    7210           2 :             nColNew = (long) ::rtl::math::approxFloor(GetDouble());
    7211           2 :         if (nParamCount >= 4)
    7212           2 :             nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
    7213           2 :         nColPlus = (long) ::rtl::math::approxFloor(GetDouble());
    7214           2 :         nRowPlus = (long) ::rtl::math::approxFloor(GetDouble());
    7215           2 :         SCCOL nCol1(0);
    7216           2 :         SCROW nRow1(0);
    7217           2 :         SCTAB nTab1(0);
    7218           2 :         SCCOL nCol2(0);
    7219           2 :         SCROW nRow2(0);
    7220           2 :         SCTAB nTab2(0);
    7221           2 :         if (nColNew == 0 || nRowNew == 0)
    7222             :         {
    7223           0 :             PushIllegalArgument();
    7224           2 :             return;
    7225             :         }
    7226           2 :         switch (GetStackType())
    7227             :         {
    7228             :         case svSingleRef:
    7229             :         {
    7230           0 :             PopSingleRef(nCol1, nRow1, nTab1);
    7231           0 :             if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
    7232             :             {
    7233           0 :                 nCol1 = (SCCOL)((long) nCol1 + nColPlus);
    7234           0 :                 nRow1 = (SCROW)((long) nRow1 + nRowPlus);
    7235           0 :                 if (!ValidCol(nCol1) || !ValidRow(nRow1))
    7236           0 :                     PushIllegalArgument();
    7237             :                 else
    7238           0 :                     PushSingleRef(nCol1, nRow1, nTab1);
    7239             :             }
    7240             :             else
    7241             :             {
    7242           0 :                 if (nColNew < 0)
    7243           0 :                     nColNew = 1;
    7244           0 :                 if (nRowNew < 0)
    7245           0 :                     nRowNew = 1;
    7246           0 :                 nCol1 = (SCCOL)((long)nCol1+nColPlus);
    7247           0 :                 nRow1 = (SCROW)((long)nRow1+nRowPlus);
    7248           0 :                 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
    7249           0 :                 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
    7250           0 :                 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
    7251           0 :                     !ValidCol(nCol2) || !ValidRow(nRow2))
    7252           0 :                     PushIllegalArgument();
    7253             :                 else
    7254           0 :                     PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
    7255             :             }
    7256           0 :             break;
    7257             :         }
    7258             :         case svExternalSingleRef:
    7259             :         {
    7260             :             sal_uInt16 nFileId;
    7261           2 :             OUString aTabName;
    7262             :             ScSingleRefData aRef;
    7263           2 :             PopExternalSingleRef(nFileId, aTabName, aRef);
    7264           2 :             ScAddress aAbsRef = aRef.toAbs(aPos);
    7265           2 :             nCol1 = aAbsRef.Col();
    7266           2 :             nRow1 = aAbsRef.Row();
    7267           2 :             nTab1 = aAbsRef.Tab();
    7268             : 
    7269           2 :             if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
    7270             :             {
    7271           0 :                 nCol1 = (SCCOL)((long) nCol1 + nColPlus);
    7272           0 :                 nRow1 = (SCROW)((long) nRow1 + nRowPlus);
    7273           0 :                 if (!ValidCol(nCol1) || !ValidRow(nRow1))
    7274           0 :                     PushIllegalArgument();
    7275             :                 else
    7276           0 :                     PushExternalSingleRef(nFileId, aTabName, nCol1, nRow1, nTab1);
    7277             :             }
    7278             :             else
    7279             :             {
    7280           2 :                 if (nColNew < 0)
    7281           0 :                     nColNew = 1;
    7282           2 :                 if (nRowNew < 0)
    7283           0 :                     nRowNew = 1;
    7284           2 :                 nCol1 = (SCCOL)((long)nCol1+nColPlus);
    7285           2 :                 nRow1 = (SCROW)((long)nRow1+nRowPlus);
    7286           2 :                 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
    7287           2 :                 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
    7288           2 :                 nTab2 = nTab1;
    7289           8 :                 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
    7290           6 :                     !ValidCol(nCol2) || !ValidRow(nRow2))
    7291           0 :                     PushIllegalArgument();
    7292             :                 else
    7293           2 :                     PushExternalDoubleRef(nFileId, aTabName, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    7294             :             }
    7295           2 :             break;
    7296             :         }
    7297             :         case svDoubleRef:
    7298             :         {
    7299           0 :             PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    7300           0 :             if (nColNew < 0)
    7301           0 :                 nColNew = nCol2 - nCol1 + 1;
    7302           0 :             if (nRowNew < 0)
    7303           0 :                 nRowNew = nRow2 - nRow1 + 1;
    7304           0 :             nCol1 = (SCCOL)((long)nCol1+nColPlus);
    7305           0 :             nRow1 = (SCROW)((long)nRow1+nRowPlus);
    7306           0 :             nCol2 = (SCCOL)((long)nCol1+nColNew-1);
    7307           0 :             nRow2 = (SCROW)((long)nRow1+nRowNew-1);
    7308           0 :             if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
    7309           0 :                 !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
    7310           0 :                 PushIllegalArgument();
    7311             :             else
    7312           0 :                 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
    7313           0 :             break;
    7314             :         }
    7315             :         case svExternalDoubleRef:
    7316             :         {
    7317             :             sal_uInt16 nFileId;
    7318           0 :             OUString aTabName;
    7319             :             ScComplexRefData aRef;
    7320           0 :             PopExternalDoubleRef(nFileId, aTabName, aRef);
    7321           0 :             ScRange aAbs = aRef.toAbs(aPos);
    7322           0 :             nCol1 = aAbs.aStart.Col();
    7323           0 :             nRow1 = aAbs.aStart.Row();
    7324           0 :             nTab1 = aAbs.aStart.Tab();
    7325           0 :             nCol2 = aAbs.aEnd.Col();
    7326           0 :             nRow2 = aAbs.aEnd.Row();
    7327           0 :             nTab2 = aAbs.aEnd.Tab();
    7328           0 :             if (nColNew < 0)
    7329           0 :                 nColNew = nCol2 - nCol1 + 1;
    7330           0 :             if (nRowNew < 0)
    7331           0 :                 nRowNew = nRow2 - nRow1 + 1;
    7332           0 :             nCol1 = (SCCOL)((long)nCol1+nColPlus);
    7333           0 :             nRow1 = (SCROW)((long)nRow1+nRowPlus);
    7334           0 :             nCol2 = (SCCOL)((long)nCol1+nColNew-1);
    7335           0 :             nRow2 = (SCROW)((long)nRow1+nRowNew-1);
    7336           0 :             if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
    7337           0 :                 !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
    7338           0 :                 PushIllegalArgument();
    7339             :             else
    7340           0 :                 PushExternalDoubleRef(nFileId, aTabName, nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    7341           0 :             break;
    7342             :         }
    7343             :         default:
    7344           0 :             PushIllegalParameter();
    7345           0 :             break;
    7346             :         } // end switch
    7347             :     }
    7348             : }
    7349             : 
    7350           0 : void ScInterpreter::ScIndex()
    7351             : {
    7352           0 :     sal_uInt8 nParamCount = GetByte();
    7353           0 :     if ( MustHaveParamCount( nParamCount, 1, 4 ) )
    7354             :     {
    7355             :         long nArea;
    7356             :         size_t nAreaCount;
    7357             :         SCCOL nCol;
    7358             :         SCROW nRow;
    7359           0 :         if (nParamCount == 4)
    7360           0 :             nArea = (long) ::rtl::math::approxFloor(GetDouble());
    7361             :         else
    7362           0 :             nArea = 1;
    7363           0 :         if (nParamCount >= 3)
    7364           0 :             nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
    7365             :         else
    7366           0 :             nCol = 0;
    7367           0 :         if (nParamCount >= 2)
    7368           0 :             nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
    7369             :         else
    7370           0 :             nRow = 0;
    7371           0 :         if (GetStackType() == svRefList)
    7372           0 :             nAreaCount = (sp ? pStack[sp-1]->GetRefList()->size() : 0);
    7373             :         else
    7374           0 :             nAreaCount = 1;     // one reference or array or whatever
    7375           0 :         if (nAreaCount == 0 || (size_t)nArea > nAreaCount)
    7376             :         {
    7377           0 :             PushError( errNoRef);
    7378           0 :             return;
    7379             :         }
    7380           0 :         else if (nArea < 1 || nCol < 0 || nRow < 0)
    7381             :         {
    7382           0 :             PushIllegalArgument();
    7383           0 :             return;
    7384             :         }
    7385           0 :         switch (GetStackType())
    7386             :         {
    7387             :             case svMatrix:
    7388             :             case svExternalSingleRef:
    7389             :             case svExternalDoubleRef:
    7390             :                 {
    7391           0 :                     if (nArea != 1)
    7392           0 :                         SetError(errIllegalArgument);
    7393           0 :                     sal_uInt16 nOldSp = sp;
    7394           0 :                     ScMatrixRef pMat = GetMatrix();
    7395           0 :                     if (pMat)
    7396             :                     {
    7397             :                         SCSIZE nC, nR;
    7398           0 :                         pMat->GetDimensions(nC, nR);
    7399             :                         // Access one element of a vector independent of col/row
    7400             :                         // orientation?
    7401           0 :                         bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1));
    7402             :                         SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol),
    7403           0 :                                 static_cast<SCSIZE>(nRow));
    7404           0 :                         if (nC == 0 || nR == 0 ||
    7405           0 :                                 (!bVector && (static_cast<SCSIZE>(nCol) > nC ||
    7406           0 :                                               static_cast<SCSIZE>(nRow) > nR)) ||
    7407           0 :                                 (bVector && nElement > nC * nR))
    7408           0 :                             PushIllegalArgument();
    7409           0 :                         else if (nCol == 0 && nRow == 0)
    7410           0 :                             sp = nOldSp;
    7411           0 :                         else if (bVector)
    7412             :                         {
    7413           0 :                             --nElement;
    7414           0 :                             if (pMat->IsString( nElement))
    7415           0 :                                 PushString( pMat->GetString(nElement).getString());
    7416             :                             else
    7417           0 :                                 PushDouble( pMat->GetDouble( nElement));
    7418             :                         }
    7419           0 :                         else if (nCol == 0)
    7420             :                         {
    7421           0 :                             ScMatrixRef pResMat = GetNewMat(nC, 1);
    7422           0 :                             if (pResMat)
    7423             :                             {
    7424           0 :                                 SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
    7425           0 :                                 for (SCSIZE i = 0; i < nC; i++)
    7426           0 :                                     if (!pMat->IsString(i, nRowMinus1))
    7427             :                                         pResMat->PutDouble(pMat->GetDouble(i,
    7428           0 :                                                     nRowMinus1), i, 0);
    7429             :                                     else
    7430           0 :                                         pResMat->PutString(pMat->GetString(i, nRowMinus1), i, 0);
    7431             : 
    7432           0 :                                 PushMatrix(pResMat);
    7433             :                             }
    7434             :                             else
    7435           0 :                                 PushIllegalArgument();
    7436             :                         }
    7437           0 :                         else if (nRow == 0)
    7438             :                         {
    7439           0 :                             ScMatrixRef pResMat = GetNewMat(1, nR);
    7440           0 :                             if (pResMat)
    7441             :                             {
    7442           0 :                                 SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
    7443           0 :                                 for (SCSIZE i = 0; i < nR; i++)
    7444           0 :                                     if (!pMat->IsString(nColMinus1, i))
    7445             :                                         pResMat->PutDouble(pMat->GetDouble(nColMinus1,
    7446           0 :                                                     i), i);
    7447             :                                     else
    7448           0 :                                         pResMat->PutString(pMat->GetString(nColMinus1, i), i);
    7449           0 :                                 PushMatrix(pResMat);
    7450             :                             }
    7451             :                             else
    7452           0 :                                 PushIllegalArgument();
    7453             :                         }
    7454             :                         else
    7455             :                         {
    7456           0 :                             if (!pMat->IsString( static_cast<SCSIZE>(nCol-1),
    7457           0 :                                         static_cast<SCSIZE>(nRow-1)))
    7458             :                                 PushDouble( pMat->GetDouble(
    7459           0 :                                             static_cast<SCSIZE>(nCol-1),
    7460           0 :                                             static_cast<SCSIZE>(nRow-1)));
    7461             :                             else
    7462             :                                 PushString( pMat->GetString(
    7463           0 :                                             static_cast<SCSIZE>(nCol-1),
    7464           0 :                                             static_cast<SCSIZE>(nRow-1)).getString());
    7465             :                         }
    7466           0 :                     }
    7467             :                 }
    7468           0 :                 break;
    7469             :             case svSingleRef:
    7470             :                 {
    7471           0 :                     SCCOL nCol1 = 0;
    7472           0 :                     SCROW nRow1 = 0;
    7473           0 :                     SCTAB nTab1 = 0;
    7474           0 :                     PopSingleRef( nCol1, nRow1, nTab1);
    7475           0 :                     if (nCol > 1 || nRow > 1)
    7476           0 :                         PushIllegalArgument();
    7477             :                     else
    7478           0 :                         PushSingleRef( nCol1, nRow1, nTab1);
    7479             :                 }
    7480           0 :                 break;
    7481             :             case svDoubleRef:
    7482             :             case svRefList:
    7483             :                 {
    7484           0 :                     SCCOL nCol1 = 0;
    7485           0 :                     SCROW nRow1 = 0;
    7486           0 :                     SCTAB nTab1 = 0;
    7487           0 :                     SCCOL nCol2 = 0;
    7488           0 :                     SCROW nRow2 = 0;
    7489           0 :                     SCTAB nTab2 = 0;
    7490           0 :                     bool bRowArray = false;
    7491           0 :                     if (GetStackType() == svRefList)
    7492             :                     {
    7493           0 :                         FormulaTokenRef xRef = PopToken();
    7494           0 :                         if (nGlobalError || !xRef)
    7495             :                         {
    7496           0 :                             PushIllegalParameter();
    7497           0 :                             return;
    7498             :                         }
    7499           0 :                         ScRange aRange( ScAddress::UNINITIALIZED);
    7500           0 :                         DoubleRefToRange( (*(xRef.get()->GetRefList()))[nArea-1], aRange);
    7501           0 :                         aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    7502           0 :                         if ( nParamCount == 2 && nRow1 == nRow2 )
    7503           0 :                             bRowArray = true;
    7504             :                     }
    7505             :                     else
    7506             :                     {
    7507           0 :                         PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
    7508           0 :                         if ( nParamCount == 2 && nRow1 == nRow2 )
    7509           0 :                             bRowArray = true;
    7510             :                     }
    7511           0 :                     if ( nTab1 != nTab2 ||
    7512           0 :                             (nCol > 0 && nCol1+nCol-1 > nCol2) ||
    7513           0 :                             (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
    7514           0 :                             ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
    7515           0 :                         PushIllegalArgument();
    7516           0 :                     else if (nCol == 0 && nRow == 0)
    7517             :                     {
    7518           0 :                         if ( nCol1 == nCol2 && nRow1 == nRow2 )
    7519           0 :                             PushSingleRef( nCol1, nRow1, nTab1 );
    7520             :                         else
    7521           0 :                             PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 );
    7522             :                     }
    7523           0 :                     else if (nRow == 0)
    7524             :                     {
    7525           0 :                         if ( nRow1 == nRow2 )
    7526           0 :                             PushSingleRef( nCol1+nCol-1, nRow1, nTab1 );
    7527             :                         else
    7528             :                             PushDoubleRef( nCol1+nCol-1, nRow1, nTab1,
    7529           0 :                                     nCol1+nCol-1, nRow2, nTab1 );
    7530             :                     }
    7531           0 :                     else if (nCol == 0)
    7532             :                     {
    7533           0 :                         if ( nCol1 == nCol2 )
    7534           0 :                             PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
    7535           0 :                         else if ( bRowArray )
    7536             :                         {
    7537           0 :                             nCol =(SCCOL) nRow;
    7538           0 :                             nRow = 1;
    7539           0 :                             PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
    7540             :                         }
    7541             :                         else
    7542           0 :                             PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
    7543           0 :                                     nCol2, nRow1+nRow-1, nTab1);
    7544             :                     }
    7545             :                     else
    7546           0 :                         PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
    7547             :                 }
    7548           0 :                 break;
    7549             :             default:
    7550           0 :                 PushIllegalParameter();
    7551             :         }
    7552             :     }
    7553             : }
    7554             : 
    7555           0 : void ScInterpreter::ScMultiArea()
    7556             : {
    7557             :     // Legacy support, convert to RefList
    7558           0 :     sal_uInt8 nParamCount = GetByte();
    7559           0 :     if (MustHaveParamCountMin( nParamCount, 1))
    7560             :     {
    7561           0 :         while (!nGlobalError && nParamCount-- > 1)
    7562             :         {
    7563           0 :             ScUnionFunc();
    7564             :         }
    7565             :     }
    7566           0 : }
    7567             : 
    7568           0 : void ScInterpreter::ScAreas()
    7569             : {
    7570           0 :     sal_uInt8 nParamCount = GetByte();
    7571           0 :     if (MustHaveParamCount( nParamCount, 1))
    7572             :     {
    7573           0 :         size_t nCount = 0;
    7574           0 :         switch (GetStackType())
    7575             :         {
    7576             :             case svSingleRef:
    7577             :                 {
    7578           0 :                     FormulaTokenRef xT = PopToken();
    7579           0 :                     ValidateRef( *xT.get()->GetSingleRef());
    7580           0 :                     ++nCount;
    7581             :                 }
    7582           0 :                 break;
    7583             :             case svDoubleRef:
    7584             :                 {
    7585           0 :                     FormulaTokenRef xT = PopToken();
    7586           0 :                     ValidateRef( *xT.get()->GetDoubleRef());
    7587           0 :                     ++nCount;
    7588             :                 }
    7589           0 :                 break;
    7590             :             case svRefList:
    7591             :                 {
    7592           0 :                     FormulaTokenRef xT = PopToken();
    7593           0 :                     ValidateRef( *(xT.get()->GetRefList()));
    7594           0 :                     nCount += xT.get()->GetRefList()->size();
    7595             :                 }
    7596           0 :                 break;
    7597             :             default:
    7598           0 :                 SetError( errIllegalParameter);
    7599             :         }
    7600           0 :         PushDouble( double(nCount));
    7601             :     }
    7602           0 : }
    7603             : 
    7604           4 : void ScInterpreter::ScCurrency()
    7605             : {
    7606           4 :     sal_uInt8 nParamCount = GetByte();
    7607           4 :     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
    7608             :     {
    7609           4 :         OUString aStr;
    7610             :         double fDec;
    7611           4 :         if (nParamCount == 2)
    7612             :         {
    7613           2 :             fDec = ::rtl::math::approxFloor(GetDouble());
    7614           2 :             if (fDec < -15.0 || fDec > 15.0)
    7615             :             {
    7616           0 :                 PushIllegalArgument();
    7617           4 :                 return;
    7618             :             }
    7619             :         }
    7620             :         else
    7621           2 :             fDec = 2.0;
    7622           4 :         double fVal = GetDouble();
    7623             :         double fFac;
    7624           4 :         if ( fDec != 0.0 )
    7625           4 :             fFac = pow( (double)10, fDec );
    7626             :         else
    7627           0 :             fFac = 1.0;
    7628           4 :         if (fVal < 0.0)
    7629           0 :             fVal = ceil(fVal*fFac-0.5)/fFac;
    7630             :         else
    7631           4 :             fVal = floor(fVal*fFac+0.5)/fFac;
    7632           4 :         Color* pColor = NULL;
    7633           4 :         if ( fDec < 0.0 )
    7634           0 :             fDec = 0.0;
    7635             :         sal_uLong nIndex = pFormatter->GetStandardFormat(
    7636             :                                         NUMBERFORMAT_CURRENCY,
    7637           4 :                                         ScGlobal::eLnge);
    7638           4 :         if ( (sal_uInt16) fDec != pFormatter->GetFormatPrecision( nIndex ) )
    7639             :         {
    7640             :             OUString sFormatString = pFormatter->GenerateFormat(
    7641             :                                                    nIndex,
    7642             :                                                    ScGlobal::eLnge,
    7643             :                                                    true,        // mit Tausenderpunkt
    7644             :                                                    false,       // nicht rot
    7645             :                                                   (sal_uInt16) fDec,// Nachkommastellen
    7646           0 :                                                    1);          // 1 Vorkommanull
    7647           0 :             if (!pFormatter->GetPreviewString(sFormatString,
    7648             :                                               fVal,
    7649             :                                               aStr,
    7650             :                                               &pColor,
    7651           0 :                                               ScGlobal::eLnge))
    7652           0 :                 SetError(errIllegalArgument);
    7653             :         }
    7654             :         else
    7655             :         {
    7656           4 :             pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor);
    7657             :         }
    7658           4 :         PushString(aStr);
    7659             :     }
    7660             : }
    7661             : 
    7662           4 : void ScInterpreter::ScReplace()
    7663             : {
    7664           4 :     if ( MustHaveParamCount( GetByte(), 4 ) )
    7665             :     {
    7666           4 :         OUString aNewStr = GetString().getString();
    7667           4 :         double fCount = GetStringPositionArgument();
    7668           4 :         double fPos   = GetStringPositionArgument();
    7669           8 :         OUString aOldStr = GetString().getString();
    7670           4 :         if (fPos < 1.0 || fCount < 0.0)
    7671           0 :             PushIllegalArgument();
    7672             :         else
    7673             :         {
    7674           4 :             sal_Int32 nCount = static_cast<sal_Int32>(fCount);
    7675           4 :             sal_Int32 nPos   = static_cast<sal_Int32>(fPos);
    7676           4 :             sal_Int32 nLen   = aOldStr.getLength();
    7677           4 :             if (nPos > nLen + 1)
    7678           0 :                 nPos = nLen + 1;
    7679           4 :             if (nCount > nLen - nPos + 1)
    7680           0 :                 nCount = nLen - nPos + 1;
    7681           4 :             aOldStr = aOldStr.replaceAt( nPos-1, nCount, "" );
    7682           4 :             if ( CheckStringResultLen( aOldStr, aNewStr ) )
    7683           4 :                 aOldStr = aOldStr.replaceAt( nPos-1, 0, aNewStr );
    7684           4 :             PushString( aOldStr );
    7685           4 :         }
    7686             :     }
    7687           4 : }
    7688             : 
    7689           2 : void ScInterpreter::ScFixed()
    7690             : {
    7691           2 :     sal_uInt8 nParamCount = GetByte();
    7692           2 :     if ( MustHaveParamCount( nParamCount, 1, 3 ) )
    7693             :     {
    7694           2 :         OUString aStr;
    7695             :         double fDec;
    7696             :         bool bThousand;
    7697           2 :         if (nParamCount == 3)
    7698           2 :             bThousand = !GetBool();     // Param TRUE: keine Tausenderpunkte
    7699             :         else
    7700           0 :             bThousand = true;
    7701           2 :         if (nParamCount >= 2)
    7702             :         {
    7703           2 :             fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
    7704           2 :             if (fDec < -15.0 || fDec > 15.0)
    7705             :             {
    7706           0 :                 PushIllegalArgument();
    7707           2 :                 return;
    7708             :             }
    7709             :         }
    7710             :         else
    7711           0 :             fDec = 2.0;
    7712           2 :         double fVal = GetDouble();
    7713             :         double fFac;
    7714           2 :         if ( fDec != 0.0 )
    7715           2 :             fFac = pow( (double)10, fDec );
    7716             :         else
    7717           0 :             fFac = 1.0;
    7718           2 :         if (fVal < 0.0)
    7719           0 :             fVal = ceil(fVal*fFac-0.5)/fFac;
    7720             :         else
    7721           2 :             fVal = floor(fVal*fFac+0.5)/fFac;
    7722           2 :         Color* pColor = NULL;
    7723           2 :         if (fDec < 0.0)
    7724           0 :             fDec = 0.0;
    7725             :         sal_uLong nIndex = pFormatter->GetStandardFormat(
    7726             :                                             NUMBERFORMAT_NUMBER,
    7727           2 :                                             ScGlobal::eLnge);
    7728             :         OUString sFormatString = pFormatter->GenerateFormat(
    7729             :                                                nIndex,
    7730             :                                                ScGlobal::eLnge,
    7731             :                                                bThousand,   // mit Tausenderpunkt
    7732             :                                                false,       // nicht rot
    7733             :                                                (sal_uInt16) fDec,// Nachkommastellen
    7734           4 :                                                1);          // 1 Vorkommanull
    7735           2 :         if (!pFormatter->GetPreviewString(sFormatString,
    7736             :                                                   fVal,
    7737             :                                                   aStr,
    7738             :                                                   &pColor,
    7739           2 :                                                   ScGlobal::eLnge))
    7740           0 :             PushIllegalArgument();
    7741             :         else
    7742           4 :             PushString(aStr);
    7743             :     }
    7744             : }
    7745             : 
    7746           4 : void ScInterpreter::ScFind()
    7747             : {
    7748           4 :     sal_uInt8 nParamCount = GetByte();
    7749           4 :     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
    7750             :     {
    7751             :         double fAnz;
    7752           4 :         if (nParamCount == 3)
    7753           0 :             fAnz = GetDouble();
    7754             :         else
    7755           4 :             fAnz = 1.0;
    7756           4 :         OUString sStr = GetString().getString();
    7757           4 :         if( fAnz < 1.0 || fAnz > (double) sStr.getLength() )
    7758           0 :             PushNoValue();
    7759             :         else
    7760             :         {
    7761           4 :             sal_Int32 nPos = sStr.indexOf(GetString().getString(), static_cast<sal_Int32>(fAnz - 1));
    7762           4 :             if (nPos == -1)
    7763           0 :                 PushNoValue();
    7764             :             else
    7765           4 :                 PushDouble((double)(nPos + 1));
    7766           4 :         }
    7767             :     }
    7768           4 : }
    7769             : 
    7770           4 : void ScInterpreter::ScExact()
    7771             : {
    7772           4 :     nFuncFmtType = NUMBERFORMAT_LOGICAL;
    7773           4 :     if ( MustHaveParamCount( GetByte(), 2 ) )
    7774             :     {
    7775           4 :         svl::SharedString s1 = GetString();
    7776           8 :         svl::SharedString s2 = GetString();
    7777           8 :         PushInt( int(s1.getData() == s2.getData()) );
    7778             :     }
    7779           4 : }
    7780             : 
    7781           6 : void ScInterpreter::ScLeft()
    7782             : {
    7783           6 :     sal_uInt8 nParamCount = GetByte();
    7784           6 :     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
    7785             :     {
    7786             :         sal_Int32 n;
    7787           6 :         if (nParamCount == 2)
    7788             :         {
    7789           4 :             double nVal = GetStringPositionArgument();
    7790           4 :             if (nVal < 0.0)
    7791             :             {
    7792           0 :                 PushIllegalArgument();
    7793           0 :                 return ;
    7794             :             }
    7795             :             else
    7796           4 :                 n = (sal_Int32) nVal;
    7797             :         }
    7798             :         else
    7799           2 :             n = 1;
    7800           6 :         OUString aStr = GetString().getString();
    7801           6 :         n = std::min(n, aStr.getLength());
    7802           6 :         aStr = aStr.copy( 0, n );
    7803           6 :         PushString( aStr );
    7804             :     }
    7805             : }
    7806             : 
    7807             : typedef struct {
    7808             :     UBlockCode from;
    7809             :     UBlockCode to;
    7810             : } UBlockScript;
    7811             : 
    7812             : static const UBlockScript scriptList[] = {
    7813             :     {UBLOCK_HANGUL_JAMO, UBLOCK_HANGUL_JAMO},
    7814             :     {UBLOCK_CJK_RADICALS_SUPPLEMENT, UBLOCK_HANGUL_SYLLABLES},
    7815             :     {UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS,UBLOCK_CJK_RADICALS_SUPPLEMENT },
    7816             :     {UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS,UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS},
    7817             :     {UBLOCK_CJK_COMPATIBILITY_FORMS, UBLOCK_CJK_COMPATIBILITY_FORMS},
    7818             :     {UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS, UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS},
    7819             :     {UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT},
    7820             :     {UBLOCK_CJK_STROKES, UBLOCK_CJK_STROKES}
    7821             : };
    7822             : #define scriptListCount sizeof (scriptList) / sizeof (UBlockScript)
    7823          12 : bool SAL_CALL lcl_getScriptClass(sal_uInt32 currentChar)
    7824             : {
    7825             :     // for the locale of ja-JP, character U+0x005c and U+0x20ac should be ScriptType::Asian
    7826          12 :     if( (currentChar == 0x005c || currentChar == 0x20ac) &&
    7827           0 :           (MsLangId::getSystemLanguage() == LANGUAGE_JAPANESE) )
    7828           0 :         return true;
    7829             :     sal_uInt16 i;
    7830             :     static bool nRet = false;
    7831          12 :     UBlockCode block = (UBlockCode)ublock_getCode((sal_uInt32)currentChar);
    7832          72 :     for ( i = 0; i < scriptListCount; i++) {
    7833          72 :         if (block <= scriptList[i].to) break;
    7834             :     }
    7835          12 :     nRet = (i < scriptListCount && block >= scriptList[i].from);
    7836          12 :     return nRet;
    7837             : }
    7838          12 : bool IsDBCS(sal_Unicode ch)
    7839             : {
    7840          12 :     return lcl_getScriptClass(ch);
    7841             : }
    7842           2 : sal_Int32 getLengthB(const OUString &str)
    7843             : {
    7844           2 :     if(str.isEmpty())
    7845           0 :         return 0;
    7846           2 :     sal_Int32 index = 0;
    7847           2 :     sal_Int32 length = 0;
    7848          16 :     while(index < str.getLength()){
    7849          12 :         if(IsDBCS(str[index]))
    7850          12 :             length += 2;
    7851             :         else
    7852           0 :             length++;
    7853          12 :         index++;
    7854             :     }
    7855           2 :     return length;
    7856             : }
    7857           2 : void ScInterpreter::ScLenB()
    7858             : {
    7859           2 :     PushDouble( getLengthB(GetString().getString()) );
    7860           2 : }
    7861           0 : OUString lcl_RightB(const OUString &rStr, sal_Int32 n)
    7862             : {
    7863           0 :     if( n < getLengthB(rStr) )
    7864             :     {
    7865           0 :         OUStringBuffer aBuf(rStr);
    7866           0 :         sal_Int32 index = aBuf.getLength();
    7867           0 :         while(index-- >= 0)
    7868             :         {
    7869           0 :             if(0 == n)
    7870             :             {
    7871           0 :                 aBuf.remove( 0, index + 1);
    7872           0 :                 break;
    7873             :             }
    7874           0 :             if(-1 == n)
    7875             :             {
    7876           0 :                 aBuf.remove( 0, index + 2 );
    7877           0 :                 aBuf.insert( 0, " ");
    7878           0 :                 break;
    7879             :             }
    7880           0 :             if(IsDBCS(aBuf[index]))
    7881           0 :                 n -= 2;
    7882             :             else
    7883           0 :                 n--;
    7884             :         }
    7885           0 :         return aBuf.makeStringAndClear();
    7886             :     }
    7887           0 :     return rStr;
    7888             : }
    7889           0 : void ScInterpreter::ScRightB()
    7890             : {
    7891           0 :     sal_uInt8 nParamCount = GetByte();
    7892           0 :     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
    7893             :     {
    7894             :         sal_Int32 n;
    7895           0 :         if (nParamCount == 2)
    7896             :         {
    7897           0 :             double nVal = GetStringPositionArgument();
    7898           0 :             if ( nVal < 0.0 )
    7899             :             {
    7900           0 :                 PushIllegalArgument();
    7901           0 :                 return ;
    7902             :             }
    7903             :             else
    7904           0 :                 n = (sal_Int32) nVal;
    7905             :         }
    7906             :         else
    7907           0 :             n = 1;
    7908           0 :         OUString aStr(lcl_RightB(GetString().getString(), n));
    7909           0 :         PushString( aStr );
    7910             :     }
    7911             : }
    7912           0 : OUString lcl_LeftB(const OUString &rStr, sal_Int32 n)
    7913             : {
    7914           0 :     if( n < getLengthB(rStr) )
    7915             :     {
    7916           0 :         OUStringBuffer aBuf(rStr);
    7917           0 :         sal_Int32 index = -1;
    7918           0 :         while(index++ < aBuf.getLength())
    7919             :         {
    7920           0 :             if(0 == n)
    7921             :             {
    7922           0 :                 aBuf.truncate(index);
    7923           0 :                 break;
    7924             :             }
    7925           0 :             if(-1 == n)
    7926             :             {
    7927           0 :                 aBuf.truncate( index - 1 );
    7928           0 :                 aBuf.append(" ");
    7929           0 :                 break;
    7930             :             }
    7931           0 :             if(IsDBCS(aBuf[index]))
    7932           0 :                 n -= 2;
    7933             :             else
    7934           0 :                 n--;
    7935             :         }
    7936           0 :         return aBuf.makeStringAndClear();
    7937             :     }
    7938           0 :     return rStr;
    7939             : }
    7940           0 : void ScInterpreter::ScLeftB()
    7941             : {
    7942           0 :     sal_uInt8 nParamCount = GetByte();
    7943           0 :     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
    7944             :     {
    7945             :         sal_Int32 n;
    7946           0 :         if (nParamCount == 2)
    7947             :         {
    7948           0 :             double nVal = GetStringPositionArgument();
    7949           0 :             if ( nVal < 0.0 )
    7950             :             {
    7951           0 :                 PushIllegalArgument();
    7952           0 :                 return ;
    7953             :             }
    7954             :             else
    7955           0 :                 n = (sal_Int32) nVal;
    7956             :         }
    7957             :         else
    7958           0 :             n = 1;
    7959           0 :         OUString aStr(lcl_LeftB(GetString().getString(), n));
    7960           0 :         PushString( aStr );
    7961             :     }
    7962             : }
    7963           0 : void ScInterpreter::ScMidB()
    7964             : {
    7965           0 :     if ( MustHaveParamCount( GetByte(), 3 ) )
    7966             :     {
    7967           0 :         double fAnz    = GetStringPositionArgument();
    7968           0 :         double fAnfang = GetStringPositionArgument();
    7969           0 :         OUString aStr = GetString().getString();
    7970           0 :         if (fAnfang < 1.0 || fAnz < 0.0)
    7971           0 :             PushIllegalArgument();
    7972             :         else
    7973             :         {
    7974             : 
    7975           0 :             aStr = lcl_LeftB(aStr, (sal_Int32)fAnfang + (sal_Int32)fAnz - 1);
    7976           0 :             sal_Int32 nCnt = getLengthB(aStr) - (sal_Int32)fAnfang + 1;
    7977           0 :             aStr = lcl_RightB(aStr, nCnt>0 ? nCnt:0);
    7978           0 :             PushString(aStr);
    7979           0 :         }
    7980             :     }
    7981           0 : }
    7982             : 
    7983           2 : void ScInterpreter::ScRight()
    7984             : {
    7985           2 :     sal_uInt8 nParamCount = GetByte();
    7986           2 :     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
    7987             :     {
    7988             :         sal_Int32 n;
    7989           2 :         if (nParamCount == 2)
    7990             :         {
    7991           2 :             double nVal = GetStringPositionArgument();
    7992           2 :             if (nVal < 0.0)
    7993             :             {
    7994           0 :                 PushIllegalArgument();
    7995           0 :                 return ;
    7996             :             }
    7997             :             else
    7998           2 :                 n = (sal_Int32) nVal;
    7999             :         }
    8000             :         else
    8001           0 :             n = 1;
    8002           2 :         OUString aStr = GetString().getString();
    8003           2 :         if( n < aStr.getLength() )
    8004           2 :             aStr = aStr.copy( aStr.getLength() - n );
    8005           2 :         PushString( aStr );
    8006             :     }
    8007             : }
    8008             : 
    8009           2 : void ScInterpreter::ScSearch()
    8010             : {
    8011           2 :     sal_uInt8 nParamCount = GetByte();
    8012           2 :     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
    8013             :     {
    8014             :         double fAnz;
    8015           2 :         if (nParamCount == 3)
    8016             :         {
    8017             :             // This should use GetStringPositionArgument() but old versions up
    8018             :             // to LibreOffice 4.2.5 allowed and ignored 0 and negative values.
    8019             :             // It is unnecessary to break existing documents that "rely" on
    8020             :             // that behavior. Though ODFF constrains Start to be >=1.
    8021             :             /* TODO: fix this and possibly break those broken documents? */
    8022           2 :             fAnz = rtl::math::approxFloor( GetDouble());
    8023           2 :             if (fAnz < 1.0)
    8024           0 :                 fAnz = 1.0;
    8025           2 :             else if (!CheckStringPositionArgument( fAnz))
    8026             :             {
    8027           0 :                 PushIllegalArgument();
    8028           2 :                 return;
    8029             :             }
    8030             :         }
    8031             :         else
    8032           0 :             fAnz = 1.0;
    8033           2 :         OUString sStr = GetString().getString();
    8034           4 :         OUString SearchStr = GetString().getString();
    8035           2 :         sal_Int32 nPos = fAnz - 1;
    8036           2 :         sal_Int32 nEndPos = sStr.getLength();
    8037           2 :         if( nPos >= nEndPos )
    8038           0 :             PushNoValue();
    8039             :         else
    8040             :         {
    8041             :             utl::SearchParam::SearchType eSearchType =
    8042           2 :                 (MayBeRegExp( SearchStr, pDok ) ?
    8043           2 :                 utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL);
    8044           2 :             utl::SearchParam sPar(SearchStr, eSearchType, false, false, false);
    8045           4 :             utl::TextSearch sT( sPar, *ScGlobal::pCharClass );
    8046           2 :             bool nBool = sT.SearchForward(sStr, &nPos, &nEndPos);
    8047           2 :             if (!nBool)
    8048           0 :                 PushNoValue();
    8049             :             else
    8050           4 :                 PushDouble((double)(nPos) + 1);
    8051           2 :         }
    8052             :     }
    8053             : }
    8054             : 
    8055           6 : void ScInterpreter::ScMid()
    8056             : {
    8057           6 :     if ( MustHaveParamCount( GetByte(), 3 ) )
    8058             :     {
    8059           6 :         double fAnz    = GetStringPositionArgument();
    8060           6 :         double fAnfang = GetStringPositionArgument();
    8061           6 :         OUString aStr = GetString().getString();
    8062           6 :         if (fAnfang < 1.0 || fAnz < 0.0)
    8063           0 :             PushIllegalArgument();
    8064             :         else
    8065             :         {
    8066           6 :             sal_Int32 nCharacters = std::min<sal_Int32>(static_cast<sal_Int32>(fAnz), aStr.getLength() - fAnfang + 1);
    8067           6 :             OUString sRes;
    8068           6 :             if (nCharacters > 0)
    8069           6 :                 sRes = aStr.copy(static_cast<sal_Int32>(fAnfang-1), nCharacters);
    8070           6 :             PushString(sRes);
    8071           6 :         }
    8072             :     }
    8073           6 : }
    8074             : 
    8075          10 : void ScInterpreter::ScText()
    8076             : {
    8077          10 :     if ( MustHaveParamCount( GetByte(), 2 ) )
    8078             :     {
    8079          10 :         OUString sFormatString = GetString().getString();
    8080          20 :         svl::SharedString aStr;
    8081          10 :         bool bString = false;
    8082          10 :         double fVal = 0.0;
    8083          10 :         switch (GetStackType())
    8084             :         {
    8085             :             case svError:
    8086           0 :                 PopError();
    8087           0 :                 break;
    8088             :             case svDouble:
    8089          10 :                 fVal = PopDouble();
    8090          10 :                 break;
    8091             :             default:
    8092             :                 {
    8093           0 :                     FormulaTokenRef xTok( PopToken());
    8094           0 :                     if (!nGlobalError)
    8095             :                     {
    8096           0 :                         PushTempToken( xTok.get());
    8097             :                         // Temporarily override the ConvertStringToValue()
    8098             :                         // error for GetCellValue() / GetCellValueOrZero()
    8099           0 :                         sal_uInt16 nSErr = mnStringNoValueError;
    8100           0 :                         mnStringNoValueError = errNotNumericString;
    8101           0 :                         fVal = GetDouble();
    8102           0 :                         mnStringNoValueError = nSErr;
    8103           0 :                         if (nGlobalError == errNotNumericString)
    8104             :                         {
    8105             :                             // Not numeric.
    8106           0 :                             nGlobalError = 0;
    8107           0 :                             PushTempToken( xTok.get());
    8108           0 :                             aStr = GetString();
    8109           0 :                             bString = true;
    8110             :                         }
    8111           0 :                     }
    8112             :                 }
    8113             :         }
    8114          10 :         if (nGlobalError)
    8115           0 :             PushError( nGlobalError);
    8116             :         else
    8117             :         {
    8118          10 :             OUString aResult;
    8119          10 :             Color* pColor = NULL;
    8120             :             LanguageType eCellLang;
    8121             :             const ScPatternAttr* pPattern = pDok->GetPattern(
    8122          10 :                     aPos.Col(), aPos.Row(), aPos.Tab() );
    8123          10 :             if ( pPattern )
    8124             :                 eCellLang = static_cast<const SvxLanguageItem&>(
    8125          10 :                         pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue();
    8126             :             else
    8127           0 :                 eCellLang = ScGlobal::eLnge;
    8128          10 :             if (bString)
    8129             :             {
    8130           0 :                 if (!pFormatter->GetPreviewString( sFormatString, aStr.getString(),
    8131           0 :                             aResult, &pColor, eCellLang))
    8132           0 :                     PushIllegalArgument();
    8133             :                 else
    8134           0 :                     PushString( aResult);
    8135             :             }
    8136             :             else
    8137             :             {
    8138          10 :                 if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal,
    8139          10 :                             aResult, &pColor, eCellLang))
    8140           0 :                     PushIllegalArgument();
    8141             :                 else
    8142          10 :                     PushString( aResult);
    8143          10 :             }
    8144          10 :         }
    8145             :     }
    8146          10 : }
    8147             : 
    8148           4 : void ScInterpreter::ScSubstitute()
    8149             : {
    8150           4 :     sal_uInt8 nParamCount = GetByte();
    8151           4 :     if ( MustHaveParamCount( nParamCount, 3, 4 ) )
    8152             :     {
    8153             :         sal_Int32 nAnz;
    8154           4 :         if (nParamCount == 4)
    8155             :         {
    8156           2 :             double fAnz = GetStringPositionArgument();
    8157           2 :             if( fAnz < 1 )
    8158             :             {
    8159           0 :                 PushIllegalArgument();
    8160           0 :                 return;
    8161             :             }
    8162             :             else
    8163           2 :                 nAnz = (sal_Int32) fAnz;
    8164             :         }
    8165             :         else
    8166           2 :             nAnz = 0;
    8167           4 :         OUString sNewStr = GetString().getString();
    8168           8 :         OUString sOldStr = GetString().getString();
    8169           8 :         OUString sStr    = GetString().getString();
    8170           4 :         sal_Int32 nPos = 0;
    8171           4 :         sal_Int32 nCount = 0;
    8172           4 :         sal_Int32 nNewLen = sNewStr.getLength();
    8173           4 :         sal_Int32 nOldLen = sOldStr.getLength();
    8174             :         while( true )
    8175             :         {
    8176          16 :             nPos = sStr.indexOf( sOldStr, nPos );
    8177          16 :             if (nPos != -1)
    8178             :             {
    8179          12 :                 nCount++;
    8180          12 :                 if( !nAnz || nCount == nAnz )
    8181             :                 {
    8182           8 :                     sStr = sStr.replaceAt(nPos,nOldLen, "");
    8183          16 :                     if ( CheckStringResultLen( sStr, sNewStr ) )
    8184             :                     {
    8185           8 :                         sStr = sStr.replaceAt(nPos, 0, sNewStr);
    8186           8 :                         nPos = sal::static_int_cast<sal_Int32>( nPos + nNewLen );
    8187             :                     }
    8188             :                     else
    8189           0 :                         break;
    8190             :                 }
    8191             :                 else
    8192           4 :                     nPos++;
    8193             :             }
    8194             :             else
    8195           4 :                 break;
    8196             :         }
    8197           8 :         PushString( sStr );
    8198             :     }
    8199             : }
    8200             : 
    8201           2 : void ScInterpreter::ScRept()
    8202             : {
    8203           2 :     if ( MustHaveParamCount( GetByte(), 2 ) )
    8204             :     {
    8205           2 :         double fAnz = GetStringPositionArgument();
    8206           2 :         OUString aStr = GetString().getString();
    8207           2 :         if ( fAnz < 0.0 )
    8208           0 :             PushIllegalArgument();
    8209           2 :         else if ( fAnz * aStr.getLength() > SAL_MAX_UINT16 )
    8210             :         {
    8211           0 :             PushError( errStringOverflow );
    8212             :         }
    8213           2 :         else if ( fAnz == 0.0 )
    8214           0 :             PushString( EMPTY_OUSTRING );
    8215             :         else
    8216             :         {
    8217           2 :             const sal_Int32 nLen = aStr.getLength();
    8218           2 :             sal_Int32 n = (sal_Int32) fAnz;
    8219           2 :             OUStringBuffer aRes(n*nLen);
    8220          10 :             while( n-- )
    8221           6 :                 aRes.append(aStr);
    8222           2 :             PushString( aRes.makeStringAndClear() );
    8223           2 :         }
    8224             :     }
    8225           2 : }
    8226             : 
    8227          28 : void ScInterpreter::ScConcat()
    8228             : {
    8229          28 :     sal_uInt8 nParamCount = GetByte();
    8230          28 :     OUString aRes;
    8231         130 :     while( nParamCount-- > 0)
    8232             :     {
    8233          74 :         OUString aStr = GetString().getString();
    8234          74 :         aRes = aStr + aRes;
    8235          74 :     }
    8236          28 :     PushString( aRes );
    8237          28 : }
    8238             : 
    8239           0 : void ScInterpreter::ScErrorType()
    8240             : {
    8241             :     sal_uInt16 nErr;
    8242           0 :     sal_uInt16 nOldError = nGlobalError;
    8243           0 :     nGlobalError = 0;
    8244           0 :     switch ( GetStackType() )
    8245             :     {
    8246             :         case svRefList :
    8247             :         {
    8248           0 :             FormulaTokenRef x = PopToken();
    8249           0 :             if (nGlobalError)
    8250           0 :                 nErr = nGlobalError;
    8251             :             else
    8252             :             {
    8253           0 :                 const ScRefList* pRefList = x.get()->GetRefList();
    8254           0 :                 size_t n = pRefList->size();
    8255           0 :                 if (!n)
    8256           0 :                     nErr = errNoRef;
    8257           0 :                 else if (n > 1)
    8258           0 :                     nErr = errNoValue;
    8259             :                 else
    8260             :                 {
    8261           0 :                     ScRange aRange;
    8262           0 :                     DoubleRefToRange( (*pRefList)[0], aRange);
    8263           0 :                     if (nGlobalError)
    8264           0 :                         nErr = nGlobalError;
    8265             :                     else
    8266             :                     {
    8267           0 :                         ScAddress aAdr;
    8268           0 :                         if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
    8269           0 :                             nErr = pDok->GetErrCode( aAdr );
    8270             :                         else
    8271           0 :                             nErr = nGlobalError;
    8272             :                     }
    8273             :                 }
    8274           0 :             }
    8275             :         }
    8276           0 :         break;
    8277             :         case svDoubleRef :
    8278             :         {
    8279           0 :             ScRange aRange;
    8280           0 :             PopDoubleRef( aRange );
    8281           0 :             if ( nGlobalError )
    8282           0 :                 nErr = nGlobalError;
    8283             :             else
    8284             :             {
    8285           0 :                 ScAddress aAdr;
    8286           0 :                 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
    8287           0 :                     nErr = pDok->GetErrCode( aAdr );
    8288             :                 else
    8289           0 :                     nErr = nGlobalError;
    8290             :             }
    8291             :         }
    8292           0 :         break;
    8293             :         case svSingleRef :
    8294             :         {
    8295           0 :             ScAddress aAdr;
    8296           0 :             PopSingleRef( aAdr );
    8297           0 :             if ( nGlobalError )
    8298           0 :                 nErr = nGlobalError;
    8299             :             else
    8300           0 :                 nErr = pDok->GetErrCode( aAdr );
    8301             :         }
    8302           0 :         break;
    8303             :         default:
    8304           0 :             PopError();
    8305           0 :             nErr = nGlobalError;
    8306             :     }
    8307           0 :     if ( nErr )
    8308             :     {
    8309           0 :         nGlobalError = 0;
    8310           0 :         PushDouble( nErr );
    8311             :     }
    8312             :     else
    8313             :     {
    8314           0 :         nGlobalError = nOldError;
    8315           0 :         PushNA();
    8316             :     }
    8317           0 : }
    8318             : 
    8319          94 : bool ScInterpreter::MayBeRegExp( const OUString& rStr, const ScDocument* pDoc  )
    8320             : {
    8321          94 :     if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
    8322           0 :         return false;
    8323          94 :     if ( rStr.isEmpty() || (rStr.getLength() == 1 && !rStr.startsWith(".")) )
    8324          16 :         return false;   // single meta characters can not be a regexp
    8325             :     static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
    8326          78 :     const sal_Unicode* p1 = rStr.getStr();
    8327             :     sal_Unicode c1;
    8328         510 :     while ( ( c1 = *p1++ ) != 0 )
    8329             :     {
    8330         356 :         const sal_Unicode* p2 = cre;
    8331        5668 :         while ( *p2 )
    8332             :         {
    8333        4958 :             if ( c1 == *p2++ )
    8334           2 :                 return true;
    8335             :         }
    8336             :     }
    8337          76 :     return false;
    8338             : }
    8339             : 
    8340         126 : static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
    8341             :         const ScQueryParam & rParam, const ScQueryEntry & rEntry )
    8342             : {
    8343         126 :     bool bFound = false;
    8344         126 :     ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, false);
    8345         126 :     if (rEntry.eOp != SC_EQUAL)
    8346             :     {
    8347             :         // range lookup <= or >=
    8348             :         SCCOL nCol;
    8349             :         SCROW nRow;
    8350         112 :         bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow);
    8351         112 :         if (bFound)
    8352             :         {
    8353         102 :             o_rResultPos.SetCol( nCol);
    8354         102 :             o_rResultPos.SetRow( nRow);
    8355             :         }
    8356             :     }
    8357          14 :     else if (aCellIter.GetFirst())
    8358             :     {
    8359             :         // EQUAL
    8360           8 :         bFound = true;
    8361           8 :         o_rResultPos.SetCol( aCellIter.GetCol());
    8362           8 :         o_rResultPos.SetRow( aCellIter.GetRow());
    8363             :     }
    8364         126 :     return bFound;
    8365             : }
    8366             : 
    8367         126 : bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
    8368             :         const ScQueryParam & rParam ) const
    8369             : {
    8370         126 :     bool bFound = false;
    8371         126 :     const ScQueryEntry& rEntry = rParam.GetEntry(0);
    8372         126 :     bool bColumnsMatch = (rParam.nCol1 == rEntry.nField);
    8373             :     OSL_ENSURE( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match");
    8374         126 :     if (!bColumnsMatch)
    8375           0 :         bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
    8376             :     else
    8377             :     {
    8378             :         ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
    8379         126 :                 rParam.nCol2, rParam.nRow2, rParam.nTab);
    8380         126 :         ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange);
    8381         126 :         ScLookupCache::QueryCriteria aCriteria( rEntry);
    8382             :         ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos,
    8383         126 :                 aCriteria, aPos);
    8384         126 :         switch (eCacheResult)
    8385             :         {
    8386             :             case ScLookupCache::NOT_CACHED :
    8387             :             case ScLookupCache::CRITERIA_DIFFERENT :
    8388         126 :                 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
    8389         126 :                 if (eCacheResult == ScLookupCache::NOT_CACHED)
    8390         122 :                     rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
    8391         126 :                 break;
    8392             :             case ScLookupCache::FOUND :
    8393           0 :                 bFound = true;
    8394           0 :                 break;
    8395             :             case ScLookupCache::NOT_AVAILABLE :
    8396             :                 ;   // nothing, bFound remains FALSE
    8397           0 :                 break;
    8398         126 :         }
    8399             :     }
    8400         126 :     return bFound;
    8401         228 : }
    8402             : 
    8403             : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */

Generated by: LCOV version 1.10