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