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