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