xref: /aoo42x/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