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