xref: /aoo41x/main/sc/source/core/tool/interpr1.cxx (revision 1b1b70fb)
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;
4617             SCROW nRow1;
4618             SCTAB nTab1;
4619             SCCOL nCol2;
4620             SCROW nRow2;
4621             SCTAB nTab2;
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 
5107         while (nParamCount > 1 && !nGlobalError)
5108         {
5109             // take criteria
5110             String rString;
5111             fVal = 0.0;
5112             bool bIsString = true;
5113             switch ( GetStackType() )
5114             {
5115                 case svDoubleRef :
5116                 case svSingleRef :
5117                     {
5118                         ScAddress aAdr;
5119                         if ( !PopDoubleRefOrSingleRef( aAdr ) )
5120                             return 0;
5121 
5122                         ScBaseCell* pCell = GetCell( aAdr );
5123                         switch ( GetCellType( pCell ) )
5124                         {
5125                             case CELLTYPE_VALUE :
5126                                 fVal = GetCellValue( aAdr, pCell );
5127                                 bIsString = false;
5128                                 break;
5129                             case CELLTYPE_FORMULA :
5130                                 if( ((ScFormulaCell*)pCell)->IsValue() )
5131                                 {
5132                                     fVal = GetCellValue( aAdr, pCell );
5133                                     bIsString = false;
5134                                 }
5135                                 else
5136                                     GetCellString(rString, pCell);
5137                                 break;
5138                             case CELLTYPE_STRING :
5139                             case CELLTYPE_EDIT :
5140                                 GetCellString(rString, pCell);
5141                                 break;
5142                             default:
5143                                 fVal = 0.0;
5144                                 bIsString = false;
5145                         }
5146                     }
5147                     break;
5148                 case svString:
5149                     rString = GetString();
5150                     break;
5151                 case svMatrix :
5152                     {
5153                         ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
5154                         bIsString = ScMatrix::IsNonValueType( nType);
5155                     }
5156                     break;
5157                 default:
5158                     {
5159                         fVal = GetDouble();
5160                         bIsString = false;
5161                     }
5162             }
5163 
5164             // take range
5165             nParam = 1;
5166             nRefInList = 0;
5167             SCCOL nCol1;
5168             SCROW nRow1;
5169             SCTAB nTab1;
5170             SCCOL nCol2;
5171             SCROW nRow2;
5172             SCTAB nTab2;
5173             ScMatrixRef pQueryMatrix;
5174             switch ( GetStackType() )
5175             {
5176                 case svRefList :
5177                     {
5178                         ScRange aRange;
5179                         PopDoubleRef( aRange, nParam, nRefInList);
5180                         aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
5181                     }
5182                     break;
5183                 case svDoubleRef :
5184                     PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
5185                     break;
5186                 case svSingleRef :
5187                     PopSingleRef( nCol1, nRow1, nTab1 );
5188                     nCol2 = nCol1;
5189                     nRow2 = nRow1;
5190                     nTab2 = nTab1;
5191                     break;
5192                 case svMatrix:
5193                     {
5194                         pQueryMatrix = PopMatrix();
5195                         if (!pQueryMatrix)
5196                         {
5197                             SetError( errIllegalParameter);
5198                         }
5199                         nCol1 = 0;
5200                         nRow1 = 0;
5201                         nTab1 = 0;
5202                         SCSIZE nC, nR;
5203                         pQueryMatrix->GetDimensions( nC, nR);
5204                         nCol2 = static_cast<SCCOL>(nC - 1);
5205                         nRow2 = static_cast<SCROW>(nR - 1);
5206                         nTab2 = 0;
5207                     }
5208                     break;
5209                 default:
5210                     SetError( errIllegalParameter);
5211             }
5212             if ( nTab1 != nTab2 )
5213             {
5214                 SetError( errIllegalParameter);
5215             }
5216             // initialize temporary result matrix
5217             if (!pResMat)
5218             {
5219                 SCSIZE nResC, nResR;
5220                 nResC = nCol2 - nCol1 + 1;
5221                 nResR = nRow2 - nRow1 + 1;
5222                 pResMat = GetNewMat(nResC, nResR);
5223                 if (!pResMat)
5224                 {
5225                     SetError( errIllegalParameter);
5226                 }
5227                 else
5228                 {
5229                     pResMat->FillDouble( 0.0, 0, 0, nResC-1, nResR-1);
5230                 }
5231             }
5232             // recalculate matrix values
5233             if (nGlobalError == 0)
5234             {
5235                 ScQueryParam rParam;
5236                 rParam.nRow1       = nRow1;
5237                 rParam.nRow2       = nRow2;
5238 
5239                 ScQueryEntry& rEntry = rParam.GetEntry(0);
5240                 rEntry.bDoQuery = true;
5241                 if (!bIsString)
5242                 {
5243                     rEntry.bQueryByString = false;
5244                     rEntry.nVal = fVal;
5245                     rEntry.eOp = SC_EQUAL;
5246                 }
5247                 else
5248                 {
5249                     rParam.FillInExcelSyntax(rString, 0);
5250                     sal_uInt32 nIndex = 0;
5251                     rEntry.bQueryByString =
5252                         !(pFormatter->IsNumberFormat(
5253                                     *rEntry.pStr, nIndex, rEntry.nVal));
5254                     if ( rEntry.bQueryByString )
5255                         rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5256                 }
5257                 ScAddress aAdr;
5258                 aAdr.SetTab( nTab1 );
5259                 rParam.nCol1  = nCol1;
5260                 rParam.nCol2  = nCol2;
5261                 rEntry.nField = nCol1;
5262                 SCsCOL nColDiff = -nCol1;
5263                 SCsROW nRowDiff = -nRow1;
5264                 if (pQueryMatrix)
5265                 {
5266                     // Never case-sensitive.
5267                     ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
5268                     ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
5269                     if (nGlobalError || !pResultMatrix)
5270                     {
5271                         SetError( errIllegalParameter);
5272                     }
5273 
5274                     for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
5275                     {
5276                         for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
5277                         {
5278                             if (pResultMatrix->IsValue( nCol, nRow) &&
5279                                     pResultMatrix->GetDouble( nCol, nRow))
5280                             {
5281                                 SCSIZE nC = nCol + nColDiff;
5282                                 SCSIZE nR = nRow + nRowDiff;
5283                                 pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR);
5284                             }
5285                         }
5286                     }
5287                 }
5288                 else
5289                 {
5290                     ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
5291                     // Increment Entry.nField in iterator when switching to next column.
5292                     aCellIter.SetAdvanceQueryParamEntryField( true );
5293                     if ( aCellIter.GetFirst() )
5294                     {
5295                         do
5296                         {
5297                             SCSIZE nC = aCellIter.GetCol() + nColDiff;
5298                             SCSIZE nR = aCellIter.GetRow() + nRowDiff;
5299                             pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR);
5300                         } while ( aCellIter.GetNext() );
5301                     }
5302                 }
5303             }
5304             else
5305             {
5306                 SetError( errIllegalParameter);
5307             }
5308             nParamCount -= 2;
5309         }
5310 
5311         // main range - only for AVERAGEIFS and SUMIFS
5312         if (nParamCount == 1)
5313         {
5314             nParam = 1;
5315             nRefInList = 0;
5316             bool bNull = true;
5317             SCCOL nMainCol1;
5318             SCROW nMainRow1;
5319             SCTAB nMainTab1;
5320             SCCOL nMainCol2;
5321             SCROW nMainRow2;
5322             SCTAB nMainTab2;
5323             ScMatrixRef pMainMatrix;
5324             switch ( GetStackType() )
5325             {
5326                 case svRefList :
5327                     {
5328                         ScRange aRange;
5329                         PopDoubleRef( aRange, nParam, nRefInList);
5330                         aRange.GetVars( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2);
5331                     }
5332                     break;
5333                 case svDoubleRef :
5334                     PopDoubleRef( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2 );
5335                     break;
5336                 case svSingleRef :
5337                     PopSingleRef( nMainCol1, nMainRow1, nMainTab1 );
5338                     nMainCol2 = nMainCol1;
5339                     nMainRow2 = nMainRow1;
5340                     nMainTab2 = nMainTab1;
5341                     break;
5342                 case svMatrix:
5343                     {
5344                         pMainMatrix = PopMatrix();
5345                         if (!pMainMatrix)
5346                         {
5347                             SetError( errIllegalParameter);
5348                         }
5349                         nMainCol1 = 0;
5350                         nMainRow1 = 0;
5351                         nMainTab1 = 0;
5352                         SCSIZE nC, nR;
5353                         pMainMatrix->GetDimensions( nC, nR);
5354                         nMainCol2 = static_cast<SCCOL>(nC - 1);
5355                         nMainRow2 = static_cast<SCROW>(nR - 1);
5356                         nMainTab2 = 0;
5357                     }
5358                     break;
5359                 default:
5360                     SetError( errIllegalParameter);
5361             }
5362             if ( nMainTab1 != nMainTab2 )
5363             {
5364                 SetError( errIllegalParameter);
5365             }
5366             // end-result calculation
5367             ScAddress aAdr;
5368             aAdr.SetTab( nMainTab1 );
5369             if (pMainMatrix)
5370             {
5371                 SCSIZE nC, nR;
5372                 pResMat->GetDimensions(nC, nR);
5373                 for (SCSIZE nCol = 0; nCol < nC; ++nCol)
5374                 {
5375                     for (SCSIZE nRow = 0; nRow < nR; ++nRow)
5376                     {
5377                         if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
5378                         {
5379                             if (pMainMatrix->IsValue( nCol, nRow))
5380                             {
5381                                 fVal = pMainMatrix->GetDouble( nCol, nRow);
5382                                 ++fCount;
5383                                 if ( bNull && fVal != 0.0 )
5384                                 {
5385                                     bNull = false;
5386                                     fMem = fVal;
5387                                 }
5388                                 else
5389                                     fSum += fVal;
5390                             }
5391                         }
5392                     }
5393                 }
5394             }
5395             else
5396             {
5397                 SCSIZE nC, nR;
5398                 pResMat->GetDimensions(nC, nR);
5399                 for (SCSIZE nCol = 0; nCol < nC; ++nCol)
5400                 {
5401                     for (SCSIZE nRow = 0; nRow < nR; ++nRow)
5402                     {
5403                         if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
5404                         {
5405                             aAdr.SetCol( nCol + nMainCol1);
5406                             aAdr.SetRow( nRow + nMainRow1);
5407                             ScBaseCell* pCell = GetCell( aAdr );
5408                             if ( HasCellValueData(pCell) )
5409                             {
5410                                 fVal = GetCellValue( aAdr, pCell );
5411                                 ++fCount;
5412                                 if ( bNull && fVal != 0.0 )
5413                                 {
5414                                     bNull = false;
5415                                     fMem = fVal;
5416                                 }
5417                                 else
5418                                     fSum += fVal;
5419                             }
5420                         }
5421                     }
5422                 }
5423             }
5424         }
5425         else
5426         {
5427             SCSIZE nC, nR;
5428             pResMat->GetDimensions(nC, nR);
5429             for (SCSIZE nCol = 0; nCol < nC; ++nCol)
5430             {
5431                 for (SCSIZE nRow = 0; nRow < nR; ++nRow)
5432                     if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
5433                         ++fCount;
5434             }
5435         }
5436         //
5437         switch( eFunc )
5438         {
5439             case ifSUMIFS:     fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
5440             case ifAVERAGEIFS: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
5441             case ifCOUNTIFS:   fRes = fCount; break;
5442             default: ; // nothing
5443         }
5444         return fRes;
5445     }
5446     return 0;
5447 }
5448 
5449 void ScInterpreter::ScSumIfs()
5450 {
5451     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScSumIfs" );
5452     PushDouble( IterateParametersIfs( ifSUMIFS));
5453 }
5454 
5455 void ScInterpreter::ScAverageIfs()
5456 {
5457     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScAverageIfs" );
5458     PushDouble( IterateParametersIfs( ifAVERAGEIFS));
5459 }
5460 
5461 void ScInterpreter::ScCountIfs()
5462 {
5463     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScCountIfs" );
5464     PushDouble( IterateParametersIfs( ifCOUNTIFS));
5465 }
5466 
5467 void ScInterpreter::ScLookup()
5468 {
5469     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLookup" );
5470     sal_uInt8 nParamCount = GetByte();
5471     if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
5472         return ;
5473 
5474     ScMatrixRef pDataMat = NULL, pResMat = NULL;
5475     SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
5476     SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
5477     SCTAB nTab1 = 0, nResTab = 0;
5478     SCSIZE nLenMajor = 0;   // length of major direction
5479     bool bVertical = true;  // whether to lookup vertically or horizontally
5480 
5481     // The third parameter, result array, for double, string and single reference.
5482     double fResVal = 0.0;
5483     String aResStr;
5484     ScAddress aResAdr;
5485     StackVar eResArrayType = svUnknown;
5486 
5487     if (nParamCount == 3)
5488     {
5489         eResArrayType = GetStackType();
5490         switch (eResArrayType)
5491         {
5492             case svDoubleRef:
5493             {
5494                 SCTAB nTabJunk;
5495                 PopDoubleRef(nResCol1, nResRow1, nResTab,
5496                              nResCol2, nResRow2, nTabJunk);
5497                 if (nResTab != nTabJunk ||
5498                     ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
5499                 {
5500                     // The result array must be a vector.
5501                     PushIllegalParameter();
5502                     return;
5503                 }
5504             }
5505             break;
5506             case svMatrix:
5507             {
5508                 pResMat = PopMatrix();
5509                 if (!pResMat)
5510                 {
5511                     PushIllegalParameter();
5512                     return;
5513                 }
5514                 SCSIZE nC, nR;
5515                 pResMat->GetDimensions(nC, nR);
5516                 if (nC != 1 && nR != 1)
5517                 {
5518                     // Result matrix must be a vector.
5519                     PushIllegalParameter();
5520                     return;
5521                 }
5522             }
5523             break;
5524             case svDouble:
5525                 fResVal = GetDouble();
5526             break;
5527             case svString:
5528                 aResStr = GetString();
5529             break;
5530             case svSingleRef:
5531                 PopSingleRef( aResAdr );
5532             break;
5533             default:
5534                 PushIllegalParameter();
5535                 return;
5536         }
5537     }
5538 
5539     // For double, string and single reference.
5540     double fDataVal = 0.0;
5541     String aDataStr;
5542     ScAddress aDataAdr;
5543     bool bValueData = false;
5544 
5545     // Get the data-result range and also determine whether this is vertical
5546     // lookup or horizontal lookup.
5547 
5548     StackVar eDataArrayType = GetStackType();
5549     switch (eDataArrayType)
5550     {
5551         case svDoubleRef:
5552         {
5553             SCTAB nTabJunk;
5554             PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
5555             if (nTab1 != nTabJunk)
5556             {
5557                 PushIllegalParameter();
5558                 return;
5559             }
5560             bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
5561             nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
5562         }
5563         break;
5564         case svMatrix:
5565         {
5566             pDataMat = PopMatrix();
5567             if (!pDataMat)
5568             {
5569                 PushIllegalParameter();
5570                 return;
5571             }
5572 
5573             SCSIZE nC, nR;
5574             pDataMat->GetDimensions(nC, nR);
5575             bVertical = (nR >= nC);
5576             nLenMajor = bVertical ? nR : nC;
5577         }
5578         break;
5579         case svDouble:
5580         {
5581             fDataVal = GetDouble();
5582             bValueData = true;
5583         }
5584         break;
5585         case svString:
5586         {
5587             aDataStr = GetString();
5588         }
5589         break;
5590         case svSingleRef:
5591         {
5592             PopSingleRef( aDataAdr );
5593             const ScBaseCell* pDataCell = GetCell( aDataAdr );
5594             if (HasCellEmptyData( pDataCell))
5595             {
5596                 // Empty cells aren't found anywhere, bail out early.
5597                 SetError( NOTAVAILABLE);
5598             }
5599             else if (HasCellValueData( pDataCell))
5600             {
5601                 fDataVal = GetCellValue( aDataAdr, pDataCell );
5602                 bValueData = true;
5603             }
5604             else
5605                 GetCellString( aDataStr, pDataCell );
5606         }
5607         break;
5608         default:
5609             SetError( errIllegalParameter);
5610     }
5611 
5612 
5613     if (nGlobalError)
5614     {
5615         PushError( nGlobalError);
5616         return;
5617     }
5618 
5619     // Get the lookup value.
5620 
5621     ScQueryParam aParam;
5622     ScQueryEntry& rEntry = aParam.GetEntry(0);
5623     if ( !FillEntry(rEntry) )
5624         return;
5625 
5626     if ( eDataArrayType == svDouble || eDataArrayType == svString ||
5627             eDataArrayType == svSingleRef )
5628     {
5629         // Delta position for a single value is always 0.
5630 
5631         // Found if data <= query, but not if query is string and found data is
5632         // numeric or vice versa. This is how Excel does it but doesn't
5633         // document it.
5634 
5635         bool bFound = false;
5636         if ( bValueData )
5637         {
5638             if ( rEntry.bQueryByString )
5639                 bFound = false;
5640             else
5641                 bFound = (fDataVal <= rEntry.nVal);
5642         }
5643         else
5644         {
5645             if ( !rEntry.bQueryByString )
5646                 bFound = false;
5647             else
5648                 bFound = (ScGlobal::GetCollator()->compareString( aDataStr, *rEntry.pStr) <= 0);
5649         }
5650 
5651         if (!bFound)
5652         {
5653             PushNA();
5654             return;
5655         }
5656 
5657         if (pResMat)
5658         {
5659             if (pResMat->IsValue( 0 ))
5660                 PushDouble(pResMat->GetDouble( 0 ));
5661             else
5662                 PushString(pResMat->GetString( 0 ));
5663         }
5664         else if (nParamCount == 3)
5665         {
5666             switch (eResArrayType)
5667             {
5668                 case svDouble:
5669                     PushDouble( fResVal );
5670                     break;
5671                 case svString:
5672                     PushString( aResStr );
5673                     break;
5674                 case svDoubleRef:
5675                     aResAdr.Set( nResCol1, nResRow1, nResTab);
5676                     // fallthru
5677                 case svSingleRef:
5678                     PushCellResultToken( true, aResAdr, NULL, NULL);
5679                     break;
5680                 default:
5681                     DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
5682             }
5683         }
5684         else
5685         {
5686             switch (eDataArrayType)
5687             {
5688                 case svDouble:
5689                     PushDouble( fDataVal );
5690                     break;
5691                 case svString:
5692                     PushString( aDataStr );
5693                     break;
5694                 case svSingleRef:
5695                     PushCellResultToken( true, aDataAdr, NULL, NULL);
5696                     break;
5697                 default:
5698                     DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
5699             }
5700         }
5701         return;
5702     }
5703 
5704     // Now, perform the search to compute the delta position (nDelta).
5705 
5706     if (pDataMat)
5707     {
5708         // Data array is given as a matrix.
5709         rEntry.bDoQuery = true;
5710         rEntry.eOp = SC_LESS_EQUAL;
5711         bool bFound = false;
5712 
5713         SCSIZE nC, nR;
5714         pDataMat->GetDimensions(nC, nR);
5715 
5716         // In case of non-vector matrix, only search the first row or column.
5717         ScMatrixRef pDataMat2;
5718         if (bVertical)
5719         {
5720             ScMatrixRef pTempMat(new ScMatrix(1, nR));
5721             for (SCSIZE i = 0; i < nR; ++i)
5722                 if (pDataMat->IsValue(0, i))
5723                     pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
5724                 else
5725                     pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
5726             pDataMat2 = pTempMat;
5727         }
5728         else
5729         {
5730             ScMatrixRef pTempMat(new ScMatrix(nC, 1));
5731             for (SCSIZE i = 0; i < nC; ++i)
5732                 if (pDataMat->IsValue(i, 0))
5733                     pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
5734                 else
5735                     pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
5736             pDataMat2 = pTempMat;
5737         }
5738 
5739         // binary search for non-equality mode (the source data is
5740         // assumed to be sorted in ascending order).
5741 
5742         SCCOLROW nDelta = -1;
5743 
5744         SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
5745         for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
5746         {
5747             SCSIZE nMid = nFirst + nLen/2;
5748             sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry);
5749             if (nCmp == 0)
5750             {
5751                 // exact match.  find the last item with the same value.
5752                 lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false);
5753                 nDelta = nMid;
5754                 bFound = true;
5755                 break;
5756             }
5757 
5758             if (nLen == 1) // first and last items are next to each other.
5759             {
5760                 nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
5761                 // If already the 1st item is greater there's nothing found.
5762                 bFound = (nDelta >= 0);
5763                 break;
5764             }
5765 
5766             if (nCmp < 0)
5767                 nFirst = nMid;
5768             else
5769                 nLast = nMid;
5770         }
5771 
5772         if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
5773         {
5774             sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry);
5775             if (nCmp <= 0)
5776             {
5777                 // either the last item is an exact match or the real
5778                 // hit is beyond the last item.
5779                 nDelta += 1;
5780                 bFound = true;
5781             }
5782         }
5783         else if (nDelta > 0) // valid hit must be 2nd item or higher
5784         {
5785             // non-exact match
5786             bFound = true;
5787         }
5788 
5789         // With 0-9 < A-Z, if query is numeric and data found is string, or
5790         // vice versa, the (yet another undocumented) Excel behavior is to
5791         // return #N/A instead.
5792 
5793         if (bFound)
5794         {
5795             SCCOLROW i = nDelta;
5796             SCSIZE n = pDataMat->GetElementCount();
5797             if (static_cast<SCSIZE>(i) >= n)
5798                 i = static_cast<SCCOLROW>(n);
5799             if (bool(rEntry.bQueryByString) == bool(pDataMat->IsValue(i)))
5800                 bFound = false;
5801         }
5802 
5803         if (!bFound)
5804         {
5805             PushNA();
5806             return;
5807         }
5808 
5809         // Now that we've found the delta, push the result back to the cell.
5810 
5811         if (pResMat)
5812         {
5813             // result array is matrix.
5814             if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount())
5815             {
5816                 PushNA();
5817                 return;
5818             }
5819             if (pResMat->IsValue(nDelta))
5820                 PushDouble(pResMat->GetDouble(nDelta));
5821             else
5822                 PushString(pResMat->GetString(nDelta));
5823         }
5824         else if (nParamCount == 3)
5825         {
5826             // result array is cell range.
5827             ScAddress aAdr;
5828             aAdr.SetTab(nResTab);
5829             bool bResVertical = (nResRow2 - nResRow1) > 0;
5830             if (bResVertical)
5831             {
5832                 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
5833                 if (nTempRow > MAXROW)
5834                 {
5835                     PushDouble(0);
5836                     return;
5837                 }
5838                 aAdr.SetCol(nResCol1);
5839                 aAdr.SetRow(nTempRow);
5840             }
5841             else
5842             {
5843                 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
5844                 if (nTempCol > MAXCOL)
5845                 {
5846                     PushDouble(0);
5847                     return;
5848                 }
5849                 aAdr.SetCol(nTempCol);
5850                 aAdr.SetRow(nResRow1);
5851             }
5852             PushCellResultToken(true, aAdr, NULL, NULL);
5853         }
5854         else
5855         {
5856             // no result array.  Use the data array to get the final value from.
5857             if (bVertical)
5858             {
5859                 if (pDataMat->IsValue(nC-1, nDelta))
5860                     PushDouble(pDataMat->GetDouble(nC-1, nDelta));
5861                 else
5862                     PushString(pDataMat->GetString(nC-1, nDelta));
5863             }
5864             else
5865             {
5866                 if (pDataMat->IsValue(nDelta, nR-1))
5867                     PushDouble(pDataMat->GetDouble(nDelta, nR-1));
5868                 else
5869                     PushString(pDataMat->GetString(nDelta, nR-1));
5870             }
5871         }
5872 
5873         return;
5874     }
5875 
5876     // Perform cell range search.
5877 
5878     aParam.nCol1            = nCol1;
5879     aParam.nRow1            = nRow1;
5880     aParam.nCol2            = bVertical ? nCol1 : nCol2;
5881     aParam.nRow2            = bVertical ? nRow2 : nRow1;
5882     aParam.bByRow           = bVertical;
5883     aParam.bMixedComparison = true;
5884 
5885     rEntry.bDoQuery = sal_True;
5886     rEntry.eOp = SC_LESS_EQUAL;
5887     rEntry.nField = nCol1;
5888     if ( rEntry.bQueryByString )
5889         aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5890 
5891     ScQueryCellIterator aCellIter(pDok, nTab1, aParam, sal_False);
5892     SCCOL nC;
5893     SCROW nR;
5894     // Advance Entry.nField in iterator upon switching columns if
5895     // lookup in row.
5896     aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
5897     if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
5898     {
5899         PushNA();
5900         return;
5901     }
5902 
5903     SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
5904 
5905     if (pResMat)
5906     {
5907         // Use the matrix result array.
5908         if (pResMat->IsValue(nDelta))
5909             PushDouble(pResMat->GetDouble(nDelta));
5910         else
5911             PushString(pResMat->GetString(nDelta));
5912     }
5913     else if (nParamCount == 3)
5914     {
5915         switch (eResArrayType)
5916         {
5917             case svDoubleRef:
5918             {
5919                 // Use the result array vector.  Note that the result array is assumed
5920                 // to be a vector (i.e. 1-dimensinoal array).
5921 
5922                 ScAddress aAdr;
5923                 aAdr.SetTab(nResTab);
5924                 bool bResVertical = (nResRow2 - nResRow1) > 0;
5925                 if (bResVertical)
5926                 {
5927                     SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
5928                     if (nTempRow > MAXROW)
5929                     {
5930                         PushDouble(0);
5931                         return;
5932                     }
5933                     aAdr.SetCol(nResCol1);
5934                     aAdr.SetRow(nTempRow);
5935                 }
5936                 else
5937                 {
5938                     SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
5939                     if (nTempCol > MAXCOL)
5940                     {
5941                         PushDouble(0);
5942                         return;
5943                     }
5944                     aAdr.SetCol(nTempCol);
5945                     aAdr.SetRow(nResRow1);
5946                 }
5947                 PushCellResultToken( true, aAdr, NULL, NULL);
5948             }
5949             break;
5950             case svDouble:
5951             case svString:
5952             case svSingleRef:
5953             {
5954                 if (nDelta != 0)
5955                     PushNA();
5956                 else
5957                 {
5958                     switch (eResArrayType)
5959                     {
5960                         case svDouble:
5961                             PushDouble( fResVal );
5962                             break;
5963                         case svString:
5964                             PushString( aResStr );
5965                             break;
5966                         case svSingleRef:
5967                             PushCellResultToken( true, aResAdr, NULL, NULL);
5968                             break;
5969                         default:
5970                             ;   // nothing
5971                     }
5972                 }
5973             }
5974             break;
5975             default:
5976                 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
5977         }
5978     }
5979     else
5980     {
5981         // Regardless of whether or not the result array exists, the last
5982         // array is always used as the "result" array.
5983 
5984         ScAddress aAdr;
5985         aAdr.SetTab(nTab1);
5986         if (bVertical)
5987         {
5988             SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
5989             if (nTempRow > MAXROW)
5990             {
5991                 PushDouble(0);
5992                 return;
5993             }
5994             aAdr.SetCol(nCol2);
5995             aAdr.SetRow(nTempRow);
5996         }
5997         else
5998         {
5999             SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
6000             if (nTempCol > MAXCOL)
6001             {
6002                 PushDouble(0);
6003                 return;
6004             }
6005             aAdr.SetCol(nTempCol);
6006             aAdr.SetRow(nRow2);
6007         }
6008         PushCellResultToken(true, aAdr, NULL, NULL);
6009     }
6010 }
6011 
6012 
6013 void ScInterpreter::ScHLookup()
6014 {
6015     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHLookup" );
6016     CalculateLookup(sal_True);
6017 }
6018 void ScInterpreter::CalculateLookup(sal_Bool HLookup)
6019 {
6020     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateLookup" );
6021     sal_uInt8 nParamCount = GetByte();
6022     if ( MustHaveParamCount( nParamCount, 3, 4 ) )
6023     {
6024         sal_Bool bSorted;
6025         if (nParamCount == 4)
6026             bSorted = GetBool();
6027         else
6028             bSorted = sal_True;
6029         double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
6030         ScMatrixRef pMat = NULL;
6031         SCSIZE nC = 0, nR = 0;
6032         SCCOL nCol1 = 0;
6033         SCROW nRow1 = 0;
6034         SCTAB nTab1 = 0;
6035         SCCOL nCol2 = 0;
6036         SCROW nRow2 = 0;
6037         SCTAB nTab2;
6038         if (GetStackType() == svDoubleRef)
6039         {
6040             PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6041             if (nTab1 != nTab2)
6042             {
6043                 PushIllegalParameter();
6044                 return;
6045             }
6046         }
6047         else if (GetStackType() == svMatrix)
6048         {
6049             pMat = PopMatrix();
6050             if (pMat)
6051                 pMat->GetDimensions(nC, nR);
6052             else
6053             {
6054                 PushIllegalParameter();
6055                 return;
6056             }
6057         }
6058         else
6059         {
6060             PushIllegalParameter();
6061             return;
6062         }
6063         if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
6064         {
6065             PushIllegalArgument();
6066             return;
6067         }
6068         SCROW nZIndex = static_cast<SCROW>(fIndex);
6069         SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
6070 
6071         if (!pMat)
6072         {
6073             nZIndex += nRow1;                       // Wertzeile
6074             nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 );     // value column
6075         }
6076 
6077         if (nGlobalError == 0)
6078         {
6079             ScQueryParam rParam;
6080             rParam.nCol1       = nCol1;
6081             rParam.nRow1       = nRow1;
6082             if ( HLookup )
6083             {
6084                 rParam.nCol2       = nCol2;
6085                 rParam.nRow2       = nRow1;     // nur in der ersten Zeile suchen
6086                 rParam.bByRow      = sal_False;
6087             } // if ( HLookup )
6088             else
6089             {
6090                 rParam.nCol2       = nCol1;     // nur in der ersten Spalte suchen
6091                 rParam.nRow2       = nRow2;
6092                 rParam.nTab        = nTab1;
6093             }
6094             rParam.bMixedComparison = sal_True;
6095 
6096             ScQueryEntry& rEntry = rParam.GetEntry(0);
6097             rEntry.bDoQuery = sal_True;
6098             if ( bSorted )
6099                 rEntry.eOp = SC_LESS_EQUAL;
6100             if ( !FillEntry(rEntry) )
6101                 return;
6102             if ( rEntry.bQueryByString )
6103                 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
6104             if (pMat)
6105             {
6106                 SCSIZE nMatCount = HLookup ? nC : nR;
6107                 SCSIZE nDelta = SCSIZE_MAX;
6108                 if (rEntry.bQueryByString)
6109                 {
6110         //!!!!!!!
6111         //! TODO: enable regex on matrix strings
6112         //!!!!!!!
6113                     String aParamStr = *rEntry.pStr;
6114                     if ( bSorted )
6115                     {
6116                         static CollatorWrapper* pCollator = ScGlobal::GetCollator();
6117                         for (SCSIZE i = 0; i < nMatCount; i++)
6118                         {
6119                             if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
6120                             {
6121                                 sal_Int32 nRes =
6122                                     pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr);
6123                                 if (nRes <= 0)
6124                                     nDelta = i;
6125                                 else if (i>0)   // #i2168# ignore first mismatch
6126                                     i = nMatCount+1;
6127                             }
6128                             else
6129                                 nDelta = i;
6130                         }
6131                     }
6132                     else
6133                     {
6134                         for (SCSIZE i = 0; i < nMatCount; i++)
6135                         {
6136                             if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
6137                             {
6138                                 if ( ScGlobal::GetpTransliteration()->isEqual(
6139                                     HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr ) )
6140                                 {
6141                                     nDelta = i;
6142                                     i = nMatCount + 1;
6143                                 }
6144                             }
6145                         }
6146                     }
6147                 }
6148                 else
6149                 {
6150                     if ( bSorted )
6151                     {
6152                         // #i2168# ignore strings
6153                         for (SCSIZE i = 0; i < nMatCount; i++)
6154                         {
6155                             if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
6156                             {
6157                                 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rEntry.nVal)
6158                                     nDelta = i;
6159                                 else
6160                                     i = nMatCount+1;
6161                             }
6162                         }
6163                     }
6164                     else
6165                     {
6166                         for (SCSIZE i = 0; i < nMatCount; i++)
6167                         {
6168                             if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
6169                             {
6170                                 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) == rEntry.nVal)
6171                                 {
6172                                     nDelta = i;
6173                                     i = nMatCount + 1;
6174                                 }
6175                             }
6176                         }
6177                     }
6178                 }
6179                 if ( nDelta != SCSIZE_MAX )
6180                 {
6181                     SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
6182                     SCSIZE nY = nDelta;
6183                     if ( HLookup )
6184                     {
6185                         nX = nDelta;
6186                         nY = static_cast<SCSIZE>(nZIndex);
6187                     }
6188                     if ( pMat->IsString( nX, nY) )
6189                         PushString(pMat->GetString( nX,nY));
6190                     else
6191                         PushDouble(pMat->GetDouble( nX,nY));
6192                 }
6193                 else
6194                     PushNA();
6195             }
6196             else
6197             {
6198                 rEntry.nField = nCol1;
6199                 sal_Bool bFound = sal_False;
6200                 SCCOL nCol = 0;
6201                 SCROW nRow = 0;
6202                 if ( bSorted )
6203                     rEntry.eOp = SC_LESS_EQUAL;
6204                 if ( HLookup )
6205                 {
6206                     ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
6207                     // advance Entry.nField in Iterator upon switching columns
6208                     aCellIter.SetAdvanceQueryParamEntryField( sal_True );
6209                     if ( bSorted )
6210                     {
6211                         SCROW nRow1_temp;
6212                         bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
6213                     }
6214                     else if ( aCellIter.GetFirst() )
6215                     {
6216                         bFound = sal_True;
6217                         nCol = aCellIter.GetCol();
6218                     }
6219                     nRow = nZIndex;
6220                 } // if ( HLookup )
6221                 else
6222                 {
6223                     ScAddress aResultPos( nCol1, nRow1, nTab1);
6224                     bFound = LookupQueryWithCache( aResultPos, rParam);
6225                     nRow = aResultPos.Row();
6226                     nCol = nSpIndex;
6227                 }
6228                 if ( bFound )
6229                 {
6230                     ScAddress aAdr( nCol, nRow, nTab1 );
6231                     PushCellResultToken( true, aAdr, NULL, NULL);
6232                 }
6233                 else
6234                     PushNA();
6235             }
6236         }
6237         else
6238             PushIllegalParameter();
6239     }
6240 }
6241 
6242 bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
6243 {
6244     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::FillEntry" );
6245     switch ( GetStackType() )
6246     {
6247         case svDouble:
6248         {
6249             rEntry.bQueryByString = sal_False;
6250             rEntry.nVal = GetDouble();
6251         }
6252         break;
6253         case svString:
6254         {
6255             const String sStr = GetString();
6256             rEntry.bQueryByString = sal_True;
6257             *rEntry.pStr = sStr;
6258         }
6259         break;
6260         case svDoubleRef :
6261         case svSingleRef :
6262         {
6263             ScAddress aAdr;
6264             if ( !PopDoubleRefOrSingleRef( aAdr ) )
6265             {
6266                 PushInt(0);
6267                 return false;
6268             }
6269             ScBaseCell* pCell = GetCell( aAdr );
6270             if (HasCellValueData(pCell))
6271             {
6272                 rEntry.bQueryByString = sal_False;
6273                 rEntry.nVal = GetCellValue( aAdr, pCell );
6274             }
6275             else
6276             {
6277                 if ( GetCellType( pCell ) == CELLTYPE_NOTE )
6278                 {
6279                     rEntry.bQueryByString = sal_False;
6280                     rEntry.nVal = 0.0;
6281                 }
6282                 else
6283                 {
6284                     String sStr;
6285                     GetCellString(sStr, pCell);
6286                     rEntry.bQueryByString = sal_True;
6287                     *rEntry.pStr = sStr;
6288                 }
6289             }
6290         }
6291         break;
6292         case svMatrix :
6293         {
6294             const ScMatValType nType = GetDoubleOrStringFromMatrix(rEntry.nVal, *rEntry.pStr);
6295             rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
6296         }
6297         break;
6298         default:
6299         {
6300             PushIllegalParameter();
6301             return false;
6302         }
6303     } // switch ( GetStackType() )
6304     return true;
6305 }
6306 void ScInterpreter::ScVLookup()
6307 {
6308     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVLookup" );
6309     CalculateLookup(sal_False);
6310 }
6311 
6312 void ScInterpreter::ScSubTotal()
6313 {
6314     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubTotal" );
6315     sal_uInt8 nParamCount = GetByte();
6316     if ( MustHaveParamCountMin( nParamCount, 2 ) )
6317     {
6318         // We must fish the 1st parameter deep from the stack! And push it on top.
6319         const FormulaToken* p = pStack[ sp - nParamCount ];
6320         PushTempToken( *p );
6321         int nFunc = (int) ::rtl::math::approxFloor( GetDouble() );
6322         if( nFunc < 1 || nFunc > 11 )
6323             PushIllegalArgument();  // simulate return on stack, not SetError(...)
6324         else
6325         {
6326             cPar = nParamCount - 1;
6327             glSubTotal = sal_True;
6328             switch( nFunc )
6329             {
6330                 case SUBTOTAL_FUNC_AVE  : ScAverage(); break;
6331                 case SUBTOTAL_FUNC_CNT  : ScCount();   break;
6332                 case SUBTOTAL_FUNC_CNT2 : ScCount2();  break;
6333                 case SUBTOTAL_FUNC_MAX  : ScMax();     break;
6334                 case SUBTOTAL_FUNC_MIN  : ScMin();     break;
6335                 case SUBTOTAL_FUNC_PROD : ScProduct(); break;
6336                 case SUBTOTAL_FUNC_STD  : ScStDev();   break;
6337                 case SUBTOTAL_FUNC_STDP : ScStDevP();  break;
6338                 case SUBTOTAL_FUNC_SUM  : ScSum();     break;
6339                 case SUBTOTAL_FUNC_VAR  : ScVar();     break;
6340                 case SUBTOTAL_FUNC_VARP : ScVarP();    break;
6341                 default : PushIllegalArgument();       break;
6342             }
6343             glSubTotal = sal_False;
6344         }
6345         // Get rid of the 1st (fished) parameter.
6346         double nVal = GetDouble();
6347         Pop();
6348         PushDouble( nVal );
6349     }
6350 }
6351 
6352 ScDBQueryParamBase* ScInterpreter::GetDBParams( sal_Bool& rMissingField )
6353 {
6354     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" );
6355     sal_Bool bAllowMissingField = sal_False;
6356     if ( rMissingField )
6357     {
6358         bAllowMissingField = sal_True;
6359         rMissingField = sal_False;
6360     }
6361     if ( GetByte() == 3 )
6362     {
6363         // First, get the query criteria range.
6364         ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
6365         if (!pQueryRef.get())
6366             return NULL;
6367 
6368         sal_Bool    bByVal = sal_True;
6369         double  nVal = 0.0;
6370         String  aStr;
6371         ScRange aMissingRange;
6372         sal_Bool bRangeFake = sal_False;
6373         switch (GetStackType())
6374         {
6375             case svDouble :
6376                 nVal = ::rtl::math::approxFloor( GetDouble() );
6377                 if ( bAllowMissingField && nVal == 0.0 )
6378                     rMissingField = sal_True;   // fake missing parameter
6379                 break;
6380             case svString :
6381                 bByVal = sal_False;
6382                 aStr = GetString();
6383                 break;
6384             case svSingleRef :
6385                 {
6386                     ScAddress aAdr;
6387                     PopSingleRef( aAdr );
6388                     ScBaseCell* pCell = GetCell( aAdr );
6389                     if (HasCellValueData(pCell))
6390                         nVal = GetCellValue( aAdr, pCell );
6391                     else
6392                     {
6393                         bByVal = sal_False;
6394                         GetCellString(aStr, pCell);
6395                     }
6396                 }
6397                 break;
6398             case svDoubleRef :
6399                 if ( bAllowMissingField )
6400                 {   // fake missing parameter for old SO compatibility
6401                     bRangeFake = sal_True;
6402                     PopDoubleRef( aMissingRange );
6403                 }
6404                 else
6405                 {
6406                     PopError();
6407                     SetError( errIllegalParameter );
6408                 }
6409                 break;
6410             case svMissing :
6411                 PopError();
6412                 if ( bAllowMissingField )
6413                     rMissingField = sal_True;
6414                 else
6415                     SetError( errIllegalParameter );
6416                 break;
6417             default:
6418                 PopError();
6419                 SetError( errIllegalParameter );
6420         }
6421 
6422         auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
6423 
6424         if (nGlobalError || !pDBRef.get())
6425             return NULL;
6426 
6427         if ( bRangeFake )
6428         {
6429             // range parameter must match entire database range
6430             if (pDBRef->isRangeEqual(aMissingRange))
6431                 rMissingField = sal_True;
6432             else
6433                 SetError( errIllegalParameter );
6434         }
6435 
6436         if (nGlobalError)
6437             return NULL;
6438 
6439         SCCOL nField = pDBRef->getFirstFieldColumn();
6440         if (rMissingField)
6441             ; // special case
6442         else if (bByVal)
6443             nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal));
6444         else
6445         {
6446             sal_uInt16 nErr = 0;
6447             nField = pDBRef->findFieldColumn(aStr, &nErr);
6448             SetError(nErr);
6449         }
6450 
6451         if (!ValidCol(nField))
6452             return NULL;
6453 
6454         auto_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) );
6455 
6456         if (pParam.get())
6457         {
6458             // An allowed missing field parameter sets the result field
6459             // to any of the query fields, just to be able to return
6460             // some cell from the iterator.
6461             if ( rMissingField )
6462                 nField = static_cast<SCCOL>(pParam->GetEntry(0).nField);
6463             pParam->mnField = nField;
6464 
6465             SCSIZE nCount = pParam->GetEntryCount();
6466             for ( SCSIZE i=0; i < nCount; i++ )
6467             {
6468                 ScQueryEntry& rEntry = pParam->GetEntry(i);
6469                 if ( rEntry.bDoQuery )
6470                 {
6471                     sal_uInt32 nIndex = 0;
6472                     rEntry.bQueryByString = !pFormatter->IsNumberFormat(
6473                         *rEntry.pStr, nIndex, rEntry.nVal );
6474                     if ( rEntry.bQueryByString && !pParam->bRegExp )
6475                         pParam->bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
6476                 }
6477                 else
6478                     break;  // for
6479             }
6480             return pParam.release();
6481         }
6482     }
6483     return false;
6484 }
6485 
6486 
6487 void ScInterpreter::DBIterator( ScIterFunc eFunc )
6488 {
6489     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" );
6490     double nErg = 0.0;
6491     double fMem = 0.0;
6492     sal_Bool bNull = sal_True;
6493     sal_uLong nCount = 0;
6494     sal_Bool bMissingField = sal_False;
6495     auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6496     if (pQueryParam.get())
6497     {
6498         ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
6499         ScDBQueryDataIterator::Value aValue;
6500         if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6501         {
6502             switch( eFunc )
6503             {
6504                 case ifPRODUCT: nErg = 1; break;
6505                 case ifMAX:     nErg = -MAXDOUBLE; break;
6506                 case ifMIN:     nErg = MAXDOUBLE; break;
6507                 default: ; // nothing
6508             }
6509             do
6510             {
6511                 nCount++;
6512                 switch( eFunc )
6513                 {
6514                     case ifAVERAGE:
6515                     case ifSUM:
6516                         if ( bNull && aValue.mfValue != 0.0 )
6517                         {
6518                             bNull = sal_False;
6519                             fMem = aValue.mfValue;
6520                         }
6521                         else
6522                             nErg += aValue.mfValue;
6523                         break;
6524                     case ifSUMSQ:   nErg += aValue.mfValue * aValue.mfValue; break;
6525                     case ifPRODUCT: nErg *= aValue.mfValue; break;
6526                     case ifMAX:     if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break;
6527                     case ifMIN:     if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break;
6528                     default: ; // nothing
6529                 }
6530             }
6531             while ( aValIter.GetNext(aValue) && !aValue.mnError );
6532         }
6533         SetError(aValue.mnError);
6534     }
6535     else
6536         SetError( errIllegalParameter);
6537     switch( eFunc )
6538     {
6539         case ifCOUNT:   nErg = nCount; break;
6540         case ifSUM:     nErg = ::rtl::math::approxAdd( nErg, fMem ); break;
6541         case ifAVERAGE: nErg = ::rtl::math::approxAdd( nErg, fMem ) / nCount; break;
6542         default: ; // nothing
6543     }
6544     PushDouble( nErg );
6545 }
6546 
6547 
6548 void ScInterpreter::ScDBSum()
6549 {
6550     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBSum" );
6551     DBIterator( ifSUM );
6552 }
6553 
6554 
6555 void ScInterpreter::ScDBCount()
6556 {
6557     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount" );
6558     sal_Bool bMissingField = sal_True;
6559     auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6560     if (pQueryParam.get())
6561     {
6562         sal_uLong nCount = 0;
6563         if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL )
6564         {   // count all matching records
6565             // TODO: currently the QueryIterators only return cell pointers of
6566             // existing cells, so if a query matches an empty cell there's
6567             // nothing returned, and therefor not counted!
6568             // Since this has ever been the case and this code here only came
6569             // into existance to fix #i6899 and it never worked before we'll
6570             // have to live with it until we reimplement the iterators to also
6571             // return empty cells, which would mean to adapt all callers of
6572             // iterators.
6573             ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get());
6574             SCTAB nTab = p->nTab;
6575             // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField,
6576             // so the source range has to be restricted, like before the introduction
6577             // of ScDBQueryParamBase.
6578             p->nCol1 = p->nCol2 = p->mnField;
6579             ScQueryCellIterator aCellIter( pDok, nTab, *p);
6580             if ( aCellIter.GetFirst() )
6581             {
6582                 do
6583                 {
6584                     nCount++;
6585                 } while ( aCellIter.GetNext() );
6586             }
6587         }
6588         else
6589         {   // count only matching records with a value in the "result" field
6590             ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
6591             ScDBQueryDataIterator::Value aValue;
6592             if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6593             {
6594                 do
6595                 {
6596                     nCount++;
6597                 }
6598                 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6599             }
6600             SetError(aValue.mnError);
6601         }
6602         PushDouble( nCount );
6603     }
6604     else
6605         PushIllegalParameter();
6606 }
6607 
6608 
6609 void ScInterpreter::ScDBCount2()
6610 {
6611     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount2" );
6612     sal_Bool bMissingField = sal_True;
6613     auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6614     if (pQueryParam.get())
6615     {
6616         sal_uLong nCount = 0;
6617         pQueryParam->mbSkipString = false;
6618         ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
6619         ScDBQueryDataIterator::Value aValue;
6620         if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6621         {
6622             do
6623             {
6624                 nCount++;
6625             }
6626             while ( aValIter.GetNext(aValue) && !aValue.mnError );
6627         }
6628         SetError(aValue.mnError);
6629         PushDouble( nCount );
6630     }
6631     else
6632         PushIllegalParameter();
6633 }
6634 
6635 
6636 void ScInterpreter::ScDBAverage()
6637 {
6638     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBAverage" );
6639     DBIterator( ifAVERAGE );
6640 }
6641 
6642 
6643 void ScInterpreter::ScDBMax()
6644 {
6645     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMax" );
6646     DBIterator( ifMAX );
6647 }
6648 
6649 
6650 void ScInterpreter::ScDBMin()
6651 {
6652     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMin" );
6653     DBIterator( ifMIN );
6654 }
6655 
6656 
6657 void ScInterpreter::ScDBProduct()
6658 {
6659     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBProduct" );
6660     DBIterator( ifPRODUCT );
6661 }
6662 
6663 
6664 void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
6665 {
6666     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBStVarParams" );
6667     std::vector<double> values;
6668     double vSum    = 0.0;
6669     double vMean    = 0.0;
6670 
6671     rValCount = 0.0;
6672     double fSum    = 0.0;
6673     sal_Bool bMissingField = sal_False;
6674     auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6675     if (pQueryParam.get())
6676     {
6677         ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
6678         ScDBQueryDataIterator::Value aValue;
6679         if (aValIter.GetFirst(aValue) && !aValue.mnError)
6680         {
6681             do
6682             {
6683                 rValCount++;
6684                 values.push_back(aValue.mfValue);
6685                 fSum += aValue.mfValue;
6686             }
6687             while ((aValue.mnError == 0) && aValIter.GetNext(aValue));
6688         }
6689         SetError(aValue.mnError);
6690     }
6691     else
6692         SetError( errIllegalParameter);
6693 
6694     vMean = fSum / values.size();
6695 
6696     for (size_t i = 0; i < values.size(); i++)
6697         vSum += (values[i] - vMean) * (values[i] - vMean);
6698 
6699     rVal = vSum;
6700 }
6701 
6702 
6703 void ScInterpreter::ScDBStdDev()
6704 {
6705     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDev" );
6706     double fVal, fCount;
6707     GetDBStVarParams( fVal, fCount );
6708     PushDouble( sqrt(fVal/(fCount-1)));
6709 }
6710 
6711 
6712 void ScInterpreter::ScDBStdDevP()
6713 {
6714     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDevP" );
6715     double fVal, fCount;
6716     GetDBStVarParams( fVal, fCount );
6717     PushDouble( sqrt(fVal/fCount));
6718 }
6719 
6720 
6721 void ScInterpreter::ScDBVar()
6722 {
6723     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVar" );
6724     double fVal, fCount;
6725     GetDBStVarParams( fVal, fCount );
6726     PushDouble(fVal/(fCount-1));
6727 }
6728 
6729 
6730 void ScInterpreter::ScDBVarP()
6731 {
6732     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVarP" );
6733     double fVal, fCount;
6734     GetDBStVarParams( fVal, fCount );
6735     PushDouble(fVal/fCount);
6736 }
6737 
6738 
6739 FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, ScDocument* pDoc,
6740         const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1,
6741         const ScRefAddress* pRefAd2 )
6742 {
6743     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
6744     size_t nSheets = 1;
6745     const String* pRealTab = pRefMgr->getRealTableName( rExtInfo.mnFileId, rExtInfo.maTabName);
6746     ScTokenArray* pTokenArray = new ScTokenArray;
6747     if (pRefAd2)
6748     {
6749         ScComplexRefData aRef;
6750         aRef.InitRangeRel( ScRange( rRefAd1.GetAddress(), pRefAd2->GetAddress()), rPos);
6751         aRef.Ref1.SetColRel( rRefAd1.IsRelCol());
6752         aRef.Ref1.SetRowRel( rRefAd1.IsRelRow());
6753         aRef.Ref1.SetTabRel( rRefAd1.IsRelTab());
6754         aRef.Ref1.SetFlag3D( true);
6755         aRef.Ref2.SetColRel( pRefAd2->IsRelCol());
6756         aRef.Ref2.SetRowRel( pRefAd2->IsRelRow());
6757         aRef.Ref2.SetTabRel( pRefAd2->IsRelTab());
6758         nSheets = aRef.Ref2.nTab - aRef.Ref1.nTab + 1;
6759         aRef.Ref2.SetFlag3D( nSheets > 1 );
6760         pTokenArray->AddExternalDoubleReference( rExtInfo.mnFileId,
6761                 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
6762     }
6763     else
6764     {
6765         ScSingleRefData aRef;
6766         aRef.InitAddressRel( rRefAd1.GetAddress(), rPos);
6767         aRef.SetColRel( rRefAd1.IsRelCol());
6768         aRef.SetRowRel( rRefAd1.IsRelRow());
6769         aRef.SetTabRel( rRefAd1.IsRelTab());
6770         aRef.SetFlag3D( true);
6771         pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId,
6772                 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
6773     }
6774     // The indirect usage of the external table can't be detected during the
6775     // store-to-file cycle, mark it as permanently referenced so it gets stored
6776     // even if not directly referenced anywhere.
6777     pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId,
6778             rExtInfo.maTabName, nSheets);
6779     ScCompiler aComp( pDoc, rPos, *pTokenArray);
6780     aComp.CompileTokenArray();
6781     return new FormulaSubroutineToken( pTokenArray);
6782 }
6783 
6784 
6785 void ScInterpreter::ScIndirect()
6786 {
6787     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndirect" );
6788     sal_uInt8 nParamCount = GetByte();
6789     if ( MustHaveParamCount( nParamCount, 1, 2 )  )
6790     {
6791         bool bTryXlA1 = true;   // whether to try XL_A1 style as well.
6792         FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;
6793         if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
6794         {
6795             eConv = FormulaGrammar::CONV_XL_R1C1;
6796             bTryXlA1 = false;
6797         }
6798         const ScAddress::Details aDetails( eConv, aPos );
6799         const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos );
6800         SCTAB nTab = aPos.Tab();
6801         String sRefStr( GetString() );
6802         ScRefAddress aRefAd, aRefAd2;
6803         ScAddress::ExternalInfo aExtInfo;
6804         if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) ||
6805                 (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd,
6806                                                aRefAd2, aDetailsXlA1, &aExtInfo)))
6807         {
6808             if (aExtInfo.mbExternal)
6809             {
6810                 // Push a subroutine that resolves the external reference as
6811                 // the next instruction.
6812                 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok,
6813                             aExtInfo, aRefAd, &aRefAd2));
6814             }
6815             else
6816                 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
6817                         aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() );
6818         }
6819         else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) ||
6820                 (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd,
6821                                                 aDetailsXlA1, &aExtInfo)))
6822         {
6823             if (aExtInfo.mbExternal)
6824             {
6825                 // Push a subroutine that resolves the external reference as
6826                 // the next instruction.
6827                 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok,
6828                             aExtInfo, aRefAd, NULL));
6829             }
6830             else
6831                 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
6832         }
6833         else
6834         {
6835             do
6836             {
6837                 ScRangeName* pNames = pDok->GetRangeName();
6838                 if (!pNames)
6839                     break;
6840 
6841                 sal_uInt16 nPos = 0;
6842                 if (!pNames->SearchName( sRefStr, nPos))
6843                     break;
6844 
6845                 ScRangeData* rData = (*pNames)[nPos];
6846                 if (!rData)
6847                     break;
6848 
6849                 // We need this in order to obtain a good range.
6850                 rData->ValidateTabRefs();
6851 
6852                 ScRange aRange;
6853 #if 0
6854                 // This is some really odd Excel behavior and renders named
6855                 // ranges containing relative references totally useless.
6856                 if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0)))
6857                     break;
6858 #else
6859                 // This is the usual way to treat named ranges containing
6860                 // relative references.
6861                 if (!rData->IsReference( aRange, aPos))
6862                     break;
6863 #endif
6864 
6865                 if (aRange.aStart == aRange.aEnd)
6866                     PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
6867                             aRange.aStart.Tab());
6868                 else
6869                     PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(),
6870                             aRange.aStart.Tab(), aRange.aEnd.Col(),
6871                             aRange.aEnd.Row(), aRange.aEnd.Tab());
6872 
6873                 // success!
6874                 return;
6875             }
6876             while (false);
6877 
6878             PushIllegalArgument();
6879         }
6880     }
6881 }
6882 
6883 
6884 void ScInterpreter::ScAddressFunc()
6885 {
6886     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAddressFunc" );
6887     String  sTabStr;
6888 
6889     sal_uInt8    nParamCount = GetByte();
6890     if( !MustHaveParamCount( nParamCount, 2, 5 ) )
6891         return;
6892 
6893     if( nParamCount >= 5 )
6894         sTabStr = GetString();
6895 
6896     FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;      // default
6897     if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
6898         eConv = FormulaGrammar::CONV_XL_R1C1;
6899 
6900     sal_uInt16  nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE;   // default
6901     if( nParamCount >= 3 )
6902     {
6903         sal_uInt16 n = (sal_uInt16) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
6904         switch ( n )
6905         {
6906             default :
6907                 PushNoValue();
6908                 return;
6909 
6910             case 5:
6911             case 1 : break; // default
6912             case 6:
6913             case 2 : nFlags = SCA_ROW_ABSOLUTE; break;
6914             case 7:
6915             case 3 : nFlags = SCA_COL_ABSOLUTE; break;
6916             case 8:
6917             case 4 : nFlags = 0; break; // both relative
6918         }
6919     }
6920     nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL;
6921 
6922     SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
6923     SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
6924     if( eConv == FormulaGrammar::CONV_XL_R1C1 )
6925     {
6926         // YUCK!  The XL interface actually treats rel R1C1 refs differently
6927         // than A1
6928         if( !(nFlags & SCA_COL_ABSOLUTE) )
6929             nCol += aPos.Col() + 1;
6930         if( !(nFlags & SCA_ROW_ABSOLUTE) )
6931             nRow += aPos.Row() + 1;
6932     }
6933 
6934     --nCol;
6935     --nRow;
6936     if(!ValidCol( nCol) || !ValidRow( nRow))
6937     {
6938         PushIllegalArgument();
6939         return;
6940     }
6941 
6942     String aRefStr;
6943     const ScAddress::Details aDetails( eConv, aPos );
6944     const ScAddress aAdr( nCol, nRow, 0);
6945     aAdr.Format( aRefStr, nFlags, pDok, aDetails );
6946 
6947     if( nParamCount >= 5 && sTabStr.Len() )
6948     {
6949         String aDoc;
6950         if (eConv == FormulaGrammar::CONV_OOO)
6951         {
6952             // Isolate Tab from 'Doc'#Tab
6953             xub_StrLen nPos = ScCompiler::GetDocTabPos( sTabStr);
6954             if (nPos != STRING_NOTFOUND)
6955             {
6956                 if (sTabStr.GetChar(nPos+1) == '$')
6957                     ++nPos;     // also split 'Doc'#$Tab
6958                 aDoc = sTabStr.Copy( 0, nPos+1);
6959                 sTabStr.Erase( 0, nPos+1);
6960             }
6961         }
6962         /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may
6963          * need some extra handling to isolate Tab from Doc. */
6964         if (sTabStr.GetChar(0) != '\'' || sTabStr.GetChar(sTabStr.Len()-1) != '\'')
6965             ScCompiler::CheckTabQuotes( sTabStr, eConv);
6966         if (aDoc.Len())
6967             sTabStr.Insert( aDoc, 0);
6968         sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.');
6969         sTabStr += aRefStr;
6970         PushString( sTabStr );
6971     }
6972     else
6973         PushString( aRefStr );
6974 }
6975 
6976 
6977 FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos,
6978         ScDocument* pDoc, const FormulaTokenRef& xExtRef )
6979 {
6980     // The exact usage (which cell range) of the external table can't be
6981     // detected during the store-to-file cycle, mark it as permanently
6982     // referenced so it gets stored even if not directly referenced anywhere.
6983     ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
6984     pRefMgr->setCacheTableReferencedPermanently(
6985             static_cast<const ScToken*>(xExtRef.get())->GetIndex(),
6986             static_cast<const ScToken*>(xExtRef.get())->GetString(), 1);
6987     ScTokenArray* pTokenArray = new ScTokenArray;
6988     pTokenArray->AddToken( *xExtRef);
6989     ScCompiler aComp( pDoc, rPos, *pTokenArray);
6990     aComp.CompileTokenArray();
6991     return new FormulaSubroutineToken( pTokenArray);
6992 }
6993 
6994 
6995 void ScInterpreter::ScOffset()
6996 {
6997     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" );
6998     sal_uInt8 nParamCount = GetByte();
6999     if ( MustHaveParamCount( nParamCount, 3, 5 ) )
7000     {
7001         long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus;
7002         if (nParamCount == 5)
7003             nColNew = (long) ::rtl::math::approxFloor(GetDouble());
7004         if (nParamCount >= 4)
7005             nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
7006         nColPlus = (long) ::rtl::math::approxFloor(GetDouble());
7007         nRowPlus = (long) ::rtl::math::approxFloor(GetDouble());
7008         SCCOL nCol1;
7009         SCROW nRow1;
7010         SCTAB nTab1;
7011         SCCOL nCol2;
7012         SCROW nRow2;
7013         SCTAB nTab2;
7014         if (nColNew == 0 || nRowNew == 0)
7015         {
7016             PushIllegalArgument();
7017             return;
7018         }
7019         FormulaTokenRef xExtRef;
7020         switch (GetStackType())
7021         {
7022             case svExternalSingleRef:
7023                 xExtRef = PopToken()->Clone();
7024                 // fallthru
7025             case svSingleRef:
7026                 {
7027                     if (xExtRef)
7028                     {
7029                         ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef();
7030                         rData.CalcAbsIfRel( aPos);
7031                         nCol1 = rData.nCol;
7032                         nRow1 = rData.nRow;
7033                         nTab1 = rData.nTab;
7034                     }
7035                     else
7036                         PopSingleRef( nCol1, nRow1, nTab1);
7037                     if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
7038                     {
7039                         nCol1 = (SCCOL)((long) nCol1 + nColPlus);
7040                         nRow1 = (SCROW)((long) nRow1 + nRowPlus);
7041                         if (!ValidCol(nCol1) || !ValidRow(nRow1))
7042                             PushIllegalArgument();
7043                         else if (xExtRef)
7044                         {
7045                             ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef();
7046                             rData.nCol = nCol1;
7047                             rData.nRow = nRow1;
7048                             rData.nTab = nTab1;
7049                             rData.CalcRelFromAbs( aPos);
7050                             // Push a subroutine that resolves the external
7051                             // reference as the next instruction.
7052                             PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef));
7053                         }
7054                         else
7055                             PushSingleRef(nCol1, nRow1, nTab1);
7056                     }
7057                     else
7058                     {
7059                         if (nColNew < 0)
7060                             nColNew = 1;
7061                         if (nRowNew < 0)
7062                             nRowNew = 1;
7063                         nCol1 = (SCCOL)((long)nCol1+nColPlus);  // ! nCol1 is modified
7064                         nRow1 = (SCROW)((long)nRow1+nRowPlus);
7065                         nCol2 = (SCCOL)((long)nCol1+nColNew-1);
7066                         nRow2 = (SCROW)((long)nRow1+nRowNew-1);
7067                         if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
7068                                 !ValidCol(nCol2) || !ValidRow(nRow2))
7069                             PushIllegalArgument();
7070                         else if (xExtRef)
7071                         {
7072                             // Convert SingleRef to DoubleRef.
7073                             xExtRef = new ScExternalDoubleRefToken(
7074                                     *static_cast<const ScExternalSingleRefToken*>(xExtRef.get()));
7075                             ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef();
7076                             rData.Ref1.nCol = nCol1;
7077                             rData.Ref1.nRow = nRow1;
7078                             rData.Ref1.nTab = nTab1;
7079                             rData.Ref2.nCol = nCol2;
7080                             rData.Ref2.nRow = nRow2;
7081                             rData.Ref2.nTab = nTab1;
7082                             rData.CalcRelFromAbs( aPos);
7083                             // Push a subroutine that resolves the external
7084                             // reference as the next instruction.
7085                             PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef));
7086                         }
7087                         else
7088                             PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
7089                     }
7090                 }
7091                 break;
7092             case svExternalDoubleRef:
7093                 xExtRef = PopToken()->Clone();
7094                 // fallthru
7095             case svDoubleRef:
7096                 {
7097                     if (xExtRef)
7098                     {
7099                         ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef();
7100                         rData.CalcAbsIfRel( aPos);
7101                         nCol1 = rData.Ref1.nCol;
7102                         nRow1 = rData.Ref1.nRow;
7103                         nTab1 = rData.Ref1.nTab;
7104                         nCol2 = rData.Ref2.nCol;
7105                         nRow2 = rData.Ref2.nRow;
7106                         nTab2 = rData.Ref2.nTab;
7107                     }
7108                     else
7109                         PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
7110                     if (nColNew < 0)
7111                         nColNew = nCol2 - nCol1 + 1;
7112                     if (nRowNew < 0)
7113                         nRowNew = nRow2 - nRow1 + 1;
7114                     nCol1 = (SCCOL)((long)nCol1+nColPlus);
7115                     nRow1 = (SCROW)((long)nRow1+nRowPlus);
7116                     nCol2 = (SCCOL)((long)nCol1+nColNew-1);
7117                     nRow2 = (SCROW)((long)nRow1+nRowNew-1);
7118                     if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
7119                             !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
7120                         PushIllegalArgument();
7121                     else if (xExtRef)
7122                     {
7123                         ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef();
7124                         rData.Ref1.nCol = nCol1;
7125                         rData.Ref1.nRow = nRow1;
7126                         rData.Ref1.nTab = nTab1;
7127                         rData.Ref2.nCol = nCol2;
7128                         rData.Ref2.nRow = nRow2;
7129                         rData.Ref2.nTab = nTab1;
7130                         rData.CalcRelFromAbs( aPos);
7131                         // Push a subroutine that resolves the external
7132                         // reference as the next instruction.
7133                         PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef));
7134                     }
7135                     else
7136                         PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
7137                 }
7138                 break;
7139             default:
7140                 PushIllegalParameter();
7141         }
7142     }
7143 }
7144 
7145 
7146 void ScInterpreter::ScIndex()
7147 {
7148     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndex" );
7149     sal_uInt8 nParamCount = GetByte();
7150     if ( MustHaveParamCount( nParamCount, 1, 4 ) )
7151     {
7152         long nArea;
7153         size_t nAreaCount;
7154         SCCOL nCol;
7155         SCROW nRow;
7156         if (nParamCount == 4)
7157             nArea = (long) ::rtl::math::approxFloor(GetDouble());
7158         else
7159             nArea = 1;
7160         if (nParamCount >= 3)
7161             nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
7162         else
7163             nCol = 0;
7164         if (nParamCount >= 2)
7165             nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
7166         else
7167             nRow = 0;
7168         if (GetStackType() == svRefList)
7169             nAreaCount = (sp ? static_cast<ScToken*>(pStack[sp-1])->GetRefList()->size() : 0);
7170         else
7171             nAreaCount = 1;     // one reference or array or whatever
7172         if (nAreaCount == 0 || (size_t)nArea > nAreaCount)
7173         {
7174             PushError( errNoRef);
7175             return;
7176         }
7177         else if (nArea < 1 || nCol < 0 || nRow < 0)
7178         {
7179             PushIllegalArgument();
7180             return;
7181         }
7182         switch (GetStackType())
7183         {
7184             case svMatrix:
7185                 {
7186                     if (nArea != 1)
7187                         SetError(errIllegalArgument);
7188                     sal_uInt16 nOldSp = sp;
7189                     ScMatrixRef pMat = GetMatrix();
7190                     if (pMat)
7191                     {
7192                         SCSIZE nC, nR;
7193                         pMat->GetDimensions(nC, nR);
7194                         // Access one element of a vector independent of col/row
7195                         // orientation?
7196                         bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1));
7197                         SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol),
7198                                 static_cast<SCSIZE>(nRow));
7199                         if (nC == 0 || nR == 0 ||
7200                                 (!bVector && (static_cast<SCSIZE>(nCol) > nC ||
7201                                               static_cast<SCSIZE>(nRow) > nR)) ||
7202                                 (bVector && nElement > nC * nR))
7203                             PushIllegalArgument();
7204                         else if (nCol == 0 && nRow == 0)
7205                             sp = nOldSp;
7206                         else if (bVector)
7207                         {
7208                             --nElement;
7209                             if (pMat->IsString( nElement))
7210                                 PushString( pMat->GetString( nElement));
7211                             else
7212                                 PushDouble( pMat->GetDouble( nElement));
7213                         }
7214                         else if (nCol == 0)
7215                         {
7216                             ScMatrixRef pResMat = GetNewMat(nC, 1);
7217                             if (pResMat)
7218                             {
7219                                 SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
7220                                 for (SCSIZE i = 0; i < nC; i++)
7221                                     if (!pMat->IsString(i, nRowMinus1))
7222                                         pResMat->PutDouble(pMat->GetDouble(i,
7223                                                     nRowMinus1), i, 0);
7224                                     else
7225                                         pResMat->PutString(pMat->GetString(i,
7226                                                     nRowMinus1), i, 0);
7227                                 PushMatrix(pResMat);
7228                             }
7229                             else
7230                                 PushIllegalArgument();
7231                         }
7232                         else if (nRow == 0)
7233                         {
7234                             ScMatrixRef pResMat = GetNewMat(1, nR);
7235                             if (pResMat)
7236                             {
7237                                 SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
7238                                 for (SCSIZE i = 0; i < nR; i++)
7239                                     if (!pMat->IsString(nColMinus1, i))
7240                                         pResMat->PutDouble(pMat->GetDouble(nColMinus1,
7241                                                     i), i);
7242                                     else
7243                                         pResMat->PutString(pMat->GetString(nColMinus1,
7244                                                     i), i);
7245                                 PushMatrix(pResMat);
7246                             }
7247                             else
7248                                 PushIllegalArgument();
7249                         }
7250                         else
7251                         {
7252                             if (!pMat->IsString( static_cast<SCSIZE>(nCol-1),
7253                                         static_cast<SCSIZE>(nRow-1)))
7254                                 PushDouble( pMat->GetDouble(
7255                                             static_cast<SCSIZE>(nCol-1),
7256                                             static_cast<SCSIZE>(nRow-1)));
7257                             else
7258                                 PushString( pMat->GetString(
7259                                             static_cast<SCSIZE>(nCol-1),
7260                                             static_cast<SCSIZE>(nRow-1)));
7261                         }
7262                     }
7263                 }
7264                 break;
7265             case svSingleRef:
7266                 {
7267                     SCCOL nCol1 = 0;
7268                     SCROW nRow1 = 0;
7269                     SCTAB nTab1 = 0;
7270                     PopSingleRef( nCol1, nRow1, nTab1);
7271                     if (nCol > 1 || nRow > 1)
7272                         PushIllegalArgument();
7273                     else
7274                         PushSingleRef( nCol1, nRow1, nTab1);
7275                 }
7276                 break;
7277             case svDoubleRef:
7278             case svRefList:
7279                 {
7280                     SCCOL nCol1 = 0;
7281                     SCROW nRow1 = 0;
7282                     SCTAB nTab1 = 0;
7283                     SCCOL nCol2 = 0;
7284                     SCROW nRow2 = 0;
7285                     SCTAB nTab2 = 0;
7286                     sal_Bool bRowArray = sal_False;
7287                     if (GetStackType() == svRefList)
7288                     {
7289                         FormulaTokenRef xRef = PopToken();
7290                         if (nGlobalError || !xRef)
7291                         {
7292                             PushIllegalParameter();
7293                             return;
7294                         }
7295                         ScRange aRange( ScAddress::UNINITIALIZED);
7296                         DoubleRefToRange( (*(static_cast<ScToken*>(xRef.get())->GetRefList()))[nArea-1], aRange);
7297                         aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
7298                         if ( nParamCount == 2 && nRow1 == nRow2 )
7299                             bRowArray = sal_True;
7300                     }
7301                     else
7302                     {
7303                         PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
7304                         if ( nParamCount == 2 && nRow1 == nRow2 )
7305                             bRowArray = sal_True;
7306                     }
7307                     if ( nTab1 != nTab2 ||
7308                             (nCol > 0 && nCol1+nCol-1 > nCol2) ||
7309                             (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
7310                             ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
7311                         PushIllegalArgument();
7312                     else if (nCol == 0 && nRow == 0)
7313                     {
7314                         if ( nCol1 == nCol2 && nRow1 == nRow2 )
7315                             PushSingleRef( nCol1, nRow1, nTab1 );
7316                         else
7317                             PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 );
7318                     }
7319                     else if (nRow == 0)
7320                     {
7321                         if ( nRow1 == nRow2 )
7322                             PushSingleRef( nCol1+nCol-1, nRow1, nTab1 );
7323                         else
7324                             PushDoubleRef( nCol1+nCol-1, nRow1, nTab1,
7325                                     nCol1+nCol-1, nRow2, nTab1 );
7326                     }
7327                     else if (nCol == 0)
7328                     {
7329                         if ( nCol1 == nCol2 )
7330                             PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
7331                         else if ( bRowArray )
7332                         {
7333                             nCol =(SCCOL) nRow;
7334                             nRow = 1;
7335                             PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
7336                         }
7337                         else
7338                             PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
7339                                     nCol2, nRow1+nRow-1, nTab1);
7340                     }
7341                     else
7342                         PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
7343                 }
7344                 break;
7345             default:
7346                 PushIllegalParameter();
7347         }
7348     }
7349 }
7350 
7351 
7352 void ScInterpreter::ScMultiArea()
7353 {
7354     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMultiArea" );
7355     // Legacy support, convert to RefList
7356     sal_uInt8 nParamCount = GetByte();
7357     if (MustHaveParamCountMin( nParamCount, 1))
7358     {
7359         while (!nGlobalError && nParamCount-- > 1)
7360         {
7361             ScUnionFunc();
7362         }
7363     }
7364 }
7365 
7366 
7367 void ScInterpreter::ScAreas()
7368 {
7369     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAreas" );
7370     sal_uInt8 nParamCount = GetByte();
7371     if (MustHaveParamCount( nParamCount, 1))
7372     {
7373         size_t nCount = 0;
7374         switch (GetStackType())
7375         {
7376             case svSingleRef:
7377                 {
7378                     FormulaTokenRef xT = PopToken();
7379                     ValidateRef( static_cast<ScToken*>(xT.get())->GetSingleRef());
7380                     ++nCount;
7381                 }
7382                 break;
7383             case svDoubleRef:
7384                 {
7385                     FormulaTokenRef xT = PopToken();
7386                     ValidateRef( static_cast<ScToken*>(xT.get())->GetDoubleRef());
7387                     ++nCount;
7388                 }
7389                 break;
7390             case svRefList:
7391                 {
7392                     FormulaTokenRef xT = PopToken();
7393                     ValidateRef( *(static_cast<ScToken*>(xT.get())->GetRefList()));
7394                     nCount += static_cast<ScToken*>(xT.get())->GetRefList()->size();
7395                 }
7396                 break;
7397             default:
7398                 SetError( errIllegalParameter);
7399         }
7400         PushDouble( double(nCount));
7401     }
7402 }
7403 
7404 
7405 void ScInterpreter::ScCurrency()
7406 {
7407     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrency" );
7408     sal_uInt8 nParamCount = GetByte();
7409     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7410     {
7411         String aStr;
7412         double fDec;
7413         if (nParamCount == 2)
7414         {
7415             fDec = ::rtl::math::approxFloor(GetDouble());
7416             if (fDec < -15.0 || fDec > 15.0)
7417             {
7418                 PushIllegalArgument();
7419                 return;
7420             }
7421         }
7422         else
7423             fDec = 2.0;
7424         double fVal = GetDouble();
7425         double fFac;
7426         if ( fDec != 0.0 )
7427             fFac = pow( (double)10, fDec );
7428         else
7429             fFac = 1.0;
7430         if (fVal < 0.0)
7431             fVal = ceil(fVal*fFac-0.5)/fFac;
7432         else
7433             fVal = floor(fVal*fFac+0.5)/fFac;
7434         Color* pColor = NULL;
7435         if ( fDec < 0.0 )
7436             fDec = 0.0;
7437         sal_uLong nIndex = pFormatter->GetStandardFormat(
7438                                         NUMBERFORMAT_CURRENCY,
7439                                         ScGlobal::eLnge);
7440         if ( (sal_uInt16) fDec != pFormatter->GetFormatPrecision( nIndex ) )
7441         {
7442             String sFormatString;
7443             pFormatter->GenerateFormat(sFormatString,
7444                                                    nIndex,
7445                                                    ScGlobal::eLnge,
7446                                                    sal_True,        // mit Tausenderpunkt
7447                                                    sal_False,       // nicht rot
7448                                                   (sal_uInt16) fDec,// Nachkommastellen
7449                                                    1);          // 1 Vorkommanull
7450             if (!pFormatter->GetPreviewString(sFormatString,
7451                                                   fVal,
7452                                                   aStr,
7453                                                   &pColor,
7454                                                   ScGlobal::eLnge))
7455                 SetError(errIllegalArgument);
7456         }
7457         else
7458         {
7459             pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor);
7460         }
7461         PushString(aStr);
7462     }
7463 }
7464 
7465 
7466 void ScInterpreter::ScReplace()
7467 {
7468     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScReplace" );
7469     if ( MustHaveParamCount( GetByte(), 4 ) )
7470     {
7471         String aNewStr( GetString() );
7472         double fCount = ::rtl::math::approxFloor( GetDouble());
7473         double fPos   = ::rtl::math::approxFloor( GetDouble());
7474         String aOldStr( GetString() );
7475         if (fPos < 1.0 || fPos > static_cast<double>(STRING_MAXLEN)
7476                 || fCount < 0.0 || fCount > static_cast<double>(STRING_MAXLEN))
7477             PushIllegalArgument();
7478         else
7479         {
7480             xub_StrLen nCount = static_cast<xub_StrLen>(fCount);
7481             xub_StrLen nPos   = static_cast<xub_StrLen>(fPos);
7482             xub_StrLen nLen   = aOldStr.Len();
7483             if (nPos > nLen + 1)
7484                 nPos = nLen + 1;
7485             if (nCount > nLen - nPos + 1)
7486                 nCount = nLen - nPos + 1;
7487             aOldStr.Erase( nPos-1, nCount );
7488             if ( CheckStringResultLen( aOldStr, aNewStr ) )
7489                 aOldStr.Insert( aNewStr, nPos-1 );
7490             PushString( aOldStr );
7491         }
7492     }
7493 }
7494 
7495 
7496 void ScInterpreter::ScFixed()
7497 {
7498     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFixed" );
7499     sal_uInt8 nParamCount = GetByte();
7500     if ( MustHaveParamCount( nParamCount, 1, 3 ) )
7501     {
7502         String aStr;
7503         double fDec;
7504         sal_Bool bThousand;
7505         if (nParamCount == 3)
7506             bThousand = !GetBool();     // Param TRUE: keine Tausenderpunkte
7507         else
7508             bThousand = sal_True;
7509         if (nParamCount >= 2)
7510         {
7511             fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
7512             if (fDec < -15.0 || fDec > 15.0)
7513             {
7514                 PushIllegalArgument();
7515                 return;
7516             }
7517         }
7518         else
7519             fDec = 2.0;
7520         double fVal = GetDouble();
7521         double fFac;
7522         if ( fDec != 0.0 )
7523             fFac = pow( (double)10, fDec );
7524         else
7525             fFac = 1.0;
7526         if (fVal < 0.0)
7527             fVal = ceil(fVal*fFac-0.5)/fFac;
7528         else
7529             fVal = floor(fVal*fFac+0.5)/fFac;
7530         Color* pColor = NULL;
7531         String sFormatString;
7532         if (fDec < 0.0)
7533             fDec = 0.0;
7534         sal_uLong nIndex = pFormatter->GetStandardFormat(
7535                                             NUMBERFORMAT_NUMBER,
7536                                             ScGlobal::eLnge);
7537         pFormatter->GenerateFormat(sFormatString,
7538                                                nIndex,
7539                                                ScGlobal::eLnge,
7540                                                bThousand,   // mit Tausenderpunkt
7541                                                sal_False,       // nicht rot
7542                                                (sal_uInt16) fDec,// Nachkommastellen
7543                                                1);          // 1 Vorkommanull
7544         if (!pFormatter->GetPreviewString(sFormatString,
7545                                                   fVal,
7546                                                   aStr,
7547                                                   &pColor,
7548                                                   ScGlobal::eLnge))
7549             PushIllegalArgument();
7550         else
7551             PushString(aStr);
7552     }
7553 }
7554 
7555 
7556 void ScInterpreter::ScFind()
7557 {
7558     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFind" );
7559     sal_uInt8 nParamCount = GetByte();
7560     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
7561     {
7562         double fAnz;
7563         if (nParamCount == 3)
7564             fAnz = GetDouble();
7565         else
7566             fAnz = 1.0;
7567         String sStr = GetString();
7568         if( fAnz < 1.0 || fAnz > (double) sStr.Len() )
7569             PushNoValue();
7570         else
7571         {
7572             xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 );
7573             if (nPos == STRING_NOTFOUND)
7574                 PushNoValue();
7575             else
7576                 PushDouble((double)(nPos + 1));
7577         }
7578     }
7579 }
7580 
7581 
7582 void ScInterpreter::ScExact()
7583 {
7584     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExact" );
7585     nFuncFmtType = NUMBERFORMAT_LOGICAL;
7586     if ( MustHaveParamCount( GetByte(), 2 ) )
7587     {
7588         String s1( GetString() );
7589         String s2( GetString() );
7590         PushInt( s1 == s2 );
7591     }
7592 }
7593 
7594 
7595 void ScInterpreter::ScLeft()
7596 {
7597     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLeft" );
7598     sal_uInt8 nParamCount = GetByte();
7599     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7600     {
7601         xub_StrLen n;
7602         if (nParamCount == 2)
7603         {
7604             double nVal = ::rtl::math::approxFloor(GetDouble());
7605             if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7606             {
7607                 PushIllegalArgument();
7608                 return ;
7609             }
7610             else
7611                 n = (xub_StrLen) nVal;
7612         }
7613         else
7614             n = 1;
7615         String aStr( GetString() );
7616         aStr.Erase( n );
7617         PushString( aStr );
7618     }
7619 }
7620 
7621 
7622 void ScInterpreter::ScRight()
7623 {
7624     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRight" );
7625     sal_uInt8 nParamCount = GetByte();
7626     if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7627     {
7628         xub_StrLen n;
7629         if (nParamCount == 2)
7630         {
7631             double nVal = ::rtl::math::approxFloor(GetDouble());
7632             if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7633             {
7634                 PushIllegalArgument();
7635                 return ;
7636             }
7637             else
7638                 n = (xub_StrLen) nVal;
7639         }
7640         else
7641             n = 1;
7642         String aStr( GetString() );
7643         if( n < aStr.Len() )
7644             aStr.Erase( 0, aStr.Len() - n );
7645         PushString( aStr );
7646     }
7647 }
7648 
7649 
7650 void ScInterpreter::ScSearch()
7651 {
7652     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSearch" );
7653     double fAnz;
7654     sal_uInt8 nParamCount = GetByte();
7655     if ( MustHaveParamCount( nParamCount, 2, 3 ) )
7656     {
7657         if (nParamCount == 3)
7658         {
7659             fAnz = ::rtl::math::approxFloor(GetDouble());
7660             if (fAnz > double(STRING_MAXLEN))
7661             {
7662                 PushIllegalArgument();
7663                 return;
7664             }
7665         }
7666         else
7667             fAnz = 1.0;
7668         String sStr = GetString();
7669         String SearchStr = GetString();
7670         xub_StrLen nPos = (xub_StrLen) fAnz - 1;
7671         xub_StrLen nEndPos = sStr.Len();
7672         if( nPos >= nEndPos )
7673             PushNoValue();
7674         else
7675         {
7676             utl::SearchParam::SearchType eSearchType =
7677                 (MayBeRegExp( SearchStr, pDok ) ?
7678                 utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL);
7679             utl::SearchParam sPar(SearchStr, eSearchType, sal_False, sal_False, sal_False);
7680             utl::TextSearch sT( sPar, *ScGlobal::pCharClass );
7681             int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos);
7682             if (!nBool)
7683                 PushNoValue();
7684             else
7685                 PushDouble((double)(nPos) + 1);
7686         }
7687     }
7688 }
7689 
7690 
7691 void ScInterpreter::ScMid()
7692 {
7693     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMid" );
7694     if ( MustHaveParamCount( GetByte(), 3 ) )
7695     {
7696         double fAnz    = ::rtl::math::approxFloor(GetDouble());
7697         double fAnfang = ::rtl::math::approxFloor(GetDouble());
7698         const String& rStr = GetString();
7699         if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
7700             PushIllegalArgument();
7701         else
7702             PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
7703     }
7704 }
7705 
7706 
7707 void ScInterpreter::ScText()
7708 {
7709     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScText" );
7710     if ( MustHaveParamCount( GetByte(), 2 ) )
7711     {
7712         String sFormatString = GetString();
7713         String aStr;
7714         bool bString = false;
7715         double fVal = 0.0;
7716         switch (GetStackType())
7717         {
7718             case svError:
7719                 PopError();
7720                 break;
7721             case svDouble:
7722                 fVal = PopDouble();
7723                 break;
7724             default:
7725                 {
7726                     FormulaTokenRef xTok( PopToken());
7727                     if (!nGlobalError)
7728                     {
7729                         PushTempToken( xTok);
7730                         // Temporarily override the ConvertStringToValue()
7731                         // error for GetCellValue() / GetCellValueOrZero()
7732                         sal_uInt16 nSErr = mnStringNoValueError;
7733                         mnStringNoValueError = errNotNumericString;
7734                         fVal = GetDouble();
7735                         mnStringNoValueError = nSErr;
7736                         if (nGlobalError == errNotNumericString)
7737                         {
7738                             // Not numeric.
7739                             nGlobalError = 0;
7740                             PushTempToken( xTok);
7741                             aStr = GetString();
7742                             bString = true;
7743                         }
7744                     }
7745                 }
7746         }
7747         if (nGlobalError)
7748             PushError( nGlobalError);
7749         else
7750         {
7751             String aResult;
7752             Color* pColor = NULL;
7753             LanguageType eCellLang;
7754             const ScPatternAttr* pPattern = pDok->GetPattern(
7755                     aPos.Col(), aPos.Row(), aPos.Tab() );
7756             if ( pPattern )
7757                 eCellLang = ((const SvxLanguageItem&)
7758                         pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue();
7759             else
7760                 eCellLang = ScGlobal::eLnge;
7761             if (bString)
7762             {
7763                 if (!pFormatter->GetPreviewString( sFormatString, aStr,
7764                             aResult, &pColor, eCellLang))
7765                     PushIllegalArgument();
7766                 else
7767                     PushString( aResult);
7768             }
7769             else
7770             {
7771                 if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal,
7772                             aResult, &pColor, eCellLang))
7773                     PushIllegalArgument();
7774                 else
7775                     PushString( aResult);
7776             }
7777         }
7778     }
7779 }
7780 
7781 
7782 void ScInterpreter::ScSubstitute()
7783 {
7784     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubstitute" );
7785     sal_uInt8 nParamCount = GetByte();
7786     if ( MustHaveParamCount( nParamCount, 3, 4 ) )
7787     {
7788         xub_StrLen nAnz;
7789         if (nParamCount == 4)
7790         {
7791             double fAnz = ::rtl::math::approxFloor(GetDouble());
7792             if( fAnz < 1 || fAnz > STRING_MAXLEN )
7793             {
7794                 PushIllegalArgument();
7795                 return;
7796             }
7797             else
7798                 nAnz = (xub_StrLen) fAnz;
7799         }
7800         else
7801             nAnz = 0;
7802         String sNewStr = GetString();
7803         String sOldStr = GetString();
7804         String sStr    = GetString();
7805         xub_StrLen nPos = 0;
7806         xub_StrLen nCount = 0;
7807         xub_StrLen nNewLen = sNewStr.Len();
7808         xub_StrLen nOldLen = sOldStr.Len();
7809         while( sal_True )
7810         {
7811             nPos = sStr.Search( sOldStr, nPos );
7812             if (nPos != STRING_NOTFOUND)
7813             {
7814                 nCount++;
7815                 if( !nAnz || nCount == nAnz )
7816                 {
7817                     sStr.Erase(nPos,nOldLen);
7818                     if ( CheckStringResultLen( sStr, sNewStr ) )
7819                     {
7820                         sStr.Insert(sNewStr,nPos);
7821                         nPos = sal::static_int_cast<xub_StrLen>( nPos + nNewLen );
7822                     }
7823                     else
7824                         break;
7825                 }
7826                 else
7827                     nPos++;
7828             }
7829             else
7830                 break;
7831         }
7832         PushString( sStr );
7833     }
7834 }
7835 
7836 
7837 void ScInterpreter::ScRept()
7838 {
7839     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRept" );
7840     if ( MustHaveParamCount( GetByte(), 2 ) )
7841     {
7842         double fAnz = ::rtl::math::approxFloor(GetDouble());
7843         String aStr( GetString() );
7844         if ( fAnz < 0.0 )
7845             PushIllegalArgument();
7846         else if ( fAnz * aStr.Len() > STRING_MAXLEN )
7847         {
7848             PushError( errStringOverflow );
7849         }
7850         else if ( fAnz == 0.0 )
7851             PushString( EMPTY_STRING );
7852         else
7853         {
7854             xub_StrLen n = (xub_StrLen) fAnz;
7855             const xub_StrLen nLen = aStr.Len();
7856             String aRes;
7857             const sal_Unicode* const pSrc = aStr.GetBuffer();
7858             sal_Unicode* pDst = aRes.AllocBuffer( n * nLen );
7859             while( n-- )
7860             {
7861                 memcpy( pDst, pSrc, nLen * sizeof(sal_Unicode) );
7862                 pDst += nLen;
7863             }
7864             PushString( aRes );
7865         }
7866     }
7867 }
7868 
7869 
7870 void ScInterpreter::ScConcat()
7871 {
7872     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConcat" );
7873     sal_uInt8 nParamCount = GetByte();
7874     String aRes;
7875     while( nParamCount-- > 0)
7876     {
7877         const String& rStr = GetString();
7878         aRes.Insert( rStr, 0 );
7879     }
7880     PushString( aRes );
7881 }
7882 
7883 
7884 void ScInterpreter::ScErrorType()
7885 {
7886     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScErrorType" );
7887     sal_uInt16 nErr;
7888     sal_uInt16 nOldError = nGlobalError;
7889     nGlobalError = 0;
7890     switch ( GetStackType() )
7891     {
7892         case svRefList :
7893         {
7894             FormulaTokenRef x = PopToken();
7895             if (nGlobalError)
7896                 nErr = nGlobalError;
7897             else
7898             {
7899                 const ScRefList* pRefList = static_cast<ScToken*>(x.get())->GetRefList();
7900                 size_t n = pRefList->size();
7901                 if (!n)
7902                     nErr = errNoRef;
7903                 else if (n > 1)
7904                     nErr = errNoValue;
7905                 else
7906                 {
7907                     ScRange aRange;
7908                     DoubleRefToRange( (*pRefList)[0], aRange);
7909                     if (nGlobalError)
7910                         nErr = nGlobalError;
7911                     else
7912                     {
7913                         ScAddress aAdr;
7914                         if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
7915                             nErr = pDok->GetErrCode( aAdr );
7916                         else
7917                             nErr = nGlobalError;
7918                     }
7919                 }
7920             }
7921         }
7922         break;
7923         case svDoubleRef :
7924         {
7925             ScRange aRange;
7926             PopDoubleRef( aRange );
7927             if ( nGlobalError )
7928                 nErr = nGlobalError;
7929             else
7930             {
7931                 ScAddress aAdr;
7932                 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
7933                     nErr = pDok->GetErrCode( aAdr );
7934                 else
7935                     nErr = nGlobalError;
7936             }
7937         }
7938         break;
7939         case svSingleRef :
7940         {
7941             ScAddress aAdr;
7942             PopSingleRef( aAdr );
7943             if ( nGlobalError )
7944                 nErr = nGlobalError;
7945             else
7946                 nErr = pDok->GetErrCode( aAdr );
7947         }
7948         break;
7949         default:
7950             PopError();
7951             nErr = nGlobalError;
7952     }
7953     if ( nErr )
7954     {
7955         nGlobalError = 0;
7956         PushDouble( nErr );
7957     }
7958     else
7959     {
7960         nGlobalError = nOldError;
7961         PushNA();
7962     }
7963 }
7964 
7965 
7966 sal_Bool ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc  )
7967 {
7968     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MayBeRegExp" );
7969     if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
7970         return sal_False;
7971     if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') )
7972         return sal_False;   // einzelnes Metazeichen kann keine RegExp sein
7973     static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
7974     const sal_Unicode* p1 = rStr.GetBuffer();
7975     sal_Unicode c1;
7976     while ( ( c1 = *p1++ ) != 0 )
7977     {
7978         const sal_Unicode* p2 = cre;
7979         while ( *p2 )
7980         {
7981             if ( c1 == *p2++ )
7982                 return sal_True;
7983         }
7984     }
7985     return sal_False;
7986 }
7987 
7988 static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
7989         const ScQueryParam & rParam, const ScQueryEntry & rEntry )
7990 {
7991     bool bFound = false;
7992     ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, sal_False);
7993     if (rEntry.eOp != SC_EQUAL)
7994     {
7995         // range lookup <= or >=
7996         SCCOL nCol;
7997         SCROW nRow;
7998         bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow);
7999         if (bFound)
8000         {
8001             o_rResultPos.SetCol( nCol);
8002             o_rResultPos.SetRow( nRow);
8003         }
8004     }
8005     else if (aCellIter.GetFirst())
8006     {
8007         // EQUAL
8008         bFound = true;
8009         o_rResultPos.SetCol( aCellIter.GetCol());
8010         o_rResultPos.SetRow( aCellIter.GetRow());
8011     }
8012     return bFound;
8013 }
8014 
8015 #define erDEBUG_LOOKUPCACHE 0
8016 #if erDEBUG_LOOKUPCACHE
8017 #include <cstdio>
8018 using ::std::fprintf;
8019 using ::std::fflush;
8020 static struct LookupCacheDebugCounter
8021 {
8022     unsigned long nMiss;
8023     unsigned long nHit;
8024     LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
8025     ~LookupCacheDebugCounter()
8026     {
8027         fprintf( stderr, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
8028                 nMiss, nHit, nHit+nMiss, (nMiss>0 ? nHit/nMiss : 0),
8029                 ((nHit+nMiss)>0 ? (100*nHit)/(nHit+nMiss) : 0));
8030         fflush( stderr);
8031     }
8032 } aLookupCacheDebugCounter;
8033 #endif
8034 
8035 bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
8036         const ScQueryParam & rParam ) const
8037 {
8038     RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::LookupQueryWithCache" );
8039     bool bFound = false;
8040     const ScQueryEntry& rEntry = rParam.GetEntry(0);
8041     bool bColumnsMatch = (rParam.nCol1 == rEntry.nField);
8042     DBG_ASSERT( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match");
8043     if (!bColumnsMatch)
8044         bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
8045     else
8046     {
8047         ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
8048                 rParam.nCol2, rParam.nRow2, rParam.nTab);
8049         ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange);
8050         ScLookupCache::QueryCriteria aCriteria( rEntry);
8051         ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos,
8052                 aCriteria, aPos);
8053         switch (eCacheResult)
8054         {
8055             case ScLookupCache::NOT_CACHED :
8056             case ScLookupCache::CRITERIA_DIFFERENT :
8057 #if erDEBUG_LOOKUPCACHE
8058                 ++aLookupCacheDebugCounter.nMiss;
8059 #if erDEBUG_LOOKUPCACHE > 1
8060                 fprintf( stderr, "miss %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
8061 #endif
8062 #endif
8063                 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
8064                 if (eCacheResult == ScLookupCache::NOT_CACHED)
8065                     rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
8066                 break;
8067             case ScLookupCache::FOUND :
8068 #if erDEBUG_LOOKUPCACHE
8069                 ++aLookupCacheDebugCounter.nHit;
8070 #if erDEBUG_LOOKUPCACHE > 1
8071                 fprintf( stderr, "hit  %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
8072 #endif
8073 #endif
8074                 bFound = true;
8075                 break;
8076             case ScLookupCache::NOT_AVAILABLE :
8077                 ;   // nothing, bFound remains FALSE
8078                 break;
8079         }
8080     }
8081     return bFound;
8082 }
8083