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