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