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