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