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