Update ooo320-m1
[ooovba.git] / sc / source / core / tool / interpr1.cxx
blob48cf41f791bba66690e2a9ac248f4786464c1435
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 *
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr1.cxx,v $
10 * $Revision: 1.61 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include "scitems.hxx"
37 #include <svx/langitem.hxx>
38 #include <svx/algitem.hxx>
39 #include <unotools/textsearch.hxx>
40 #include <svtools/zforlist.hxx>
41 #include <svtools/zformat.hxx>
42 #include <tools/urlobj.hxx>
43 #include <unotools/charclass.hxx>
44 #include <sfx2/docfile.hxx>
45 #include <sfx2/printer.hxx>
46 #include <unotools/collatorwrapper.hxx>
47 #include <unotools/transliterationwrapper.hxx>
48 #include <rtl/ustring.hxx>
49 #include <rtl/logfile.hxx>
51 #include "interpre.hxx"
52 #include "patattr.hxx"
53 #include "global.hxx"
54 #include "document.hxx"
55 #include "dociter.hxx"
56 #include "cell.hxx"
57 #include "scmatrix.hxx"
58 #include "docoptio.hxx"
59 #include "globstr.hrc"
60 #include "attrib.hxx"
61 #include "jumpmatrix.hxx"
63 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
64 #include <comphelper/processfactory.hxx>
65 #endif
67 #include <stdlib.h>
68 #include <string.h>
69 #include <math.h>
70 #include <vector>
71 #include <memory>
72 #include "cellkeytranslator.hxx"
73 #include "lookupcache.hxx"
74 #include "rangenam.hxx"
75 #include "compiler.hxx"
76 #include "externalrefmgr.hxx"
77 #include <basic/sbstar.hxx>
78 #include "doubleref.hxx"
79 #include "queryparam.hxx"
81 #define SC_DOUBLE_MAXVALUE 1.7e307
83 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack, 8, 4 )
84 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter, 32, 16 )
86 ScTokenStack* ScInterpreter::pGlobalStack = NULL;
87 BOOL ScInterpreter::bGlobalStackInUse = FALSE;
89 using namespace formula;
90 using ::std::auto_ptr;
92 //-----------------------------------------------------------------------------
93 // Funktionen
94 //-----------------------------------------------------------------------------
97 void ScInterpreter::ScIfJump()
99 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIfJump" );
100 const short* pJump = pCur->GetJump();
101 short nJumpCount = pJump[ 0 ];
102 MatrixDoubleRefToMatrix();
103 switch ( GetStackType() )
105 case svMatrix:
107 ScMatrixRef pMat = PopMatrix();
108 if ( !pMat )
109 PushIllegalParameter();
110 else
112 FormulaTokenRef xNew;
113 ScTokenMatrixMap::const_iterator aMapIter;
114 // DoubleError handled by JumpMatrix
115 pMat->SetErrorInterpreter( NULL);
116 SCSIZE nCols, nRows;
117 pMat->GetDimensions( nCols, nRows );
118 if ( nCols == 0 || nRows == 0 )
119 PushIllegalArgument();
120 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
121 pCur)) != pTokenMatrixMap->end()))
122 xNew = (*aMapIter).second;
123 else
125 ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
126 for ( SCSIZE nC=0; nC < nCols; ++nC )
128 for ( SCSIZE nR=0; nR < nRows; ++nR )
130 double fVal;
131 bool bTrue;
132 ScMatValType nType = 0;
133 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
134 nType);
135 bool bIsValue = ScMatrix::IsValueType( nType);
136 if ( bIsValue )
138 fVal = pMatVal->fVal;
139 bIsValue = ::rtl::math::isFinite( fVal );
140 bTrue = bIsValue && (fVal != 0.0);
141 if ( bTrue )
142 fVal = 1.0;
144 else
146 // Treat empty and empty path as 0, but string
147 // as error.
148 bIsValue = !ScMatrix::IsRealStringType( nType);
149 bTrue = false;
150 fVal = (bIsValue ? 0.0 : CreateDoubleError( errNoValue));
152 if ( bTrue )
153 { // TRUE
154 if( nJumpCount >= 2 )
155 { // THEN path
156 pJumpMat->SetJump( nC, nR, fVal,
157 pJump[ 1 ],
158 pJump[ nJumpCount ]);
160 else
161 { // no parameter given for THEN
162 pJumpMat->SetJump( nC, nR, fVal,
163 pJump[ nJumpCount ],
164 pJump[ nJumpCount ]);
167 else
168 { // FALSE
169 if( nJumpCount == 3 && bIsValue )
170 { // ELSE path
171 pJumpMat->SetJump( nC, nR, fVal,
172 pJump[ 2 ],
173 pJump[ nJumpCount ]);
175 else
176 { // no parameter given for ELSE,
177 // or DoubleError
178 pJumpMat->SetJump( nC, nR, fVal,
179 pJump[ nJumpCount ],
180 pJump[ nJumpCount ]);
185 xNew = new ScJumpMatrixToken( pJumpMat );
186 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur, xNew));
188 PushTempToken( xNew);
189 // set endpoint of path for main code line
190 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
193 break;
194 default:
196 if ( GetBool() )
197 { // TRUE
198 if( nJumpCount >= 2 )
199 { // THEN path
200 aCode.Jump( pJump[ 1 ], pJump[ nJumpCount ] );
202 else
203 { // no parameter given for THEN
204 nFuncFmtType = NUMBERFORMAT_LOGICAL;
205 PushInt(1);
206 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
209 else
210 { // FALSE
211 if( nJumpCount == 3 )
212 { // ELSE path
213 aCode.Jump( pJump[ 2 ], pJump[ nJumpCount ] );
215 else
216 { // no parameter given for ELSE
217 nFuncFmtType = NUMBERFORMAT_LOGICAL;
218 PushInt(0);
219 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
227 void ScInterpreter::ScChoseJump()
229 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChoseJump" );
230 // We have to set a jump, if there was none chosen because of an error set
231 // it to endpoint.
232 bool bHaveJump = false;
233 const short* pJump = pCur->GetJump();
234 short nJumpCount = pJump[ 0 ];
235 MatrixDoubleRefToMatrix();
236 switch ( GetStackType() )
238 case svMatrix:
240 ScMatrixRef pMat = PopMatrix();
241 if ( !pMat )
242 PushIllegalParameter();
243 else
245 FormulaTokenRef xNew;
246 ScTokenMatrixMap::const_iterator aMapIter;
247 // DoubleError handled by JumpMatrix
248 pMat->SetErrorInterpreter( NULL);
249 SCSIZE nCols, nRows;
250 pMat->GetDimensions( nCols, nRows );
251 if ( nCols == 0 || nRows == 0 )
252 PushIllegalParameter();
253 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
254 pCur)) != pTokenMatrixMap->end()))
255 xNew = (*aMapIter).second;
256 else
258 ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
259 for ( SCSIZE nC=0; nC < nCols; ++nC )
261 for ( SCSIZE nR=0; nR < nRows; ++nR )
263 double fVal;
264 ScMatValType nType;
265 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
266 nType);
267 bool bIsValue = ScMatrix::IsValueType( nType);
268 if ( bIsValue )
270 fVal = pMatVal->fVal;
271 bIsValue = ::rtl::math::isFinite( fVal );
272 if ( bIsValue )
274 fVal = ::rtl::math::approxFloor( fVal);
275 if ( (fVal < 1) || (fVal >= nJumpCount))
277 bIsValue = FALSE;
278 fVal = CreateDoubleError(
279 errIllegalArgument);
283 else
285 fVal = CreateDoubleError( errNoValue);
287 if ( bIsValue )
289 pJumpMat->SetJump( nC, nR, fVal,
290 pJump[ (short)fVal ],
291 pJump[ nJumpCount ]);
293 else
295 pJumpMat->SetJump( nC, nR, fVal,
296 pJump[ nJumpCount ],
297 pJump[ nJumpCount ]);
301 xNew = new ScJumpMatrixToken( pJumpMat );
302 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
303 pCur, xNew));
305 PushTempToken( xNew);
306 // set endpoint of path for main code line
307 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
308 bHaveJump = true;
311 break;
312 default:
314 double nJumpIndex = ::rtl::math::approxFloor( GetDouble() );
315 if (!nGlobalError && (nJumpIndex >= 1) && (nJumpIndex < nJumpCount))
317 aCode.Jump( pJump[ (short) nJumpIndex ], pJump[ nJumpCount ] );
318 bHaveJump = true;
320 else
321 PushIllegalArgument();
324 if (!bHaveJump)
325 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
328 void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, ScMatrixRef& pResMat, SCSIZE nParmCols, SCSIZE nParmRows )
330 SCSIZE nJumpCols, nJumpRows;
331 SCSIZE nResCols, nResRows;
332 SCSIZE nAdjustCols, nAdjustRows;
333 pJumpM->GetDimensions( nJumpCols, nJumpRows );
334 pJumpM->GetResMatDimensions( nResCols, nResRows );
335 if (( nJumpCols == 1 && nParmCols > nResCols ) ||
336 ( nJumpRows == 1 && nParmRows > nResRows ))
338 if ( nJumpCols == 1 && nJumpRows == 1 )
340 nAdjustCols = nParmCols > nResCols ? nParmCols : nResCols;
341 nAdjustRows = nParmRows > nResRows ? nParmRows : nResRows;
343 else if ( nJumpCols == 1 )
345 nAdjustCols = nParmCols;
346 nAdjustRows = nResRows;
348 else
350 nAdjustCols = nResCols;
351 nAdjustRows = nParmRows;
353 pJumpM->SetNewResMat( nAdjustCols, nAdjustRows );
354 pResMat = pJumpM->GetResultMatrix();
358 bool ScInterpreter::JumpMatrix( short nStackLevel )
360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::JumpMatrix" );
361 pJumpMatrix = static_cast<ScToken*>(pStack[sp-nStackLevel])->GetJumpMatrix();
362 ScMatrixRef pResMat = pJumpMatrix->GetResultMatrix();
363 SCSIZE nC, nR;
364 if ( nStackLevel == 2 )
366 if ( aCode.HasStacked() )
367 aCode.Pop(); // pop what Jump() pushed
368 else
370 DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
373 if ( !pResMat )
375 Pop();
376 SetError( errUnknownStackVariable );
378 else
380 pJumpMatrix->GetPos( nC, nR );
381 switch ( GetStackType() )
383 case svDouble:
385 double fVal = GetDouble();
386 if ( nGlobalError )
388 fVal = CreateDoubleError( nGlobalError );
389 nGlobalError = 0;
391 pResMat->PutDouble( fVal, nC, nR );
393 break;
394 case svString:
396 const String& rStr = GetString();
397 if ( nGlobalError )
399 pResMat->PutDouble( CreateDoubleError( nGlobalError),
400 nC, nR);
401 nGlobalError = 0;
403 else
404 pResMat->PutString( rStr, nC, nR );
406 break;
407 case svSingleRef:
409 ScAddress aAdr;
410 PopSingleRef( aAdr );
411 if ( nGlobalError )
413 pResMat->PutDouble( CreateDoubleError( nGlobalError),
414 nC, nR);
415 nGlobalError = 0;
417 else
419 ScBaseCell* pCell = GetCell( aAdr );
420 if (HasCellEmptyData( pCell))
421 pResMat->PutEmpty( nC, nR );
422 else if (HasCellValueData( pCell))
424 double fVal = GetCellValue( aAdr, pCell);
425 if ( nGlobalError )
427 fVal = CreateDoubleError(
428 nGlobalError);
429 nGlobalError = 0;
431 pResMat->PutDouble( fVal, nC, nR );
433 else
435 String aStr;
436 GetCellString( aStr, pCell );
437 if ( nGlobalError )
439 pResMat->PutDouble( CreateDoubleError(
440 nGlobalError), nC, nR);
441 nGlobalError = 0;
443 else
444 pResMat->PutString( aStr, nC, nR);
448 break;
449 case svDoubleRef:
450 { // upper left plus offset within matrix
451 double fVal;
452 ScRange aRange;
453 PopDoubleRef( aRange );
454 if ( nGlobalError )
456 fVal = CreateDoubleError( nGlobalError );
457 nGlobalError = 0;
458 pResMat->PutDouble( fVal, nC, nR );
460 else
462 // Do not modify the original range because we use it
463 // to adjust the size of the result matrix if necessary.
464 ScAddress aAdr( aRange.aStart);
465 ULONG nCol = (ULONG)aAdr.Col() + nC;
466 ULONG nRow = (ULONG)aAdr.Row() + nR;
467 if ((nCol > static_cast<ULONG>(aRange.aEnd.Col()) &&
468 aRange.aEnd.Col() != aRange.aStart.Col())
469 || (nRow > static_cast<ULONG>(aRange.aEnd.Row()) &&
470 aRange.aEnd.Row() != aRange.aStart.Row()))
472 fVal = CreateDoubleError( NOTAVAILABLE );
473 pResMat->PutDouble( fVal, nC, nR );
475 else
477 // Replicate column and/or row of a vector if it is
478 // one. Note that this could be a range reference
479 // that in fact consists of only one cell, e.g. A1:A1
480 if (aRange.aEnd.Col() == aRange.aStart.Col())
481 nCol = aRange.aStart.Col();
482 if (aRange.aEnd.Row() == aRange.aStart.Row())
483 nRow = aRange.aStart.Row();
484 aAdr.SetCol( static_cast<SCCOL>(nCol) );
485 aAdr.SetRow( static_cast<SCROW>(nRow) );
486 ScBaseCell* pCell = GetCell( aAdr );
487 if (HasCellEmptyData( pCell))
488 pResMat->PutEmpty( nC, nR );
489 else if (HasCellValueData( pCell))
491 double fCellVal = GetCellValue( aAdr, pCell);
492 if ( nGlobalError )
494 fCellVal = CreateDoubleError(
495 nGlobalError);
496 nGlobalError = 0;
498 pResMat->PutDouble( fCellVal, nC, nR );
500 else
502 String aStr;
503 GetCellString( aStr, pCell );
504 if ( nGlobalError )
506 pResMat->PutDouble( CreateDoubleError(
507 nGlobalError), nC, nR);
508 nGlobalError = 0;
510 else
511 pResMat->PutString( aStr, nC, nR );
514 SCSIZE nParmCols = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
515 SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
516 lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nParmCols, nParmRows );
519 break;
520 case svMatrix:
521 { // match matrix offsets
522 double fVal;
523 ScMatrixRef pMat = PopMatrix();
524 if ( nGlobalError )
526 fVal = CreateDoubleError( nGlobalError );
527 nGlobalError = 0;
528 pResMat->PutDouble( fVal, nC, nR );
530 else if ( !pMat )
532 fVal = CreateDoubleError( errUnknownVariable );
533 pResMat->PutDouble( fVal, nC, nR );
535 else
537 SCSIZE nCols, nRows;
538 pMat->GetDimensions( nCols, nRows );
539 if ((nCols <= nC && nCols != 1) ||
540 (nRows <= nR && nRows != 1))
542 fVal = CreateDoubleError( NOTAVAILABLE );
543 pResMat->PutDouble( fVal, nC, nR );
545 else
547 if ( pMat->IsValue( nC, nR ) )
549 fVal = pMat->GetDouble( nC, nR );
550 pResMat->PutDouble( fVal, nC, nR );
552 else if ( pMat->IsEmpty( nC, nR ) )
553 pResMat->PutEmpty( nC, nR );
554 else
556 const String& rStr = pMat->GetString( nC, nR );
557 pResMat->PutString( rStr, nC, nR );
560 lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nCols, nRows );
563 break;
564 case svError:
566 PopError();
567 double fVal = CreateDoubleError( nGlobalError);
568 nGlobalError = 0;
569 pResMat->PutDouble( fVal, nC, nR );
571 break;
572 default:
574 Pop();
575 double fVal = CreateDoubleError( errIllegalArgument);
576 pResMat->PutDouble( fVal, nC, nR );
581 bool bCont = pJumpMatrix->Next( nC, nR );
582 if ( bCont )
584 double fBool;
585 short nStart, nNext, nStop;
586 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
587 while ( bCont && nStart == nNext )
588 { // push all results that have no jump path
589 if ( pResMat )
591 // a FALSE without path results in an empty path value
592 if ( fBool == 0.0 )
593 pResMat->PutEmptyPath( nC, nR );
594 else
595 pResMat->PutDouble( fBool, nC, nR );
597 bCont = pJumpMatrix->Next( nC, nR );
598 if ( bCont )
599 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
601 if ( bCont && nStart != nNext )
603 const ScTokenVec* pParams = pJumpMatrix->GetJumpParameters();
604 if ( pParams )
606 for ( ScTokenVec::const_iterator i = pParams->begin();
607 i != pParams->end(); ++i )
609 // This is not the current state of the interpreter, so
610 // push without error, and elements' errors are coded into
611 // double.
612 PushWithoutError( *(*i));
615 aCode.Jump( nStart, nNext, nStop );
618 if ( !bCont )
619 { // we're done with it, throw away jump matrix, keep result
620 pJumpMatrix = NULL;
621 Pop();
622 PushMatrix( pResMat );
623 // Remove jump matrix from map and remember result matrix in case it
624 // could be reused in another path of the same condition.
625 if (pTokenMatrixMap)
627 pTokenMatrixMap->erase( pCur);
628 pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
629 pStack[sp-1]));
631 return true;
633 return false;
637 ScCompareOptions::ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
638 aQueryEntry(rEntry),
639 bRegEx(bReg),
640 bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell()),
641 bIgnoreCase(true)
643 bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
644 // Interpreter functions usually are case insensitive, except the simple
645 // comparison operators, for which these options aren't used. Override in
646 // struct if needed.
650 double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions )
652 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CompareFunc" );
653 // Keep DoubleError if encountered
654 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
655 if ( !rComp.bEmpty[0] && rComp.bVal[0] && !::rtl::math::isFinite( rComp.nVal[0]))
656 return rComp.nVal[0];
657 if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1]))
658 return rComp.nVal[1];
660 double fRes = 0;
661 if ( rComp.bEmpty[ 0 ] )
663 if ( rComp.bEmpty[ 1 ] )
664 ; // empty cell == empty cell, fRes 0
665 else if( rComp.bVal[ 1 ] )
667 if ( !::rtl::math::approxEqual( rComp.nVal[ 1 ], 0.0 ) )
669 if ( rComp.nVal[ 1 ] < 0.0 )
670 fRes = 1; // empty cell > -x
671 else
672 fRes = -1; // empty cell < x
674 // else: empty cell == 0.0
676 else
678 if ( rComp.pVal[ 1 ]->Len() )
679 fRes = -1; // empty cell < "..."
680 // else: empty cell == ""
683 else if ( rComp.bEmpty[ 1 ] )
685 if( rComp.bVal[ 0 ] )
687 if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], 0.0 ) )
689 if ( rComp.nVal[ 0 ] < 0.0 )
690 fRes = -1; // -x < empty cell
691 else
692 fRes = 1; // x > empty cell
694 // else: empty cell == 0.0
696 else
698 if ( rComp.pVal[ 0 ]->Len() )
699 fRes = 1; // "..." > empty cell
700 // else: "" == empty cell
703 else if( rComp.bVal[ 0 ] )
705 if( rComp.bVal[ 1 ] )
707 if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], rComp.nVal[ 1 ] ) )
709 if( rComp.nVal[ 0 ] - rComp.nVal[ 1 ] < 0 )
710 fRes = -1;
711 else
712 fRes = 1;
715 else
716 fRes = -1; // number is less than string
718 else if( rComp.bVal[ 1 ] )
719 fRes = 1; // number is less than string
720 else
722 // Both strings.
723 if (pOptions)
725 // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually
726 // is/must be identical to *rEntry.pStr, which is essential for
727 // regex to work through GetSearchTextPtr().
728 ScQueryEntry& rEntry = pOptions->aQueryEntry;
729 DBG_ASSERT( *rComp.pVal[1] == *rEntry.pStr, "ScInterpreter::CompareFunc: broken options");
730 if (pOptions->bRegEx)
732 xub_StrLen nStart = 0;
733 xub_StrLen nStop = rComp.pVal[0]->Len();
734 bool bMatch = rEntry.GetSearchTextPtr(
735 !pOptions->bIgnoreCase)->SearchFrwrd( *rComp.pVal[0],
736 &nStart, &nStop);
737 if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->Len()))
738 bMatch = false; // RegEx must match entire string.
739 fRes = (bMatch ? 0 : 1);
741 else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
743 ::utl::TransliterationWrapper* pTransliteration =
744 (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() :
745 ScGlobal::GetCaseTransliteration());
746 bool bMatch;
747 if (pOptions->bMatchWholeCell)
748 bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]);
749 else
751 String aCell( pTransliteration->transliterate(
752 *rComp.pVal[0], ScGlobal::eLnge, 0,
753 rComp.pVal[0]->Len(), NULL));
754 String aQuer( pTransliteration->transliterate(
755 *rComp.pVal[1], ScGlobal::eLnge, 0,
756 rComp.pVal[1]->Len(), NULL));
757 bMatch = (aCell.Search( aQuer ) != STRING_NOTFOUND);
759 fRes = (bMatch ? 0 : 1);
761 else if (pOptions->bIgnoreCase)
762 fRes = (double) ScGlobal::GetCollator()->compareString(
763 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
764 else
765 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
766 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
768 else if (pDok->GetDocOptions().IsIgnoreCase())
769 fRes = (double) ScGlobal::GetCollator()->compareString(
770 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
771 else
772 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
773 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
775 return fRes;
779 double ScInterpreter::Compare()
781 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Compare" );
782 String aVal1, aVal2;
783 ScCompare aComp( &aVal1, &aVal2 );
784 for( short i = 1; i >= 0; i-- )
786 switch ( GetRawStackType() )
788 case svEmptyCell:
789 aComp.bEmpty[ i ] = TRUE;
790 break;
791 case svMissing:
792 case svDouble:
793 aComp.nVal[ i ] = GetDouble();
794 aComp.bVal[ i ] = TRUE;
795 break;
796 case svString:
797 *aComp.pVal[ i ] = GetString();
798 aComp.bVal[ i ] = FALSE;
799 break;
800 case svDoubleRef :
801 case svSingleRef :
803 ScAddress aAdr;
804 if ( !PopDoubleRefOrSingleRef( aAdr ) )
805 break;
806 ScBaseCell* pCell = GetCell( aAdr );
807 if (HasCellEmptyData( pCell))
808 aComp.bEmpty[ i ] = TRUE;
809 else if (HasCellStringData( pCell))
811 GetCellString( *aComp.pVal[ i ], pCell);
812 aComp.bVal[ i ] = FALSE;
814 else
816 aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
817 aComp.bVal[ i ] = TRUE;
820 break;
821 default:
822 SetError( errIllegalParameter);
823 break;
826 if( nGlobalError )
827 return 0;
828 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
829 return CompareFunc( aComp );
833 ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions )
835 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CompareMat" );
836 String aVal1, aVal2;
837 ScCompare aComp( &aVal1, &aVal2 );
838 ScMatrixRef pMat[2];
839 ScAddress aAdr;
840 for( short i = 1; i >= 0; i-- )
842 switch (GetRawStackType())
844 case svEmptyCell:
845 aComp.bEmpty[ i ] = TRUE;
846 break;
847 case svMissing:
848 case svDouble:
849 aComp.nVal[ i ] = GetDouble();
850 aComp.bVal[ i ] = TRUE;
851 break;
852 case svString:
853 *aComp.pVal[ i ] = GetString();
854 aComp.bVal[ i ] = FALSE;
855 break;
856 case svSingleRef:
858 PopSingleRef( aAdr );
859 ScBaseCell* pCell = GetCell( aAdr );
860 if (HasCellEmptyData( pCell))
861 aComp.bEmpty[ i ] = TRUE;
862 else if (HasCellStringData( pCell))
864 GetCellString( *aComp.pVal[ i ], pCell);
865 aComp.bVal[ i ] = FALSE;
867 else
869 aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
870 aComp.bVal[ i ] = TRUE;
873 break;
874 case svDoubleRef:
875 case svMatrix:
876 pMat[ i ] = GetMatrix();
877 if ( !pMat[ i ] )
878 SetError( errIllegalParameter);
879 else
880 pMat[i]->SetErrorInterpreter( NULL);
881 // errors are transported as DoubleError inside matrix
882 break;
883 default:
884 SetError( errIllegalParameter);
885 break;
888 ScMatrixRef pResMat = NULL;
889 if( !nGlobalError )
891 if ( pMat[0] && pMat[1] )
893 SCSIZE nC0, nC1;
894 SCSIZE nR0, nR1;
895 pMat[0]->GetDimensions( nC0, nR0 );
896 pMat[1]->GetDimensions( nC1, nR1 );
897 SCSIZE nC = Max( nC0, nC1 );
898 SCSIZE nR = Max( nR0, nR1 );
899 pResMat = GetNewMat( nC, nR);
900 if ( !pResMat )
901 return NULL;
902 for ( SCSIZE j=0; j<nC; j++ )
904 for ( SCSIZE k=0; k<nR; k++ )
906 SCSIZE nCol = j, nRow = k;
907 if ( pMat[0]->ValidColRowOrReplicated( nCol, nRow ) &&
908 pMat[1]->ValidColRowOrReplicated( nCol, nRow ))
910 for ( short i=1; i>=0; i-- )
912 if ( pMat[i]->IsString(j,k) )
914 aComp.bVal[i] = FALSE;
915 *aComp.pVal[i] = pMat[i]->GetString(j,k);
916 aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
918 else
920 aComp.bVal[i] = TRUE;
921 aComp.nVal[i] = pMat[i]->GetDouble(j,k);
922 aComp.bEmpty[i] = FALSE;
925 pResMat->PutDouble( CompareFunc( aComp, pOptions ), j,k );
927 else
928 pResMat->PutString( ScGlobal::GetRscString(STR_NO_VALUE), j,k );
932 else if ( pMat[0] || pMat[1] )
934 short i = ( pMat[0] ? 0 : 1);
935 SCSIZE nC, nR;
936 pMat[i]->GetDimensions( nC, nR );
937 pResMat = GetNewMat( nC, nR);
938 if ( !pResMat )
939 return NULL;
940 SCSIZE n = nC * nR;
941 for ( SCSIZE j=0; j<n; j++ )
943 if ( pMat[i]->IsValue(j) )
945 aComp.bVal[i] = TRUE;
946 aComp.nVal[i] = pMat[i]->GetDouble(j);
947 aComp.bEmpty[i] = FALSE;
949 else
951 aComp.bVal[i] = FALSE;
952 *aComp.pVal[i] = pMat[i]->GetString(j);
953 aComp.bEmpty[i] = pMat[i]->IsEmpty(j);
955 pResMat->PutDouble( CompareFunc( aComp, pOptions ), j );
959 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
960 return pResMat;
964 ScMatrixRef ScInterpreter::QueryMat( ScMatrix* pMat, ScCompareOptions& rOptions )
966 short nSaveCurFmtType = nCurFmtType;
967 short nSaveFuncFmtType = nFuncFmtType;
968 PushMatrix( pMat);
969 if (rOptions.aQueryEntry.bQueryByString)
970 PushString( *rOptions.aQueryEntry.pStr);
971 else
972 PushDouble( rOptions.aQueryEntry.nVal);
973 ScMatrixRef pResultMatrix = CompareMat( &rOptions);
974 nCurFmtType = nSaveCurFmtType;
975 nFuncFmtType = nSaveFuncFmtType;
976 if (nGlobalError || !pResultMatrix)
978 SetError( errIllegalParameter);
979 return pResultMatrix;
982 switch (rOptions.aQueryEntry.eOp)
984 case SC_EQUAL:
985 pResultMatrix->CompareEqual();
986 break;
987 case SC_LESS:
988 pResultMatrix->CompareLess();
989 break;
990 case SC_GREATER:
991 pResultMatrix->CompareGreater();
992 break;
993 case SC_LESS_EQUAL:
994 pResultMatrix->CompareLessEqual();
995 break;
996 case SC_GREATER_EQUAL:
997 pResultMatrix->CompareGreaterEqual();
998 break;
999 case SC_NOT_EQUAL:
1000 pResultMatrix->CompareNotEqual();
1001 break;
1002 default:
1003 SetError( errIllegalArgument);
1004 DBG_ERROR1( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)rOptions.aQueryEntry.eOp);
1006 return pResultMatrix;
1010 void ScInterpreter::ScEqual()
1012 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEqual" );
1013 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1015 ScMatrixRef pMat = CompareMat();
1016 if ( !pMat )
1017 PushIllegalParameter();
1018 else
1020 pMat->CompareEqual();
1021 PushMatrix( pMat );
1024 else
1025 PushInt( Compare() == 0 );
1029 void ScInterpreter::ScNotEqual()
1031 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNotEqual" );
1032 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1034 ScMatrixRef pMat = CompareMat();
1035 if ( !pMat )
1036 PushIllegalParameter();
1037 else
1039 pMat->CompareNotEqual();
1040 PushMatrix( pMat );
1043 else
1044 PushInt( Compare() != 0 );
1048 void ScInterpreter::ScLess()
1050 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLess" );
1051 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1053 ScMatrixRef pMat = CompareMat();
1054 if ( !pMat )
1055 PushIllegalParameter();
1056 else
1058 pMat->CompareLess();
1059 PushMatrix( pMat );
1062 else
1063 PushInt( Compare() < 0 );
1067 void ScInterpreter::ScGreater()
1069 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGreater" );
1070 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1072 ScMatrixRef pMat = CompareMat();
1073 if ( !pMat )
1074 PushIllegalParameter();
1075 else
1077 pMat->CompareGreater();
1078 PushMatrix( pMat );
1081 else
1082 PushInt( Compare() > 0 );
1086 void ScInterpreter::ScLessEqual()
1088 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLessEqual" );
1089 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1091 ScMatrixRef pMat = CompareMat();
1092 if ( !pMat )
1093 PushIllegalParameter();
1094 else
1096 pMat->CompareLessEqual();
1097 PushMatrix( pMat );
1100 else
1101 PushInt( Compare() <= 0 );
1105 void ScInterpreter::ScGreaterEqual()
1107 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGreaterEqual" );
1108 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1110 ScMatrixRef pMat = CompareMat();
1111 if ( !pMat )
1112 PushIllegalParameter();
1113 else
1115 pMat->CompareGreaterEqual();
1116 PushMatrix( pMat );
1119 else
1120 PushInt( Compare() >= 0 );
1124 void ScInterpreter::ScAnd()
1126 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAnd" );
1127 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1128 short nParamCount = GetByte();
1129 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1131 BOOL bHaveValue = FALSE;
1132 short nRes = TRUE;
1133 size_t nRefInList = 0;
1134 while( nParamCount-- > 0)
1136 if ( !nGlobalError )
1138 switch ( GetStackType() )
1140 case svDouble :
1141 bHaveValue = TRUE;
1142 nRes &= ( PopDouble() != 0.0 );
1143 break;
1144 case svString :
1145 Pop();
1146 SetError( errNoValue );
1147 break;
1148 case svSingleRef :
1150 ScAddress aAdr;
1151 PopSingleRef( aAdr );
1152 if ( !nGlobalError )
1154 ScBaseCell* pCell = GetCell( aAdr );
1155 if ( HasCellValueData( pCell ) )
1157 bHaveValue = TRUE;
1158 nRes &= ( GetCellValue( aAdr, pCell ) != 0.0 );
1160 // else: Xcl setzt hier keinen Fehler
1163 break;
1164 case svDoubleRef:
1165 case svRefList:
1167 ScRange aRange;
1168 PopDoubleRef( aRange, nParamCount, nRefInList);
1169 if ( !nGlobalError )
1171 double fVal;
1172 USHORT nErr = 0;
1173 ScValueIterator aValIter( pDok, aRange );
1174 if ( aValIter.GetFirst( fVal, nErr ) )
1176 bHaveValue = TRUE;
1179 nRes &= ( fVal != 0.0 );
1180 } while ( (nErr == 0) &&
1181 aValIter.GetNext( fVal, nErr ) );
1183 SetError( nErr );
1186 break;
1187 case svMatrix:
1189 ScMatrixRef pMat = GetMatrix();
1190 if ( pMat )
1192 bHaveValue = TRUE;
1193 double fVal = pMat->And();
1194 USHORT nErr = GetDoubleErrorValue( fVal );
1195 if ( nErr )
1197 SetError( nErr );
1198 nRes = FALSE;
1200 else
1201 nRes &= (fVal != 0.0);
1203 // else: GetMatrix did set errIllegalParameter
1205 break;
1206 default:
1207 Pop();
1208 SetError( errIllegalParameter);
1211 else
1212 Pop();
1214 if ( bHaveValue )
1215 PushInt( nRes );
1216 else
1217 PushNoValue();
1222 void ScInterpreter::ScOr()
1224 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOr" );
1225 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1226 short nParamCount = GetByte();
1227 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1229 BOOL bHaveValue = FALSE;
1230 short nRes = FALSE;
1231 size_t nRefInList = 0;
1232 while( nParamCount-- > 0)
1234 if ( !nGlobalError )
1236 switch ( GetStackType() )
1238 case svDouble :
1239 bHaveValue = TRUE;
1240 nRes |= ( PopDouble() != 0.0 );
1241 break;
1242 case svString :
1243 Pop();
1244 SetError( errNoValue );
1245 break;
1246 case svSingleRef :
1248 ScAddress aAdr;
1249 PopSingleRef( aAdr );
1250 if ( !nGlobalError )
1252 ScBaseCell* pCell = GetCell( aAdr );
1253 if ( HasCellValueData( pCell ) )
1255 bHaveValue = TRUE;
1256 nRes |= ( GetCellValue( aAdr, pCell ) != 0.0 );
1258 // else: Xcl setzt hier keinen Fehler
1261 break;
1262 case svDoubleRef:
1263 case svRefList:
1265 ScRange aRange;
1266 PopDoubleRef( aRange, nParamCount, nRefInList);
1267 if ( !nGlobalError )
1269 double fVal;
1270 USHORT nErr = 0;
1271 ScValueIterator aValIter( pDok, aRange );
1272 if ( aValIter.GetFirst( fVal, nErr ) )
1274 bHaveValue = TRUE;
1277 nRes |= ( fVal != 0.0 );
1278 } while ( (nErr == 0) &&
1279 aValIter.GetNext( fVal, nErr ) );
1281 SetError( nErr );
1284 break;
1285 case svMatrix:
1287 bHaveValue = TRUE;
1288 ScMatrixRef pMat = GetMatrix();
1289 if ( pMat )
1291 bHaveValue = TRUE;
1292 double fVal = pMat->Or();
1293 USHORT nErr = GetDoubleErrorValue( fVal );
1294 if ( nErr )
1296 SetError( nErr );
1297 nRes = FALSE;
1299 else
1300 nRes |= (fVal != 0.0);
1302 // else: GetMatrix did set errIllegalParameter
1304 break;
1305 default:
1306 Pop();
1307 SetError( errIllegalParameter);
1310 else
1311 Pop();
1313 if ( bHaveValue )
1314 PushInt( nRes );
1315 else
1316 PushNoValue();
1321 void ScInterpreter::ScNeg()
1323 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNeg" );
1324 // Simple negation doesn't change current format type to number, keep
1325 // current type.
1326 nFuncFmtType = nCurFmtType;
1327 switch ( GetStackType() )
1329 case svMatrix :
1331 ScMatrixRef pMat = GetMatrix();
1332 if ( !pMat )
1333 PushIllegalParameter();
1334 else
1336 SCSIZE nC, nR;
1337 pMat->GetDimensions( nC, nR );
1338 ScMatrixRef pResMat = GetNewMat( nC, nR);
1339 if ( !pResMat )
1340 PushIllegalArgument();
1341 else
1343 SCSIZE nCount = nC * nR;
1344 for ( SCSIZE j=0; j<nCount; ++j )
1346 if ( pMat->IsValueOrEmpty(j) )
1347 pResMat->PutDouble( -pMat->GetDouble(j), j );
1348 else
1349 pResMat->PutString(
1350 ScGlobal::GetRscString( STR_NO_VALUE ), j );
1352 PushMatrix( pResMat );
1356 break;
1357 default:
1358 PushDouble( -GetDouble() );
1363 void ScInterpreter::ScPercentSign()
1365 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentSign" );
1366 nFuncFmtType = NUMBERFORMAT_PERCENT;
1367 const FormulaToken* pSaveCur = pCur;
1368 BYTE nSavePar = cPar;
1369 PushInt( 100 );
1370 cPar = 2;
1371 FormulaByteToken aDivOp( ocDiv, cPar );
1372 pCur = &aDivOp;
1373 ScDiv();
1374 pCur = pSaveCur;
1375 cPar = nSavePar;
1379 void ScInterpreter::ScNot()
1381 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNot" );
1382 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1383 switch ( GetStackType() )
1385 case svMatrix :
1387 ScMatrixRef pMat = GetMatrix();
1388 if ( !pMat )
1389 PushIllegalParameter();
1390 else
1392 SCSIZE nC, nR;
1393 pMat->GetDimensions( nC, nR );
1394 ScMatrixRef pResMat = GetNewMat( nC, nR);
1395 if ( !pResMat )
1396 PushIllegalArgument();
1397 else
1399 SCSIZE nCount = nC * nR;
1400 for ( SCSIZE j=0; j<nCount; ++j )
1402 if ( pMat->IsValueOrEmpty(j) )
1403 pResMat->PutDouble( (pMat->GetDouble(j) == 0.0), j );
1404 else
1405 pResMat->PutString(
1406 ScGlobal::GetRscString( STR_NO_VALUE ), j );
1408 PushMatrix( pResMat );
1412 break;
1413 default:
1414 PushInt( GetDouble() == 0.0 );
1419 void ScInterpreter::ScPi()
1421 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPi" );
1422 PushDouble(F_PI);
1426 void ScInterpreter::ScRandom()
1428 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRandom" );
1429 PushDouble((double)rand() / ((double)RAND_MAX+1.0));
1433 void ScInterpreter::ScTrue()
1435 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrue" );
1436 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1437 PushInt(1);
1441 void ScInterpreter::ScFalse()
1443 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFalse" );
1444 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1445 PushInt(0);
1449 void ScInterpreter::ScDeg()
1451 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDeg" );
1452 PushDouble((GetDouble() / F_PI) * 180.0);
1456 void ScInterpreter::ScRad()
1458 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRad" );
1459 PushDouble(GetDouble() * (F_PI / 180));
1463 void ScInterpreter::ScSin()
1465 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSin" );
1466 PushDouble(::rtl::math::sin(GetDouble()));
1470 void ScInterpreter::ScCos()
1472 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCos" );
1473 PushDouble(::rtl::math::cos(GetDouble()));
1477 void ScInterpreter::ScTan()
1479 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTan" );
1480 PushDouble(::rtl::math::tan(GetDouble()));
1484 void ScInterpreter::ScCot()
1486 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCot" );
1487 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1491 void ScInterpreter::ScArcSin()
1493 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcSin" );
1494 PushDouble(asin(GetDouble()));
1498 void ScInterpreter::ScArcCos()
1500 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCos" );
1501 PushDouble(acos(GetDouble()));
1505 void ScInterpreter::ScArcTan()
1507 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan" );
1508 PushDouble(atan(GetDouble()));
1512 void ScInterpreter::ScArcCot()
1514 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCot" );
1515 PushDouble((F_PI2) - atan(GetDouble()));
1519 void ScInterpreter::ScSinHyp()
1521 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSinHyp" );
1522 PushDouble(sinh(GetDouble()));
1526 void ScInterpreter::ScCosHyp()
1528 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCosHyp" );
1529 PushDouble(cosh(GetDouble()));
1533 void ScInterpreter::ScTanHyp()
1535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTanHyp" );
1536 PushDouble(tanh(GetDouble()));
1540 void ScInterpreter::ScCotHyp()
1542 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCotHyp" );
1543 PushDouble(1.0 / tanh(GetDouble()));
1547 void ScInterpreter::ScArcSinHyp()
1549 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcSinHyp" );
1550 PushDouble( ::rtl::math::asinh( GetDouble()));
1553 void ScInterpreter::ScArcCosHyp()
1555 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCosHyp" );
1556 double fVal = GetDouble();
1557 if (fVal < 1.0)
1558 PushIllegalArgument();
1559 else
1560 PushDouble( ::rtl::math::acosh( fVal));
1563 void ScInterpreter::ScArcTanHyp()
1565 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTanHyp" );
1566 double fVal = GetDouble();
1567 if (fabs(fVal) >= 1.0)
1568 PushIllegalArgument();
1569 else
1570 PushDouble( ::rtl::math::atanh( fVal));
1574 void ScInterpreter::ScArcCotHyp()
1576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCotHyp" );
1577 double nVal = GetDouble();
1578 if (fabs(nVal) <= 1.0)
1579 PushIllegalArgument();
1580 else
1581 PushDouble(0.5 * log((nVal + 1.0) / (nVal - 1.0)));
1585 void ScInterpreter::ScExp()
1587 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExp" );
1588 PushDouble(exp(GetDouble()));
1592 void ScInterpreter::ScSqrt()
1594 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSqrt" );
1595 double fVal = GetDouble();
1596 if (fVal >= 0.0)
1597 PushDouble(sqrt(fVal));
1598 else
1599 PushIllegalArgument();
1603 void ScInterpreter::ScIsEmpty()
1605 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsEmpty" );
1606 short nRes = 0;
1607 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1608 switch ( GetRawStackType() )
1610 case svEmptyCell:
1612 FormulaTokenRef p = PopToken();
1613 if (!static_cast<const ScEmptyCellToken*>(p.get())->IsInherited())
1614 nRes = 1;
1616 break;
1617 case svDoubleRef :
1618 case svSingleRef :
1620 ScAddress aAdr;
1621 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1622 break;
1623 // NOTE: this could test also on inherited emptiness, but then the
1624 // cell tested wouldn't be empty. Must correspond with
1625 // ScCountEmptyCells().
1626 // if (HasCellEmptyData( GetCell( aAdr)))
1627 CellType eCellType = GetCellType( GetCell( aAdr ) );
1628 if((eCellType == CELLTYPE_NONE) || (eCellType == CELLTYPE_NOTE))
1629 nRes = 1;
1631 break;
1632 case svMatrix:
1634 ScMatrixRef pMat = PopMatrix();
1635 if ( !pMat )
1636 ; // nothing
1637 else if ( !pJumpMatrix )
1638 nRes = pMat->IsEmpty( 0 );
1639 else
1641 SCSIZE nCols, nRows, nC, nR;
1642 pMat->GetDimensions( nCols, nRows);
1643 pJumpMatrix->GetPos( nC, nR);
1644 if ( nC < nCols && nR < nRows )
1645 nRes = pMat->IsEmpty( nC, nR);
1646 // else: FALSE, not empty (which is what Xcl does)
1649 break;
1650 default:
1651 Pop();
1653 nGlobalError = 0;
1654 PushInt( nRes );
1658 short ScInterpreter::IsString()
1660 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsString" );
1661 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1662 short nRes = 0;
1663 switch ( GetRawStackType() )
1665 case svString:
1666 Pop();
1667 nRes = 1;
1668 break;
1669 case svDoubleRef :
1670 case svSingleRef :
1672 ScAddress aAdr;
1673 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1674 break;
1675 ScBaseCell* pCell = GetCell( aAdr );
1676 if (GetCellErrCode( pCell ) == 0)
1678 switch ( GetCellType( pCell ) )
1680 case CELLTYPE_STRING :
1681 case CELLTYPE_EDIT :
1682 nRes = 1;
1683 break;
1684 case CELLTYPE_FORMULA :
1685 nRes = !((ScFormulaCell*)pCell)->IsValue() &&
1686 !((ScFormulaCell*)pCell)->IsEmpty();
1687 break;
1688 default:
1689 ; // nothing
1693 break;
1694 case svMatrix:
1696 ScMatrixRef pMat = PopMatrix();
1697 if ( !pMat )
1698 ; // nothing
1699 else if ( !pJumpMatrix )
1700 nRes = pMat->IsString(0) && !pMat->IsEmpty(0);
1701 else
1703 SCSIZE nCols, nRows, nC, nR;
1704 pMat->GetDimensions( nCols, nRows);
1705 pJumpMatrix->GetPos( nC, nR);
1706 if ( nC < nCols && nR < nRows )
1707 nRes = pMat->IsString( nC, nR) && !pMat->IsEmpty( nC, nR);
1710 break;
1711 default:
1712 Pop();
1714 nGlobalError = 0;
1715 return nRes;
1719 void ScInterpreter::ScIsString()
1721 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsString" );
1722 PushInt( IsString() );
1726 void ScInterpreter::ScIsNonString()
1728 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsNonString" );
1729 PushInt( !IsString() );
1733 void ScInterpreter::ScIsLogical()
1735 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsLogical" );
1736 short nRes = 0;
1737 switch ( GetStackType() )
1739 case svDoubleRef :
1740 case svSingleRef :
1742 ScAddress aAdr;
1743 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1744 break;
1745 ScBaseCell* pCell = GetCell( aAdr );
1746 if (GetCellErrCode( pCell ) == 0)
1748 if (HasCellValueData(pCell))
1750 ULONG nFormat = GetCellNumberFormat( aAdr, pCell );
1751 nRes = ( pFormatter->GetType(nFormat)
1752 == NUMBERFORMAT_LOGICAL);
1756 break;
1757 case svMatrix:
1758 // TODO: we don't have type information for arrays except
1759 // numerical/string.
1760 // Fall thru
1761 default:
1762 PopError();
1763 if ( !nGlobalError )
1764 nRes = ( nCurFmtType == NUMBERFORMAT_LOGICAL );
1766 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
1767 nGlobalError = 0;
1768 PushInt( nRes );
1772 void ScInterpreter::ScType()
1774 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScType" );
1775 short nType = 0;
1776 switch ( GetStackType() )
1778 case svDoubleRef :
1779 case svSingleRef :
1781 ScAddress aAdr;
1782 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1783 break;
1784 ScBaseCell* pCell = GetCell( aAdr );
1785 if (GetCellErrCode( pCell ) == 0)
1787 switch ( GetCellType( pCell ) )
1789 // NOTE: this is Xcl nonsense!
1790 case CELLTYPE_NOTE :
1791 nType = 1; // empty cell is value (0)
1792 break;
1793 case CELLTYPE_STRING :
1794 case CELLTYPE_EDIT :
1795 nType = 2;
1796 break;
1797 case CELLTYPE_VALUE :
1799 ULONG nFormat = GetCellNumberFormat( aAdr, pCell );
1800 if (pFormatter->GetType(nFormat)
1801 == NUMBERFORMAT_LOGICAL)
1802 nType = 4;
1803 else
1804 nType = 1;
1806 break;
1807 case CELLTYPE_FORMULA :
1808 nType = 8;
1809 break;
1810 default:
1811 PushIllegalArgument();
1814 else
1815 nType = 16;
1817 break;
1818 case svString:
1819 PopError();
1820 if ( nGlobalError )
1822 nType = 16;
1823 nGlobalError = 0;
1825 else
1826 nType = 2;
1827 break;
1828 case svMatrix:
1829 PopMatrix();
1830 if ( nGlobalError )
1832 nType = 16;
1833 nGlobalError = 0;
1835 else
1836 nType = 64;
1837 // we could return the type of one element if in JumpMatrix or
1838 // ForceArray mode, but Xcl doesn't ...
1839 break;
1840 default:
1841 PopError();
1842 if ( nGlobalError )
1844 nType = 16;
1845 nGlobalError = 0;
1847 else
1848 nType = 1;
1850 PushInt( nType );
1854 inline BOOL lcl_FormatHasNegColor( const SvNumberformat* pFormat )
1856 return pFormat && pFormat->GetColor( 1 );
1860 inline BOOL lcl_FormatHasOpenPar( const SvNumberformat* pFormat )
1862 return pFormat && (pFormat->GetFormatstring().Search( '(' ) != STRING_NOTFOUND);
1866 void ScInterpreter::ScCell()
1867 { // ATTRIBUTE ; [REF]
1868 BYTE nParamCount = GetByte();
1869 if( MustHaveParamCount( nParamCount, 1, 2 ) )
1871 ScAddress aCellPos( aPos );
1872 BOOL bError = FALSE;
1873 if( nParamCount == 2 )
1874 bError = !PopDoubleRefOrSingleRef( aCellPos );
1875 String aInfoType( GetString() );
1876 if( bError || nGlobalError )
1877 PushIllegalParameter();
1878 else
1880 String aFuncResult;
1881 ScBaseCell* pCell = GetCell( aCellPos );
1883 ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::GetLocale(), ocCell);
1885 // *** ADDRESS INFO ***
1886 if( aInfoType.EqualsAscii( "COL" ) )
1887 { // column number (1-based)
1888 PushInt( aCellPos.Col() + 1 );
1890 else if( aInfoType.EqualsAscii( "ROW" ) )
1891 { // row number (1-based)
1892 PushInt( aCellPos.Row() + 1 );
1894 else if( aInfoType.EqualsAscii( "SHEET" ) )
1895 { // table number (1-based)
1896 PushInt( aCellPos.Tab() + 1 );
1898 else if( aInfoType.EqualsAscii( "ADDRESS" ) )
1899 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
1900 USHORT nFlags = (aCellPos.Tab() == aPos.Tab()) ? (SCA_ABS) : (SCA_ABS_3D);
1901 aCellPos.Format( aFuncResult, nFlags, pDok, pDok->GetAddressConvention() );
1902 PushString( aFuncResult );
1904 else if( aInfoType.EqualsAscii( "FILENAME" ) )
1905 { // file name and table name: 'FILENAME'#$TABLE
1906 SCTAB nTab = aCellPos.Tab();
1907 if( nTab < pDok->GetTableCount() )
1909 if( pDok->GetLinkMode( nTab ) == SC_LINK_VALUE )
1910 pDok->GetName( nTab, aFuncResult );
1911 else
1913 SfxObjectShell* pShell = pDok->GetDocumentShell();
1914 if( pShell && pShell->GetMedium() )
1916 aFuncResult = (sal_Unicode) '\'';
1917 const INetURLObject& rURLObj = pShell->GetMedium()->GetURLObject();
1918 aFuncResult += String( rURLObj.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS ) );
1919 aFuncResult.AppendAscii( "'#$" );
1920 String aTabName;
1921 pDok->GetName( nTab, aTabName );
1922 aFuncResult += aTabName;
1926 PushString( aFuncResult );
1928 else if( aInfoType.EqualsAscii( "COORD" ) )
1929 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
1930 // Yes, passing tab as col is intentional!
1931 ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format(
1932 aFuncResult, (SCA_COL_ABSOLUTE|SCA_VALID_COL), NULL, pDok->GetAddressConvention() );
1933 aFuncResult += ':';
1934 String aCellStr;
1935 aCellPos.Format( aCellStr, (SCA_COL_ABSOLUTE|SCA_VALID_COL|SCA_ROW_ABSOLUTE|SCA_VALID_ROW),
1936 NULL, pDok->GetAddressConvention() );
1937 aFuncResult += aCellStr;
1938 PushString( aFuncResult );
1941 // *** CELL PROPERTIES ***
1942 else if( aInfoType.EqualsAscii( "CONTENTS" ) )
1943 { // contents of the cell, no formatting
1944 if( pCell && pCell->HasStringData() )
1946 GetCellString( aFuncResult, pCell );
1947 PushString( aFuncResult );
1949 else
1950 PushDouble( GetCellValue( aCellPos, pCell ) );
1952 else if( aInfoType.EqualsAscii( "TYPE" ) )
1953 { // b = blank; l = string (label); v = otherwise (value)
1954 if( HasCellStringData( pCell ) )
1955 aFuncResult = 'l';
1956 else
1957 aFuncResult = HasCellValueData( pCell ) ? 'v' : 'b';
1958 PushString( aFuncResult );
1960 else if( aInfoType.EqualsAscii( "WIDTH" ) )
1961 { // column width (rounded off as count of zero characters in standard font and size)
1962 Printer* pPrinter = pDok->GetPrinter();
1963 MapMode aOldMode( pPrinter->GetMapMode() );
1964 Font aOldFont( pPrinter->GetFont() );
1965 Font aDefFont;
1967 pPrinter->SetMapMode( MAP_TWIP );
1968 // font color doesn't matter here
1969 pDok->GetDefPattern()->GetFont( aDefFont, SC_AUTOCOL_BLACK, pPrinter );
1970 pPrinter->SetFont( aDefFont );
1971 long nZeroWidth = pPrinter->GetTextWidth( String( '0' ) );
1972 pPrinter->SetFont( aOldFont );
1973 pPrinter->SetMapMode( aOldMode );
1974 int nZeroCount = (int)(pDok->GetColWidth( aCellPos.Col(), aCellPos.Tab() ) / nZeroWidth);
1975 PushInt( nZeroCount );
1977 else if( aInfoType.EqualsAscii( "PREFIX" ) )
1978 { // ' = left; " = right; ^ = centered
1979 if( HasCellStringData( pCell ) )
1981 const SvxHorJustifyItem* pJustAttr = (const SvxHorJustifyItem*)
1982 pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_HOR_JUSTIFY );
1983 switch( pJustAttr->GetValue() )
1985 case SVX_HOR_JUSTIFY_STANDARD:
1986 case SVX_HOR_JUSTIFY_LEFT:
1987 case SVX_HOR_JUSTIFY_BLOCK: aFuncResult = '\''; break;
1988 case SVX_HOR_JUSTIFY_CENTER: aFuncResult = '^'; break;
1989 case SVX_HOR_JUSTIFY_RIGHT: aFuncResult = '"'; break;
1990 case SVX_HOR_JUSTIFY_REPEAT: aFuncResult = '\\'; break;
1993 PushString( aFuncResult );
1995 else if( aInfoType.EqualsAscii( "PROTECT" ) )
1996 { // 1 = cell locked
1997 const ScProtectionAttr* pProtAttr = (const ScProtectionAttr*)
1998 pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION );
1999 PushInt( pProtAttr->GetProtection() ? 1 : 0 );
2002 // *** FORMATTING ***
2003 else if( aInfoType.EqualsAscii( "FORMAT" ) )
2004 { // specific format code for standard formats
2005 ULONG nFormat = pDok->GetNumberFormat( aCellPos );
2006 BOOL bAppendPrec = TRUE;
2007 USHORT nPrec, nLeading;
2008 BOOL bThousand, bIsRed;
2009 pFormatter->GetFormatSpecialInfo( nFormat, bThousand, bIsRed, nPrec, nLeading );
2011 switch( pFormatter->GetType( nFormat ) )
2013 case NUMBERFORMAT_NUMBER: aFuncResult = (bThousand ? ',' : 'F'); break;
2014 case NUMBERFORMAT_CURRENCY: aFuncResult = 'C'; break;
2015 case NUMBERFORMAT_SCIENTIFIC: aFuncResult = 'S'; break;
2016 case NUMBERFORMAT_PERCENT: aFuncResult = 'P'; break;
2017 default:
2019 bAppendPrec = FALSE;
2020 switch( pFormatter->GetIndexTableOffset( nFormat ) )
2022 case NF_DATE_SYSTEM_SHORT:
2023 case NF_DATE_SYS_DMMMYY:
2024 case NF_DATE_SYS_DDMMYY:
2025 case NF_DATE_SYS_DDMMYYYY:
2026 case NF_DATE_SYS_DMMMYYYY:
2027 case NF_DATE_DIN_DMMMYYYY:
2028 case NF_DATE_SYS_DMMMMYYYY:
2029 case NF_DATE_DIN_DMMMMYYYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
2030 case NF_DATE_SYS_DDMMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
2031 case NF_DATE_SYS_MMYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
2032 case NF_DATETIME_SYSTEM_SHORT_HHMM:
2033 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
2034 aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
2035 case NF_DATE_DIN_MMDD: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
2036 case NF_TIME_HHMMSSAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
2037 case NF_TIME_HHMMAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
2038 case NF_TIME_HHMMSS: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
2039 case NF_TIME_HHMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
2040 default: aFuncResult = 'G';
2044 if( bAppendPrec )
2045 aFuncResult += String::CreateFromInt32( nPrec );
2046 const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
2047 if( lcl_FormatHasNegColor( pFormat ) )
2048 aFuncResult += '-';
2049 if( lcl_FormatHasOpenPar( pFormat ) )
2050 aFuncResult.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
2051 PushString( aFuncResult );
2053 else if( aInfoType.EqualsAscii( "COLOR" ) )
2054 { // 1 = negative values are colored, otherwise 0
2055 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
2056 PushInt( lcl_FormatHasNegColor( pFormat ) ? 1 : 0 );
2058 else if( aInfoType.EqualsAscii( "PARENTHESES" ) )
2059 { // 1 = format string contains a '(' character, otherwise 0
2060 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
2061 PushInt( lcl_FormatHasOpenPar( pFormat ) ? 1 : 0 );
2063 else
2064 PushIllegalArgument();
2070 void ScInterpreter::ScIsRef()
2072 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCell" );
2073 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2074 short nRes = 0;
2075 switch ( GetStackType() )
2077 case svSingleRef :
2079 ScAddress aAdr;
2080 PopSingleRef( aAdr );
2081 if ( !nGlobalError )
2082 nRes = 1;
2084 break;
2085 case svDoubleRef :
2087 ScRange aRange;
2088 PopDoubleRef( aRange );
2089 if ( !nGlobalError )
2090 nRes = 1;
2092 break;
2093 case svRefList :
2095 FormulaTokenRef x = PopToken();
2096 if ( !nGlobalError )
2097 nRes = !static_cast<ScToken*>(x.get())->GetRefList()->empty();
2099 break;
2100 default:
2101 Pop();
2103 nGlobalError = 0;
2104 PushInt( nRes );
2108 void ScInterpreter::ScIsValue()
2110 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsValue" );
2111 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2112 short nRes = 0;
2113 switch ( GetRawStackType() )
2115 case svDouble:
2116 Pop();
2117 nRes = 1;
2118 break;
2119 case svDoubleRef :
2120 case svSingleRef :
2122 ScAddress aAdr;
2123 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2124 break;
2125 ScBaseCell* pCell = GetCell( aAdr );
2126 if (GetCellErrCode( pCell ) == 0)
2128 switch ( GetCellType( pCell ) )
2130 case CELLTYPE_VALUE :
2131 nRes = 1;
2132 break;
2133 case CELLTYPE_FORMULA :
2134 nRes = ((ScFormulaCell*)pCell)->IsValue() &&
2135 !((ScFormulaCell*)pCell)->IsEmpty();
2136 break;
2137 default:
2138 ; // nothing
2142 break;
2143 case svMatrix:
2145 ScMatrixRef pMat = PopMatrix();
2146 if ( !pMat )
2147 ; // nothing
2148 else if ( !pJumpMatrix )
2150 if (pMat->GetErrorIfNotString( 0 ) == 0)
2151 nRes = pMat->IsValue( 0 );
2153 else
2155 SCSIZE nCols, nRows, nC, nR;
2156 pMat->GetDimensions( nCols, nRows);
2157 pJumpMatrix->GetPos( nC, nR);
2158 if ( nC < nCols && nR < nRows )
2159 if (pMat->GetErrorIfNotString( nC, nR) == 0)
2160 nRes = pMat->IsValue( nC, nR);
2163 break;
2164 default:
2165 Pop();
2167 nGlobalError = 0;
2168 PushInt( nRes );
2172 void ScInterpreter::ScIsFormula()
2174 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsFormula" );
2175 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2176 short nRes = 0;
2177 switch ( GetStackType() )
2179 case svDoubleRef :
2180 case svSingleRef :
2182 ScAddress aAdr;
2183 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2184 break;
2185 nRes = (GetCellType( GetCell( aAdr ) ) == CELLTYPE_FORMULA);
2187 break;
2188 default:
2189 Pop();
2191 nGlobalError = 0;
2192 PushInt( nRes );
2196 void ScInterpreter::ScFormula()
2198 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFormula" );
2199 String aFormula;
2200 switch ( GetStackType() )
2202 case svDoubleRef :
2203 case svSingleRef :
2205 ScAddress aAdr;
2206 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2207 break;
2208 ScBaseCell* pCell = GetCell( aAdr );
2209 switch ( GetCellType( pCell ) )
2211 case CELLTYPE_FORMULA :
2212 ((ScFormulaCell*)pCell)->GetFormula( aFormula );
2213 break;
2214 default:
2215 SetError( NOTAVAILABLE );
2218 break;
2219 default:
2220 Pop();
2221 SetError( NOTAVAILABLE );
2223 PushString( aFormula );
2228 void ScInterpreter::ScIsNV()
2230 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsNV" );
2231 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2232 short nRes = 0;
2233 switch ( GetStackType() )
2235 case svDoubleRef :
2236 case svSingleRef :
2238 ScAddress aAdr;
2239 PopDoubleRefOrSingleRef( aAdr );
2240 if ( nGlobalError == NOTAVAILABLE )
2241 nRes = 1;
2242 else
2244 ScBaseCell* pCell = GetCell( aAdr );
2245 USHORT nErr = GetCellErrCode( pCell );
2246 nRes = (nErr == NOTAVAILABLE);
2249 break;
2250 case svMatrix:
2252 ScMatrixRef pMat = PopMatrix();
2253 if ( !pMat )
2254 ; // nothing
2255 else if ( !pJumpMatrix )
2256 nRes = (pMat->GetErrorIfNotString( 0 ) == NOTAVAILABLE);
2257 else
2259 SCSIZE nCols, nRows, nC, nR;
2260 pMat->GetDimensions( nCols, nRows);
2261 pJumpMatrix->GetPos( nC, nR);
2262 if ( nC < nCols && nR < nRows )
2263 nRes = (pMat->GetErrorIfNotString( nC, nR) == NOTAVAILABLE);
2266 break;
2267 default:
2268 PopError();
2269 if ( nGlobalError == NOTAVAILABLE )
2270 nRes = 1;
2272 nGlobalError = 0;
2273 PushInt( nRes );
2277 void ScInterpreter::ScIsErr()
2279 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsErr" );
2280 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2281 short nRes = 0;
2282 switch ( GetStackType() )
2284 case svDoubleRef :
2285 case svSingleRef :
2287 ScAddress aAdr;
2288 PopDoubleRefOrSingleRef( aAdr );
2289 if ( nGlobalError && nGlobalError != NOTAVAILABLE )
2290 nRes = 1;
2291 else
2293 ScBaseCell* pCell = GetCell( aAdr );
2294 USHORT nErr = GetCellErrCode( pCell );
2295 nRes = (nErr && nErr != NOTAVAILABLE);
2298 break;
2299 case svMatrix:
2301 ScMatrixRef pMat = PopMatrix();
2302 if ( nGlobalError || !pMat )
2303 nRes = ((nGlobalError && nGlobalError != NOTAVAILABLE) || !pMat);
2304 else if ( !pJumpMatrix )
2306 USHORT nErr = pMat->GetErrorIfNotString( 0 );
2307 nRes = (nErr && nErr != NOTAVAILABLE);
2309 else
2311 SCSIZE nCols, nRows, nC, nR;
2312 pMat->GetDimensions( nCols, nRows);
2313 pJumpMatrix->GetPos( nC, nR);
2314 if ( nC < nCols && nR < nRows )
2316 USHORT nErr = pMat->GetErrorIfNotString( nC, nR);
2317 nRes = (nErr && nErr != NOTAVAILABLE);
2321 break;
2322 default:
2323 PopError();
2324 if ( nGlobalError && nGlobalError != NOTAVAILABLE )
2325 nRes = 1;
2327 nGlobalError = 0;
2328 PushInt( nRes );
2332 void ScInterpreter::ScIsError()
2334 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsError" );
2335 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2336 short nRes = 0;
2337 switch ( GetStackType() )
2339 case svDoubleRef :
2340 case svSingleRef :
2342 ScAddress aAdr;
2343 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2345 nRes = 1;
2346 break;
2348 if ( nGlobalError )
2349 nRes = 1;
2350 else
2352 ScBaseCell* pCell = GetCell( aAdr );
2353 nRes = (GetCellErrCode( pCell ) != 0);
2356 break;
2357 case svMatrix:
2359 ScMatrixRef pMat = PopMatrix();
2360 if ( nGlobalError || !pMat )
2361 nRes = 1;
2362 else if ( !pJumpMatrix )
2363 nRes = (pMat->GetErrorIfNotString( 0 ) != 0);
2364 else
2366 SCSIZE nCols, nRows, nC, nR;
2367 pMat->GetDimensions( nCols, nRows);
2368 pJumpMatrix->GetPos( nC, nR);
2369 if ( nC < nCols && nR < nRows )
2370 nRes = (pMat->GetErrorIfNotString( nC, nR) != 0);
2373 break;
2374 default:
2375 PopError();
2376 if ( nGlobalError )
2377 nRes = 1;
2379 nGlobalError = 0;
2380 PushInt( nRes );
2384 short ScInterpreter::IsEven()
2386 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsEven" );
2387 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2388 short nRes = 0;
2389 double fVal = 0.0;
2390 switch ( GetStackType() )
2392 case svDoubleRef :
2393 case svSingleRef :
2395 ScAddress aAdr;
2396 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2397 break;
2398 ScBaseCell* pCell = GetCell( aAdr );
2399 USHORT nErr = GetCellErrCode( pCell );
2400 if (nErr != 0)
2401 SetError(nErr);
2402 else
2404 switch ( GetCellType( pCell ) )
2406 case CELLTYPE_VALUE :
2407 fVal = GetCellValue( aAdr, pCell );
2408 nRes = 1;
2409 break;
2410 case CELLTYPE_FORMULA :
2411 if( ((ScFormulaCell*)pCell)->IsValue() )
2413 fVal = GetCellValue( aAdr, pCell );
2414 nRes = 1;
2416 break;
2417 default:
2418 ; // nothing
2422 break;
2423 case svDouble:
2425 fVal = PopDouble();
2426 nRes = 1;
2428 break;
2429 case svMatrix:
2431 ScMatrixRef pMat = PopMatrix();
2432 if ( !pMat )
2433 ; // nothing
2434 else if ( !pJumpMatrix )
2436 nRes = pMat->IsValue( 0 );
2437 if ( nRes )
2438 fVal = pMat->GetDouble( 0 );
2440 else
2442 SCSIZE nCols, nRows, nC, nR;
2443 pMat->GetDimensions( nCols, nRows);
2444 pJumpMatrix->GetPos( nC, nR);
2445 if ( nC < nCols && nR < nRows )
2447 nRes = pMat->IsValue( nC, nR);
2448 if ( nRes )
2449 fVal = pMat->GetDouble( nC, nR);
2451 else
2452 SetError( errNoValue);
2455 break;
2456 default:
2457 ; // nothing
2459 if ( !nRes )
2460 SetError( errIllegalParameter);
2461 else
2462 nRes = ( fmod( ::rtl::math::approxFloor( fabs( fVal ) ), 2.0 ) < 0.5 );
2463 return nRes;
2467 void ScInterpreter::ScIsEven()
2469 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsEven" );
2470 PushInt( IsEven() );
2474 void ScInterpreter::ScIsOdd()
2476 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsOdd" );
2477 PushInt( !IsEven() );
2481 void ScInterpreter::ScN()
2483 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScN" );
2484 USHORT nErr = nGlobalError;
2485 nGlobalError = 0;
2486 double fVal;
2487 if ( GetRawStackType() == svString )
2489 fVal = 0.0;
2490 Pop();
2492 else
2493 fVal = GetDouble();
2494 if ( nGlobalError == NOTAVAILABLE || nGlobalError == errIllegalArgument )
2495 nGlobalError = 0; // N(#NA) and N("text") are ok
2496 if ( !nGlobalError && nErr != NOTAVAILABLE )
2497 nGlobalError = nErr;
2498 PushDouble( fVal );
2502 void ScInterpreter::ScTrim()
2503 { // trimmt nicht nur sondern schnibbelt auch doppelte raus!
2504 String aVal( GetString() );
2505 aVal.EraseLeadingChars();
2506 aVal.EraseTrailingChars();
2507 String aStr;
2508 register const sal_Unicode* p = aVal.GetBuffer();
2509 register const sal_Unicode* const pEnd = p + aVal.Len();
2510 while ( p < pEnd )
2512 if ( *p != ' ' || p[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
2513 aStr += *p;
2514 p++;
2516 PushString( aStr );
2520 void ScInterpreter::ScUpper()
2522 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrim" );
2523 String aString = GetString();
2524 ScGlobal::pCharClass->toUpper(aString);
2525 PushString(aString);
2529 void ScInterpreter::ScPropper()
2531 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPropper" );
2532 //2do: what to do with I18N-CJK ?!?
2533 String aStr( GetString() );
2534 const xub_StrLen nLen = aStr.Len();
2535 // #i82487# don't try to write to empty string's BufferAccess
2536 // (would crash now that the empty string is const)
2537 if ( nLen > 0 )
2539 String aUpr( ScGlobal::pCharClass->upper( aStr ) );
2540 String aLwr( ScGlobal::pCharClass->lower( aStr ) );
2541 register sal_Unicode* pStr = aStr.GetBufferAccess();
2542 const sal_Unicode* pUpr = aUpr.GetBuffer();
2543 const sal_Unicode* pLwr = aLwr.GetBuffer();
2544 *pStr = *pUpr;
2545 String aTmpStr( 'x' );
2546 xub_StrLen nPos = 1;
2547 while( nPos < nLen )
2549 aTmpStr.SetChar( 0, pStr[nPos-1] );
2550 if ( !ScGlobal::pCharClass->isLetter( aTmpStr, 0 ) )
2551 pStr[nPos] = pUpr[nPos];
2552 else
2553 pStr[nPos] = pLwr[nPos];
2554 nPos++;
2556 aStr.ReleaseBufferAccess( nLen );
2558 PushString( aStr );
2562 void ScInterpreter::ScLower()
2564 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLower" );
2565 String aString( GetString() );
2566 ScGlobal::pCharClass->toLower(aString);
2567 PushString(aString);
2571 void ScInterpreter::ScLen()
2573 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLen" );
2574 String aStr( GetString() );
2575 PushDouble( aStr.Len() );
2579 void ScInterpreter::ScT()
2581 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScT" );
2582 switch ( GetStackType() )
2584 case svDoubleRef :
2585 case svSingleRef :
2587 ScAddress aAdr;
2588 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2590 PushInt(0);
2591 return ;
2593 BOOL bValue = FALSE;
2594 ScBaseCell* pCell = GetCell( aAdr );
2595 if ( GetCellErrCode( pCell ) == 0 )
2597 switch ( GetCellType( pCell ) )
2599 case CELLTYPE_VALUE :
2600 bValue = TRUE;
2601 break;
2602 case CELLTYPE_FORMULA :
2603 bValue = ((ScFormulaCell*)pCell)->IsValue();
2604 break;
2605 default:
2606 ; // nothing
2609 if ( bValue )
2610 PushString( EMPTY_STRING );
2611 else
2613 // wie GetString()
2614 GetCellString( aTempStr, pCell );
2615 PushString( aTempStr );
2618 break;
2619 case svDouble :
2621 PopError();
2622 PushString( EMPTY_STRING );
2624 break;
2625 case svString :
2626 ; // leave on stack
2627 break;
2628 default :
2629 PushError( errUnknownOpCode);
2634 void ScInterpreter::ScValue()
2636 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScValue" );
2637 String aInputString;
2638 double fVal;
2640 switch ( GetRawStackType() )
2642 case svMissing:
2643 case svEmptyCell:
2644 Pop();
2645 PushInt(0);
2646 return;
2647 case svDouble:
2648 return; // leave on stack
2649 //break;
2651 case svSingleRef:
2652 case svDoubleRef:
2654 ScAddress aAdr;
2655 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2657 PushInt(0);
2658 return;
2660 ScBaseCell* pCell = GetCell( aAdr );
2661 if ( pCell && pCell->HasStringData() )
2662 GetCellString( aInputString, pCell );
2663 else if ( pCell && pCell->HasValueData() )
2665 PushDouble( GetCellValue(aAdr, pCell) );
2666 return;
2668 else
2670 PushDouble(0.0);
2671 return;
2674 break;
2675 case svMatrix:
2677 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
2678 aInputString);
2679 switch (nType)
2681 case SC_MATVAL_EMPTY:
2682 fVal = 0.0;
2683 // fallthru
2684 case SC_MATVAL_VALUE:
2685 case SC_MATVAL_BOOLEAN:
2686 PushDouble( fVal);
2687 return;
2688 //break;
2689 case SC_MATVAL_STRING:
2690 // evaluated below
2691 break;
2692 default:
2693 PushIllegalArgument();
2696 break;
2697 default:
2698 aInputString = GetString();
2699 break;
2702 sal_uInt32 nFIndex = 0; // 0 for default locale
2703 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
2704 PushDouble(fVal);
2705 else
2706 PushIllegalArgument();
2710 //2do: this should be a proper unicode string method
2711 inline BOOL lcl_ScInterpreter_IsPrintable( sal_Unicode c )
2713 return 0x20 <= c && c != 0x7f;
2716 void ScInterpreter::ScClean()
2718 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScClean" );
2719 String aStr( GetString() );
2720 for ( xub_StrLen i = 0; i < aStr.Len(); i++ )
2722 if ( !lcl_ScInterpreter_IsPrintable( aStr.GetChar( i ) ) )
2723 aStr.Erase(i,1);
2725 PushString(aStr);
2729 void ScInterpreter::ScCode()
2731 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCode" );
2732 //2do: make it full range unicode?
2733 const String& rStr = GetString();
2734 PushInt( (sal_uChar) ByteString::ConvertFromUnicode( rStr.GetChar(0), gsl_getSystemTextEncoding() ) );
2738 void ScInterpreter::ScChar()
2740 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChar" );
2741 //2do: make it full range unicode?
2742 double fVal = GetDouble();
2743 if (fVal < 0.0 || fVal >= 256.0)
2744 PushIllegalArgument();
2745 else
2747 String aStr( '0' );
2748 aStr.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char) fVal, gsl_getSystemTextEncoding() ) );
2749 PushString( aStr );
2754 /* #i70213# fullwidth/halfwidth conversion provided by
2755 * Takashi Nakamoto <bluedwarf@ooo>
2756 * erAck: added Excel compatibility conversions as seen in issue's test case. */
2758 static ::rtl::OUString lcl_convertIntoHalfWidth( const ::rtl::OUString & rStr )
2760 static bool bFirstASCCall = true;
2761 static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2763 if( bFirstASCCall )
2765 aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM );
2766 bFirstASCCall = false;
2769 return aTrans.transliterate( rStr, 0, USHORT( rStr.getLength() ), NULL );
2773 static ::rtl::OUString lcl_convertIntoFullWidth( const ::rtl::OUString & rStr )
2775 static bool bFirstJISCall = true;
2776 static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2778 if( bFirstJISCall )
2780 aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM );
2781 bFirstJISCall = false;
2784 return aTrans.transliterate( rStr, 0, USHORT( rStr.getLength() ), NULL );
2788 /* ODFF:
2789 * Summary: Converts half-width to full-width ASCII and katakana characters.
2790 * Semantics: Conversion is done for half-width ASCII and katakana characters,
2791 * other characters are simply copied from T to the result. This is the
2792 * complementary function to ASC.
2793 * For references regarding halfwidth and fullwidth characters see
2794 * http://www.unicode.org/reports/tr11/
2795 * http://www.unicode.org/charts/charindex2.html#H
2796 * http://www.unicode.org/charts/charindex2.html#F
2798 void ScInterpreter::ScJis()
2800 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScJis" );
2801 if (MustHaveParamCount( GetByte(), 1))
2802 PushString( lcl_convertIntoFullWidth( GetString()));
2806 /* ODFF:
2807 * Summary: Converts full-width to half-width ASCII and katakana characters.
2808 * Semantics: Conversion is done for full-width ASCII and katakana characters,
2809 * other characters are simply copied from T to the result. This is the
2810 * complementary function to JIS.
2812 void ScInterpreter::ScAsc()
2814 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAsc" );
2815 if (MustHaveParamCount( GetByte(), 1))
2816 PushString( lcl_convertIntoHalfWidth( GetString()));
2819 void ScInterpreter::ScUnicode()
2821 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnicode" );
2822 if ( MustHaveParamCount( GetByte(), 1 ) )
2824 const rtl::OUString& rStr = GetString();
2825 if (rStr.getLength() <= 0)
2826 PushIllegalParameter();
2827 else
2829 sal_Int32 i = 0;
2830 PushDouble( rStr.iterateCodePoints(&i) );
2835 void ScInterpreter::ScUnichar()
2837 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnichar" );
2838 if ( MustHaveParamCount( GetByte(), 1 ) )
2840 double dVal = ::rtl::math::approxFloor( GetDouble() );
2841 if ((dVal < 0x000000) || (dVal > 0x10FFFF))
2842 PushIllegalArgument();
2843 else
2845 sal_uInt32 nCodePoint = static_cast<sal_uInt32>( dVal );
2846 rtl::OUString aStr( &nCodePoint, 1 );
2847 PushString( aStr );
2853 void ScInterpreter::ScMin( BOOL bTextAsZero )
2855 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMin" );
2856 short nParamCount = GetByte();
2857 if (!MustHaveParamCountMin( nParamCount, 1))
2858 return;
2859 double nMin = ::std::numeric_limits<double>::max();
2860 double nVal = 0.0;
2861 ScAddress aAdr;
2862 ScRange aRange;
2863 size_t nRefInList = 0;
2864 while (nParamCount-- > 0)
2866 switch (GetStackType())
2868 case svDouble :
2870 nVal = GetDouble();
2871 if (nMin > nVal) nMin = nVal;
2872 nFuncFmtType = NUMBERFORMAT_NUMBER;
2874 break;
2875 case svSingleRef :
2877 PopSingleRef( aAdr );
2878 ScBaseCell* pCell = GetCell( aAdr );
2879 if (HasCellValueData(pCell))
2881 nVal = GetCellValue( aAdr, pCell );
2882 CurFmtToFuncFmt();
2883 if (nMin > nVal) nMin = nVal;
2885 else if ( bTextAsZero && HasCellStringData( pCell ) )
2887 if ( nMin > 0.0 )
2888 nMin = 0.0;
2891 break;
2892 case svDoubleRef :
2893 case svRefList :
2895 USHORT nErr = 0;
2896 PopDoubleRef( aRange, nParamCount, nRefInList);
2897 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
2898 if (aValIter.GetFirst(nVal, nErr))
2900 if (nMin > nVal)
2901 nMin = nVal;
2902 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
2903 while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
2905 if (nMin > nVal)
2906 nMin = nVal;
2908 SetError(nErr);
2911 break;
2912 case svMatrix :
2914 ScMatrixRef pMat = PopMatrix();
2915 if (pMat)
2917 SCSIZE nC, nR;
2918 nFuncFmtType = NUMBERFORMAT_NUMBER;
2919 pMat->GetDimensions(nC, nR);
2920 if (pMat->IsNumeric())
2922 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
2923 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
2925 nVal = pMat->GetDouble(nMatCol,nMatRow);
2926 if (nMin > nVal) nMin = nVal;
2929 else
2931 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
2933 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
2935 if (!pMat->IsString(nMatCol,nMatRow))
2937 nVal = pMat->GetDouble(nMatCol,nMatRow);
2938 if (nMin > nVal) nMin = nVal;
2940 else if ( bTextAsZero )
2942 if ( nMin > 0.0 )
2943 nMin = 0.0;
2950 break;
2951 case svString :
2953 Pop();
2954 if ( bTextAsZero )
2956 if ( nMin > 0.0 )
2957 nMin = 0.0;
2959 else
2960 SetError(errIllegalParameter);
2962 break;
2963 default :
2964 Pop();
2965 SetError(errIllegalParameter);
2968 if ( nVal < nMin )
2969 PushDouble(0.0);
2970 else
2971 PushDouble(nMin);
2974 #if defined(WIN) && defined(MSC)
2975 #pragma optimize("",off)
2976 #endif
2978 void ScInterpreter::ScMax( BOOL bTextAsZero )
2980 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMax" );
2981 short nParamCount = GetByte();
2982 if (!MustHaveParamCountMin( nParamCount, 1))
2983 return;
2984 double nMax = -(::std::numeric_limits<double>::max());
2985 double nVal = 0.0;
2986 ScAddress aAdr;
2987 ScRange aRange;
2988 size_t nRefInList = 0;
2989 while (nParamCount-- > 0)
2991 switch (GetStackType())
2993 case svDouble :
2995 nVal = GetDouble();
2996 if (nMax < nVal) nMax = nVal;
2997 nFuncFmtType = NUMBERFORMAT_NUMBER;
2999 break;
3000 case svSingleRef :
3002 PopSingleRef( aAdr );
3003 ScBaseCell* pCell = GetCell( aAdr );
3004 if (HasCellValueData(pCell))
3006 nVal = GetCellValue( aAdr, pCell );
3007 CurFmtToFuncFmt();
3008 if (nMax < nVal) nMax = nVal;
3010 else if ( bTextAsZero && HasCellStringData( pCell ) )
3012 if ( nMax < 0.0 )
3013 nMax = 0.0;
3016 break;
3017 case svDoubleRef :
3018 case svRefList :
3020 USHORT nErr = 0;
3021 PopDoubleRef( aRange, nParamCount, nRefInList);
3022 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3023 if (aValIter.GetFirst(nVal, nErr))
3025 if (nMax < nVal)
3026 nMax = nVal;
3027 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
3028 while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
3030 if (nMax < nVal)
3031 nMax = nVal;
3033 SetError(nErr);
3036 break;
3037 case svMatrix :
3039 ScMatrixRef pMat = PopMatrix();
3040 if (pMat)
3042 nFuncFmtType = NUMBERFORMAT_NUMBER;
3043 SCSIZE nC, nR;
3044 pMat->GetDimensions(nC, nR);
3045 if (pMat->IsNumeric())
3047 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3048 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3050 nVal = pMat->GetDouble(nMatCol,nMatRow);
3051 if (nMax < nVal) nMax = nVal;
3054 else
3056 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3058 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3060 if (!pMat->IsString(nMatCol,nMatRow))
3062 nVal = pMat->GetDouble(nMatCol,nMatRow);
3063 if (nMax < nVal) nMax = nVal;
3065 else if ( bTextAsZero )
3067 if ( nMax < 0.0 )
3068 nMax = 0.0;
3075 break;
3076 case svString :
3078 Pop();
3079 if ( bTextAsZero )
3081 if ( nMax < 0.0 )
3082 nMax = 0.0;
3084 else
3085 SetError(errIllegalParameter);
3087 break;
3088 default :
3089 Pop();
3090 SetError(errIllegalParameter);
3093 if ( nVal > nMax )
3094 PushDouble(0.0);
3095 else
3096 PushDouble(nMax);
3098 #if defined(WIN) && defined(MSC)
3099 #pragma optimize("",on)
3100 #endif
3103 double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
3105 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
3106 short nParamCount = GetByte();
3107 double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
3108 double fVal = 0.0;
3109 double fMem = 0.0;
3110 BOOL bNull = TRUE;
3111 ULONG nCount = 0;
3112 ScAddress aAdr;
3113 ScRange aRange;
3114 size_t nRefInList = 0;
3115 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3116 nGlobalError = 0;
3117 while (nParamCount-- > 0)
3119 switch (GetStackType())
3122 case svString:
3124 if( eFunc == ifCOUNT )
3126 String aStr( PopString() );
3127 sal_uInt32 nFIndex = 0; // damit default Land/Spr.
3128 if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
3129 nCount++;
3131 else
3133 switch ( eFunc )
3135 case ifAVERAGE:
3136 case ifSUM:
3137 case ifSUMSQ:
3138 case ifPRODUCT:
3140 if ( bTextAsZero )
3142 Pop();
3143 nCount++;
3144 if ( eFunc == ifPRODUCT )
3145 fRes = 0.0;
3147 else
3149 while (nParamCount-- > 0)
3150 Pop();
3151 SetError( errNoValue );
3154 break;
3155 default:
3156 Pop();
3157 nCount++;
3161 break;
3162 case svDouble :
3163 fVal = GetDouble();
3164 nCount++;
3165 switch( eFunc )
3167 case ifAVERAGE:
3168 case ifSUM:
3169 if ( bNull && fVal != 0.0 )
3171 bNull = FALSE;
3172 fMem = fVal;
3174 else
3175 fRes += fVal;
3176 break;
3177 case ifSUMSQ: fRes += fVal * fVal; break;
3178 case ifPRODUCT: fRes *= fVal; break;
3179 default: ; // nothing
3181 nFuncFmtType = NUMBERFORMAT_NUMBER;
3182 break;
3183 case svSingleRef :
3185 PopSingleRef( aAdr );
3186 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3188 nGlobalError = 0;
3189 if ( eFunc == ifCOUNT2 )
3190 ++nCount;
3191 break;
3193 ScBaseCell* pCell = GetCell( aAdr );
3194 if ( pCell )
3196 if( eFunc == ifCOUNT2 )
3198 CellType eCellType = pCell->GetCellType();
3199 if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
3200 nCount++;
3201 if ( nGlobalError )
3202 nGlobalError = 0;
3204 else if ( pCell->HasValueData() )
3206 nCount++;
3207 fVal = GetCellValue( aAdr, pCell );
3208 CurFmtToFuncFmt();
3209 switch( eFunc )
3211 case ifAVERAGE:
3212 case ifSUM:
3213 if ( bNull && fVal != 0.0 )
3215 bNull = FALSE;
3216 fMem = fVal;
3218 else
3219 fRes += fVal;
3220 break;
3221 case ifSUMSQ: fRes += fVal * fVal; break;
3222 case ifPRODUCT: fRes *= fVal; break;
3223 case ifCOUNT:
3224 if ( nGlobalError )
3226 nGlobalError = 0;
3227 nCount--;
3229 break;
3230 default: ; // nothing
3233 else if ( bTextAsZero && pCell->HasStringData() )
3235 nCount++;
3236 if ( eFunc == ifPRODUCT )
3237 fRes = 0.0;
3241 break;
3242 case svDoubleRef :
3243 case svRefList :
3245 USHORT nErr = 0;
3246 PopDoubleRef( aRange, nParamCount, nRefInList);
3247 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3249 nGlobalError = 0;
3250 if ( eFunc == ifCOUNT2 )
3251 ++nCount;
3252 break;
3254 if( eFunc == ifCOUNT2 )
3256 ScBaseCell* pCell;
3257 ScCellIterator aIter( pDok, aRange, glSubTotal );
3258 if ( (pCell = aIter.GetFirst()) != NULL )
3262 CellType eType = pCell->GetCellType();
3263 if( eType != CELLTYPE_NONE && eType != CELLTYPE_NOTE )
3264 nCount++;
3266 while ( (pCell = aIter.GetNext()) != NULL );
3268 if ( nGlobalError )
3269 nGlobalError = 0;
3271 else
3273 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3274 if (aValIter.GetFirst(fVal, nErr))
3276 // Schleife aus Performance-Gruenden nach innen verlegt:
3277 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
3278 switch( eFunc )
3280 case ifAVERAGE:
3281 case ifSUM:
3284 SetError(nErr);
3285 if ( bNull && fVal != 0.0 )
3287 bNull = FALSE;
3288 fMem = fVal;
3290 else
3291 fRes += fVal;
3292 nCount++;
3294 while (aValIter.GetNext(fVal, nErr));
3295 break;
3296 case ifSUMSQ:
3299 SetError(nErr);
3300 fRes += fVal * fVal;
3301 nCount++;
3303 while (aValIter.GetNext(fVal, nErr));
3304 break;
3305 case ifPRODUCT:
3308 SetError(nErr);
3309 fRes *= fVal;
3310 nCount++;
3312 while (aValIter.GetNext(fVal, nErr));
3313 break;
3314 case ifCOUNT:
3317 if ( !nErr )
3318 nCount++;
3320 while (aValIter.GetNext(fVal, nErr));
3321 break;
3322 default: ; // nothing
3324 SetError( nErr );
3328 break;
3329 case svMatrix :
3331 ScMatrixRef pMat = PopMatrix();
3332 if (pMat)
3334 SCSIZE nC, nR;
3335 nFuncFmtType = NUMBERFORMAT_NUMBER;
3336 pMat->GetDimensions(nC, nR);
3337 if( eFunc == ifCOUNT2 )
3338 nCount += (ULONG) nC * nR;
3339 else
3341 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3343 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3345 if (!pMat->IsString(nMatCol,nMatRow))
3347 nCount++;
3348 fVal = pMat->GetDouble(nMatCol,nMatRow);
3349 switch( eFunc )
3351 case ifAVERAGE:
3352 case ifSUM:
3353 if ( bNull && fVal != 0.0 )
3355 bNull = FALSE;
3356 fMem = fVal;
3358 else
3359 fRes += fVal;
3360 break;
3361 case ifSUMSQ: fRes += fVal * fVal; break;
3362 case ifPRODUCT: fRes *= fVal; break;
3363 default: ; // nothing
3366 else if ( bTextAsZero )
3368 nCount++;
3369 if ( eFunc == ifPRODUCT )
3370 fRes = 0.0;
3377 break;
3378 case svError:
3380 Pop();
3381 if ( eFunc == ifCOUNT )
3383 nGlobalError = 0;
3385 else if ( eFunc == ifCOUNT2 )
3387 nCount++;
3388 nGlobalError = 0;
3391 break;
3392 default :
3393 while (nParamCount-- > 0)
3394 PopError();
3395 SetError(errIllegalParameter);
3398 switch( eFunc )
3400 case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
3401 case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
3402 case ifCOUNT2:
3403 case ifCOUNT: fRes = nCount; break;
3404 case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
3405 default: ; // nothing
3407 // Bei Summen etc. macht ein BOOL-Ergebnis keinen Sinn
3408 // und Anzahl ist immer Number (#38345#)
3409 if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
3410 nFuncFmtType = NUMBERFORMAT_NUMBER;
3411 return fRes;
3415 void ScInterpreter::ScSumSQ()
3417 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
3418 PushDouble( IterateParameters( ifSUMSQ ) );
3422 void ScInterpreter::ScSum()
3424 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSum" );
3425 PushDouble( IterateParameters( ifSUM ) );
3429 void ScInterpreter::ScProduct()
3431 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
3432 PushDouble( IterateParameters( ifPRODUCT ) );
3436 void ScInterpreter::ScAverage( BOOL bTextAsZero )
3438 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
3439 PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
3443 void ScInterpreter::ScCount()
3445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount" );
3446 PushDouble( IterateParameters( ifCOUNT ) );
3450 void ScInterpreter::ScCount2()
3452 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
3453 PushDouble( IterateParameters( ifCOUNT2 ) );
3457 void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
3458 BOOL bTextAsZero )
3460 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetStVarParams" );
3461 short nParamCount = GetByte();
3463 std::vector<double> values;
3464 double fSum = 0.0;
3465 double vSum = 0.0;
3466 double vMean = 0.0;
3467 double fVal = 0.0;
3468 rValCount = 0.0;
3469 ScAddress aAdr;
3470 ScRange aRange;
3471 size_t nRefInList = 0;
3472 while (nParamCount-- > 0)
3474 switch (GetStackType())
3476 case svDouble :
3478 fVal = GetDouble();
3479 values.push_back(fVal);
3480 fSum += fVal;
3481 rValCount++;
3483 break;
3484 case svSingleRef :
3486 PopSingleRef( aAdr );
3487 ScBaseCell* pCell = GetCell( aAdr );
3488 if (HasCellValueData(pCell))
3490 fVal = GetCellValue( aAdr, pCell );
3491 values.push_back(fVal);
3492 fSum += fVal;
3493 rValCount++;
3495 else if ( bTextAsZero && HasCellStringData( pCell ) )
3497 values.push_back(0.0);
3498 rValCount++;
3501 break;
3502 case svDoubleRef :
3503 case svRefList :
3505 USHORT nErr = 0;
3506 PopDoubleRef( aRange, nParamCount, nRefInList);
3507 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3508 if (aValIter.GetFirst(fVal, nErr))
3512 values.push_back(fVal);
3513 fSum += fVal;
3514 rValCount++;
3516 while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
3519 break;
3520 case svMatrix :
3522 ScMatrixRef pMat = PopMatrix();
3523 if (pMat)
3525 SCSIZE nC, nR;
3526 pMat->GetDimensions(nC, nR);
3527 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3529 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3531 if (!pMat->IsString(nMatCol,nMatRow))
3533 fVal= pMat->GetDouble(nMatCol,nMatRow);
3534 values.push_back(fVal);
3535 fSum += fVal;
3536 rValCount++;
3538 else if ( bTextAsZero )
3540 values.push_back(0.0);
3541 rValCount++;
3547 break;
3548 case svString :
3550 Pop();
3551 if ( bTextAsZero )
3553 values.push_back(0.0);
3554 rValCount++;
3556 else
3557 SetError(errIllegalParameter);
3559 break;
3560 default :
3561 Pop();
3562 SetError(errIllegalParameter);
3566 ::std::vector<double>::size_type n = values.size();
3567 vMean = fSum / n;
3568 for (::std::vector<double>::size_type i = 0; i < n; i++)
3569 vSum += ::rtl::math::approxSub( values[i], vMean) * ::rtl::math::approxSub( values[i], vMean);
3570 rVal = vSum;
3574 void ScInterpreter::ScVar( BOOL bTextAsZero )
3576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVar" );
3577 double nVal;
3578 double nValCount;
3579 GetStVarParams( nVal, nValCount, bTextAsZero );
3581 if (nValCount <= 1.0)
3582 PushError( errDivisionByZero );
3583 else
3584 PushDouble( nVal / (nValCount - 1.0));
3588 void ScInterpreter::ScVarP( BOOL bTextAsZero )
3590 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVarP" );
3591 double nVal;
3592 double nValCount;
3593 GetStVarParams( nVal, nValCount, bTextAsZero );
3595 PushDouble( div( nVal, nValCount));
3599 void ScInterpreter::ScStDev( BOOL bTextAsZero )
3601 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStDev" );
3602 double nVal;
3603 double nValCount;
3604 GetStVarParams( nVal, nValCount, bTextAsZero );
3605 if (nValCount <= 1.0)
3606 PushError( errDivisionByZero );
3607 else
3608 PushDouble( sqrt( nVal / (nValCount - 1.0)));
3612 void ScInterpreter::ScStDevP( BOOL bTextAsZero )
3614 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStDevP" );
3615 double nVal;
3616 double nValCount;
3617 GetStVarParams( nVal, nValCount, bTextAsZero );
3618 if (nValCount == 0.0)
3619 PushError( errDivisionByZero );
3620 else
3621 PushDouble( sqrt( nVal / nValCount));
3623 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3625 * Besides that the special NAN gets lost in the call through sqrt(),
3626 * unxlngi6.pro then looped back and forth somewhere between div() and
3627 * ::rtl::math::setNan(). Tests showed that
3629 * sqrt( div( 1, 0));
3631 * produced a loop, but
3633 * double f1 = div( 1, 0);
3634 * sqrt( f1 );
3636 * was fine. There seems to be some compiler optimization problem. It does
3637 * not occur when compiled with debug=t.
3642 void ScInterpreter::ScColumns()
3644 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColumns" );
3645 BYTE nParamCount = GetByte();
3646 ULONG nVal = 0;
3647 SCCOL nCol1;
3648 SCROW nRow1;
3649 SCTAB nTab1;
3650 SCCOL nCol2;
3651 SCROW nRow2;
3652 SCTAB nTab2;
3653 while (nParamCount-- > 0)
3655 switch ( GetStackType() )
3657 case svSingleRef:
3658 PopError();
3659 nVal++;
3660 break;
3661 case svDoubleRef:
3662 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3663 nVal += static_cast<ULONG>(nTab2 - nTab1 + 1) *
3664 static_cast<ULONG>(nCol2 - nCol1 + 1);
3665 break;
3666 case svMatrix:
3668 ScMatrixRef pMat = PopMatrix();
3669 if (pMat)
3671 SCSIZE nC, nR;
3672 pMat->GetDimensions(nC, nR);
3673 nVal += nC;
3676 break;
3677 default:
3678 PopError();
3679 SetError(errIllegalParameter);
3682 PushDouble((double)nVal);
3686 void ScInterpreter::ScRows()
3688 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRows" );
3689 BYTE nParamCount = GetByte();
3690 ULONG nVal = 0;
3691 SCCOL nCol1;
3692 SCROW nRow1;
3693 SCTAB nTab1;
3694 SCCOL nCol2;
3695 SCROW nRow2;
3696 SCTAB nTab2;
3697 while (nParamCount-- > 0)
3699 switch ( GetStackType() )
3701 case svSingleRef:
3702 PopError();
3703 nVal++;
3704 break;
3705 case svDoubleRef:
3706 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3707 nVal += static_cast<ULONG>(nTab2 - nTab1 + 1) *
3708 static_cast<ULONG>(nRow2 - nRow1 + 1);
3709 break;
3710 case svMatrix:
3712 ScMatrixRef pMat = PopMatrix();
3713 if (pMat)
3715 SCSIZE nC, nR;
3716 pMat->GetDimensions(nC, nR);
3717 nVal += nR;
3720 break;
3721 default:
3722 PopError();
3723 SetError(errIllegalParameter);
3726 PushDouble((double)nVal);
3729 void ScInterpreter::ScTables()
3731 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTables" );
3732 BYTE nParamCount = GetByte();
3733 ULONG nVal;
3734 if ( nParamCount == 0 )
3735 nVal = pDok->GetTableCount();
3736 else
3738 nVal = 0;
3739 SCCOL nCol1;
3740 SCROW nRow1;
3741 SCTAB nTab1;
3742 SCCOL nCol2;
3743 SCROW nRow2;
3744 SCTAB nTab2;
3745 while (nParamCount-- > 0)
3747 switch ( GetStackType() )
3749 case svSingleRef:
3750 PopError();
3751 nVal++;
3752 break;
3753 case svDoubleRef:
3754 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3755 nVal += static_cast<ULONG>(nTab2 - nTab1 + 1);
3756 break;
3757 case svMatrix:
3758 PopError();
3759 nVal++;
3760 break;
3761 default:
3762 PopError();
3763 SetError( errIllegalParameter );
3767 PushDouble( (double) nVal );
3771 void ScInterpreter::ScColumn()
3773 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColumn" );
3774 BYTE nParamCount = GetByte();
3775 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
3777 double nVal = 0;
3778 if (nParamCount == 0)
3780 nVal = aPos.Col() + 1;
3781 if (bMatrixFormula)
3783 SCCOL nCols;
3784 SCROW nRows;
3785 pMyFormulaCell->GetMatColsRows( nCols, nRows);
3786 ScMatrixRef pResMat = GetNewMat( static_cast<SCSIZE>(nCols), 1);
3787 if (pResMat)
3789 for (SCCOL i=0; i < nCols; ++i)
3790 pResMat->PutDouble( nVal + i, static_cast<SCSIZE>(i), 0);
3791 PushMatrix( pResMat);
3792 return;
3796 else
3798 switch ( GetStackType() )
3800 case svSingleRef :
3802 SCCOL nCol1;
3803 SCROW nRow1;
3804 SCTAB nTab1;
3805 PopSingleRef( nCol1, nRow1, nTab1 );
3806 nVal = (double) (nCol1 + 1);
3808 break;
3809 case svDoubleRef :
3811 SCCOL nCol1;
3812 SCROW nRow1;
3813 SCTAB nTab1;
3814 SCCOL nCol2;
3815 SCROW nRow2;
3816 SCTAB nTab2;
3817 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
3818 if (nCol2 > nCol1)
3820 ScMatrixRef pResMat = GetNewMat(
3821 static_cast<SCSIZE>(nCol2-nCol1+1), 1);
3822 if (pResMat)
3824 for (SCCOL i = nCol1; i <= nCol2; i++)
3825 pResMat->PutDouble((double)(i+1),
3826 static_cast<SCSIZE>(i-nCol1), 0);
3827 PushMatrix(pResMat);
3828 return;
3830 else
3831 nVal = 0.0;
3833 else
3834 nVal = (double) (nCol1 + 1);
3836 break;
3837 default:
3838 SetError( errIllegalParameter );
3839 nVal = 0.0;
3842 PushDouble( nVal );
3847 void ScInterpreter::ScRow()
3849 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRow" );
3850 BYTE nParamCount = GetByte();
3851 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
3853 double nVal = 0;
3854 if (nParamCount == 0)
3856 nVal = aPos.Row() + 1;
3857 if (bMatrixFormula)
3859 SCCOL nCols;
3860 SCROW nRows;
3861 pMyFormulaCell->GetMatColsRows( nCols, nRows);
3862 ScMatrixRef pResMat = GetNewMat( 1, static_cast<SCSIZE>(nRows));
3863 if (pResMat)
3865 for (SCROW i=0; i < nRows; i++)
3866 pResMat->PutDouble( nVal + i, 0, static_cast<SCSIZE>(i));
3867 PushMatrix( pResMat);
3868 return;
3872 else
3874 switch ( GetStackType() )
3876 case svSingleRef :
3878 SCCOL nCol1;
3879 SCROW nRow1;
3880 SCTAB nTab1;
3881 PopSingleRef( nCol1, nRow1, nTab1 );
3882 nVal = (double) (nRow1 + 1);
3884 break;
3885 case svDoubleRef :
3887 SCCOL nCol1;
3888 SCROW nRow1;
3889 SCTAB nTab1;
3890 SCCOL nCol2;
3891 SCROW nRow2;
3892 SCTAB nTab2;
3893 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
3894 if (nRow2 > nRow1)
3896 ScMatrixRef pResMat = GetNewMat( 1,
3897 static_cast<SCSIZE>(nRow2-nRow1+1));
3898 if (pResMat)
3900 for (SCROW i = nRow1; i <= nRow2; i++)
3901 pResMat->PutDouble((double)(i+1), 0,
3902 static_cast<SCSIZE>(i-nRow1));
3903 PushMatrix(pResMat);
3904 return;
3906 else
3907 nVal = 0.0;
3909 else
3910 nVal = (double) (nRow1 + 1);
3912 break;
3913 default:
3914 SetError( errIllegalParameter );
3915 nVal = 0.0;
3918 PushDouble( nVal );
3922 void ScInterpreter::ScTable()
3924 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTable" );
3925 BYTE nParamCount = GetByte();
3926 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
3928 SCTAB nVal = 0;
3929 if ( nParamCount == 0 )
3930 nVal = aPos.Tab() + 1;
3931 else
3933 switch ( GetStackType() )
3935 case svString :
3937 String aStr( PopString() );
3938 if ( pDok->GetTable( aStr, nVal ) )
3939 ++nVal;
3940 else
3941 SetError( errIllegalArgument );
3943 break;
3944 case svSingleRef :
3946 SCCOL nCol1;
3947 SCROW nRow1;
3948 SCTAB nTab1;
3949 PopSingleRef( nCol1, nRow1, nTab1 );
3950 nVal = nTab1 + 1;
3952 break;
3953 case svDoubleRef :
3955 SCCOL nCol1;
3956 SCROW nRow1;
3957 SCTAB nTab1;
3958 SCCOL nCol2;
3959 SCROW nRow2;
3960 SCTAB nTab2;
3961 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
3962 nVal = nTab1 + 1;
3964 break;
3965 default:
3966 SetError( errIllegalParameter );
3968 if ( nGlobalError )
3969 nVal = 0;
3971 PushDouble( (double) nVal );
3975 /** returns -1 when the matrix value is smaller than the query value, 0 when
3976 they are equal, and 1 when the matrix value is larger than the query
3977 value. */
3978 static sal_Int32 lcl_CompareMatrix2Query( SCSIZE i, const ScMatrix& rMat,
3979 const ScQueryEntry& rEntry)
3981 if (rMat.IsEmpty(i))
3983 /* TODO: in case we introduced query for real empty this would have to
3984 * be changed! */
3985 return -1; // empty always less than anything else
3988 /* FIXME: what is an empty path (result of IF(false;true_path) in
3989 * comparisons? */
3991 if (rMat.IsValue(i))
3993 if (rEntry.bQueryByString)
3994 return -1; // numeric always less than string
3996 const double nVal1 = rMat.GetDouble(i);
3997 const double nVal2 = rEntry.nVal;
3998 if (nVal1 == nVal2)
3999 return 0;
4001 return nVal1 < nVal2 ? -1 : 1;
4004 if (!rEntry.bQueryByString)
4005 return 1; // string always greater than numeric
4007 if (!rEntry.pStr)
4008 // this should not happen!
4009 return 1;
4011 const String& rStr1 = rMat.GetString(i);
4012 const String& rStr2 = *rEntry.pStr;
4014 return ScGlobal::GetCollator()->compareString( rStr1, rStr2); // case-insensitive
4017 /** returns the last item with the identical value as the original item
4018 value. */
4019 static void lcl_GetLastMatch( SCSIZE& rIndex, const ScMatrix& rMat,
4020 SCSIZE nMatCount, bool bReverse)
4022 if (rMat.IsValue(rIndex))
4024 double nVal = rMat.GetDouble(rIndex);
4025 if (bReverse)
4026 while (rIndex > 0 && rMat.IsValue(rIndex-1) &&
4027 nVal == rMat.GetDouble(rIndex-1))
4028 --rIndex;
4029 else
4030 while (rIndex < nMatCount-1 && rMat.IsValue(rIndex+1) &&
4031 nVal == rMat.GetDouble(rIndex+1))
4032 ++rIndex;
4034 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
4035 else if (rMat.IsEmptyPath(rIndex))
4037 if (bReverse)
4038 while (rIndex > 0 && rMat.IsEmptyPath(rIndex-1))
4039 --rIndex;
4040 else
4041 while (rIndex < nMatCount-1 && rMat.IsEmptyPath(rIndex+1))
4042 ++rIndex;
4044 else if (rMat.IsEmpty(rIndex))
4046 if (bReverse)
4047 while (rIndex > 0 && rMat.IsEmpty(rIndex-1))
4048 --rIndex;
4049 else
4050 while (rIndex < nMatCount-1 && rMat.IsEmpty(rIndex+1))
4051 ++rIndex;
4053 else if (rMat.IsString(rIndex))
4055 String aStr( rMat.GetString(rIndex));
4056 if (bReverse)
4057 while (rIndex > 0 && rMat.IsString(rIndex-1) &&
4058 aStr == rMat.GetString(rIndex-1))
4059 --rIndex;
4060 else
4061 while (rIndex < nMatCount-1 && rMat.IsString(rIndex+1) &&
4062 aStr == rMat.GetString(rIndex+1))
4063 ++rIndex;
4065 else
4067 DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
4071 void ScInterpreter::ScMatch()
4073 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatch" );
4074 ScMatrixRef pMatSrc = NULL;
4076 BYTE nParamCount = GetByte();
4077 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
4079 double fTyp;
4080 if (nParamCount == 3)
4081 fTyp = GetDouble();
4082 else
4083 fTyp = 1.0;
4084 SCCOL nCol1 = 0;
4085 SCROW nRow1 = 0;
4086 SCTAB nTab1 = 0;
4087 SCCOL nCol2 = 0;
4088 SCROW nRow2 = 0;
4089 SCTAB nTab2 = 0;
4090 if (GetStackType() == svDoubleRef)
4092 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4093 if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
4095 PushIllegalParameter();
4096 return;
4099 else if (GetStackType() == svMatrix)
4101 pMatSrc = PopMatrix();
4102 if (!pMatSrc)
4104 PushIllegalParameter();
4105 return;
4108 else
4110 PushIllegalParameter();
4111 return;
4113 if (nGlobalError == 0)
4115 double fVal;
4116 String sStr;
4117 ScQueryParam rParam;
4118 rParam.nCol1 = nCol1;
4119 rParam.nRow1 = nRow1;
4120 rParam.nCol2 = nCol2;
4121 rParam.nTab = nTab1;
4122 rParam.bMixedComparison = TRUE;
4124 ScQueryEntry& rEntry = rParam.GetEntry(0);
4125 rEntry.bDoQuery = TRUE;
4126 if (fTyp < 0.0)
4127 rEntry.eOp = SC_GREATER_EQUAL;
4128 else if (fTyp > 0.0)
4129 rEntry.eOp = SC_LESS_EQUAL;
4130 switch ( GetStackType() )
4132 case svDouble:
4134 fVal = GetDouble();
4135 rEntry.bQueryByString = FALSE;
4136 rEntry.nVal = fVal;
4138 break;
4139 case svString:
4141 sStr = GetString();
4142 rEntry.bQueryByString = TRUE;
4143 *rEntry.pStr = sStr;
4145 break;
4146 case svDoubleRef :
4147 case svSingleRef :
4149 ScAddress aAdr;
4150 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4152 PushInt(0);
4153 return ;
4155 ScBaseCell* pCell = GetCell( aAdr );
4156 if (HasCellValueData(pCell))
4158 fVal = GetCellValue( aAdr, pCell );
4159 rEntry.bQueryByString = FALSE;
4160 rEntry.nVal = fVal;
4162 else
4164 GetCellString(sStr, pCell);
4165 rEntry.bQueryByString = TRUE;
4166 *rEntry.pStr = sStr;
4169 break;
4170 case svMatrix :
4172 ScMatValType nType = GetDoubleOrStringFromMatrix(
4173 rEntry.nVal, *rEntry.pStr);
4174 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
4176 break;
4177 default:
4179 PushIllegalParameter();
4180 return;
4183 if ( rEntry.bQueryByString )
4185 BOOL bIsVBAMode = FALSE;
4186 if ( pDok )
4188 SfxObjectShell* pDocSh = pDok->GetDocumentShell();
4189 if ( pDocSh )
4190 bIsVBAMode = pDocSh->GetBasic()->isVBAEnabled();
4192 // #TODO handle MSO wildcards
4193 if ( bIsVBAMode )
4194 rParam.bRegExp = FALSE;
4195 else
4196 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4199 if (pMatSrc) // The source data is matrix array.
4201 SCSIZE nC, nR;
4202 pMatSrc->GetDimensions( nC, nR);
4203 if (nC > 1 && nR > 1)
4205 // The source matrix must be a vector.
4206 PushIllegalParameter();
4207 return;
4209 SCSIZE nMatCount = (nC == 1) ? nR : nC;
4211 // simple serial search for equality mode (source data doesn't
4212 // need to be sorted).
4214 if (rEntry.eOp == SC_EQUAL)
4216 for (SCSIZE i = 0; i < nMatCount; ++i)
4218 if (lcl_CompareMatrix2Query( i, *pMatSrc, rEntry) == 0)
4220 PushDouble(i+1); // found !
4221 return;
4224 PushNA(); // not found
4225 return;
4228 // binary search for non-equality mode (the source data is
4229 // assumed to be sorted).
4231 bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL);
4232 SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0;
4233 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
4235 SCSIZE nMid = nFirst + nLen/2;
4236 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry);
4237 if (nCmp == 0)
4239 // exact match. find the last item with the same value.
4240 lcl_GetLastMatch( nMid, *pMatSrc, nMatCount, !bAscOrder);
4241 PushDouble( nMid+1);
4242 return;
4245 if (nLen == 1) // first and last items are next to each other.
4247 if (nCmp < 0)
4248 nHitIndex = bAscOrder ? nLast : nFirst;
4249 else
4250 nHitIndex = bAscOrder ? nFirst : nLast;
4251 break;
4254 if (nCmp < 0)
4256 if (bAscOrder)
4257 nFirst = nMid;
4258 else
4259 nLast = nMid;
4261 else
4263 if (bAscOrder)
4264 nLast = nMid;
4265 else
4266 nFirst = nMid;
4270 if (nHitIndex == nMatCount-1) // last item
4272 sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry);
4273 if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
4275 // either the last item is an exact match or the real
4276 // hit is beyond the last item.
4277 PushDouble( nHitIndex+1);
4278 return;
4282 if (nHitIndex > 0) // valid hit must be 2nd item or higher
4284 PushDouble( nHitIndex); // non-exact match
4285 return;
4288 PushNA();
4289 return;
4292 SCCOLROW nDelta = 0;
4293 if (nCol1 == nCol2)
4294 { // search row in column
4295 rParam.nRow2 = nRow2;
4296 rEntry.nField = nCol1;
4297 ScAddress aResultPos( nCol1, nRow1, nTab1);
4298 if (!LookupQueryWithCache( aResultPos, rParam))
4300 PushNA();
4301 return;
4303 nDelta = aResultPos.Row() - nRow1;
4305 else
4306 { // search column in row
4307 SCCOL nC;
4308 rParam.bByRow = FALSE;
4309 rParam.nRow2 = nRow1;
4310 rEntry.nField = nCol1;
4311 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
4312 // Advance Entry.nField in Iterator if column changed
4313 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
4314 if (fTyp == 0.0)
4315 { // EQUAL
4316 if ( aCellIter.GetFirst() )
4317 nC = aCellIter.GetCol();
4318 else
4320 PushNA();
4321 return;
4324 else
4325 { // <= or >=
4326 SCROW nR;
4327 if ( !aCellIter.FindEqualOrSortedLastInRange( nC, nR ) )
4329 PushNA();
4330 return;
4333 nDelta = nC - nCol1;
4335 PushDouble((double) (nDelta + 1));
4337 else
4338 PushIllegalParameter();
4343 void ScInterpreter::ScCountEmptyCells()
4345 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountEmptyCells" );
4346 if ( MustHaveParamCount( GetByte(), 1 ) )
4348 ULONG nMaxCount = 0, nCount = 0;
4349 CellType eCellType;
4350 switch (GetStackType())
4352 case svSingleRef :
4354 nMaxCount = 1;
4355 ScAddress aAdr;
4356 PopSingleRef( aAdr );
4357 eCellType = GetCellType( GetCell( aAdr ) );
4358 if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
4359 nCount = 1;
4361 break;
4362 case svDoubleRef :
4363 case svRefList :
4365 ScRange aRange;
4366 short nParam = 1;
4367 size_t nRefInList = 0;
4368 while (nParam-- > 0)
4370 PopDoubleRef( aRange, nParam, nRefInList);
4371 nMaxCount +=
4372 static_cast<ULONG>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) *
4373 static_cast<ULONG>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) *
4374 static_cast<ULONG>(aRange.aEnd.Tab() - aRange.aStart.Tab() + 1);
4375 ScBaseCell* pCell;
4376 ScCellIterator aDocIter( pDok, aRange, glSubTotal);
4377 if ( (pCell = aDocIter.GetFirst()) != NULL )
4381 if ((eCellType = pCell->GetCellType()) != CELLTYPE_NONE
4382 && eCellType != CELLTYPE_NOTE)
4383 nCount++;
4384 } while ( (pCell = aDocIter.GetNext()) != NULL );
4388 break;
4389 default : SetError(errIllegalParameter); break;
4391 PushDouble(nMaxCount - nCount);
4396 void ScInterpreter::ScCountIf()
4398 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountIf" );
4399 if ( MustHaveParamCount( GetByte(), 2 ) )
4401 String rString;
4402 double fVal = 0.0;
4403 BOOL bIsString = TRUE;
4404 switch ( GetStackType() )
4406 case svDoubleRef :
4407 case svSingleRef :
4409 ScAddress aAdr;
4410 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4412 PushInt(0);
4413 return ;
4415 ScBaseCell* pCell = GetCell( aAdr );
4416 switch ( GetCellType( pCell ) )
4418 case CELLTYPE_VALUE :
4419 fVal = GetCellValue( aAdr, pCell );
4420 bIsString = FALSE;
4421 break;
4422 case CELLTYPE_FORMULA :
4423 if( ((ScFormulaCell*)pCell)->IsValue() )
4425 fVal = GetCellValue( aAdr, pCell );
4426 bIsString = FALSE;
4428 else
4429 GetCellString(rString, pCell);
4430 break;
4431 case CELLTYPE_STRING :
4432 case CELLTYPE_EDIT :
4433 GetCellString(rString, pCell);
4434 break;
4435 default:
4436 fVal = 0.0;
4437 bIsString = FALSE;
4440 break;
4441 case svMatrix :
4443 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
4444 rString);
4445 bIsString = ScMatrix::IsNonValueType( nType);
4447 break;
4448 case svString:
4449 rString = GetString();
4450 break;
4451 default:
4453 fVal = GetDouble();
4454 bIsString = FALSE;
4457 double fSum = 0.0;
4458 short nParam = 1;
4459 size_t nRefInList = 0;
4460 while (nParam-- > 0)
4462 SCCOL nCol1;
4463 SCROW nRow1;
4464 SCTAB nTab1;
4465 SCCOL nCol2;
4466 SCROW nRow2;
4467 SCTAB nTab2;
4468 ScMatrixRef pQueryMatrix;
4469 switch ( GetStackType() )
4471 case svDoubleRef :
4472 case svRefList :
4474 ScRange aRange;
4475 PopDoubleRef( aRange, nParam, nRefInList);
4476 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4478 break;
4479 case svSingleRef :
4480 PopSingleRef( nCol1, nRow1, nTab1 );
4481 nCol2 = nCol1;
4482 nRow2 = nRow1;
4483 nTab2 = nTab1;
4484 break;
4485 case svMatrix:
4487 pQueryMatrix = PopMatrix();
4488 if (!pQueryMatrix)
4490 PushIllegalParameter();
4491 return;
4493 nCol1 = 0;
4494 nRow1 = 0;
4495 nTab1 = 0;
4496 SCSIZE nC, nR;
4497 pQueryMatrix->GetDimensions( nC, nR);
4498 nCol2 = static_cast<SCCOL>(nC - 1);
4499 nRow2 = static_cast<SCROW>(nR - 1);
4500 nTab2 = 0;
4502 break;
4503 default:
4504 PushIllegalParameter();
4505 return ;
4507 if ( nTab1 != nTab2 )
4509 PushIllegalParameter();
4510 return;
4512 if (nCol1 > nCol2)
4514 PushIllegalParameter();
4515 return;
4517 if (nGlobalError == 0)
4519 ScQueryParam rParam;
4520 rParam.nRow1 = nRow1;
4521 rParam.nRow2 = nRow2;
4523 ScQueryEntry& rEntry = rParam.GetEntry(0);
4524 rEntry.bDoQuery = TRUE;
4525 if (!bIsString)
4527 rEntry.bQueryByString = FALSE;
4528 rEntry.nVal = fVal;
4529 rEntry.eOp = SC_EQUAL;
4531 else
4533 rParam.FillInExcelSyntax(rString, 0);
4534 sal_uInt32 nIndex = 0;
4535 rEntry.bQueryByString =
4536 !(pFormatter->IsNumberFormat(
4537 *rEntry.pStr, nIndex, rEntry.nVal));
4538 if ( rEntry.bQueryByString )
4539 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4541 rParam.nCol1 = nCol1;
4542 rParam.nCol2 = nCol2;
4543 rEntry.nField = nCol1;
4544 if (pQueryMatrix)
4546 // Never case-sensitive.
4547 ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
4548 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
4549 if (nGlobalError || !pResultMatrix)
4551 PushIllegalParameter();
4552 return;
4555 SCSIZE nSize = pResultMatrix->GetElementCount();
4556 for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
4558 if (pResultMatrix->IsValue( nIndex) &&
4559 pResultMatrix->GetDouble( nIndex))
4560 ++fSum;
4563 else
4565 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
4566 // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
4567 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
4568 if ( aCellIter.GetFirst() )
4572 fSum++;
4573 } while ( aCellIter.GetNext() );
4577 else
4579 PushIllegalParameter();
4580 return;
4583 PushDouble(fSum);
4588 void ScInterpreter::ScSumIf()
4590 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumIf" );
4591 BYTE nParamCount = GetByte();
4592 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
4594 SCCOL nCol3 = 0;
4595 SCROW nRow3 = 0;
4596 SCTAB nTab3 = 0;
4598 ScMatrixRef pSumExtraMatrix;
4599 bool bSumExtraRange = (nParamCount == 3);
4600 if (bSumExtraRange)
4602 // Save only the upperleft cell in case of cell range. The geometry
4603 // of the 3rd parameter is taken from the 1st parameter.
4605 switch ( GetStackType() )
4607 case svDoubleRef :
4609 SCCOL nColJunk = 0;
4610 SCROW nRowJunk = 0;
4611 SCTAB nTabJunk = 0;
4612 PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
4613 if ( nTabJunk != nTab3 )
4615 PushIllegalParameter();
4616 return;
4619 break;
4620 case svSingleRef :
4621 PopSingleRef( nCol3, nRow3, nTab3 );
4622 break;
4623 case svMatrix:
4624 pSumExtraMatrix = PopMatrix();
4625 //! nCol3, nRow3, nTab3 remain 0
4626 break;
4627 default:
4628 PushIllegalParameter();
4629 return ;
4632 String rString;
4633 double fVal = 0.0;
4634 BOOL bIsString = TRUE;
4635 switch ( GetStackType() )
4637 case svDoubleRef :
4638 case svSingleRef :
4640 ScAddress aAdr;
4641 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4643 PushInt(0);
4644 return ;
4646 ScBaseCell* pCell = GetCell( aAdr );
4647 switch ( GetCellType( pCell ) )
4649 case CELLTYPE_VALUE :
4650 fVal = GetCellValue( aAdr, pCell );
4651 bIsString = FALSE;
4652 break;
4653 case CELLTYPE_FORMULA :
4654 if( ((ScFormulaCell*)pCell)->IsValue() )
4656 fVal = GetCellValue( aAdr, pCell );
4657 bIsString = FALSE;
4659 else
4660 GetCellString(rString, pCell);
4661 break;
4662 case CELLTYPE_STRING :
4663 case CELLTYPE_EDIT :
4664 GetCellString(rString, pCell);
4665 break;
4666 default:
4667 fVal = 0.0;
4668 bIsString = FALSE;
4671 break;
4672 case svString:
4673 rString = GetString();
4674 break;
4675 case svMatrix :
4677 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
4678 rString);
4679 bIsString = ScMatrix::IsNonValueType( nType);
4681 break;
4682 default:
4684 fVal = GetDouble();
4685 bIsString = FALSE;
4689 double fSum = 0.0;
4690 double fMem = 0.0;
4691 BOOL bNull = TRUE;
4692 short nParam = 1;
4693 size_t nRefInList = 0;
4694 while (nParam-- > 0)
4696 SCCOL nCol1;
4697 SCROW nRow1;
4698 SCTAB nTab1;
4699 SCCOL nCol2;
4700 SCROW nRow2;
4701 SCTAB nTab2;
4702 ScMatrixRef pQueryMatrix;
4703 switch ( GetStackType() )
4705 case svRefList :
4706 if (bSumExtraRange)
4708 PushIllegalParameter();
4709 return;
4711 else
4713 ScRange aRange;
4714 PopDoubleRef( aRange, nParam, nRefInList);
4715 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4717 break;
4718 case svDoubleRef :
4719 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
4720 break;
4721 case svSingleRef :
4722 PopSingleRef( nCol1, nRow1, nTab1 );
4723 nCol2 = nCol1;
4724 nRow2 = nRow1;
4725 nTab2 = nTab1;
4726 break;
4727 case svMatrix:
4729 pQueryMatrix = PopMatrix();
4730 if (!pQueryMatrix)
4732 PushIllegalParameter();
4733 return;
4735 nCol1 = 0;
4736 nRow1 = 0;
4737 nTab1 = 0;
4738 SCSIZE nC, nR;
4739 pQueryMatrix->GetDimensions( nC, nR);
4740 nCol2 = static_cast<SCCOL>(nC - 1);
4741 nRow2 = static_cast<SCROW>(nR - 1);
4742 nTab2 = 0;
4744 break;
4745 default:
4746 PushIllegalParameter();
4747 return ;
4749 if ( nTab1 != nTab2 )
4751 PushIllegalArgument();
4752 return;
4755 if (bSumExtraRange)
4757 // Take the range geometry of the 1st parameter and apply it to
4758 // the 3rd. If parts of the resulting range would point outside
4759 // the sheet, don't complain but silently ignore and simply cut
4760 // them away, this is what Xcl does :-/
4762 // For the cut-away part we also don't need to determine the
4763 // criteria match, so shrink the source range accordingly,
4764 // instead of the result range.
4765 SCCOL nColDelta = nCol2 - nCol1;
4766 SCROW nRowDelta = nRow2 - nRow1;
4767 SCCOL nMaxCol;
4768 SCROW nMaxRow;
4769 if (pSumExtraMatrix)
4771 SCSIZE nC, nR;
4772 pSumExtraMatrix->GetDimensions( nC, nR);
4773 nMaxCol = static_cast<SCCOL>(nC - 1);
4774 nMaxRow = static_cast<SCROW>(nR - 1);
4776 else
4778 nMaxCol = MAXCOL;
4779 nMaxRow = MAXROW;
4781 if (nCol3 + nColDelta > nMaxCol)
4783 SCCOL nNewDelta = nMaxCol - nCol3;
4784 nCol2 = nCol1 + nNewDelta;
4787 if (nRow3 + nRowDelta > nMaxRow)
4789 SCROW nNewDelta = nMaxRow - nRow3;
4790 nRow2 = nRow1 + nNewDelta;
4793 else
4795 nCol3 = nCol1;
4796 nRow3 = nRow1;
4797 nTab3 = nTab1;
4800 if (nGlobalError == 0)
4802 ScQueryParam rParam;
4803 rParam.nRow1 = nRow1;
4804 rParam.nRow2 = nRow2;
4806 ScQueryEntry& rEntry = rParam.GetEntry(0);
4807 rEntry.bDoQuery = TRUE;
4808 if (!bIsString)
4810 rEntry.bQueryByString = FALSE;
4811 rEntry.nVal = fVal;
4812 rEntry.eOp = SC_EQUAL;
4814 else
4816 rParam.FillInExcelSyntax(rString, 0);
4817 sal_uInt32 nIndex = 0;
4818 rEntry.bQueryByString =
4819 !(pFormatter->IsNumberFormat(
4820 *rEntry.pStr, nIndex, rEntry.nVal));
4821 if ( rEntry.bQueryByString )
4822 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4824 ScAddress aAdr;
4825 aAdr.SetTab( nTab3 );
4826 rParam.nCol1 = nCol1;
4827 rParam.nCol2 = nCol2;
4828 rEntry.nField = nCol1;
4829 SCsCOL nColDiff = nCol3 - nCol1;
4830 SCsROW nRowDiff = nRow3 - nRow1;
4831 if (pQueryMatrix)
4833 // Never case-sensitive.
4834 ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
4835 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
4836 if (nGlobalError || !pResultMatrix)
4838 PushIllegalParameter();
4839 return;
4842 if (pSumExtraMatrix)
4844 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
4846 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
4848 if (pResultMatrix->IsValue( nCol, nRow) &&
4849 pResultMatrix->GetDouble( nCol, nRow))
4851 SCSIZE nC = nCol + nColDiff;
4852 SCSIZE nR = nRow + nRowDiff;
4853 if (pSumExtraMatrix->IsValue( nC, nR))
4855 fVal = pSumExtraMatrix->GetDouble( nC, nR);
4856 if ( bNull && fVal != 0.0 )
4858 bNull = FALSE;
4859 fMem = fVal;
4861 else
4862 fSum += fVal;
4868 else
4870 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
4872 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
4874 if (pResultMatrix->GetDouble( nCol, nRow))
4876 aAdr.SetCol( nCol + nColDiff);
4877 aAdr.SetRow( nRow + nRowDiff);
4878 ScBaseCell* pCell = GetCell( aAdr );
4879 if ( HasCellValueData(pCell) )
4881 fVal = GetCellValue( aAdr, pCell );
4882 if ( bNull && fVal != 0.0 )
4884 bNull = FALSE;
4885 fMem = fVal;
4887 else
4888 fSum += fVal;
4895 else
4897 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
4898 // Increment Entry.nField in iterator when switching to next column.
4899 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
4900 if ( aCellIter.GetFirst() )
4902 if (pSumExtraMatrix)
4906 SCSIZE nC = aCellIter.GetCol() + nColDiff;
4907 SCSIZE nR = aCellIter.GetRow() + nRowDiff;
4908 if (pSumExtraMatrix->IsValue( nC, nR))
4910 fVal = pSumExtraMatrix->GetDouble( nC, nR);
4911 if ( bNull && fVal != 0.0 )
4913 bNull = FALSE;
4914 fMem = fVal;
4916 else
4917 fSum += fVal;
4919 } while ( aCellIter.GetNext() );
4921 else
4925 aAdr.SetCol( aCellIter.GetCol() + nColDiff);
4926 aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
4927 ScBaseCell* pCell = GetCell( aAdr );
4928 if ( HasCellValueData(pCell) )
4930 fVal = GetCellValue( aAdr, pCell );
4931 if ( bNull && fVal != 0.0 )
4933 bNull = FALSE;
4934 fMem = fVal;
4936 else
4937 fSum += fVal;
4939 } while ( aCellIter.GetNext() );
4944 else
4946 PushIllegalParameter();
4947 return;
4950 PushDouble( ::rtl::math::approxAdd( fSum, fMem ) );
4955 void ScInterpreter::ScLookup()
4957 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLookup" );
4958 BYTE nParamCount = GetByte();
4959 if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
4960 return ;
4962 ScMatrixRef pDataMat = NULL, pResMat = NULL;
4963 SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
4964 SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
4965 SCTAB nTab1 = 0, nResTab = 0;
4966 SCSIZE nLenMajor = 0; // length of major direction
4967 bool bVertical = true; // whether to lookup vertically or horizontally
4969 // The third parameter, result array, for double, string and single reference.
4970 double fResVal = 0.0;
4971 String aResStr;
4972 ScAddress aResAdr;
4973 StackVar eResArrayType = svUnknown;
4975 if (nParamCount == 3)
4977 eResArrayType = GetStackType();
4978 switch (eResArrayType)
4980 case svDoubleRef:
4982 SCTAB nTabJunk;
4983 PopDoubleRef(nResCol1, nResRow1, nResTab,
4984 nResCol2, nResRow2, nTabJunk);
4985 if (nResTab != nTabJunk ||
4986 ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
4988 // The result array must be a vector.
4989 PushIllegalParameter();
4990 return;
4993 break;
4994 case svMatrix:
4996 pResMat = PopMatrix();
4997 if (!pResMat)
4999 PushIllegalParameter();
5000 return;
5002 SCSIZE nC, nR;
5003 pResMat->GetDimensions(nC, nR);
5004 if (nC != 1 && nR != 1)
5006 // Result matrix must be a vector.
5007 PushIllegalParameter();
5008 return;
5011 break;
5012 case svDouble:
5013 fResVal = GetDouble();
5014 break;
5015 case svString:
5016 aResStr = GetString();
5017 break;
5018 case svSingleRef:
5019 PopSingleRef( aResAdr );
5020 break;
5021 default:
5022 PushIllegalParameter();
5023 return;
5027 // For double, string and single reference.
5028 double fDataVal = 0.0;
5029 String aDataStr;
5030 ScAddress aDataAdr;
5031 bool bValueData = false;
5033 // Get the data-result range and also determine whether this is vertical
5034 // lookup or horizontal lookup.
5036 StackVar eDataArrayType = GetStackType();
5037 switch (eDataArrayType)
5039 case svDoubleRef:
5041 SCTAB nTabJunk;
5042 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
5043 if (nTab1 != nTabJunk)
5045 PushIllegalParameter();
5046 return;
5048 bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
5049 nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
5051 break;
5052 case svMatrix:
5054 pDataMat = PopMatrix();
5055 if (!pDataMat)
5057 PushIllegalParameter();
5058 return;
5061 SCSIZE nC, nR;
5062 pDataMat->GetDimensions(nC, nR);
5063 bVertical = (nR >= nC);
5064 nLenMajor = bVertical ? nR : nC;
5066 break;
5067 case svDouble:
5069 fDataVal = GetDouble();
5070 bValueData = true;
5072 break;
5073 case svString:
5075 aDataStr = GetString();
5077 break;
5078 case svSingleRef:
5080 PopSingleRef( aDataAdr );
5081 const ScBaseCell* pDataCell = GetCell( aDataAdr );
5082 if (HasCellEmptyData( pDataCell))
5084 // Empty cells aren't found anywhere, bail out early.
5085 SetError( NOTAVAILABLE);
5087 else if (HasCellValueData( pDataCell))
5089 fDataVal = GetCellValue( aDataAdr, pDataCell );
5090 bValueData = true;
5092 else
5093 GetCellString( aDataStr, pDataCell );
5095 break;
5096 default:
5097 SetError( errIllegalParameter);
5101 if (nGlobalError)
5103 PushError( nGlobalError);
5104 return;
5107 // Get the lookup value.
5109 ScQueryParam aParam;
5110 ScQueryEntry& rEntry = aParam.GetEntry(0);
5111 if ( !FillEntry(rEntry) )
5112 return;
5114 if ( eDataArrayType == svDouble || eDataArrayType == svString ||
5115 eDataArrayType == svSingleRef )
5117 // Delta position for a single value is always 0.
5119 // Found if data <= query, but not if query is string and found data is
5120 // numeric or vice versa. This is how Excel does it but doesn't
5121 // document it.
5123 bool bFound = false;
5124 if ( bValueData )
5126 if ( rEntry.bQueryByString )
5127 bFound = false;
5128 else
5129 bFound = (fDataVal <= rEntry.nVal);
5131 else
5133 if ( !rEntry.bQueryByString )
5134 bFound = false;
5135 else
5136 bFound = (ScGlobal::GetCollator()->compareString( aDataStr, *rEntry.pStr) <= 0);
5139 if (!bFound)
5141 PushNA();
5142 return;
5145 if (pResMat)
5147 if (pResMat->IsValue( 0 ))
5148 PushDouble(pResMat->GetDouble( 0 ));
5149 else
5150 PushString(pResMat->GetString( 0 ));
5152 else if (nParamCount == 3)
5154 switch (eResArrayType)
5156 case svDouble:
5157 PushDouble( fResVal );
5158 break;
5159 case svString:
5160 PushString( aResStr );
5161 break;
5162 case svDoubleRef:
5163 aResAdr.Set( nResCol1, nResRow1, nResTab);
5164 // fallthru
5165 case svSingleRef:
5166 PushCellResultToken( true, aResAdr, NULL, NULL);
5167 break;
5168 default:
5169 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
5172 else
5174 switch (eDataArrayType)
5176 case svDouble:
5177 PushDouble( fDataVal );
5178 break;
5179 case svString:
5180 PushString( aDataStr );
5181 break;
5182 case svSingleRef:
5183 PushCellResultToken( true, aDataAdr, NULL, NULL);
5184 break;
5185 default:
5186 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
5189 return;
5192 // Now, perform the search to compute the delta position (nDelta).
5194 if (pDataMat)
5196 // Data array is given as a matrix.
5197 rEntry.bDoQuery = true;
5198 rEntry.eOp = SC_LESS_EQUAL;
5199 bool bFound = false;
5201 SCSIZE nC, nR;
5202 pDataMat->GetDimensions(nC, nR);
5204 // In case of non-vector matrix, only search the first row or column.
5205 ScMatrixRef pDataMat2;
5206 if (bVertical)
5208 ScMatrixRef pTempMat(new ScMatrix(1, nR));
5209 for (SCSIZE i = 0; i < nR; ++i)
5210 if (pDataMat->IsValue(0, i))
5211 pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
5212 else
5213 pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
5214 pDataMat2 = pTempMat;
5216 else
5218 ScMatrixRef pTempMat(new ScMatrix(nC, 1));
5219 for (SCSIZE i = 0; i < nC; ++i)
5220 if (pDataMat->IsValue(i, 0))
5221 pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
5222 else
5223 pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
5224 pDataMat2 = pTempMat;
5227 // binary search for non-equality mode (the source data is
5228 // assumed to be sorted in ascending order).
5230 SCCOLROW nDelta = -1;
5232 SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
5233 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
5235 SCSIZE nMid = nFirst + nLen/2;
5236 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry);
5237 if (nCmp == 0)
5239 // exact match. find the last item with the same value.
5240 lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false);
5241 nDelta = nMid;
5242 bFound = true;
5243 break;
5246 if (nLen == 1) // first and last items are next to each other.
5248 nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
5249 // If already the 1st item is greater there's nothing found.
5250 bFound = (nDelta >= 0);
5251 break;
5254 if (nCmp < 0)
5255 nFirst = nMid;
5256 else
5257 nLast = nMid;
5260 if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
5262 sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry);
5263 if (nCmp <= 0)
5265 // either the last item is an exact match or the real
5266 // hit is beyond the last item.
5267 nDelta += 1;
5268 bFound = true;
5271 else if (nDelta > 0) // valid hit must be 2nd item or higher
5273 // non-exact match
5274 bFound = true;
5277 // With 0-9 < A-Z, if query is numeric and data found is string, or
5278 // vice versa, the (yet another undocumented) Excel behavior is to
5279 // return #N/A instead.
5281 if (bFound)
5283 SCCOLROW i = nDelta;
5284 SCSIZE n = pDataMat->GetElementCount();
5285 if (static_cast<SCSIZE>(i) >= n)
5286 i = static_cast<SCCOLROW>(n);
5287 if (bool(rEntry.bQueryByString) == bool(pDataMat->IsValue(i)))
5288 bFound = false;
5291 if (!bFound)
5293 PushNA();
5294 return;
5297 // Now that we've found the delta, push the result back to the cell.
5299 if (pResMat)
5301 // result array is matrix.
5302 if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount())
5304 PushNA();
5305 return;
5307 if (pResMat->IsValue(nDelta))
5308 PushDouble(pResMat->GetDouble(nDelta));
5309 else
5310 PushString(pResMat->GetString(nDelta));
5312 else if (nParamCount == 3)
5314 // result array is cell range.
5315 ScAddress aAdr;
5316 aAdr.SetTab(nResTab);
5317 bool bResVertical = (nResRow2 - nResRow1) > 0;
5318 if (bResVertical)
5320 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
5321 if (nTempRow > MAXROW)
5323 PushDouble(0);
5324 return;
5326 aAdr.SetCol(nResCol1);
5327 aAdr.SetRow(nTempRow);
5329 else
5331 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
5332 if (nTempCol > MAXCOL)
5334 PushDouble(0);
5335 return;
5337 aAdr.SetCol(nTempCol);
5338 aAdr.SetRow(nResRow1);
5340 PushCellResultToken(true, aAdr, NULL, NULL);
5342 else
5344 // no result array. Use the data array to get the final value from.
5345 if (bVertical)
5347 if (pDataMat->IsValue(nC-1, nDelta))
5348 PushDouble(pDataMat->GetDouble(nC-1, nDelta));
5349 else
5350 PushString(pDataMat->GetString(nC-1, nDelta));
5352 else
5354 if (pDataMat->IsValue(nDelta, nR-1))
5355 PushDouble(pDataMat->GetDouble(nDelta, nR-1));
5356 else
5357 PushString(pDataMat->GetString(nDelta, nR-1));
5361 return;
5364 // Perform cell range search.
5366 aParam.nCol1 = nCol1;
5367 aParam.nRow1 = nRow1;
5368 aParam.nCol2 = bVertical ? nCol1 : nCol2;
5369 aParam.nRow2 = bVertical ? nRow2 : nRow1;
5370 aParam.bByRow = bVertical;
5371 aParam.bMixedComparison = true;
5373 rEntry.bDoQuery = TRUE;
5374 rEntry.eOp = SC_LESS_EQUAL;
5375 rEntry.nField = nCol1;
5376 if ( rEntry.bQueryByString )
5377 aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5379 ScQueryCellIterator aCellIter(pDok, nTab1, aParam, FALSE);
5380 SCCOL nC;
5381 SCROW nR;
5382 // Advance Entry.nField in iterator upon switching columns if
5383 // lookup in row.
5384 aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
5385 if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
5387 PushNA();
5388 return;
5391 SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
5393 if (pResMat)
5395 // Use the matrix result array.
5396 if (pResMat->IsValue(nDelta))
5397 PushDouble(pResMat->GetDouble(nDelta));
5398 else
5399 PushString(pResMat->GetString(nDelta));
5401 else if (nParamCount == 3)
5403 switch (eResArrayType)
5405 case svDoubleRef:
5407 // Use the result array vector. Note that the result array is assumed
5408 // to be a vector (i.e. 1-dimensinoal array).
5410 ScAddress aAdr;
5411 aAdr.SetTab(nResTab);
5412 bool bResVertical = (nResRow2 - nResRow1) > 0;
5413 if (bResVertical)
5415 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
5416 if (nTempRow > MAXROW)
5418 PushDouble(0);
5419 return;
5421 aAdr.SetCol(nResCol1);
5422 aAdr.SetRow(nTempRow);
5424 else
5426 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
5427 if (nTempCol > MAXCOL)
5429 PushDouble(0);
5430 return;
5432 aAdr.SetCol(nTempCol);
5433 aAdr.SetRow(nResRow1);
5435 PushCellResultToken( true, aAdr, NULL, NULL);
5437 break;
5438 case svDouble:
5439 case svString:
5440 case svSingleRef:
5442 if (nDelta != 0)
5443 PushNA();
5444 else
5446 switch (eResArrayType)
5448 case svDouble:
5449 PushDouble( fResVal );
5450 break;
5451 case svString:
5452 PushString( aResStr );
5453 break;
5454 case svSingleRef:
5455 PushCellResultToken( true, aResAdr, NULL, NULL);
5456 break;
5457 default:
5458 ; // nothing
5462 break;
5463 default:
5464 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
5467 else
5469 // Regardless of whether or not the result array exists, the last
5470 // array is always used as the "result" array.
5472 ScAddress aAdr;
5473 aAdr.SetTab(nTab1);
5474 if (bVertical)
5476 SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
5477 if (nTempRow > MAXROW)
5479 PushDouble(0);
5480 return;
5482 aAdr.SetCol(nCol2);
5483 aAdr.SetRow(nTempRow);
5485 else
5487 SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
5488 if (nTempCol > MAXCOL)
5490 PushDouble(0);
5491 return;
5493 aAdr.SetCol(nTempCol);
5494 aAdr.SetRow(nRow2);
5496 PushCellResultToken(true, aAdr, NULL, NULL);
5501 void ScInterpreter::ScHLookup()
5503 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHLookup" );
5504 CalculateLookup(TRUE);
5506 void ScInterpreter::CalculateLookup(BOOL HLookup)
5508 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateLookup" );
5509 BYTE nParamCount = GetByte();
5510 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
5512 BOOL bSorted;
5513 if (nParamCount == 4)
5514 bSorted = GetBool();
5515 else
5516 bSorted = TRUE;
5517 double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
5518 ScMatrixRef pMat = NULL;
5519 SCSIZE nC = 0, nR = 0;
5520 SCCOL nCol1 = 0;
5521 SCROW nRow1 = 0;
5522 SCTAB nTab1 = 0;
5523 SCCOL nCol2 = 0;
5524 SCROW nRow2 = 0;
5525 SCTAB nTab2;
5526 if (GetStackType() == svDoubleRef)
5528 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
5529 if (nTab1 != nTab2)
5531 PushIllegalParameter();
5532 return;
5535 else if (GetStackType() == svMatrix)
5537 pMat = PopMatrix();
5538 if (pMat)
5539 pMat->GetDimensions(nC, nR);
5540 else
5542 PushIllegalParameter();
5543 return;
5546 else
5548 PushIllegalParameter();
5549 return;
5551 if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
5553 PushIllegalArgument();
5554 return;
5556 SCROW nZIndex = static_cast<SCROW>(fIndex);
5557 SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
5559 if (!pMat)
5561 nZIndex += nRow1; // Wertzeile
5562 nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 ); // value column
5565 if (nGlobalError == 0)
5567 ScQueryParam rParam;
5568 rParam.nCol1 = nCol1;
5569 rParam.nRow1 = nRow1;
5570 if ( HLookup )
5572 rParam.nCol2 = nCol2;
5573 rParam.nRow2 = nRow1; // nur in der ersten Zeile suchen
5574 rParam.bByRow = FALSE;
5575 } // if ( HLookup )
5576 else
5578 rParam.nCol2 = nCol1; // nur in der ersten Spalte suchen
5579 rParam.nRow2 = nRow2;
5580 rParam.nTab = nTab1;
5582 rParam.bMixedComparison = TRUE;
5584 ScQueryEntry& rEntry = rParam.GetEntry(0);
5585 rEntry.bDoQuery = TRUE;
5586 if ( bSorted )
5587 rEntry.eOp = SC_LESS_EQUAL;
5588 if ( !FillEntry(rEntry) )
5589 return;
5590 if ( rEntry.bQueryByString )
5591 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5592 if (pMat)
5594 SCSIZE nMatCount = HLookup ? nC : nR;
5595 SCSIZE nDelta = SCSIZE_MAX;
5596 if (rEntry.bQueryByString)
5598 //!!!!!!!
5599 //! TODO: enable regex on matrix strings
5600 //!!!!!!!
5601 String aParamStr = *rEntry.pStr;
5602 if ( bSorted )
5604 static CollatorWrapper* pCollator = ScGlobal::GetCollator();
5605 for (SCSIZE i = 0; i < nMatCount; i++)
5607 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
5609 sal_Int32 nRes =
5610 pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr);
5611 if (nRes <= 0)
5612 nDelta = i;
5613 else if (i>0) // #i2168# ignore first mismatch
5614 i = nMatCount+1;
5616 else
5617 nDelta = i;
5620 else
5622 for (SCSIZE i = 0; i < nMatCount; i++)
5624 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
5626 if ( ScGlobal::GetpTransliteration()->isEqual(
5627 HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr ) )
5629 nDelta = i;
5630 i = nMatCount + 1;
5636 else
5638 if ( bSorted )
5640 // #i2168# ignore strings
5641 for (SCSIZE i = 0; i < nMatCount; i++)
5643 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
5645 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rEntry.nVal)
5646 nDelta = i;
5647 else
5648 i = nMatCount+1;
5652 else
5654 for (SCSIZE i = 0; i < nMatCount; i++)
5656 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
5658 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) == rEntry.nVal)
5660 nDelta = i;
5661 i = nMatCount + 1;
5667 if ( nDelta != SCSIZE_MAX )
5669 SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
5670 SCSIZE nY = nDelta;
5671 if ( HLookup )
5673 nX = nDelta;
5674 nY = static_cast<SCSIZE>(nZIndex);
5676 if ( pMat->IsString( nX, nY) )
5677 PushString(pMat->GetString( nX,nY));
5678 else
5679 PushDouble(pMat->GetDouble( nX,nY));
5681 else
5682 PushNA();
5684 else
5686 rEntry.nField = nCol1;
5687 BOOL bFound = FALSE;
5688 SCCOL nCol = 0;
5689 SCROW nRow = 0;
5690 if ( bSorted )
5691 rEntry.eOp = SC_LESS_EQUAL;
5692 if ( HLookup )
5694 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
5695 // advance Entry.nField in Iterator upon switching columns
5696 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
5697 if ( bSorted )
5699 SCROW nRow1_temp;
5700 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
5702 else if ( aCellIter.GetFirst() )
5704 bFound = TRUE;
5705 nCol = aCellIter.GetCol();
5707 nRow = nZIndex;
5708 } // if ( HLookup )
5709 else
5711 ScAddress aResultPos( nCol1, nRow1, nTab1);
5712 bFound = LookupQueryWithCache( aResultPos, rParam);
5713 nRow = aResultPos.Row();
5714 nCol = nSpIndex;
5716 if ( bFound )
5718 ScAddress aAdr( nCol, nRow, nTab1 );
5719 PushCellResultToken( true, aAdr, NULL, NULL);
5721 else
5722 PushNA();
5725 else
5726 PushIllegalParameter();
5730 bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
5732 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::FillEntry" );
5733 switch ( GetStackType() )
5735 case svDouble:
5737 rEntry.bQueryByString = FALSE;
5738 rEntry.nVal = GetDouble();
5740 break;
5741 case svString:
5743 const String sStr = GetString();
5744 rEntry.bQueryByString = TRUE;
5745 *rEntry.pStr = sStr;
5747 break;
5748 case svDoubleRef :
5749 case svSingleRef :
5751 ScAddress aAdr;
5752 if ( !PopDoubleRefOrSingleRef( aAdr ) )
5754 PushInt(0);
5755 return false;
5757 ScBaseCell* pCell = GetCell( aAdr );
5758 if (HasCellValueData(pCell))
5760 rEntry.bQueryByString = FALSE;
5761 rEntry.nVal = GetCellValue( aAdr, pCell );
5763 else
5765 if ( GetCellType( pCell ) == CELLTYPE_NOTE )
5767 rEntry.bQueryByString = FALSE;
5768 rEntry.nVal = 0.0;
5770 else
5772 String sStr;
5773 GetCellString(sStr, pCell);
5774 rEntry.bQueryByString = TRUE;
5775 *rEntry.pStr = sStr;
5779 break;
5780 case svMatrix :
5782 const ScMatValType nType = GetDoubleOrStringFromMatrix(rEntry.nVal, *rEntry.pStr);
5783 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
5785 break;
5786 default:
5788 PushIllegalParameter();
5789 return false;
5791 } // switch ( GetStackType() )
5792 return true;
5794 void ScInterpreter::ScVLookup()
5796 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVLookup" );
5797 CalculateLookup(FALSE);
5800 #if defined(WIN) && defined(MSC)
5801 #pragma optimize("",off)
5802 #endif
5804 void ScInterpreter::ScSubTotal()
5806 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubTotal" );
5807 BYTE nParamCount = GetByte();
5808 if ( MustHaveParamCountMin( nParamCount, 2 ) )
5810 // We must fish the 1st parameter deep from the stack! And push it on top.
5811 const FormulaToken* p = pStack[ sp - nParamCount ];
5812 PushTempToken( *p );
5813 int nFunc = (int) ::rtl::math::approxFloor( GetDouble() );
5814 if( nFunc < 1 || nFunc > 11 )
5815 PushIllegalArgument(); // simulate return on stack, not SetError(...)
5816 else
5818 cPar = nParamCount - 1;
5819 glSubTotal = TRUE;
5820 switch( nFunc )
5822 case SUBTOTAL_FUNC_AVE : ScAverage(); break;
5823 case SUBTOTAL_FUNC_CNT : ScCount(); break;
5824 case SUBTOTAL_FUNC_CNT2 : ScCount2(); break;
5825 case SUBTOTAL_FUNC_MAX : ScMax(); break;
5826 case SUBTOTAL_FUNC_MIN : ScMin(); break;
5827 case SUBTOTAL_FUNC_PROD : ScProduct(); break;
5828 case SUBTOTAL_FUNC_STD : ScStDev(); break;
5829 case SUBTOTAL_FUNC_STDP : ScStDevP(); break;
5830 case SUBTOTAL_FUNC_SUM : ScSum(); break;
5831 case SUBTOTAL_FUNC_VAR : ScVar(); break;
5832 case SUBTOTAL_FUNC_VARP : ScVarP(); break;
5833 default : PushIllegalArgument(); break;
5835 glSubTotal = FALSE;
5837 // Get rid of the 1st (fished) parameter.
5838 double nVal = GetDouble();
5839 Pop();
5840 PushDouble( nVal );
5843 #if defined(WIN) && defined(MSC)
5844 #pragma optimize("",on)
5845 #endif
5848 ScDBQueryParamBase* ScInterpreter::GetDBParams( BOOL& rMissingField )
5850 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" );
5851 BOOL bAllowMissingField = FALSE;
5852 if ( rMissingField )
5854 bAllowMissingField = TRUE;
5855 rMissingField = FALSE;
5857 if ( GetByte() == 3 )
5859 // First, get the query criteria range.
5860 ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
5861 if (!pQueryRef.get())
5862 return NULL;
5864 BOOL bByVal = TRUE;
5865 double nVal = 0.0;
5866 String aStr;
5867 ScRange aMissingRange;
5868 BOOL bRangeFake = FALSE;
5869 switch (GetStackType())
5871 case svDouble :
5872 nVal = ::rtl::math::approxFloor( GetDouble() );
5873 if ( bAllowMissingField && nVal == 0.0 )
5874 rMissingField = TRUE; // fake missing parameter
5875 break;
5876 case svString :
5877 bByVal = FALSE;
5878 aStr = GetString();
5879 break;
5880 case svSingleRef :
5882 ScAddress aAdr;
5883 PopSingleRef( aAdr );
5884 ScBaseCell* pCell = GetCell( aAdr );
5885 if (HasCellValueData(pCell))
5886 nVal = GetCellValue( aAdr, pCell );
5887 else
5889 bByVal = FALSE;
5890 GetCellString(aStr, pCell);
5893 break;
5894 case svDoubleRef :
5895 if ( bAllowMissingField )
5896 { // fake missing parameter for old SO compatibility
5897 bRangeFake = TRUE;
5898 PopDoubleRef( aMissingRange );
5900 else
5902 PopError();
5903 SetError( errIllegalParameter );
5905 break;
5906 case svMissing :
5907 PopError();
5908 if ( bAllowMissingField )
5909 rMissingField = TRUE;
5910 else
5911 SetError( errIllegalParameter );
5912 break;
5913 default:
5914 PopError();
5915 SetError( errIllegalParameter );
5918 auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
5920 if (nGlobalError || !pDBRef.get())
5921 return NULL;
5923 if ( bRangeFake )
5925 // range parameter must match entire database range
5926 if (pDBRef->isRangeEqual(aMissingRange))
5927 rMissingField = TRUE;
5928 else
5929 SetError( errIllegalParameter );
5932 if (nGlobalError)
5933 return NULL;
5935 SCCOL nField = pDBRef->getFirstFieldColumn();
5936 if (rMissingField)
5937 ; // special case
5938 else if (bByVal)
5939 nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal));
5940 else
5942 sal_uInt16 nErr = 0;
5943 nField = pDBRef->findFieldColumn(aStr, &nErr);
5944 SetError(nErr);
5947 if (!ValidCol(nField))
5948 return NULL;
5950 auto_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) );
5952 if (pParam.get())
5954 // An allowed missing field parameter sets the result field
5955 // to any of the query fields, just to be able to return
5956 // some cell from the iterator.
5957 if ( rMissingField )
5958 nField = static_cast<SCCOL>(pParam->GetEntry(0).nField);
5959 pParam->mnField = nField;
5961 SCSIZE nCount = pParam->GetEntryCount();
5962 for ( SCSIZE i=0; i < nCount; i++ )
5964 ScQueryEntry& rEntry = pParam->GetEntry(i);
5965 if ( rEntry.bDoQuery )
5967 sal_uInt32 nIndex = 0;
5968 rEntry.bQueryByString = !pFormatter->IsNumberFormat(
5969 *rEntry.pStr, nIndex, rEntry.nVal );
5970 if ( rEntry.bQueryByString && !pParam->bRegExp )
5971 pParam->bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5973 else
5974 break; // for
5976 return pParam.release();
5979 return false;
5983 void ScInterpreter::DBIterator( ScIterFunc eFunc )
5985 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" );
5986 double nErg = 0.0;
5987 double fMem = 0.0;
5988 BOOL bNull = TRUE;
5989 ULONG nCount = 0;
5990 BOOL bMissingField = FALSE;
5991 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
5992 if (pQueryParam.get())
5994 ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
5995 ScDBQueryDataIterator::Value aValue;
5996 if ( aValIter.GetFirst(aValue) && !aValue.mnError )
5998 switch( eFunc )
6000 case ifPRODUCT: nErg = 1; break;
6001 case ifMAX: nErg = -MAXDOUBLE; break;
6002 case ifMIN: nErg = MAXDOUBLE; break;
6003 default: ; // nothing
6007 nCount++;
6008 switch( eFunc )
6010 case ifAVERAGE:
6011 case ifSUM:
6012 if ( bNull && aValue.mfValue != 0.0 )
6014 bNull = FALSE;
6015 fMem = aValue.mfValue;
6017 else
6018 nErg += aValue.mfValue;
6019 break;
6020 case ifSUMSQ: nErg += aValue.mfValue * aValue.mfValue; break;
6021 case ifPRODUCT: nErg *= aValue.mfValue; break;
6022 case ifMAX: if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break;
6023 case ifMIN: if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break;
6024 default: ; // nothing
6027 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6029 SetError(aValue.mnError);
6031 else
6032 SetError( errIllegalParameter);
6033 switch( eFunc )
6035 case ifCOUNT: nErg = nCount; break;
6036 case ifSUM: nErg = ::rtl::math::approxAdd( nErg, fMem ); break;
6037 case ifAVERAGE: nErg = ::rtl::math::approxAdd( nErg, fMem ) / nCount; break;
6038 default: ; // nothing
6040 PushDouble( nErg );
6044 void ScInterpreter::ScDBSum()
6046 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBSum" );
6047 DBIterator( ifSUM );
6051 void ScInterpreter::ScDBCount()
6053 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount" );
6054 BOOL bMissingField = TRUE;
6055 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6056 if (pQueryParam.get())
6058 ULONG nCount = 0;
6059 if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL )
6060 { // count all matching records
6061 // TODO: currently the QueryIterators only return cell pointers of
6062 // existing cells, so if a query matches an empty cell there's
6063 // nothing returned, and therefor not counted!
6064 // Since this has ever been the case and this code here only came
6065 // into existance to fix #i6899 and it never worked before we'll
6066 // have to live with it until we reimplement the iterators to also
6067 // return empty cells, which would mean to adapt all callers of
6068 // iterators.
6069 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get());
6070 SCTAB nTab = p->nTab;
6071 ScQueryCellIterator aCellIter( pDok, nTab, *p);
6072 if ( aCellIter.GetFirst() )
6076 nCount++;
6077 } while ( aCellIter.GetNext() );
6080 else
6081 { // count only matching records with a value in the "result" field
6082 ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
6083 ScDBQueryDataIterator::Value aValue;
6084 if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6088 nCount++;
6090 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6092 SetError(aValue.mnError);
6094 PushDouble( nCount );
6096 else
6097 PushIllegalParameter();
6101 void ScInterpreter::ScDBCount2()
6103 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount2" );
6104 BOOL bMissingField = TRUE;
6105 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6106 if (pQueryParam.get())
6108 ULONG nCount = 0;
6109 pQueryParam->mbSkipString = false;
6110 ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
6111 ScDBQueryDataIterator::Value aValue;
6112 if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6116 nCount++;
6118 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6120 SetError(aValue.mnError);
6121 PushDouble( nCount );
6123 else
6124 PushIllegalParameter();
6128 void ScInterpreter::ScDBAverage()
6130 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBAverage" );
6131 DBIterator( ifAVERAGE );
6135 void ScInterpreter::ScDBMax()
6137 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMax" );
6138 DBIterator( ifMAX );
6142 void ScInterpreter::ScDBMin()
6144 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMin" );
6145 DBIterator( ifMIN );
6149 void ScInterpreter::ScDBProduct()
6151 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBProduct" );
6152 DBIterator( ifPRODUCT );
6156 void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
6158 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBStVarParams" );
6159 std::vector<double> values;
6160 double vSum = 0.0;
6161 double vMean = 0.0;
6163 rValCount = 0.0;
6164 double fSum = 0.0;
6165 BOOL bMissingField = FALSE;
6166 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6167 if (pQueryParam.get())
6169 ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
6170 ScDBQueryDataIterator::Value aValue;
6171 if (aValIter.GetFirst(aValue) && !aValue.mnError)
6175 rValCount++;
6176 values.push_back(aValue.mfValue);
6177 fSum += aValue.mfValue;
6179 while ((aValue.mnError == 0) && aValIter.GetNext(aValue));
6181 SetError(aValue.mnError);
6183 else
6184 SetError( errIllegalParameter);
6186 vMean = fSum / values.size();
6188 for (size_t i = 0; i < values.size(); i++)
6189 vSum += (values[i] - vMean) * (values[i] - vMean);
6191 rVal = vSum;
6195 void ScInterpreter::ScDBStdDev()
6197 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDev" );
6198 double fVal, fCount;
6199 GetDBStVarParams( fVal, fCount );
6200 PushDouble( sqrt(fVal/(fCount-1)));
6204 void ScInterpreter::ScDBStdDevP()
6206 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDevP" );
6207 double fVal, fCount;
6208 GetDBStVarParams( fVal, fCount );
6209 PushDouble( sqrt(fVal/fCount));
6213 void ScInterpreter::ScDBVar()
6215 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVar" );
6216 double fVal, fCount;
6217 GetDBStVarParams( fVal, fCount );
6218 PushDouble(fVal/(fCount-1));
6222 void ScInterpreter::ScDBVarP()
6224 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVarP" );
6225 double fVal, fCount;
6226 GetDBStVarParams( fVal, fCount );
6227 PushDouble(fVal/fCount);
6231 ScTokenArray* lcl_CreateExternalRefTokenArray( const ScAddress& rPos, ScDocument* pDoc,
6232 const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1,
6233 const ScRefAddress* pRefAd2 )
6235 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
6236 size_t nSheets = 1;
6237 const String* pRealTab = pRefMgr->getRealTableName( rExtInfo.mnFileId, rExtInfo.maTabName);
6238 ScTokenArray* pTokenArray = new ScTokenArray;
6239 if (pRefAd2)
6241 ScComplexRefData aRef;
6242 aRef.InitRangeRel( ScRange( rRefAd1.GetAddress(), pRefAd2->GetAddress()), rPos);
6243 aRef.Ref1.SetColRel( rRefAd1.IsRelCol());
6244 aRef.Ref1.SetRowRel( rRefAd1.IsRelRow());
6245 aRef.Ref1.SetTabRel( rRefAd1.IsRelTab());
6246 aRef.Ref1.SetFlag3D( true);
6247 aRef.Ref2.SetColRel( pRefAd2->IsRelCol());
6248 aRef.Ref2.SetRowRel( pRefAd2->IsRelRow());
6249 aRef.Ref2.SetTabRel( pRefAd2->IsRelTab());
6250 nSheets = aRef.Ref2.nTab - aRef.Ref1.nTab + 1;
6251 aRef.Ref2.SetFlag3D( nSheets > 1 );
6252 pTokenArray->AddExternalDoubleReference( rExtInfo.mnFileId,
6253 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
6255 else
6257 ScSingleRefData aRef;
6258 aRef.InitAddressRel( rRefAd1.GetAddress(), rPos);
6259 aRef.SetColRel( rRefAd1.IsRelCol());
6260 aRef.SetRowRel( rRefAd1.IsRelRow());
6261 aRef.SetTabRel( rRefAd1.IsRelTab());
6262 aRef.SetFlag3D( true);
6263 pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId,
6264 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
6266 // The indirect usage of the external table can't be detected during the
6267 // store-to-file cycle, mark it as permanently referenced so it gets stored
6268 // even if not directly referenced anywhere.
6269 pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId,
6270 rExtInfo.maTabName, nSheets);
6271 ScCompiler aComp( pDoc, rPos, *pTokenArray);
6272 aComp.CompileTokenArray();
6273 return pTokenArray;
6277 void ScInterpreter::ScIndirect()
6279 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndirect" );
6280 BYTE nParamCount = GetByte();
6281 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6283 bool bTryXlA1 = true; // whether to try XL_A1 style as well.
6284 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;
6285 if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
6287 eConv = FormulaGrammar::CONV_XL_R1C1;
6288 bTryXlA1 = false;
6290 const ScAddress::Details aDetails( eConv, aPos );
6291 const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos );
6292 SCTAB nTab = aPos.Tab();
6293 String sRefStr( GetString() );
6294 ScRefAddress aRefAd, aRefAd2;
6295 ScAddress::ExternalInfo aExtInfo;
6296 if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) ||
6297 (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd,
6298 aRefAd2, aDetailsXlA1, &aExtInfo)))
6300 if (aExtInfo.mbExternal)
6302 /* TODO: future versions should implement a proper subroutine
6303 * token. This procedure here is a minimally invasive fix for
6304 * #i101645# in OOo3.1.1 */
6305 // Push a subroutine on the instruction code stack that
6306 // resolves the external reference as the next instruction.
6307 aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok,
6308 aExtInfo, aRefAd, &aRefAd2));
6309 // Signal subroutine call to interpreter.
6310 PushTempToken( new FormulaUnknownToken( ocCall));
6312 else
6313 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
6314 aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() );
6316 else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) ||
6317 (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd,
6318 aDetailsXlA1, &aExtInfo)))
6320 if (aExtInfo.mbExternal)
6322 /* TODO: future versions should implement a proper subroutine
6323 * token. This procedure here is a minimally invasive fix for
6324 * #i101645# in OOo3.1.1 */
6325 // Push a subroutine on the instruction code stack that
6326 // resolves the external reference as the next instruction.
6327 aCode.Push( lcl_CreateExternalRefTokenArray( aPos, pDok,
6328 aExtInfo, aRefAd, NULL));
6329 // Signal subroutine call to interpreter.
6330 PushTempToken( new FormulaUnknownToken( ocCall));
6332 else
6333 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
6335 else
6339 ScRangeName* pNames = pDok->GetRangeName();
6340 if (!pNames)
6341 break;
6343 USHORT nPos = 0;
6344 if (!pNames->SearchName( sRefStr, nPos))
6345 break;
6347 ScRangeData* rData = (*pNames)[nPos];
6348 if (!rData)
6349 break;
6351 // We need this in order to obtain a good range.
6352 rData->ValidateTabRefs();
6354 ScRange aRange;
6355 #if 0
6356 // This is some really odd Excel behavior and renders named
6357 // ranges containing relative references totally useless.
6358 if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0)))
6359 break;
6360 #else
6361 // This is the usual way to treat named ranges containing
6362 // relative references.
6363 if (!rData->IsReference( aRange, aPos))
6364 break;
6365 #endif
6367 if (aRange.aStart == aRange.aEnd)
6368 PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
6369 aRange.aStart.Tab());
6370 else
6371 PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(),
6372 aRange.aStart.Tab(), aRange.aEnd.Col(),
6373 aRange.aEnd.Row(), aRange.aEnd.Tab());
6375 // success!
6376 return;
6378 while (false);
6380 PushIllegalArgument();
6386 void ScInterpreter::ScAddressFunc()
6388 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAddressFunc" );
6389 String sTabStr;
6391 BYTE nParamCount = GetByte();
6392 if( !MustHaveParamCount( nParamCount, 2, 5 ) )
6393 return;
6395 if( nParamCount >= 5 )
6396 sTabStr = GetString();
6398 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO; // default
6399 if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
6400 eConv = FormulaGrammar::CONV_XL_R1C1;
6402 USHORT nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE; // default
6403 if( nParamCount >= 3 )
6405 USHORT n = (USHORT) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
6406 switch ( n )
6408 default :
6409 PushNoValue();
6410 return;
6412 case 5:
6413 case 1 : break; // default
6414 case 6:
6415 case 2 : nFlags = SCA_ROW_ABSOLUTE; break;
6416 case 7:
6417 case 3 : nFlags = SCA_COL_ABSOLUTE; break;
6418 case 8:
6419 case 4 : nFlags = 0; break; // both relative
6422 nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL;
6424 SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
6425 SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
6426 if( eConv == FormulaGrammar::CONV_XL_R1C1 )
6428 // YUCK! The XL interface actually treats rel R1C1 refs differently
6429 // than A1
6430 if( !(nFlags & SCA_COL_ABSOLUTE) )
6431 nCol += aPos.Col() + 1;
6432 if( !(nFlags & SCA_ROW_ABSOLUTE) )
6433 nRow += aPos.Row() + 1;
6436 --nCol;
6437 --nRow;
6438 if(!ValidCol( nCol) || !ValidRow( nRow))
6440 PushIllegalArgument();
6441 return;
6444 String aRefStr;
6445 const ScAddress::Details aDetails( eConv, aPos );
6446 const ScAddress aAdr( nCol, nRow, 0);
6447 aAdr.Format( aRefStr, nFlags, pDok, aDetails );
6449 if( nParamCount >= 5 )
6451 ScCompiler::CheckTabQuotes( sTabStr, eConv);
6452 sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.');
6453 sTabStr += aRefStr;
6454 PushString( sTabStr );
6456 else
6457 PushString( aRefStr );
6461 void ScInterpreter::ScOffset()
6463 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" );
6464 BYTE nParamCount = GetByte();
6465 if ( MustHaveParamCount( nParamCount, 3, 5 ) )
6467 long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus;
6468 if (nParamCount == 5)
6469 nColNew = (long) ::rtl::math::approxFloor(GetDouble());
6470 if (nParamCount >= 4)
6471 nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
6472 nColPlus = (long) ::rtl::math::approxFloor(GetDouble());
6473 nRowPlus = (long) ::rtl::math::approxFloor(GetDouble());
6474 SCCOL nCol1;
6475 SCROW nRow1;
6476 SCTAB nTab1;
6477 SCCOL nCol2;
6478 SCROW nRow2;
6479 SCTAB nTab2;
6480 if (nColNew == 0 || nRowNew == 0)
6482 PushIllegalArgument();
6483 return;
6485 if (GetStackType() == svSingleRef)
6487 PopSingleRef(nCol1, nRow1, nTab1);
6488 if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
6490 nCol1 = (SCCOL)((long) nCol1 + nColPlus);
6491 nRow1 = (SCROW)((long) nRow1 + nRowPlus);
6492 if (!ValidCol(nCol1) || !ValidRow(nRow1))
6493 PushIllegalArgument();
6494 else
6495 PushSingleRef(nCol1, nRow1, nTab1);
6497 else
6499 if (nColNew < 0)
6500 nColNew = 1;
6501 if (nRowNew < 0)
6502 nRowNew = 1;
6503 nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 wird veraendert!
6504 nRow1 = (SCROW)((long)nRow1+nRowPlus);
6505 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
6506 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
6507 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
6508 !ValidCol(nCol2) || !ValidRow(nRow2))
6509 PushIllegalArgument();
6510 else
6511 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
6514 else if (GetStackType() == svDoubleRef)
6516 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6517 if (nColNew < 0)
6518 nColNew = nCol2 - nCol1 + 1;
6519 if (nRowNew < 0)
6520 nRowNew = nRow2 - nRow1 + 1;
6521 nCol1 = (SCCOL)((long)nCol1+nColPlus);
6522 nRow1 = (SCROW)((long)nRow1+nRowPlus);
6523 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
6524 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
6525 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
6526 !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
6527 PushIllegalArgument();
6528 else
6529 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
6531 else
6532 PushIllegalParameter();
6537 void ScInterpreter::ScIndex()
6539 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndex" );
6540 BYTE nParamCount = GetByte();
6541 if ( MustHaveParamCount( nParamCount, 1, 4 ) )
6543 long nArea;
6544 size_t nAreaCount;
6545 SCCOL nCol;
6546 SCROW nRow;
6547 if (nParamCount == 4)
6548 nArea = (long) ::rtl::math::approxFloor(GetDouble());
6549 else
6550 nArea = 1;
6551 if (nParamCount >= 3)
6552 nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
6553 else
6554 nCol = 0;
6555 if (nParamCount >= 2)
6556 nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
6557 else
6558 nRow = 0;
6559 if (GetStackType() == svRefList)
6560 nAreaCount = (sp ? static_cast<ScToken*>(pStack[sp-1])->GetRefList()->size() : 0);
6561 else
6562 nAreaCount = 1; // one reference or array or whatever
6563 if (nAreaCount == 0 || (size_t)nArea > nAreaCount)
6565 PushError( errNoRef);
6566 return;
6568 else if (nArea < 1 || nCol < 0 || nRow < 0)
6570 PushIllegalArgument();
6571 return;
6573 switch (GetStackType())
6575 case svMatrix:
6577 if (nArea != 1)
6578 SetError(errIllegalArgument);
6579 USHORT nOldSp = sp;
6580 ScMatrixRef pMat = GetMatrix();
6581 if (pMat)
6583 SCSIZE nC, nR;
6584 pMat->GetDimensions(nC, nR);
6585 // Access one element of a vector independent of col/row
6586 // orientation?
6587 bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1));
6588 SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol),
6589 static_cast<SCSIZE>(nRow));
6590 if (nC == 0 || nR == 0 ||
6591 (!bVector && (static_cast<SCSIZE>(nCol) > nC ||
6592 static_cast<SCSIZE>(nRow) > nR)) ||
6593 (bVector && nElement > nC * nR))
6594 PushIllegalArgument();
6595 else if (nCol == 0 && nRow == 0)
6596 sp = nOldSp;
6597 else if (bVector)
6599 --nElement;
6600 if (pMat->IsString( nElement))
6601 PushString( pMat->GetString( nElement));
6602 else
6603 PushDouble( pMat->GetDouble( nElement));
6605 else if (nCol == 0)
6607 ScMatrixRef pResMat = GetNewMat(nC, 1);
6608 if (pResMat)
6610 SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
6611 for (SCSIZE i = 0; i < nC; i++)
6612 if (!pMat->IsString(i, nRowMinus1))
6613 pResMat->PutDouble(pMat->GetDouble(i,
6614 nRowMinus1), i, 0);
6615 else
6616 pResMat->PutString(pMat->GetString(i,
6617 nRowMinus1), i, 0);
6618 PushMatrix(pResMat);
6620 else
6621 PushIllegalArgument();
6623 else if (nRow == 0)
6625 ScMatrixRef pResMat = GetNewMat(1, nR);
6626 if (pResMat)
6628 SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
6629 for (SCSIZE i = 0; i < nR; i++)
6630 if (!pMat->IsString(nColMinus1, i))
6631 pResMat->PutDouble(pMat->GetDouble(nColMinus1,
6632 i), i);
6633 else
6634 pResMat->PutString(pMat->GetString(nColMinus1,
6635 i), i);
6636 PushMatrix(pResMat);
6638 else
6639 PushIllegalArgument();
6641 else
6643 if (!pMat->IsString( static_cast<SCSIZE>(nCol-1),
6644 static_cast<SCSIZE>(nRow-1)))
6645 PushDouble( pMat->GetDouble(
6646 static_cast<SCSIZE>(nCol-1),
6647 static_cast<SCSIZE>(nRow-1)));
6648 else
6649 PushString( pMat->GetString(
6650 static_cast<SCSIZE>(nCol-1),
6651 static_cast<SCSIZE>(nRow-1)));
6655 break;
6656 case svSingleRef:
6658 SCCOL nCol1 = 0;
6659 SCROW nRow1 = 0;
6660 SCTAB nTab1 = 0;
6661 PopSingleRef( nCol1, nRow1, nTab1);
6662 if (nCol > 1 || nRow > 1)
6663 PushIllegalArgument();
6664 else
6665 PushSingleRef( nCol1, nRow1, nTab1);
6667 break;
6668 case svDoubleRef:
6669 case svRefList:
6671 SCCOL nCol1 = 0;
6672 SCROW nRow1 = 0;
6673 SCTAB nTab1 = 0;
6674 SCCOL nCol2 = 0;
6675 SCROW nRow2 = 0;
6676 SCTAB nTab2 = 0;
6677 BOOL bRowArray = FALSE;
6678 if (GetStackType() == svRefList)
6680 FormulaTokenRef xRef = PopToken();
6681 if (nGlobalError || !xRef)
6683 PushIllegalParameter();
6684 return;
6686 ScRange aRange( ScAddress::UNINITIALIZED);
6687 DoubleRefToRange( (*(static_cast<ScToken*>(xRef.get())->GetRefList()))[nArea-1], aRange);
6688 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6689 if ( nParamCount == 2 && nRow1 == nRow2 )
6690 bRowArray = TRUE;
6692 else
6694 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6695 if ( nParamCount == 2 && nRow1 == nRow2 )
6696 bRowArray = TRUE;
6698 if ( nTab1 != nTab2 ||
6699 (nCol > 0 && nCol1+nCol-1 > nCol2) ||
6700 (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
6701 ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
6702 PushIllegalArgument();
6703 else if (nCol == 0 && nRow == 0)
6705 if ( nCol1 == nCol2 && nRow1 == nRow2 )
6706 PushSingleRef( nCol1, nRow1, nTab1 );
6707 else
6708 PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 );
6710 else if (nRow == 0)
6712 if ( nRow1 == nRow2 )
6713 PushSingleRef( nCol1+nCol-1, nRow1, nTab1 );
6714 else
6715 PushDoubleRef( nCol1+nCol-1, nRow1, nTab1,
6716 nCol1+nCol-1, nRow2, nTab1 );
6718 else if (nCol == 0)
6720 if ( nCol1 == nCol2 )
6721 PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
6722 else if ( bRowArray )
6724 nCol =(SCCOL) nRow;
6725 nRow = 1;
6726 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
6728 else
6729 PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
6730 nCol2, nRow1+nRow-1, nTab1);
6732 else
6733 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
6735 break;
6736 default:
6737 PushIllegalParameter();
6743 void ScInterpreter::ScMultiArea()
6745 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMultiArea" );
6746 // Legacy support, convert to RefList
6747 BYTE nParamCount = GetByte();
6748 if (MustHaveParamCountMin( nParamCount, 1))
6750 while (!nGlobalError && nParamCount-- > 1)
6752 ScUnionFunc();
6758 void ScInterpreter::ScAreas()
6760 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAreas" );
6761 BYTE nParamCount = GetByte();
6762 if (MustHaveParamCount( nParamCount, 1))
6764 size_t nCount = 0;
6765 switch (GetStackType())
6767 case svSingleRef:
6769 FormulaTokenRef xT = PopToken();
6770 ValidateRef( static_cast<ScToken*>(xT.get())->GetSingleRef());
6771 ++nCount;
6773 break;
6774 case svDoubleRef:
6776 FormulaTokenRef xT = PopToken();
6777 ValidateRef( static_cast<ScToken*>(xT.get())->GetDoubleRef());
6778 ++nCount;
6780 break;
6781 case svRefList:
6783 FormulaTokenRef xT = PopToken();
6784 ValidateRef( *(static_cast<ScToken*>(xT.get())->GetRefList()));
6785 nCount += static_cast<ScToken*>(xT.get())->GetRefList()->size();
6787 break;
6788 default:
6789 SetError( errIllegalParameter);
6791 PushDouble( double(nCount));
6796 void ScInterpreter::ScCurrency()
6798 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrency" );
6799 BYTE nParamCount = GetByte();
6800 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6802 String aStr;
6803 double fDec;
6804 if (nParamCount == 2)
6806 fDec = ::rtl::math::approxFloor(GetDouble());
6807 if (fDec < -15.0 || fDec > 15.0)
6809 PushIllegalArgument();
6810 return;
6813 else
6814 fDec = 2.0;
6815 double fVal = GetDouble();
6816 double fFac;
6817 if ( fDec != 0.0 )
6818 fFac = pow( (double)10, fDec );
6819 else
6820 fFac = 1.0;
6821 if (fVal < 0.0)
6822 fVal = ceil(fVal*fFac-0.5)/fFac;
6823 else
6824 fVal = floor(fVal*fFac+0.5)/fFac;
6825 Color* pColor = NULL;
6826 if ( fDec < 0.0 )
6827 fDec = 0.0;
6828 ULONG nIndex = pFormatter->GetStandardFormat(
6829 NUMBERFORMAT_CURRENCY,
6830 ScGlobal::eLnge);
6831 if ( (USHORT) fDec != pFormatter->GetFormatPrecision( nIndex ) )
6833 String sFormatString;
6834 pFormatter->GenerateFormat(sFormatString,
6835 nIndex,
6836 ScGlobal::eLnge,
6837 TRUE, // mit Tausenderpunkt
6838 FALSE, // nicht rot
6839 (USHORT) fDec,// Nachkommastellen
6840 1); // 1 Vorkommanull
6841 if (!pFormatter->GetPreviewString(sFormatString,
6842 fVal,
6843 aStr,
6844 &pColor,
6845 ScGlobal::eLnge))
6846 SetError(errIllegalArgument);
6848 else
6850 pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor);
6852 PushString(aStr);
6857 void ScInterpreter::ScReplace()
6859 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScReplace" );
6860 if ( MustHaveParamCount( GetByte(), 4 ) )
6862 String aNewStr( GetString() );
6863 double fCount = ::rtl::math::approxFloor( GetDouble());
6864 double fPos = ::rtl::math::approxFloor( GetDouble());
6865 String aOldStr( GetString() );
6866 if (fPos < 1.0 || fPos > static_cast<double>(STRING_MAXLEN)
6867 || fCount < 0.0 || fCount > static_cast<double>(STRING_MAXLEN))
6868 PushIllegalArgument();
6869 else
6871 xub_StrLen nCount = static_cast<xub_StrLen>(fCount);
6872 xub_StrLen nPos = static_cast<xub_StrLen>(fPos);
6873 xub_StrLen nLen = aOldStr.Len();
6874 if (nPos > nLen + 1)
6875 nPos = nLen + 1;
6876 if (nCount > nLen - nPos + 1)
6877 nCount = nLen - nPos + 1;
6878 aOldStr.Erase( nPos-1, nCount );
6879 if ( CheckStringResultLen( aOldStr, aNewStr ) )
6880 aOldStr.Insert( aNewStr, nPos-1 );
6881 PushString( aOldStr );
6887 void ScInterpreter::ScFixed()
6889 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFixed" );
6890 BYTE nParamCount = GetByte();
6891 if ( MustHaveParamCount( nParamCount, 1, 3 ) )
6893 String aStr;
6894 double fDec;
6895 BOOL bThousand;
6896 if (nParamCount == 3)
6897 bThousand = !GetBool(); // Param TRUE: keine Tausenderpunkte
6898 else
6899 bThousand = TRUE;
6900 if (nParamCount >= 2)
6902 fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
6903 if (fDec < -15.0 || fDec > 15.0)
6905 PushIllegalArgument();
6906 return;
6909 else
6910 fDec = 2.0;
6911 double fVal = GetDouble();
6912 double fFac;
6913 if ( fDec != 0.0 )
6914 fFac = pow( (double)10, fDec );
6915 else
6916 fFac = 1.0;
6917 if (fVal < 0.0)
6918 fVal = ceil(fVal*fFac-0.5)/fFac;
6919 else
6920 fVal = floor(fVal*fFac+0.5)/fFac;
6921 Color* pColor = NULL;
6922 String sFormatString;
6923 if (fDec < 0.0)
6924 fDec = 0.0;
6925 ULONG nIndex = pFormatter->GetStandardFormat(
6926 NUMBERFORMAT_NUMBER,
6927 ScGlobal::eLnge);
6928 pFormatter->GenerateFormat(sFormatString,
6929 nIndex,
6930 ScGlobal::eLnge,
6931 bThousand, // mit Tausenderpunkt
6932 FALSE, // nicht rot
6933 (USHORT) fDec,// Nachkommastellen
6934 1); // 1 Vorkommanull
6935 if (!pFormatter->GetPreviewString(sFormatString,
6936 fVal,
6937 aStr,
6938 &pColor,
6939 ScGlobal::eLnge))
6940 PushIllegalArgument();
6941 else
6942 PushString(aStr);
6947 void ScInterpreter::ScFind()
6949 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFind" );
6950 BYTE nParamCount = GetByte();
6951 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
6953 double fAnz;
6954 if (nParamCount == 3)
6955 fAnz = GetDouble();
6956 else
6957 fAnz = 1.0;
6958 String sStr = GetString();
6959 if( fAnz < 1.0 || fAnz > (double) sStr.Len() )
6960 PushNoValue();
6961 else
6963 xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 );
6964 if (nPos == STRING_NOTFOUND)
6965 PushNoValue();
6966 else
6967 PushDouble((double)(nPos + 1));
6973 void ScInterpreter::ScExact()
6975 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExact" );
6976 nFuncFmtType = NUMBERFORMAT_LOGICAL;
6977 if ( MustHaveParamCount( GetByte(), 2 ) )
6979 String s1( GetString() );
6980 String s2( GetString() );
6981 PushInt( s1 == s2 );
6986 void ScInterpreter::ScLeft()
6988 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLeft" );
6989 BYTE nParamCount = GetByte();
6990 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6992 xub_StrLen n;
6993 if (nParamCount == 2)
6995 double nVal = ::rtl::math::approxFloor(GetDouble());
6996 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
6998 PushIllegalArgument();
6999 return ;
7001 else
7002 n = (xub_StrLen) nVal;
7004 else
7005 n = 1;
7006 String aStr( GetString() );
7007 aStr.Erase( n );
7008 PushString( aStr );
7013 void ScInterpreter::ScRight()
7015 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRight" );
7016 BYTE nParamCount = GetByte();
7017 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7019 xub_StrLen n;
7020 if (nParamCount == 2)
7022 double nVal = ::rtl::math::approxFloor(GetDouble());
7023 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7025 PushIllegalArgument();
7026 return ;
7028 else
7029 n = (xub_StrLen) nVal;
7031 else
7032 n = 1;
7033 String aStr( GetString() );
7034 if( n < aStr.Len() )
7035 aStr.Erase( 0, aStr.Len() - n );
7036 PushString( aStr );
7041 void ScInterpreter::ScSearch()
7043 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSearch" );
7044 double fAnz;
7045 BYTE nParamCount = GetByte();
7046 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
7048 if (nParamCount == 3)
7050 fAnz = ::rtl::math::approxFloor(GetDouble());
7051 if (fAnz > double(STRING_MAXLEN))
7053 PushIllegalArgument();
7054 return;
7057 else
7058 fAnz = 1.0;
7059 String sStr = GetString();
7060 String SearchStr = GetString();
7061 xub_StrLen nPos = (xub_StrLen) fAnz - 1;
7062 xub_StrLen nEndPos = sStr.Len();
7063 if( nPos >= nEndPos )
7064 PushNoValue();
7065 else
7067 utl::SearchParam::SearchType eSearchType =
7068 (MayBeRegExp( SearchStr, pDok ) ?
7069 utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL);
7070 utl::SearchParam sPar(SearchStr, eSearchType, FALSE, FALSE, FALSE);
7071 utl::TextSearch sT( sPar, *ScGlobal::pCharClass );
7072 int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos);
7073 if (!nBool)
7074 PushNoValue();
7075 else
7076 PushDouble((double)(nPos) + 1);
7082 void ScInterpreter::ScMid()
7084 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMid" );
7085 if ( MustHaveParamCount( GetByte(), 3 ) )
7087 double fAnz = ::rtl::math::approxFloor(GetDouble());
7088 double fAnfang = ::rtl::math::approxFloor(GetDouble());
7089 const String& rStr = GetString();
7090 if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
7091 PushIllegalArgument();
7092 else
7093 PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
7098 void ScInterpreter::ScText()
7100 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScText" );
7101 if ( MustHaveParamCount( GetByte(), 2 ) )
7103 String sFormatString = GetString();
7104 double fVal = GetDouble();
7105 String aStr;
7106 Color* pColor = NULL;
7107 LanguageType eCellLang;
7108 const ScPatternAttr* pPattern = pDok->GetPattern(
7109 aPos.Col(), aPos.Row(), aPos.Tab() );
7110 if ( pPattern )
7111 eCellLang = ((const SvxLanguageItem&)
7112 pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue();
7113 else
7114 eCellLang = ScGlobal::eLnge;
7115 if ( !pFormatter->GetPreviewStringGuess( sFormatString, fVal, aStr,
7116 &pColor, eCellLang ) )
7117 PushIllegalArgument();
7118 else
7119 PushString(aStr);
7124 void ScInterpreter::ScSubstitute()
7126 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubstitute" );
7127 BYTE nParamCount = GetByte();
7128 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
7130 xub_StrLen nAnz;
7131 if (nParamCount == 4)
7133 double fAnz = ::rtl::math::approxFloor(GetDouble());
7134 if( fAnz < 1 || fAnz > STRING_MAXLEN )
7136 PushIllegalArgument();
7137 return;
7139 else
7140 nAnz = (xub_StrLen) fAnz;
7142 else
7143 nAnz = 0;
7144 String sNewStr = GetString();
7145 String sOldStr = GetString();
7146 String sStr = GetString();
7147 xub_StrLen nPos = 0;
7148 xub_StrLen nCount = 0;
7149 xub_StrLen nNewLen = sNewStr.Len();
7150 xub_StrLen nOldLen = sOldStr.Len();
7151 while( TRUE )
7153 nPos = sStr.Search( sOldStr, nPos );
7154 if (nPos != STRING_NOTFOUND)
7156 nCount++;
7157 if( !nAnz || nCount == nAnz )
7159 sStr.Erase(nPos,nOldLen);
7160 if ( CheckStringResultLen( sStr, sNewStr ) )
7162 sStr.Insert(sNewStr,nPos);
7163 nPos = sal::static_int_cast<xub_StrLen>( nPos + nNewLen );
7165 else
7166 break;
7168 else
7169 nPos++;
7171 else
7172 break;
7174 PushString( sStr );
7179 void ScInterpreter::ScRept()
7181 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRept" );
7182 if ( MustHaveParamCount( GetByte(), 2 ) )
7184 double fAnz = ::rtl::math::approxFloor(GetDouble());
7185 String aStr( GetString() );
7186 if ( fAnz < 0.0 )
7187 PushIllegalArgument();
7188 else if ( fAnz * aStr.Len() > STRING_MAXLEN )
7190 PushError( errStringOverflow );
7192 else if ( fAnz == 0.0 )
7193 PushString( EMPTY_STRING );
7194 else
7196 xub_StrLen n = (xub_StrLen) fAnz;
7197 const xub_StrLen nLen = aStr.Len();
7198 String aRes;
7199 const sal_Unicode* const pSrc = aStr.GetBuffer();
7200 sal_Unicode* pDst = aRes.AllocBuffer( n * nLen );
7201 while( n-- )
7203 memcpy( pDst, pSrc, nLen * sizeof(sal_Unicode) );
7204 pDst += nLen;
7206 PushString( aRes );
7212 void ScInterpreter::ScConcat()
7214 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConcat" );
7215 BYTE nParamCount = GetByte();
7216 String aRes;
7217 while( nParamCount-- > 0)
7219 const String& rStr = GetString();
7220 aRes.Insert( rStr, 0 );
7222 PushString( aRes );
7226 void ScInterpreter::ScErrorType()
7228 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScErrorType" );
7229 USHORT nErr;
7230 USHORT nOldError = nGlobalError;
7231 nGlobalError = 0;
7232 switch ( GetStackType() )
7234 case svRefList :
7236 FormulaTokenRef x = PopToken();
7237 if (nGlobalError)
7238 nErr = nGlobalError;
7239 else
7241 const ScRefList* pRefList = static_cast<ScToken*>(x.get())->GetRefList();
7242 size_t n = pRefList->size();
7243 if (!n)
7244 nErr = errNoRef;
7245 else if (n > 1)
7246 nErr = errNoValue;
7247 else
7249 ScRange aRange;
7250 DoubleRefToRange( (*pRefList)[0], aRange);
7251 if (nGlobalError)
7252 nErr = nGlobalError;
7253 else
7255 ScAddress aAdr;
7256 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
7257 nErr = pDok->GetErrCode( aAdr );
7258 else
7259 nErr = nGlobalError;
7264 break;
7265 case svDoubleRef :
7267 ScRange aRange;
7268 PopDoubleRef( aRange );
7269 if ( nGlobalError )
7270 nErr = nGlobalError;
7271 else
7273 ScAddress aAdr;
7274 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
7275 nErr = pDok->GetErrCode( aAdr );
7276 else
7277 nErr = nGlobalError;
7280 break;
7281 case svSingleRef :
7283 ScAddress aAdr;
7284 PopSingleRef( aAdr );
7285 if ( nGlobalError )
7286 nErr = nGlobalError;
7287 else
7288 nErr = pDok->GetErrCode( aAdr );
7290 break;
7291 default:
7292 PopError();
7293 nErr = nGlobalError;
7295 if ( nErr )
7297 nGlobalError = 0;
7298 PushDouble( nErr );
7300 else
7302 nGlobalError = nOldError;
7303 PushNA();
7308 BOOL ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc )
7310 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MayBeRegExp" );
7311 if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
7312 return FALSE;
7313 if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') )
7314 return FALSE; // einzelnes Metazeichen kann keine RegExp sein
7315 static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
7316 const sal_Unicode* p1 = rStr.GetBuffer();
7317 sal_Unicode c1;
7318 while ( ( c1 = *p1++ ) != 0 )
7320 const sal_Unicode* p2 = cre;
7321 while ( *p2 )
7323 if ( c1 == *p2++ )
7324 return TRUE;
7327 return FALSE;
7330 static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
7331 const ScQueryParam & rParam, const ScQueryEntry & rEntry )
7333 bool bFound = false;
7334 ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, FALSE);
7335 if (rEntry.eOp != SC_EQUAL)
7337 // range lookup <= or >=
7338 SCCOL nCol;
7339 SCROW nRow;
7340 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow);
7341 if (bFound)
7343 o_rResultPos.SetCol( nCol);
7344 o_rResultPos.SetRow( nRow);
7347 else if (aCellIter.GetFirst())
7349 // EQUAL
7350 bFound = true;
7351 o_rResultPos.SetCol( aCellIter.GetCol());
7352 o_rResultPos.SetRow( aCellIter.GetRow());
7354 return bFound;
7357 #define erDEBUG_LOOKUPCACHE 0
7358 #if erDEBUG_LOOKUPCACHE
7359 #include <cstdio>
7360 using ::std::fprintf;
7361 using ::std::fflush;
7362 static struct LookupCacheDebugCounter
7364 unsigned long nMiss;
7365 unsigned long nHit;
7366 LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
7367 ~LookupCacheDebugCounter()
7369 fprintf( stderr, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
7370 nMiss, nHit, nHit+nMiss, (nMiss>0 ? nHit/nMiss : 0),
7371 ((nHit+nMiss)>0 ? (100*nHit)/(nHit+nMiss) : 0));
7372 fflush( stderr);
7374 } aLookupCacheDebugCounter;
7375 #endif
7377 bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
7378 const ScQueryParam & rParam ) const
7380 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::LookupQueryWithCache" );
7381 bool bFound = false;
7382 const ScQueryEntry& rEntry = rParam.GetEntry(0);
7383 bool bColumnsMatch = (rParam.nCol1 == rEntry.nField);
7384 DBG_ASSERT( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match");
7385 if (!bColumnsMatch)
7386 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
7387 else
7389 ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
7390 rParam.nCol2, rParam.nRow2, rParam.nTab);
7391 ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange);
7392 ScLookupCache::QueryCriteria aCriteria( rEntry);
7393 ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos,
7394 aCriteria, aPos);
7395 switch (eCacheResult)
7397 case ScLookupCache::NOT_CACHED :
7398 case ScLookupCache::CRITERIA_DIFFERENT :
7399 #if erDEBUG_LOOKUPCACHE
7400 ++aLookupCacheDebugCounter.nMiss;
7401 #if erDEBUG_LOOKUPCACHE > 1
7402 fprintf( stderr, "miss %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
7403 #endif
7404 #endif
7405 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
7406 if (eCacheResult == ScLookupCache::NOT_CACHED)
7407 rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
7408 break;
7409 case ScLookupCache::FOUND :
7410 #if erDEBUG_LOOKUPCACHE
7411 ++aLookupCacheDebugCounter.nHit;
7412 #if erDEBUG_LOOKUPCACHE > 1
7413 fprintf( stderr, "hit %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
7414 #endif
7415 #endif
7416 bFound = true;
7417 break;
7418 case ScLookupCache::NOT_AVAILABLE :
7419 ; // nothing, bFound remains FALSE
7420 break;
7423 return bFound;