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