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