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