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