update ooo310-m15
[ooovba.git] / sc / source / core / tool / interpr1.cxx
blobe48f8e610503f46b241450118dfb38d504c30695
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/logfile.hxx>
50 #include "interpre.hxx"
51 #include "patattr.hxx"
52 #include "global.hxx"
53 #include "document.hxx"
54 #include "dociter.hxx"
55 #include "cell.hxx"
56 #include "scmatrix.hxx"
57 #include "docoptio.hxx"
58 #include "globstr.hrc"
59 #include "attrib.hxx"
60 #include "jumpmatrix.hxx"
62 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
63 #include <comphelper/processfactory.hxx>
64 #endif
66 #include <stdlib.h>
67 #include <string.h>
68 #include <math.h>
69 #include <vector>
70 #include "cellkeytranslator.hxx"
71 #include "lookupcache.hxx"
72 #include "rangenam.hxx"
73 #include "compiler.hxx"
74 #include <basic/sbstar.hxx>
76 #define SC_DOUBLE_MAXVALUE 1.7e307
78 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack, 8, 4 )
79 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter, 32, 16 )
81 ScTokenStack* ScInterpreter::pGlobalStack = NULL;
82 BOOL ScInterpreter::bGlobalStackInUse = FALSE;
84 using namespace formula;
85 //-----------------------------------------------------------------------------
86 // Funktionen
87 //-----------------------------------------------------------------------------
90 void ScInterpreter::ScIfJump()
92 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIfJump" );
93 const short* pJump = pCur->GetJump();
94 short nJumpCount = pJump[ 0 ];
95 MatrixDoubleRefToMatrix();
96 switch ( GetStackType() )
98 case svMatrix:
100 ScMatrixRef pMat = PopMatrix();
101 if ( !pMat )
102 PushIllegalParameter();
103 else
105 FormulaTokenRef xNew;
106 ScTokenMatrixMap::const_iterator aMapIter;
107 // DoubleError handled by JumpMatrix
108 pMat->SetErrorInterpreter( NULL);
109 SCSIZE nCols, nRows;
110 pMat->GetDimensions( nCols, nRows );
111 if ( nCols == 0 || nRows == 0 )
112 PushIllegalArgument();
113 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
114 pCur)) != pTokenMatrixMap->end()))
115 xNew = (*aMapIter).second;
116 else
118 ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
119 for ( SCSIZE nC=0; nC < nCols; ++nC )
121 for ( SCSIZE nR=0; nR < nRows; ++nR )
123 double fVal;
124 bool bTrue;
125 ScMatValType nType = 0;
126 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
127 nType);
128 bool bIsValue = ScMatrix::IsValueType( nType);
129 if ( bIsValue )
131 fVal = pMatVal->fVal;
132 bIsValue = ::rtl::math::isFinite( fVal );
133 bTrue = bIsValue && (fVal != 0.0);
134 if ( bTrue )
135 fVal = 1.0;
137 else
139 // Treat empty and empty path as 0, but string
140 // as error.
141 bIsValue = !ScMatrix::IsRealStringType( nType);
142 bTrue = false;
143 fVal = (bIsValue ? 0.0 : CreateDoubleError( errNoValue));
145 if ( bTrue )
146 { // TRUE
147 if( nJumpCount >= 2 )
148 { // THEN path
149 pJumpMat->SetJump( nC, nR, fVal,
150 pJump[ 1 ],
151 pJump[ nJumpCount ]);
153 else
154 { // no parameter given for THEN
155 pJumpMat->SetJump( nC, nR, fVal,
156 pJump[ nJumpCount ],
157 pJump[ nJumpCount ]);
160 else
161 { // FALSE
162 if( nJumpCount == 3 && bIsValue )
163 { // ELSE path
164 pJumpMat->SetJump( nC, nR, fVal,
165 pJump[ 2 ],
166 pJump[ nJumpCount ]);
168 else
169 { // no parameter given for ELSE,
170 // or DoubleError
171 pJumpMat->SetJump( nC, nR, fVal,
172 pJump[ nJumpCount ],
173 pJump[ nJumpCount ]);
178 xNew = new ScJumpMatrixToken( pJumpMat );
179 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur, xNew));
181 PushTempToken( xNew);
182 // set endpoint of path for main code line
183 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
186 break;
187 default:
189 if ( GetBool() )
190 { // TRUE
191 if( nJumpCount >= 2 )
192 { // THEN path
193 aCode.Jump( pJump[ 1 ], pJump[ nJumpCount ] );
195 else
196 { // no parameter given for THEN
197 nFuncFmtType = NUMBERFORMAT_LOGICAL;
198 PushInt(1);
199 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
202 else
203 { // FALSE
204 if( nJumpCount == 3 )
205 { // ELSE path
206 aCode.Jump( pJump[ 2 ], pJump[ nJumpCount ] );
208 else
209 { // no parameter given for ELSE
210 nFuncFmtType = NUMBERFORMAT_LOGICAL;
211 PushInt(0);
212 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
220 void ScInterpreter::ScChoseJump()
222 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChoseJump" );
223 // We have to set a jump, if there was none chosen because of an error set
224 // it to endpoint.
225 bool bHaveJump = false;
226 const short* pJump = pCur->GetJump();
227 short nJumpCount = pJump[ 0 ];
228 MatrixDoubleRefToMatrix();
229 switch ( GetStackType() )
231 case svMatrix:
233 ScMatrixRef pMat = PopMatrix();
234 if ( !pMat )
235 PushIllegalParameter();
236 else
238 FormulaTokenRef xNew;
239 ScTokenMatrixMap::const_iterator aMapIter;
240 // DoubleError handled by JumpMatrix
241 pMat->SetErrorInterpreter( NULL);
242 SCSIZE nCols, nRows;
243 pMat->GetDimensions( nCols, nRows );
244 if ( nCols == 0 || nRows == 0 )
245 PushIllegalParameter();
246 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
247 pCur)) != pTokenMatrixMap->end()))
248 xNew = (*aMapIter).second;
249 else
251 ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
252 for ( SCSIZE nC=0; nC < nCols; ++nC )
254 for ( SCSIZE nR=0; nR < nRows; ++nR )
256 double fVal;
257 ScMatValType nType;
258 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
259 nType);
260 bool bIsValue = ScMatrix::IsValueType( nType);
261 if ( bIsValue )
263 fVal = pMatVal->fVal;
264 bIsValue = ::rtl::math::isFinite( fVal );
265 if ( bIsValue )
267 fVal = ::rtl::math::approxFloor( fVal);
268 if ( (fVal < 1) || (fVal >= nJumpCount))
270 bIsValue = FALSE;
271 fVal = CreateDoubleError(
272 errIllegalArgument);
276 else
278 fVal = CreateDoubleError( errNoValue);
280 if ( bIsValue )
282 pJumpMat->SetJump( nC, nR, fVal,
283 pJump[ (short)fVal ],
284 pJump[ nJumpCount ]);
286 else
288 pJumpMat->SetJump( nC, nR, fVal,
289 pJump[ nJumpCount ],
290 pJump[ nJumpCount ]);
294 xNew = new ScJumpMatrixToken( pJumpMat );
295 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
296 pCur, xNew));
298 PushTempToken( xNew);
299 // set endpoint of path for main code line
300 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
301 bHaveJump = true;
304 break;
305 default:
307 double nJumpIndex = ::rtl::math::approxFloor( GetDouble() );
308 if (!nGlobalError && (nJumpIndex >= 1) && (nJumpIndex < nJumpCount))
310 aCode.Jump( pJump[ (short) nJumpIndex ], pJump[ nJumpCount ] );
311 bHaveJump = true;
313 else
314 PushIllegalArgument();
317 if (!bHaveJump)
318 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
321 void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, ScMatrixRef& pResMat, SCSIZE nParmCols, SCSIZE nParmRows )
323 SCSIZE nJumpCols, nJumpRows;
324 SCSIZE nResCols, nResRows;
325 SCSIZE nAdjustCols, nAdjustRows;
326 pJumpM->GetDimensions( nJumpCols, nJumpRows );
327 pJumpM->GetResMatDimensions( nResCols, nResRows );
328 if (( nJumpCols == 1 && nParmCols > nResCols ) ||
329 ( nJumpRows == 1 && nParmRows > nResRows ))
331 if ( nJumpCols == 1 && nJumpRows == 1 )
333 nAdjustCols = nParmCols > nResCols ? nParmCols : nResCols;
334 nAdjustRows = nParmRows > nResRows ? nParmRows : nResRows;
336 else if ( nJumpCols == 1 )
338 nAdjustCols = nParmCols;
339 nAdjustRows = nResRows;
341 else
343 nAdjustCols = nResCols;
344 nAdjustRows = nParmRows;
346 pJumpM->SetNewResMat( nAdjustCols, nAdjustRows );
347 pResMat = pJumpM->GetResultMatrix();
351 bool ScInterpreter::JumpMatrix( short nStackLevel )
353 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::JumpMatrix" );
354 pJumpMatrix = static_cast<ScToken*>(pStack[sp-nStackLevel])->GetJumpMatrix();
355 ScMatrixRef pResMat = pJumpMatrix->GetResultMatrix();
356 SCSIZE nC, nR;
357 if ( nStackLevel == 2 )
359 if ( aCode.HasStacked() )
360 aCode.Pop(); // pop what Jump() pushed
361 else
363 DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
366 if ( !pResMat )
368 Pop();
369 SetError( errUnknownStackVariable );
371 else
373 pJumpMatrix->GetPos( nC, nR );
374 switch ( GetStackType() )
376 case svDouble:
378 double fVal = GetDouble();
379 if ( nGlobalError )
381 fVal = CreateDoubleError( nGlobalError );
382 nGlobalError = 0;
384 pResMat->PutDouble( fVal, nC, nR );
386 break;
387 case svString:
389 const String& rStr = GetString();
390 if ( nGlobalError )
392 pResMat->PutDouble( CreateDoubleError( nGlobalError),
393 nC, nR);
394 nGlobalError = 0;
396 else
397 pResMat->PutString( rStr, nC, nR );
399 break;
400 case svSingleRef:
402 ScAddress aAdr;
403 PopSingleRef( aAdr );
404 if ( nGlobalError )
406 pResMat->PutDouble( CreateDoubleError( nGlobalError),
407 nC, nR);
408 nGlobalError = 0;
410 else
412 ScBaseCell* pCell = GetCell( aAdr );
413 if (HasCellEmptyData( pCell))
414 pResMat->PutEmpty( nC, nR );
415 else if (HasCellValueData( pCell))
417 double fVal = GetCellValue( aAdr, pCell);
418 if ( nGlobalError )
420 fVal = CreateDoubleError(
421 nGlobalError);
422 nGlobalError = 0;
424 pResMat->PutDouble( fVal, nC, nR );
426 else
428 String aStr;
429 GetCellString( aStr, pCell );
430 if ( nGlobalError )
432 pResMat->PutDouble( CreateDoubleError(
433 nGlobalError), nC, nR);
434 nGlobalError = 0;
436 else
437 pResMat->PutString( aStr, nC, nR);
441 break;
442 case svDoubleRef:
443 { // upper left plus offset within matrix
444 double fVal;
445 ScRange aRange;
446 PopDoubleRef( aRange );
447 if ( nGlobalError )
449 fVal = CreateDoubleError( nGlobalError );
450 nGlobalError = 0;
451 pResMat->PutDouble( fVal, nC, nR );
453 else
455 // Do not modify the original range because we use it
456 // to adjust the size of the result matrix if necessary.
457 ScAddress aAdr( aRange.aStart);
458 ULONG nCol = (ULONG)aAdr.Col() + nC;
459 ULONG nRow = (ULONG)aAdr.Row() + nR;
460 if ((nCol > static_cast<ULONG>(aRange.aEnd.Col()) &&
461 aRange.aEnd.Col() != aRange.aStart.Col())
462 || (nRow > static_cast<ULONG>(aRange.aEnd.Row()) &&
463 aRange.aEnd.Row() != aRange.aStart.Row()))
465 fVal = CreateDoubleError( NOTAVAILABLE );
466 pResMat->PutDouble( fVal, nC, nR );
468 else
470 // Replicate column and/or row of a vector if it is
471 // one. Note that this could be a range reference
472 // that in fact consists of only one cell, e.g. A1:A1
473 if (aRange.aEnd.Col() == aRange.aStart.Col())
474 nCol = aRange.aStart.Col();
475 if (aRange.aEnd.Row() == aRange.aStart.Row())
476 nRow = aRange.aStart.Row();
477 aAdr.SetCol( static_cast<SCCOL>(nCol) );
478 aAdr.SetRow( static_cast<SCROW>(nRow) );
479 ScBaseCell* pCell = GetCell( aAdr );
480 if (HasCellEmptyData( pCell))
481 pResMat->PutEmpty( nC, nR );
482 else if (HasCellValueData( pCell))
484 double fCellVal = GetCellValue( aAdr, pCell);
485 if ( nGlobalError )
487 fCellVal = CreateDoubleError(
488 nGlobalError);
489 nGlobalError = 0;
491 pResMat->PutDouble( fCellVal, nC, nR );
493 else
495 String aStr;
496 GetCellString( aStr, pCell );
497 if ( nGlobalError )
499 pResMat->PutDouble( CreateDoubleError(
500 nGlobalError), nC, nR);
501 nGlobalError = 0;
503 else
504 pResMat->PutString( aStr, nC, nR );
507 SCSIZE nParmCols = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
508 SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
509 lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nParmCols, nParmRows );
512 break;
513 case svMatrix:
514 { // match matrix offsets
515 double fVal;
516 ScMatrixRef pMat = PopMatrix();
517 if ( nGlobalError )
519 fVal = CreateDoubleError( nGlobalError );
520 nGlobalError = 0;
521 pResMat->PutDouble( fVal, nC, nR );
523 else if ( !pMat )
525 fVal = CreateDoubleError( errUnknownVariable );
526 pResMat->PutDouble( fVal, nC, nR );
528 else
530 SCSIZE nCols, nRows;
531 pMat->GetDimensions( nCols, nRows );
532 if ((nCols <= nC && nCols != 1) ||
533 (nRows <= nR && nRows != 1))
535 fVal = CreateDoubleError( NOTAVAILABLE );
536 pResMat->PutDouble( fVal, nC, nR );
538 else
540 if ( pMat->IsValue( nC, nR ) )
542 fVal = pMat->GetDouble( nC, nR );
543 pResMat->PutDouble( fVal, nC, nR );
545 else if ( pMat->IsEmpty( nC, nR ) )
546 pResMat->PutEmpty( nC, nR );
547 else
549 const String& rStr = pMat->GetString( nC, nR );
550 pResMat->PutString( rStr, nC, nR );
553 lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nCols, nRows );
556 break;
557 case svError:
559 PopError();
560 double fVal = CreateDoubleError( nGlobalError);
561 nGlobalError = 0;
562 pResMat->PutDouble( fVal, nC, nR );
564 break;
565 default:
567 Pop();
568 double fVal = CreateDoubleError( errIllegalArgument);
569 pResMat->PutDouble( fVal, nC, nR );
574 bool bCont = pJumpMatrix->Next( nC, nR );
575 if ( bCont )
577 double fBool;
578 short nStart, nNext, nStop;
579 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
580 while ( bCont && nStart == nNext )
581 { // push all results that have no jump path
582 if ( pResMat )
584 // a FALSE without path results in an empty path value
585 if ( fBool == 0.0 )
586 pResMat->PutEmptyPath( nC, nR );
587 else
588 pResMat->PutDouble( fBool, nC, nR );
590 bCont = pJumpMatrix->Next( nC, nR );
591 if ( bCont )
592 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
594 if ( bCont && nStart != nNext )
596 const ScTokenVec* pParams = pJumpMatrix->GetJumpParameters();
597 if ( pParams )
599 for ( ScTokenVec::const_iterator i = pParams->begin();
600 i != pParams->end(); ++i )
602 // This is not the current state of the interpreter, so
603 // push without error, and elements' errors are coded into
604 // double.
605 PushWithoutError( *(*i));
608 aCode.Jump( nStart, nNext, nStop );
611 if ( !bCont )
612 { // we're done with it, throw away jump matrix, keep result
613 pJumpMatrix = NULL;
614 Pop();
615 PushMatrix( pResMat );
616 // Remove jump matrix from map and remember result matrix in case it
617 // could be reused in another path of the same condition.
618 if (pTokenMatrixMap)
620 pTokenMatrixMap->erase( pCur);
621 pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
622 pStack[sp-1]));
624 return true;
626 return false;
630 double ScInterpreter::CompareFunc( const ScCompare& rComp )
632 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareFunc" );
633 // Keep DoubleError if encountered
634 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
635 if ( !rComp.bEmpty[0] && rComp.bVal[0] && !::rtl::math::isFinite( rComp.nVal[0]))
636 return rComp.nVal[0];
637 if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1]))
638 return rComp.nVal[1];
640 double fRes = 0;
641 if ( rComp.bEmpty[ 0 ] )
643 if ( rComp.bEmpty[ 1 ] )
644 ; // empty cell == empty cell, fRes 0
645 else if( rComp.bVal[ 1 ] )
647 if ( !::rtl::math::approxEqual( rComp.nVal[ 1 ], 0.0 ) )
649 if ( rComp.nVal[ 1 ] < 0.0 )
650 fRes = 1; // empty cell > -x
651 else
652 fRes = -1; // empty cell < x
654 // else: empty cell == 0.0
656 else
658 if ( rComp.pVal[ 1 ]->Len() )
659 fRes = -1; // empty cell < "..."
660 // else: empty cell == ""
663 else if ( rComp.bEmpty[ 1 ] )
665 if( rComp.bVal[ 0 ] )
667 if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], 0.0 ) )
669 if ( rComp.nVal[ 0 ] < 0.0 )
670 fRes = -1; // -x < empty cell
671 else
672 fRes = 1; // x > empty cell
674 // else: empty cell == 0.0
676 else
678 if ( rComp.pVal[ 0 ]->Len() )
679 fRes = 1; // "..." > empty cell
680 // else: "" == empty cell
683 else if( rComp.bVal[ 0 ] )
685 if( rComp.bVal[ 1 ] )
687 if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], rComp.nVal[ 1 ] ) )
689 if( rComp.nVal[ 0 ] - rComp.nVal[ 1 ] < 0 )
690 fRes = -1;
691 else
692 fRes = 1;
695 else
696 fRes = -1; // number is less than string
698 else if( rComp.bVal[ 1 ] )
699 fRes = 1; // number is less than string
700 else
702 if (pDok->GetDocOptions().IsIgnoreCase())
703 fRes = (double) ScGlobal::pCollator->compareString(
704 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
705 else
706 fRes = (double) ScGlobal::pCaseCollator->compareString(
707 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
709 return fRes;
713 double ScInterpreter::Compare()
715 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Compare" );
716 String aVal1, aVal2;
717 ScCompare aComp( &aVal1, &aVal2 );
718 for( short i = 1; i >= 0; i-- )
720 switch ( GetRawStackType() )
722 case svEmptyCell:
723 aComp.bEmpty[ i ] = TRUE;
724 break;
725 case svMissing:
726 case svDouble:
727 aComp.nVal[ i ] = GetDouble();
728 aComp.bVal[ i ] = TRUE;
729 break;
730 case svString:
731 *aComp.pVal[ i ] = GetString();
732 aComp.bVal[ i ] = FALSE;
733 break;
734 case svDoubleRef :
735 case svSingleRef :
737 ScAddress aAdr;
738 if ( !PopDoubleRefOrSingleRef( aAdr ) )
739 break;
740 ScBaseCell* pCell = GetCell( aAdr );
741 if (HasCellEmptyData( pCell))
742 aComp.bEmpty[ i ] = TRUE;
743 else if (HasCellStringData( pCell))
745 GetCellString( *aComp.pVal[ i ], pCell);
746 aComp.bVal[ i ] = FALSE;
748 else
750 aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
751 aComp.bVal[ i ] = TRUE;
754 break;
755 default:
756 SetError( errIllegalParameter);
757 break;
760 if( nGlobalError )
761 return 0;
762 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
763 return CompareFunc( aComp );
767 ScMatrixRef ScInterpreter::CompareMat()
769 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareMat" );
770 String aVal1, aVal2;
771 ScCompare aComp( &aVal1, &aVal2 );
772 ScMatrixRef pMat[2];
773 ScAddress aAdr;
774 for( short i = 1; i >= 0; i-- )
776 switch (GetRawStackType())
778 case svEmptyCell:
779 aComp.bEmpty[ i ] = TRUE;
780 break;
781 case svMissing:
782 case svDouble:
783 aComp.nVal[ i ] = GetDouble();
784 aComp.bVal[ i ] = TRUE;
785 break;
786 case svString:
787 *aComp.pVal[ i ] = GetString();
788 aComp.bVal[ i ] = FALSE;
789 break;
790 case svSingleRef:
792 PopSingleRef( aAdr );
793 ScBaseCell* pCell = GetCell( aAdr );
794 if (HasCellEmptyData( pCell))
795 aComp.bEmpty[ i ] = TRUE;
796 else if (HasCellStringData( pCell))
798 GetCellString( *aComp.pVal[ i ], pCell);
799 aComp.bVal[ i ] = FALSE;
801 else
803 aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
804 aComp.bVal[ i ] = TRUE;
807 break;
808 case svDoubleRef:
809 case svMatrix:
810 pMat[ i ] = GetMatrix();
811 if ( !pMat[ i ] )
812 SetError( errIllegalParameter);
813 else
814 pMat[i]->SetErrorInterpreter( NULL);
815 // errors are transported as DoubleError inside matrix
816 break;
817 default:
818 SetError( errIllegalParameter);
819 break;
822 ScMatrixRef pResMat = NULL;
823 if( !nGlobalError )
825 if ( pMat[0] && pMat[1] )
827 SCSIZE nC0, nC1;
828 SCSIZE nR0, nR1;
829 pMat[0]->GetDimensions( nC0, nR0 );
830 pMat[1]->GetDimensions( nC1, nR1 );
831 SCSIZE nC = Max( nC0, nC1 );
832 SCSIZE nR = Max( nR0, nR1 );
833 pResMat = GetNewMat( nC, nR);
834 if ( !pResMat )
835 return NULL;
836 for ( SCSIZE j=0; j<nC; j++ )
838 for ( SCSIZE k=0; k<nR; k++ )
840 SCSIZE nCol = j, nRow = k;
841 if ( pMat[0]->ValidColRowOrReplicated( nCol, nRow ) &&
842 pMat[1]->ValidColRowOrReplicated( nCol, nRow ))
844 for ( short i=1; i>=0; i-- )
846 if ( pMat[i]->IsString(j,k) )
848 aComp.bVal[i] = FALSE;
849 *aComp.pVal[i] = pMat[i]->GetString(j,k);
850 aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
852 else
854 aComp.bVal[i] = TRUE;
855 aComp.nVal[i] = pMat[i]->GetDouble(j,k);
856 aComp.bEmpty[i] = FALSE;
859 pResMat->PutDouble( CompareFunc( aComp ), j,k );
861 else
862 pResMat->PutString( ScGlobal::GetRscString(STR_NO_VALUE), j,k );
866 else if ( pMat[0] || pMat[1] )
868 short i = ( pMat[0] ? 0 : 1);
869 SCSIZE nC, nR;
870 pMat[i]->GetDimensions( nC, nR );
871 pResMat = GetNewMat( nC, nR);
872 if ( !pResMat )
873 return NULL;
874 SCSIZE n = nC * nR;
875 for ( SCSIZE j=0; j<n; j++ )
877 if ( pMat[i]->IsValue(j) )
879 aComp.bVal[i] = TRUE;
880 aComp.nVal[i] = pMat[i]->GetDouble(j);
881 aComp.bEmpty[i] = FALSE;
883 else
885 aComp.bVal[i] = FALSE;
886 *aComp.pVal[i] = pMat[i]->GetString(j);
887 aComp.bEmpty[i] = pMat[i]->IsEmpty(j);
889 pResMat->PutDouble( CompareFunc( aComp ), j );
893 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
894 return pResMat;
898 void ScInterpreter::ScEqual()
900 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEqual" );
901 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
903 ScMatrixRef pMat = CompareMat();
904 if ( !pMat )
905 PushIllegalParameter();
906 else
908 pMat->CompareEqual();
909 PushMatrix( pMat );
912 else
913 PushInt( Compare() == 0 );
917 void ScInterpreter::ScNotEqual()
919 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNotEqual" );
920 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
922 ScMatrixRef pMat = CompareMat();
923 if ( !pMat )
924 PushIllegalParameter();
925 else
927 pMat->CompareNotEqual();
928 PushMatrix( pMat );
931 else
932 PushInt( Compare() != 0 );
936 void ScInterpreter::ScLess()
938 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLess" );
939 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
941 ScMatrixRef pMat = CompareMat();
942 if ( !pMat )
943 PushIllegalParameter();
944 else
946 pMat->CompareLess();
947 PushMatrix( pMat );
950 else
951 PushInt( Compare() < 0 );
955 void ScInterpreter::ScGreater()
957 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGreater" );
958 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
960 ScMatrixRef pMat = CompareMat();
961 if ( !pMat )
962 PushIllegalParameter();
963 else
965 pMat->CompareGreater();
966 PushMatrix( pMat );
969 else
970 PushInt( Compare() > 0 );
974 void ScInterpreter::ScLessEqual()
976 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLessEqual" );
977 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
979 ScMatrixRef pMat = CompareMat();
980 if ( !pMat )
981 PushIllegalParameter();
982 else
984 pMat->CompareLessEqual();
985 PushMatrix( pMat );
988 else
989 PushInt( Compare() <= 0 );
993 void ScInterpreter::ScGreaterEqual()
995 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGreaterEqual" );
996 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
998 ScMatrixRef pMat = CompareMat();
999 if ( !pMat )
1000 PushIllegalParameter();
1001 else
1003 pMat->CompareGreaterEqual();
1004 PushMatrix( pMat );
1007 else
1008 PushInt( Compare() >= 0 );
1012 void ScInterpreter::ScAnd()
1014 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAnd" );
1015 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1016 short nParamCount = GetByte();
1017 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1019 BOOL bHaveValue = FALSE;
1020 short nRes = TRUE;
1021 size_t nRefInList = 0;
1022 while( nParamCount-- > 0)
1024 if ( !nGlobalError )
1026 switch ( GetStackType() )
1028 case svDouble :
1029 bHaveValue = TRUE;
1030 nRes &= ( PopDouble() != 0.0 );
1031 break;
1032 case svString :
1033 Pop();
1034 SetError( errNoValue );
1035 break;
1036 case svSingleRef :
1038 ScAddress aAdr;
1039 PopSingleRef( aAdr );
1040 if ( !nGlobalError )
1042 ScBaseCell* pCell = GetCell( aAdr );
1043 if ( HasCellValueData( pCell ) )
1045 bHaveValue = TRUE;
1046 nRes &= ( GetCellValue( aAdr, pCell ) != 0.0 );
1048 // else: Xcl setzt hier keinen Fehler
1051 break;
1052 case svDoubleRef:
1053 case svRefList:
1055 ScRange aRange;
1056 PopDoubleRef( aRange, nParamCount, nRefInList);
1057 if ( !nGlobalError )
1059 double fVal;
1060 USHORT nErr = 0;
1061 ScValueIterator aValIter( pDok, aRange );
1062 if ( aValIter.GetFirst( fVal, nErr ) )
1064 bHaveValue = TRUE;
1067 nRes &= ( fVal != 0.0 );
1068 } while ( (nErr == 0) &&
1069 aValIter.GetNext( fVal, nErr ) );
1071 SetError( nErr );
1074 break;
1075 case svMatrix:
1077 ScMatrixRef pMat = GetMatrix();
1078 if ( pMat )
1080 bHaveValue = TRUE;
1081 double fVal = pMat->And();
1082 USHORT nErr = GetDoubleErrorValue( fVal );
1083 if ( nErr )
1085 SetError( nErr );
1086 nRes = FALSE;
1088 else
1089 nRes &= (fVal != 0.0);
1091 // else: GetMatrix did set errIllegalParameter
1093 break;
1094 default:
1095 Pop();
1096 SetError( errIllegalParameter);
1099 else
1100 Pop();
1102 if ( bHaveValue )
1103 PushInt( nRes );
1104 else
1105 PushNoValue();
1110 void ScInterpreter::ScOr()
1112 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOr" );
1113 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1114 short nParamCount = GetByte();
1115 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1117 BOOL bHaveValue = FALSE;
1118 short nRes = FALSE;
1119 size_t nRefInList = 0;
1120 while( nParamCount-- > 0)
1122 if ( !nGlobalError )
1124 switch ( GetStackType() )
1126 case svDouble :
1127 bHaveValue = TRUE;
1128 nRes |= ( PopDouble() != 0.0 );
1129 break;
1130 case svString :
1131 Pop();
1132 SetError( errNoValue );
1133 break;
1134 case svSingleRef :
1136 ScAddress aAdr;
1137 PopSingleRef( aAdr );
1138 if ( !nGlobalError )
1140 ScBaseCell* pCell = GetCell( aAdr );
1141 if ( HasCellValueData( pCell ) )
1143 bHaveValue = TRUE;
1144 nRes |= ( GetCellValue( aAdr, pCell ) != 0.0 );
1146 // else: Xcl setzt hier keinen Fehler
1149 break;
1150 case svDoubleRef:
1151 case svRefList:
1153 ScRange aRange;
1154 PopDoubleRef( aRange, nParamCount, nRefInList);
1155 if ( !nGlobalError )
1157 double fVal;
1158 USHORT nErr = 0;
1159 ScValueIterator aValIter( pDok, aRange );
1160 if ( aValIter.GetFirst( fVal, nErr ) )
1162 bHaveValue = TRUE;
1165 nRes |= ( fVal != 0.0 );
1166 } while ( (nErr == 0) &&
1167 aValIter.GetNext( fVal, nErr ) );
1169 SetError( nErr );
1172 break;
1173 case svMatrix:
1175 bHaveValue = TRUE;
1176 ScMatrixRef pMat = GetMatrix();
1177 if ( pMat )
1179 bHaveValue = TRUE;
1180 double fVal = pMat->Or();
1181 USHORT nErr = GetDoubleErrorValue( fVal );
1182 if ( nErr )
1184 SetError( nErr );
1185 nRes = FALSE;
1187 else
1188 nRes |= (fVal != 0.0);
1190 // else: GetMatrix did set errIllegalParameter
1192 break;
1193 default:
1194 Pop();
1195 SetError( errIllegalParameter);
1198 else
1199 Pop();
1201 if ( bHaveValue )
1202 PushInt( nRes );
1203 else
1204 PushNoValue();
1209 void ScInterpreter::ScNeg()
1211 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNeg" );
1212 // Simple negation doesn't change current format type to number, keep
1213 // current type.
1214 nFuncFmtType = nCurFmtType;
1215 switch ( GetStackType() )
1217 case svMatrix :
1219 ScMatrixRef pMat = GetMatrix();
1220 if ( !pMat )
1221 PushIllegalParameter();
1222 else
1224 SCSIZE nC, nR;
1225 pMat->GetDimensions( nC, nR );
1226 ScMatrixRef pResMat = GetNewMat( nC, nR);
1227 if ( !pResMat )
1228 PushIllegalArgument();
1229 else
1231 SCSIZE nCount = nC * nR;
1232 for ( SCSIZE j=0; j<nCount; ++j )
1234 if ( pMat->IsValueOrEmpty(j) )
1235 pResMat->PutDouble( -pMat->GetDouble(j), j );
1236 else
1237 pResMat->PutString(
1238 ScGlobal::GetRscString( STR_NO_VALUE ), j );
1240 PushMatrix( pResMat );
1244 break;
1245 default:
1246 PushDouble( -GetDouble() );
1251 void ScInterpreter::ScPercentSign()
1253 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentSign" );
1254 nFuncFmtType = NUMBERFORMAT_PERCENT;
1255 const FormulaToken* pSaveCur = pCur;
1256 BYTE nSavePar = cPar;
1257 PushInt( 100 );
1258 cPar = 2;
1259 FormulaByteToken aDivOp( ocDiv, cPar );
1260 pCur = &aDivOp;
1261 ScDiv();
1262 pCur = pSaveCur;
1263 cPar = nSavePar;
1267 void ScInterpreter::ScNot()
1269 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNot" );
1270 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1271 switch ( GetStackType() )
1273 case svMatrix :
1275 ScMatrixRef pMat = GetMatrix();
1276 if ( !pMat )
1277 PushIllegalParameter();
1278 else
1280 SCSIZE nC, nR;
1281 pMat->GetDimensions( nC, nR );
1282 ScMatrixRef pResMat = GetNewMat( nC, nR);
1283 if ( !pResMat )
1284 PushIllegalArgument();
1285 else
1287 SCSIZE nCount = nC * nR;
1288 for ( SCSIZE j=0; j<nCount; ++j )
1290 if ( pMat->IsValueOrEmpty(j) )
1291 pResMat->PutDouble( (pMat->GetDouble(j) == 0.0), j );
1292 else
1293 pResMat->PutString(
1294 ScGlobal::GetRscString( STR_NO_VALUE ), j );
1296 PushMatrix( pResMat );
1300 break;
1301 default:
1302 PushInt( GetDouble() == 0.0 );
1307 void ScInterpreter::ScPi()
1309 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPi" );
1310 PushDouble(F_PI);
1314 void ScInterpreter::ScRandom()
1316 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRandom" );
1317 PushDouble((double)rand() / ((double)RAND_MAX+1.0));
1321 void ScInterpreter::ScTrue()
1323 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrue" );
1324 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1325 PushInt(1);
1329 void ScInterpreter::ScFalse()
1331 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFalse" );
1332 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1333 PushInt(0);
1337 void ScInterpreter::ScDeg()
1339 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDeg" );
1340 PushDouble((GetDouble() / F_PI) * 180.0);
1344 void ScInterpreter::ScRad()
1346 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRad" );
1347 PushDouble(GetDouble() * (F_PI / 180));
1351 void ScInterpreter::ScSin()
1353 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSin" );
1354 PushDouble(::rtl::math::sin(GetDouble()));
1358 void ScInterpreter::ScCos()
1360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCos" );
1361 PushDouble(::rtl::math::cos(GetDouble()));
1365 void ScInterpreter::ScTan()
1367 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTan" );
1368 PushDouble(::rtl::math::tan(GetDouble()));
1372 void ScInterpreter::ScCot()
1374 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCot" );
1375 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1379 void ScInterpreter::ScArcSin()
1381 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcSin" );
1382 PushDouble(asin(GetDouble()));
1386 void ScInterpreter::ScArcCos()
1388 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCos" );
1389 PushDouble(acos(GetDouble()));
1393 void ScInterpreter::ScArcTan()
1395 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTan" );
1396 PushDouble(atan(GetDouble()));
1400 void ScInterpreter::ScArcCot()
1402 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCot" );
1403 PushDouble((F_PI2) - atan(GetDouble()));
1407 void ScInterpreter::ScSinHyp()
1409 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSinHyp" );
1410 PushDouble(sinh(GetDouble()));
1414 void ScInterpreter::ScCosHyp()
1416 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCosHyp" );
1417 PushDouble(cosh(GetDouble()));
1421 void ScInterpreter::ScTanHyp()
1423 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTanHyp" );
1424 PushDouble(tanh(GetDouble()));
1428 void ScInterpreter::ScCotHyp()
1430 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCotHyp" );
1431 PushDouble(1.0 / tanh(GetDouble()));
1435 void ScInterpreter::ScArcSinHyp()
1437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcSinHyp" );
1438 double nVal = GetDouble();
1439 PushDouble(log(nVal + sqrt((nVal * nVal) + 1.0)));
1443 void ScInterpreter::ScArcCosHyp()
1445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCosHyp" );
1446 double nVal = GetDouble();
1447 if (nVal < 1.0)
1448 PushIllegalArgument();
1449 else
1450 PushDouble(log(nVal + sqrt((nVal * nVal) - 1.0)));
1454 void ScInterpreter::ScArcTanHyp()
1456 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTanHyp" );
1457 double fVal = GetDouble();
1458 if (fabs(fVal) >= 1.0)
1459 PushIllegalArgument();
1460 else
1461 PushDouble( ::rtl::math::atanh( fVal));
1465 void ScInterpreter::ScArcCotHyp()
1467 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCotHyp" );
1468 double nVal = GetDouble();
1469 if (fabs(nVal) <= 1.0)
1470 PushIllegalArgument();
1471 else
1472 PushDouble(0.5 * log((nVal + 1.0) / (nVal - 1.0)));
1476 void ScInterpreter::ScExp()
1478 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExp" );
1479 PushDouble(exp(GetDouble()));
1483 void ScInterpreter::ScSqrt()
1485 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSqrt" );
1486 double fVal = GetDouble();
1487 if (fVal >= 0.0)
1488 PushDouble(sqrt(fVal));
1489 else
1490 PushIllegalArgument();
1494 void ScInterpreter::ScIsEmpty()
1496 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsEmpty" );
1497 short nRes = 0;
1498 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1499 switch ( GetRawStackType() )
1501 case svEmptyCell:
1503 FormulaTokenRef p = PopToken();
1504 if (!static_cast<const ScEmptyCellToken*>(p.get())->IsInherited())
1505 nRes = 1;
1507 break;
1508 case svDoubleRef :
1509 case svSingleRef :
1511 ScAddress aAdr;
1512 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1513 break;
1514 // NOTE: this could test also on inherited emptiness, but then the
1515 // cell tested wouldn't be empty. Must correspond with
1516 // ScCountEmptyCells().
1517 // if (HasCellEmptyData( GetCell( aAdr)))
1518 CellType eCellType = GetCellType( GetCell( aAdr ) );
1519 if((eCellType == CELLTYPE_NONE) || (eCellType == CELLTYPE_NOTE))
1520 nRes = 1;
1522 break;
1523 case svMatrix:
1525 ScMatrixRef pMat = PopMatrix();
1526 if ( !pMat )
1527 ; // nothing
1528 else if ( !pJumpMatrix )
1529 nRes = pMat->IsEmpty( 0 );
1530 else
1532 SCSIZE nCols, nRows, nC, nR;
1533 pMat->GetDimensions( nCols, nRows);
1534 pJumpMatrix->GetPos( nC, nR);
1535 if ( nC < nCols && nR < nRows )
1536 nRes = pMat->IsEmpty( nC, nR);
1537 // else: FALSE, not empty (which is what Xcl does)
1540 break;
1541 default:
1542 Pop();
1544 nGlobalError = 0;
1545 PushInt( nRes );
1549 short ScInterpreter::IsString()
1551 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IsString" );
1552 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1553 short nRes = 0;
1554 switch ( GetRawStackType() )
1556 case svString:
1557 Pop();
1558 nRes = 1;
1559 break;
1560 case svDoubleRef :
1561 case svSingleRef :
1563 ScAddress aAdr;
1564 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1565 break;
1566 ScBaseCell* pCell = GetCell( aAdr );
1567 if (GetCellErrCode( pCell ) == 0)
1569 switch ( GetCellType( pCell ) )
1571 case CELLTYPE_STRING :
1572 case CELLTYPE_EDIT :
1573 nRes = 1;
1574 break;
1575 case CELLTYPE_FORMULA :
1576 nRes = !((ScFormulaCell*)pCell)->IsValue() &&
1577 !((ScFormulaCell*)pCell)->IsEmpty();
1578 break;
1579 default:
1580 ; // nothing
1584 break;
1585 case svMatrix:
1587 ScMatrixRef pMat = PopMatrix();
1588 if ( !pMat )
1589 ; // nothing
1590 else if ( !pJumpMatrix )
1591 nRes = pMat->IsString(0) && !pMat->IsEmpty(0);
1592 else
1594 SCSIZE nCols, nRows, nC, nR;
1595 pMat->GetDimensions( nCols, nRows);
1596 pJumpMatrix->GetPos( nC, nR);
1597 if ( nC < nCols && nR < nRows )
1598 nRes = pMat->IsString( nC, nR) && !pMat->IsEmpty( nC, nR);
1601 break;
1602 default:
1603 Pop();
1605 nGlobalError = 0;
1606 return nRes;
1610 void ScInterpreter::ScIsString()
1612 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsString" );
1613 PushInt( IsString() );
1617 void ScInterpreter::ScIsNonString()
1619 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsNonString" );
1620 PushInt( !IsString() );
1624 void ScInterpreter::ScIsLogical()
1626 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsLogical" );
1627 short nRes = 0;
1628 switch ( GetStackType() )
1630 case svDoubleRef :
1631 case svSingleRef :
1633 ScAddress aAdr;
1634 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1635 break;
1636 ScBaseCell* pCell = GetCell( aAdr );
1637 if (GetCellErrCode( pCell ) == 0)
1639 if (HasCellValueData(pCell))
1641 ULONG nFormat = GetCellNumberFormat( aAdr, pCell );
1642 nRes = ( pFormatter->GetType(nFormat)
1643 == NUMBERFORMAT_LOGICAL);
1647 break;
1648 case svMatrix:
1649 // TODO: we don't have type information for arrays except
1650 // numerical/string.
1651 // Fall thru
1652 default:
1653 PopError();
1654 if ( !nGlobalError )
1655 nRes = ( nCurFmtType == NUMBERFORMAT_LOGICAL );
1657 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
1658 nGlobalError = 0;
1659 PushInt( nRes );
1663 void ScInterpreter::ScType()
1665 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScType" );
1666 short nType = 0;
1667 switch ( GetStackType() )
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 // NOTE: this is Xcl nonsense!
1681 case CELLTYPE_NOTE :
1682 nType = 1; // empty cell is value (0)
1683 break;
1684 case CELLTYPE_STRING :
1685 case CELLTYPE_EDIT :
1686 nType = 2;
1687 break;
1688 case CELLTYPE_VALUE :
1690 ULONG nFormat = GetCellNumberFormat( aAdr, pCell );
1691 if (pFormatter->GetType(nFormat)
1692 == NUMBERFORMAT_LOGICAL)
1693 nType = 4;
1694 else
1695 nType = 1;
1697 break;
1698 case CELLTYPE_FORMULA :
1699 nType = 8;
1700 break;
1701 default:
1702 PushIllegalArgument();
1705 else
1706 nType = 16;
1708 break;
1709 case svString:
1710 PopError();
1711 if ( nGlobalError )
1713 nType = 16;
1714 nGlobalError = 0;
1716 else
1717 nType = 2;
1718 break;
1719 case svMatrix:
1720 PopMatrix();
1721 if ( nGlobalError )
1723 nType = 16;
1724 nGlobalError = 0;
1726 else
1727 nType = 64;
1728 // we could return the type of one element if in JumpMatrix or
1729 // ForceArray mode, but Xcl doesn't ...
1730 break;
1731 default:
1732 PopError();
1733 if ( nGlobalError )
1735 nType = 16;
1736 nGlobalError = 0;
1738 else
1739 nType = 1;
1741 PushInt( nType );
1745 inline BOOL lcl_FormatHasNegColor( const SvNumberformat* pFormat )
1747 return pFormat && pFormat->GetColor( 1 );
1751 inline BOOL lcl_FormatHasOpenPar( const SvNumberformat* pFormat )
1753 return pFormat && (pFormat->GetFormatstring().Search( '(' ) != STRING_NOTFOUND);
1757 void ScInterpreter::ScCell()
1758 { // ATTRIBUTE ; [REF]
1759 BYTE nParamCount = GetByte();
1760 if( MustHaveParamCount( nParamCount, 1, 2 ) )
1762 ScAddress aCellPos( aPos );
1763 BOOL bError = FALSE;
1764 if( nParamCount == 2 )
1765 bError = !PopDoubleRefOrSingleRef( aCellPos );
1766 String aInfoType( GetString() );
1767 if( bError || nGlobalError )
1768 PushIllegalParameter();
1769 else
1771 String aFuncResult;
1772 ScBaseCell* pCell = GetCell( aCellPos );
1774 ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::pLocale, ocCell);
1776 // *** ADDRESS INFO ***
1777 if( aInfoType.EqualsAscii( "COL" ) )
1778 { // column number (1-based)
1779 PushInt( aCellPos.Col() + 1 );
1781 else if( aInfoType.EqualsAscii( "ROW" ) )
1782 { // row number (1-based)
1783 PushInt( aCellPos.Row() + 1 );
1785 else if( aInfoType.EqualsAscii( "SHEET" ) )
1786 { // table number (1-based)
1787 PushInt( aCellPos.Tab() + 1 );
1789 else if( aInfoType.EqualsAscii( "ADDRESS" ) )
1790 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
1791 USHORT nFlags = (aCellPos.Tab() == aPos.Tab()) ? (SCA_ABS) : (SCA_ABS_3D);
1792 aCellPos.Format( aFuncResult, nFlags, pDok, pDok->GetAddressConvention() );
1793 PushString( aFuncResult );
1795 else if( aInfoType.EqualsAscii( "FILENAME" ) )
1796 { // file name and table name: 'FILENAME'#$TABLE
1797 SCTAB nTab = aCellPos.Tab();
1798 if( nTab < pDok->GetTableCount() )
1800 if( pDok->GetLinkMode( nTab ) == SC_LINK_VALUE )
1801 pDok->GetName( nTab, aFuncResult );
1802 else
1804 SfxObjectShell* pShell = pDok->GetDocumentShell();
1805 if( pShell && pShell->GetMedium() )
1807 aFuncResult = (sal_Unicode) '\'';
1808 const INetURLObject& rURLObj = pShell->GetMedium()->GetURLObject();
1809 aFuncResult += String( rURLObj.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS ) );
1810 aFuncResult.AppendAscii( "'#$" );
1811 String aTabName;
1812 pDok->GetName( nTab, aTabName );
1813 aFuncResult += aTabName;
1817 PushString( aFuncResult );
1819 else if( aInfoType.EqualsAscii( "COORD" ) )
1820 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
1821 // Yes, passing tab as col is intentional!
1822 ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format(
1823 aFuncResult, (SCA_COL_ABSOLUTE|SCA_VALID_COL), NULL, pDok->GetAddressConvention() );
1824 aFuncResult += ':';
1825 String aCellStr;
1826 aCellPos.Format( aCellStr, (SCA_COL_ABSOLUTE|SCA_VALID_COL|SCA_ROW_ABSOLUTE|SCA_VALID_ROW),
1827 NULL, pDok->GetAddressConvention() );
1828 aFuncResult += aCellStr;
1829 PushString( aFuncResult );
1832 // *** CELL PROPERTIES ***
1833 else if( aInfoType.EqualsAscii( "CONTENTS" ) )
1834 { // contents of the cell, no formatting
1835 if( pCell && pCell->HasStringData() )
1837 GetCellString( aFuncResult, pCell );
1838 PushString( aFuncResult );
1840 else
1841 PushDouble( GetCellValue( aCellPos, pCell ) );
1843 else if( aInfoType.EqualsAscii( "TYPE" ) )
1844 { // b = blank; l = string (label); v = otherwise (value)
1845 if( HasCellStringData( pCell ) )
1846 aFuncResult = 'l';
1847 else
1848 aFuncResult = HasCellValueData( pCell ) ? 'v' : 'b';
1849 PushString( aFuncResult );
1851 else if( aInfoType.EqualsAscii( "WIDTH" ) )
1852 { // column width (rounded off as count of zero characters in standard font and size)
1853 Printer* pPrinter = pDok->GetPrinter();
1854 MapMode aOldMode( pPrinter->GetMapMode() );
1855 Font aOldFont( pPrinter->GetFont() );
1856 Font aDefFont;
1858 pPrinter->SetMapMode( MAP_TWIP );
1859 // font color doesn't matter here
1860 pDok->GetDefPattern()->GetFont( aDefFont, SC_AUTOCOL_BLACK, pPrinter );
1861 pPrinter->SetFont( aDefFont );
1862 long nZeroWidth = pPrinter->GetTextWidth( String( '0' ) );
1863 pPrinter->SetFont( aOldFont );
1864 pPrinter->SetMapMode( aOldMode );
1865 int nZeroCount = (int)(pDok->GetColWidth( aCellPos.Col(), aCellPos.Tab() ) / nZeroWidth);
1866 PushInt( nZeroCount );
1868 else if( aInfoType.EqualsAscii( "PREFIX" ) )
1869 { // ' = left; " = right; ^ = centered
1870 if( HasCellStringData( pCell ) )
1872 const SvxHorJustifyItem* pJustAttr = (const SvxHorJustifyItem*)
1873 pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_HOR_JUSTIFY );
1874 switch( pJustAttr->GetValue() )
1876 case SVX_HOR_JUSTIFY_STANDARD:
1877 case SVX_HOR_JUSTIFY_LEFT:
1878 case SVX_HOR_JUSTIFY_BLOCK: aFuncResult = '\''; break;
1879 case SVX_HOR_JUSTIFY_CENTER: aFuncResult = '^'; break;
1880 case SVX_HOR_JUSTIFY_RIGHT: aFuncResult = '"'; break;
1881 case SVX_HOR_JUSTIFY_REPEAT: aFuncResult = '\\'; break;
1884 PushString( aFuncResult );
1886 else if( aInfoType.EqualsAscii( "PROTECT" ) )
1887 { // 1 = cell locked
1888 const ScProtectionAttr* pProtAttr = (const ScProtectionAttr*)
1889 pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION );
1890 PushInt( pProtAttr->GetProtection() ? 1 : 0 );
1893 // *** FORMATTING ***
1894 else if( aInfoType.EqualsAscii( "FORMAT" ) )
1895 { // specific format code for standard formats
1896 ULONG nFormat = pDok->GetNumberFormat( aCellPos );
1897 BOOL bAppendPrec = TRUE;
1898 USHORT nPrec, nLeading;
1899 BOOL bThousand, bIsRed;
1900 pFormatter->GetFormatSpecialInfo( nFormat, bThousand, bIsRed, nPrec, nLeading );
1902 switch( pFormatter->GetType( nFormat ) )
1904 case NUMBERFORMAT_NUMBER: aFuncResult = (bThousand ? ',' : 'F'); break;
1905 case NUMBERFORMAT_CURRENCY: aFuncResult = 'C'; break;
1906 case NUMBERFORMAT_SCIENTIFIC: aFuncResult = 'S'; break;
1907 case NUMBERFORMAT_PERCENT: aFuncResult = 'P'; break;
1908 default:
1910 bAppendPrec = FALSE;
1911 switch( pFormatter->GetIndexTableOffset( nFormat ) )
1913 case NF_DATE_SYSTEM_SHORT:
1914 case NF_DATE_SYS_DMMMYY:
1915 case NF_DATE_SYS_DDMMYY:
1916 case NF_DATE_SYS_DDMMYYYY:
1917 case NF_DATE_SYS_DMMMYYYY:
1918 case NF_DATE_DIN_DMMMYYYY:
1919 case NF_DATE_SYS_DMMMMYYYY:
1920 case NF_DATE_DIN_DMMMMYYYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
1921 case NF_DATE_SYS_DDMMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
1922 case NF_DATE_SYS_MMYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
1923 case NF_DATETIME_SYSTEM_SHORT_HHMM:
1924 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
1925 aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
1926 case NF_DATE_DIN_MMDD: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
1927 case NF_TIME_HHMMSSAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
1928 case NF_TIME_HHMMAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
1929 case NF_TIME_HHMMSS: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
1930 case NF_TIME_HHMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
1931 default: aFuncResult = 'G';
1935 if( bAppendPrec )
1936 aFuncResult += String::CreateFromInt32( nPrec );
1937 const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
1938 if( lcl_FormatHasNegColor( pFormat ) )
1939 aFuncResult += '-';
1940 if( lcl_FormatHasOpenPar( pFormat ) )
1941 aFuncResult.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
1942 PushString( aFuncResult );
1944 else if( aInfoType.EqualsAscii( "COLOR" ) )
1945 { // 1 = negative values are colored, otherwise 0
1946 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
1947 PushInt( lcl_FormatHasNegColor( pFormat ) ? 1 : 0 );
1949 else if( aInfoType.EqualsAscii( "PARENTHESES" ) )
1950 { // 1 = format string contains a '(' character, otherwise 0
1951 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
1952 PushInt( lcl_FormatHasOpenPar( pFormat ) ? 1 : 0 );
1954 else
1955 PushIllegalArgument();
1961 void ScInterpreter::ScIsRef()
1963 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCell" );
1964 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1965 short nRes = 0;
1966 switch ( GetStackType() )
1968 case svSingleRef :
1970 ScAddress aAdr;
1971 PopSingleRef( aAdr );
1972 if ( !nGlobalError )
1973 nRes = 1;
1975 break;
1976 case svDoubleRef :
1978 ScRange aRange;
1979 PopDoubleRef( aRange );
1980 if ( !nGlobalError )
1981 nRes = 1;
1983 break;
1984 case svRefList :
1986 FormulaTokenRef x = PopToken();
1987 if ( !nGlobalError )
1988 nRes = !static_cast<ScToken*>(x.get())->GetRefList()->empty();
1990 break;
1991 default:
1992 Pop();
1994 nGlobalError = 0;
1995 PushInt( nRes );
1999 void ScInterpreter::ScIsValue()
2001 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsValue" );
2002 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2003 short nRes = 0;
2004 switch ( GetRawStackType() )
2006 case svDouble:
2007 Pop();
2008 nRes = 1;
2009 break;
2010 case svDoubleRef :
2011 case svSingleRef :
2013 ScAddress aAdr;
2014 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2015 break;
2016 ScBaseCell* pCell = GetCell( aAdr );
2017 if (GetCellErrCode( pCell ) == 0)
2019 switch ( GetCellType( pCell ) )
2021 case CELLTYPE_VALUE :
2022 nRes = 1;
2023 break;
2024 case CELLTYPE_FORMULA :
2025 nRes = ((ScFormulaCell*)pCell)->IsValue() &&
2026 !((ScFormulaCell*)pCell)->IsEmpty();
2027 break;
2028 default:
2029 ; // nothing
2033 break;
2034 case svMatrix:
2036 ScMatrixRef pMat = PopMatrix();
2037 if ( !pMat )
2038 ; // nothing
2039 else if ( !pJumpMatrix )
2041 if (pMat->GetErrorIfNotString( 0 ) == 0)
2042 nRes = pMat->IsValue( 0 );
2044 else
2046 SCSIZE nCols, nRows, nC, nR;
2047 pMat->GetDimensions( nCols, nRows);
2048 pJumpMatrix->GetPos( nC, nR);
2049 if ( nC < nCols && nR < nRows )
2050 if (pMat->GetErrorIfNotString( nC, nR) == 0)
2051 nRes = pMat->IsValue( nC, nR);
2054 break;
2055 default:
2056 Pop();
2058 nGlobalError = 0;
2059 PushInt( nRes );
2063 void ScInterpreter::ScIsFormula()
2065 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsFormula" );
2066 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2067 short nRes = 0;
2068 switch ( GetStackType() )
2070 case svDoubleRef :
2071 case svSingleRef :
2073 ScAddress aAdr;
2074 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2075 break;
2076 nRes = (GetCellType( GetCell( aAdr ) ) == CELLTYPE_FORMULA);
2078 break;
2079 default:
2080 Pop();
2082 nGlobalError = 0;
2083 PushInt( nRes );
2087 void ScInterpreter::ScFormula()
2089 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFormula" );
2090 String aFormula;
2091 switch ( GetStackType() )
2093 case svDoubleRef :
2094 case svSingleRef :
2096 ScAddress aAdr;
2097 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2098 break;
2099 ScBaseCell* pCell = GetCell( aAdr );
2100 switch ( GetCellType( pCell ) )
2102 case CELLTYPE_FORMULA :
2103 ((ScFormulaCell*)pCell)->GetFormula( aFormula );
2104 break;
2105 default:
2106 SetError( NOTAVAILABLE );
2109 break;
2110 default:
2111 Pop();
2112 SetError( NOTAVAILABLE );
2114 PushString( aFormula );
2119 void ScInterpreter::ScIsNV()
2121 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsNV" );
2122 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2123 short nRes = 0;
2124 switch ( GetStackType() )
2126 case svDoubleRef :
2127 case svSingleRef :
2129 ScAddress aAdr;
2130 PopDoubleRefOrSingleRef( aAdr );
2131 if ( nGlobalError == NOTAVAILABLE )
2132 nRes = 1;
2133 else
2135 ScBaseCell* pCell = GetCell( aAdr );
2136 USHORT nErr = GetCellErrCode( pCell );
2137 nRes = (nErr == NOTAVAILABLE);
2140 break;
2141 case svMatrix:
2143 ScMatrixRef pMat = PopMatrix();
2144 if ( !pMat )
2145 ; // nothing
2146 else if ( !pJumpMatrix )
2147 nRes = (pMat->GetErrorIfNotString( 0 ) == NOTAVAILABLE);
2148 else
2150 SCSIZE nCols, nRows, nC, nR;
2151 pMat->GetDimensions( nCols, nRows);
2152 pJumpMatrix->GetPos( nC, nR);
2153 if ( nC < nCols && nR < nRows )
2154 nRes = (pMat->GetErrorIfNotString( nC, nR) == NOTAVAILABLE);
2157 break;
2158 default:
2159 PopError();
2160 if ( nGlobalError == NOTAVAILABLE )
2161 nRes = 1;
2163 nGlobalError = 0;
2164 PushInt( nRes );
2168 void ScInterpreter::ScIsErr()
2170 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsErr" );
2171 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2172 short nRes = 0;
2173 switch ( GetStackType() )
2175 case svDoubleRef :
2176 case svSingleRef :
2178 ScAddress aAdr;
2179 PopDoubleRefOrSingleRef( aAdr );
2180 if ( nGlobalError && nGlobalError != NOTAVAILABLE )
2181 nRes = 1;
2182 else
2184 ScBaseCell* pCell = GetCell( aAdr );
2185 USHORT nErr = GetCellErrCode( pCell );
2186 nRes = (nErr && nErr != NOTAVAILABLE);
2189 break;
2190 case svMatrix:
2192 ScMatrixRef pMat = PopMatrix();
2193 if ( nGlobalError || !pMat )
2194 nRes = ((nGlobalError && nGlobalError != NOTAVAILABLE) || !pMat);
2195 else if ( !pJumpMatrix )
2197 USHORT nErr = pMat->GetErrorIfNotString( 0 );
2198 nRes = (nErr && nErr != NOTAVAILABLE);
2200 else
2202 SCSIZE nCols, nRows, nC, nR;
2203 pMat->GetDimensions( nCols, nRows);
2204 pJumpMatrix->GetPos( nC, nR);
2205 if ( nC < nCols && nR < nRows )
2207 USHORT nErr = pMat->GetErrorIfNotString( nC, nR);
2208 nRes = (nErr && nErr != NOTAVAILABLE);
2212 break;
2213 default:
2214 PopError();
2215 if ( nGlobalError && nGlobalError != NOTAVAILABLE )
2216 nRes = 1;
2218 nGlobalError = 0;
2219 PushInt( nRes );
2223 void ScInterpreter::ScIsError()
2225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsError" );
2226 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2227 short nRes = 0;
2228 switch ( GetStackType() )
2230 case svDoubleRef :
2231 case svSingleRef :
2233 ScAddress aAdr;
2234 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2236 nRes = 1;
2237 break;
2239 if ( nGlobalError )
2240 nRes = 1;
2241 else
2243 ScBaseCell* pCell = GetCell( aAdr );
2244 nRes = (GetCellErrCode( pCell ) != 0);
2247 break;
2248 case svMatrix:
2250 ScMatrixRef pMat = PopMatrix();
2251 if ( nGlobalError || !pMat )
2252 nRes = 1;
2253 else if ( !pJumpMatrix )
2254 nRes = (pMat->GetErrorIfNotString( 0 ) != 0);
2255 else
2257 SCSIZE nCols, nRows, nC, nR;
2258 pMat->GetDimensions( nCols, nRows);
2259 pJumpMatrix->GetPos( nC, nR);
2260 if ( nC < nCols && nR < nRows )
2261 nRes = (pMat->GetErrorIfNotString( nC, nR) != 0);
2264 break;
2265 default:
2266 PopError();
2267 if ( nGlobalError )
2268 nRes = 1;
2270 nGlobalError = 0;
2271 PushInt( nRes );
2275 short ScInterpreter::IsEven()
2277 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IsEven" );
2278 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2279 short nRes = 0;
2280 double fVal = 0.0;
2281 switch ( GetStackType() )
2283 case svDoubleRef :
2284 case svSingleRef :
2286 ScAddress aAdr;
2287 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2288 break;
2289 ScBaseCell* pCell = GetCell( aAdr );
2290 USHORT nErr = GetCellErrCode( pCell );
2291 if (nErr != 0)
2292 SetError(nErr);
2293 else
2295 switch ( GetCellType( pCell ) )
2297 case CELLTYPE_VALUE :
2298 fVal = GetCellValue( aAdr, pCell );
2299 nRes = 1;
2300 break;
2301 case CELLTYPE_FORMULA :
2302 if( ((ScFormulaCell*)pCell)->IsValue() )
2304 fVal = GetCellValue( aAdr, pCell );
2305 nRes = 1;
2307 break;
2308 default:
2309 ; // nothing
2313 break;
2314 case svDouble:
2316 fVal = PopDouble();
2317 nRes = 1;
2319 break;
2320 case svMatrix:
2322 ScMatrixRef pMat = PopMatrix();
2323 if ( !pMat )
2324 ; // nothing
2325 else if ( !pJumpMatrix )
2327 nRes = pMat->IsValue( 0 );
2328 if ( nRes )
2329 fVal = pMat->GetDouble( 0 );
2331 else
2333 SCSIZE nCols, nRows, nC, nR;
2334 pMat->GetDimensions( nCols, nRows);
2335 pJumpMatrix->GetPos( nC, nR);
2336 if ( nC < nCols && nR < nRows )
2338 nRes = pMat->IsValue( nC, nR);
2339 if ( nRes )
2340 fVal = pMat->GetDouble( nC, nR);
2342 else
2343 SetError( errNoValue);
2346 break;
2347 default:
2348 ; // nothing
2350 if ( !nRes )
2351 SetError( errIllegalParameter);
2352 else
2353 nRes = ( fmod( ::rtl::math::approxFloor( fabs( fVal ) ), 2.0 ) < 0.5 );
2354 return nRes;
2358 void ScInterpreter::ScIsEven()
2360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsEven" );
2361 PushInt( IsEven() );
2365 void ScInterpreter::ScIsOdd()
2367 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsOdd" );
2368 PushInt( !IsEven() );
2372 void ScInterpreter::ScN()
2374 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScN" );
2375 USHORT nErr = nGlobalError;
2376 nGlobalError = 0;
2377 double fVal;
2378 if ( GetRawStackType() == svString )
2380 fVal = 0.0;
2381 Pop();
2383 else
2384 fVal = GetDouble();
2385 if ( nGlobalError == NOTAVAILABLE || nGlobalError == errIllegalArgument )
2386 nGlobalError = 0; // N(#NA) and N("text") are ok
2387 if ( !nGlobalError && nErr != NOTAVAILABLE )
2388 nGlobalError = nErr;
2389 PushDouble( fVal );
2393 void ScInterpreter::ScTrim()
2394 { // trimmt nicht nur sondern schnibbelt auch doppelte raus!
2395 String aVal( GetString() );
2396 aVal.EraseLeadingChars();
2397 aVal.EraseTrailingChars();
2398 String aStr;
2399 register const sal_Unicode* p = aVal.GetBuffer();
2400 register const sal_Unicode* const pEnd = p + aVal.Len();
2401 while ( p < pEnd )
2403 if ( *p != ' ' || p[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
2404 aStr += *p;
2405 p++;
2407 PushString( aStr );
2411 void ScInterpreter::ScUpper()
2413 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrim" );
2414 String aString = GetString();
2415 ScGlobal::pCharClass->toUpper(aString);
2416 PushString(aString);
2420 void ScInterpreter::ScPropper()
2422 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPropper" );
2423 //2do: what to do with I18N-CJK ?!?
2424 String aStr( GetString() );
2425 const xub_StrLen nLen = aStr.Len();
2426 // #i82487# don't try to write to empty string's BufferAccess
2427 // (would crash now that the empty string is const)
2428 if ( nLen > 0 )
2430 String aUpr( ScGlobal::pCharClass->upper( aStr ) );
2431 String aLwr( ScGlobal::pCharClass->lower( aStr ) );
2432 register sal_Unicode* pStr = aStr.GetBufferAccess();
2433 const sal_Unicode* pUpr = aUpr.GetBuffer();
2434 const sal_Unicode* pLwr = aLwr.GetBuffer();
2435 *pStr = *pUpr;
2436 String aTmpStr( 'x' );
2437 xub_StrLen nPos = 1;
2438 while( nPos < nLen )
2440 aTmpStr.SetChar( 0, pStr[nPos-1] );
2441 if ( !ScGlobal::pCharClass->isLetter( aTmpStr, 0 ) )
2442 pStr[nPos] = pUpr[nPos];
2443 else
2444 pStr[nPos] = pLwr[nPos];
2445 nPos++;
2447 aStr.ReleaseBufferAccess( nLen );
2449 PushString( aStr );
2453 void ScInterpreter::ScLower()
2455 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLower" );
2456 String aString( GetString() );
2457 ScGlobal::pCharClass->toLower(aString);
2458 PushString(aString);
2462 void ScInterpreter::ScLen()
2464 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLen" );
2465 String aStr( GetString() );
2466 PushDouble( aStr.Len() );
2470 void ScInterpreter::ScT()
2472 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScT" );
2473 switch ( GetStackType() )
2475 case svDoubleRef :
2476 case svSingleRef :
2478 ScAddress aAdr;
2479 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2481 PushInt(0);
2482 return ;
2484 BOOL bValue = FALSE;
2485 ScBaseCell* pCell = GetCell( aAdr );
2486 if ( GetCellErrCode( pCell ) == 0 )
2488 switch ( GetCellType( pCell ) )
2490 case CELLTYPE_VALUE :
2491 bValue = TRUE;
2492 break;
2493 case CELLTYPE_FORMULA :
2494 bValue = ((ScFormulaCell*)pCell)->IsValue();
2495 break;
2496 default:
2497 ; // nothing
2500 if ( bValue )
2501 PushString( EMPTY_STRING );
2502 else
2504 // wie GetString()
2505 GetCellString( aTempStr, pCell );
2506 PushString( aTempStr );
2509 break;
2510 case svDouble :
2512 PopError();
2513 PushString( EMPTY_STRING );
2515 break;
2516 case svString :
2517 ; // leave on stack
2518 break;
2519 default :
2520 PushError( errUnknownOpCode);
2525 void ScInterpreter::ScValue()
2527 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScValue" );
2528 String aInputString;
2529 double fVal;
2531 switch ( GetRawStackType() )
2533 case svMissing:
2534 case svEmptyCell:
2535 Pop();
2536 PushInt(0);
2537 return;
2538 case svDouble:
2539 return; // leave on stack
2540 //break;
2542 case svSingleRef:
2543 case svDoubleRef:
2545 ScAddress aAdr;
2546 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2548 PushInt(0);
2549 return;
2551 ScBaseCell* pCell = GetCell( aAdr );
2552 if ( pCell && pCell->HasStringData() )
2553 GetCellString( aInputString, pCell );
2554 else if ( pCell && pCell->HasValueData() )
2556 PushDouble( GetCellValue(aAdr, pCell) );
2557 return;
2559 else
2561 PushDouble(0.0);
2562 return;
2565 break;
2566 case svMatrix:
2568 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
2569 aInputString);
2570 switch (nType)
2572 case SC_MATVAL_EMPTY:
2573 fVal = 0.0;
2574 // fallthru
2575 case SC_MATVAL_VALUE:
2576 case SC_MATVAL_BOOLEAN:
2577 PushDouble( fVal);
2578 return;
2579 //break;
2580 case SC_MATVAL_STRING:
2581 // evaluated below
2582 break;
2583 default:
2584 PushIllegalArgument();
2587 break;
2588 default:
2589 aInputString = GetString();
2590 break;
2593 sal_uInt32 nFIndex = 0; // 0 for default locale
2594 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
2595 PushDouble(fVal);
2596 else
2597 PushIllegalArgument();
2601 //2do: this should be a proper unicode string method
2602 inline BOOL lcl_ScInterpreter_IsPrintable( sal_Unicode c )
2604 return 0x20 <= c && c != 0x7f;
2607 void ScInterpreter::ScClean()
2609 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScClean" );
2610 String aStr( GetString() );
2611 for ( xub_StrLen i = 0; i < aStr.Len(); i++ )
2613 if ( !lcl_ScInterpreter_IsPrintable( aStr.GetChar( i ) ) )
2614 aStr.Erase(i,1);
2616 PushString(aStr);
2620 void ScInterpreter::ScCode()
2622 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCode" );
2623 //2do: make it full range unicode?
2624 const String& rStr = GetString();
2625 PushInt( (sal_uChar) ByteString::ConvertFromUnicode( rStr.GetChar(0), gsl_getSystemTextEncoding() ) );
2629 void ScInterpreter::ScChar()
2631 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChar" );
2632 //2do: make it full range unicode?
2633 double fVal = GetDouble();
2634 if (fVal < 0.0 || fVal >= 256.0)
2635 PushIllegalArgument();
2636 else
2638 String aStr( '0' );
2639 aStr.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char) fVal, gsl_getSystemTextEncoding() ) );
2640 PushString( aStr );
2645 /* #i70213# fullwidth/halfwidth conversion provided by
2646 * Takashi Nakamoto <bluedwarf@ooo>
2647 * erAck: added Excel compatibility conversions as seen in issue's test case. */
2649 static ::rtl::OUString lcl_convertIntoHalfWidth( const ::rtl::OUString & rStr )
2651 static bool bFirstASCCall = true;
2652 static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2654 if( bFirstASCCall )
2656 aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM );
2657 bFirstASCCall = false;
2660 return aTrans.transliterate( rStr, 0, (USHORT) rStr.getLength(), NULL );
2664 static ::rtl::OUString lcl_convertIntoFullWidth( const ::rtl::OUString & rStr )
2666 static bool bFirstJISCall = true;
2667 static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2669 if( bFirstJISCall )
2671 aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM );
2672 bFirstJISCall = false;
2675 return aTrans.transliterate( rStr, 0, (USHORT) rStr.getLength(), NULL );
2679 /* ODFF:
2680 * Summary: Converts half-width to full-width ASCII and katakana characters.
2681 * Semantics: Conversion is done for half-width ASCII and katakana characters,
2682 * other characters are simply copied from T to the result. This is the
2683 * complementary function to ASC.
2684 * For references regarding halfwidth and fullwidth characters see
2685 * http://www.unicode.org/reports/tr11/
2686 * http://www.unicode.org/charts/charindex2.html#H
2687 * http://www.unicode.org/charts/charindex2.html#F
2689 void ScInterpreter::ScJis()
2691 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScJis" );
2692 if (MustHaveParamCount( GetByte(), 1))
2693 PushString( lcl_convertIntoFullWidth( GetString()));
2697 /* ODFF:
2698 * Summary: Converts full-width to half-width ASCII and katakana characters.
2699 * Semantics: Conversion is done for full-width ASCII and katakana characters,
2700 * other characters are simply copied from T to the result. This is the
2701 * complementary function to JIS.
2703 void ScInterpreter::ScAsc()
2705 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAsc" );
2706 if (MustHaveParamCount( GetByte(), 1))
2707 PushString( lcl_convertIntoHalfWidth( GetString()));
2711 void ScInterpreter::ScMin( BOOL bTextAsZero )
2713 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMin" );
2714 short nParamCount = GetByte();
2715 if (!MustHaveParamCountMin( nParamCount, 1))
2716 return;
2717 double nMin = ::std::numeric_limits<double>::max();
2718 double nVal = 0.0;
2719 ScAddress aAdr;
2720 ScRange aRange;
2721 size_t nRefInList = 0;
2722 while (nParamCount-- > 0)
2724 switch (GetStackType())
2726 case svDouble :
2728 nVal = GetDouble();
2729 if (nMin > nVal) nMin = nVal;
2730 nFuncFmtType = NUMBERFORMAT_NUMBER;
2732 break;
2733 case svSingleRef :
2735 PopSingleRef( aAdr );
2736 ScBaseCell* pCell = GetCell( aAdr );
2737 if (HasCellValueData(pCell))
2739 nVal = GetCellValue( aAdr, pCell );
2740 CurFmtToFuncFmt();
2741 if (nMin > nVal) nMin = nVal;
2743 else if ( bTextAsZero && HasCellStringData( pCell ) )
2745 if ( nMin > 0.0 )
2746 nMin = 0.0;
2749 break;
2750 case svDoubleRef :
2751 case svRefList :
2753 USHORT nErr = 0;
2754 PopDoubleRef( aRange, nParamCount, nRefInList);
2755 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
2756 if (aValIter.GetFirst(nVal, nErr))
2758 if (nMin > nVal)
2759 nMin = nVal;
2760 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
2761 while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
2763 if (nMin > nVal)
2764 nMin = nVal;
2766 SetError(nErr);
2769 break;
2770 case svMatrix :
2772 ScMatrixRef pMat = PopMatrix();
2773 if (pMat)
2775 SCSIZE nC, nR;
2776 nFuncFmtType = NUMBERFORMAT_NUMBER;
2777 pMat->GetDimensions(nC, nR);
2778 if (pMat->IsNumeric())
2780 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
2781 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
2783 nVal = pMat->GetDouble(nMatCol,nMatRow);
2784 if (nMin > nVal) nMin = nVal;
2787 else
2789 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
2791 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
2793 if (!pMat->IsString(nMatCol,nMatRow))
2795 nVal = pMat->GetDouble(nMatCol,nMatRow);
2796 if (nMin > nVal) nMin = nVal;
2798 else if ( bTextAsZero )
2800 if ( nMin > 0.0 )
2801 nMin = 0.0;
2808 break;
2809 case svString :
2811 Pop();
2812 if ( bTextAsZero )
2814 if ( nMin > 0.0 )
2815 nMin = 0.0;
2817 else
2818 SetError(errIllegalParameter);
2820 break;
2821 default :
2822 Pop();
2823 SetError(errIllegalParameter);
2826 if ( nVal < nMin )
2827 PushDouble(0.0);
2828 else
2829 PushDouble(nMin);
2832 #if defined(WIN) && defined(MSC)
2833 #pragma optimize("",off)
2834 #endif
2836 void ScInterpreter::ScMax( BOOL bTextAsZero )
2838 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMax" );
2839 short nParamCount = GetByte();
2840 if (!MustHaveParamCountMin( nParamCount, 1))
2841 return;
2842 double nMax = -(::std::numeric_limits<double>::max());
2843 double nVal = 0.0;
2844 ScAddress aAdr;
2845 ScRange aRange;
2846 size_t nRefInList = 0;
2847 while (nParamCount-- > 0)
2849 switch (GetStackType())
2851 case svDouble :
2853 nVal = GetDouble();
2854 if (nMax < nVal) nMax = nVal;
2855 nFuncFmtType = NUMBERFORMAT_NUMBER;
2857 break;
2858 case svSingleRef :
2860 PopSingleRef( aAdr );
2861 ScBaseCell* pCell = GetCell( aAdr );
2862 if (HasCellValueData(pCell))
2864 nVal = GetCellValue( aAdr, pCell );
2865 CurFmtToFuncFmt();
2866 if (nMax < nVal) nMax = nVal;
2868 else if ( bTextAsZero && HasCellStringData( pCell ) )
2870 if ( nMax < 0.0 )
2871 nMax = 0.0;
2874 break;
2875 case svDoubleRef :
2876 case svRefList :
2878 USHORT nErr = 0;
2879 PopDoubleRef( aRange, nParamCount, nRefInList);
2880 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
2881 if (aValIter.GetFirst(nVal, nErr))
2883 if (nMax < nVal)
2884 nMax = nVal;
2885 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
2886 while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
2888 if (nMax < nVal)
2889 nMax = nVal;
2891 SetError(nErr);
2894 break;
2895 case svMatrix :
2897 ScMatrixRef pMat = PopMatrix();
2898 if (pMat)
2900 nFuncFmtType = NUMBERFORMAT_NUMBER;
2901 SCSIZE nC, nR;
2902 pMat->GetDimensions(nC, nR);
2903 if (pMat->IsNumeric())
2905 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
2906 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
2908 nVal = pMat->GetDouble(nMatCol,nMatRow);
2909 if (nMax < nVal) nMax = nVal;
2912 else
2914 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
2916 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
2918 if (!pMat->IsString(nMatCol,nMatRow))
2920 nVal = pMat->GetDouble(nMatCol,nMatRow);
2921 if (nMax < nVal) nMax = nVal;
2923 else if ( bTextAsZero )
2925 if ( nMax < 0.0 )
2926 nMax = 0.0;
2933 break;
2934 case svString :
2936 Pop();
2937 if ( bTextAsZero )
2939 if ( nMax < 0.0 )
2940 nMax = 0.0;
2942 else
2943 SetError(errIllegalParameter);
2945 break;
2946 default :
2947 Pop();
2948 SetError(errIllegalParameter);
2951 if ( nVal > nMax )
2952 PushDouble(0.0);
2953 else
2954 PushDouble(nMax);
2956 #if defined(WIN) && defined(MSC)
2957 #pragma optimize("",on)
2958 #endif
2961 double ScInterpreter::IterateParameters( ScIterFunc eFunc, BOOL bTextAsZero )
2963 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IterateParameters" );
2964 short nParamCount = GetByte();
2965 double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
2966 double fVal = 0.0;
2967 double fMem = 0.0;
2968 BOOL bNull = TRUE;
2969 ULONG nCount = 0;
2970 ScAddress aAdr;
2971 ScRange aRange;
2972 size_t nRefInList = 0;
2973 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
2974 nGlobalError = 0;
2975 while (nParamCount-- > 0)
2977 StackVar eStackType = GetStackType();
2978 switch (eStackType)
2980 case svDouble:
2981 case svString:
2983 if( eFunc == ifCOUNT && eStackType == svString )
2985 String aStr( PopString() );
2986 sal_uInt32 nFIndex = 0; // damit default Land/Spr.
2987 if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
2988 nCount++;
2990 else if (eFunc == ifCOUNT2)
2991 // COUNTA - we should count both number and string.
2992 ++nCount;
2993 else
2995 if ( bTextAsZero && eStackType == svString )
2997 Pop();
2998 nCount++;
2999 if ( eFunc == ifPRODUCT )
3000 fRes = 0.0;
3001 fVal = 0;
3003 else
3005 fVal = GetDouble();
3006 nCount++;
3008 switch ( eFunc )
3010 case ifAVERAGE:
3011 case ifSUM:
3012 if ( bNull && fVal != 0.0 )
3014 bNull = FALSE;
3015 fMem = fVal;
3017 else
3018 fRes += fVal;
3019 break;
3020 case ifSUMSQ: fRes += fVal * fVal; break;
3021 case ifPRODUCT: fRes *= fVal; break;
3023 default:;
3026 nFuncFmtType = NUMBERFORMAT_NUMBER;
3028 break;
3029 case svSingleRef :
3031 PopSingleRef( aAdr );
3032 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3034 nGlobalError = 0;
3035 if ( eFunc == ifCOUNT2 )
3036 ++nCount;
3037 break;
3039 ScBaseCell* pCell = GetCell( aAdr );
3040 if ( pCell )
3042 if( eFunc == ifCOUNT2 )
3044 CellType eCellType = pCell->GetCellType();
3045 if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
3046 nCount++;
3047 if ( nGlobalError )
3048 nGlobalError = 0;
3050 else if ( pCell->HasValueData() )
3052 nCount++;
3053 fVal = GetCellValue( aAdr, pCell );
3054 CurFmtToFuncFmt();
3055 switch( eFunc )
3057 case ifAVERAGE:
3058 case ifSUM:
3059 if ( bNull && fVal != 0.0 )
3061 bNull = FALSE;
3062 fMem = fVal;
3064 else
3065 fRes += fVal;
3066 break;
3067 case ifSUMSQ: fRes += fVal * fVal; break;
3068 case ifPRODUCT: fRes *= fVal; break;
3069 case ifCOUNT:
3070 if ( nGlobalError )
3072 nGlobalError = 0;
3073 nCount--;
3075 break;
3076 default: ; // nothing
3079 else if ( bTextAsZero && pCell->HasStringData() )
3081 nCount++;
3082 if ( eFunc == ifPRODUCT )
3083 fRes = 0.0;
3087 break;
3088 case svDoubleRef :
3089 case svRefList :
3091 USHORT nErr = 0;
3092 PopDoubleRef( aRange, nParamCount, nRefInList);
3093 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3095 nGlobalError = 0;
3096 if ( eFunc == ifCOUNT2 )
3097 ++nCount;
3098 break;
3100 if( eFunc == ifCOUNT2 )
3102 ScBaseCell* pCell;
3103 ScCellIterator aIter( pDok, aRange, glSubTotal );
3104 if ( (pCell = aIter.GetFirst()) != NULL )
3108 CellType eType = pCell->GetCellType();
3109 if( eType != CELLTYPE_NONE && eType != CELLTYPE_NOTE )
3110 nCount++;
3112 while ( (pCell = aIter.GetNext()) != NULL );
3114 if ( nGlobalError )
3115 nGlobalError = 0;
3117 else
3119 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3120 if (aValIter.GetFirst(fVal, nErr))
3122 // Schleife aus Performance-Gruenden nach innen verlegt:
3123 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
3124 switch( eFunc )
3126 case ifAVERAGE:
3127 case ifSUM:
3130 SetError(nErr);
3131 if ( bNull && fVal != 0.0 )
3133 bNull = FALSE;
3134 fMem = fVal;
3136 else
3137 fRes += fVal;
3138 nCount++;
3140 while (aValIter.GetNext(fVal, nErr));
3141 break;
3142 case ifSUMSQ:
3145 SetError(nErr);
3146 fRes += fVal * fVal;
3147 nCount++;
3149 while (aValIter.GetNext(fVal, nErr));
3150 break;
3151 case ifPRODUCT:
3154 SetError(nErr);
3155 fRes *= fVal;
3156 nCount++;
3158 while (aValIter.GetNext(fVal, nErr));
3159 break;
3160 case ifCOUNT:
3163 if ( !nErr )
3164 nCount++;
3166 while (aValIter.GetNext(fVal, nErr));
3167 break;
3168 default: ; // nothing
3170 SetError( nErr );
3174 break;
3175 case svMatrix :
3177 ScMatrixRef pMat = PopMatrix();
3178 if (pMat)
3180 SCSIZE nC, nR;
3181 nFuncFmtType = NUMBERFORMAT_NUMBER;
3182 pMat->GetDimensions(nC, nR);
3183 if( eFunc == ifCOUNT2 )
3184 nCount += (ULONG) nC * nR;
3185 else
3187 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3189 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3191 if (!pMat->IsString(nMatCol,nMatRow))
3193 nCount++;
3194 fVal = pMat->GetDouble(nMatCol,nMatRow);
3195 switch( eFunc )
3197 case ifAVERAGE:
3198 case ifSUM:
3199 if ( bNull && fVal != 0.0 )
3201 bNull = FALSE;
3202 fMem = fVal;
3204 else
3205 fRes += fVal;
3206 break;
3207 case ifSUMSQ: fRes += fVal * fVal; break;
3208 case ifPRODUCT: fRes *= fVal; break;
3209 default: ; // nothing
3212 else if ( bTextAsZero )
3214 nCount++;
3215 if ( eFunc == ifPRODUCT )
3216 fRes = 0.0;
3223 break;
3224 case svError:
3226 Pop();
3227 if ( eFunc == ifCOUNT )
3229 nGlobalError = 0;
3231 else if ( eFunc == ifCOUNT2 )
3233 nCount++;
3234 nGlobalError = 0;
3237 break;
3238 default :
3239 while (nParamCount-- > 0)
3240 PopError();
3241 SetError(errIllegalParameter);
3244 switch( eFunc )
3246 case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
3247 case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
3248 case ifCOUNT2:
3249 case ifCOUNT: fRes = nCount; break;
3250 case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
3251 default: ; // nothing
3253 // Bei Summen etc. macht ein BOOL-Ergebnis keinen Sinn
3254 // und Anzahl ist immer Number (#38345#)
3255 if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
3256 nFuncFmtType = NUMBERFORMAT_NUMBER;
3257 return fRes;
3261 void ScInterpreter::ScSumSQ()
3263 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumSQ" );
3264 PushDouble( IterateParameters( ifSUMSQ ) );
3268 void ScInterpreter::ScSum()
3270 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSum" );
3271 PushDouble( IterateParameters( ifSUM ) );
3275 void ScInterpreter::ScProduct()
3277 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScProduct" );
3278 PushDouble( IterateParameters( ifPRODUCT ) );
3282 void ScInterpreter::ScAverage( BOOL bTextAsZero )
3284 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAverage" );
3285 PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
3289 void ScInterpreter::ScCount()
3291 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCount" );
3292 PushDouble( IterateParameters( ifCOUNT ) );
3296 void ScInterpreter::ScCount2()
3298 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCount2" );
3299 PushDouble( IterateParameters( ifCOUNT2 ) );
3303 void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
3304 BOOL bTextAsZero )
3306 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetStVarParams" );
3307 short nParamCount = GetByte();
3309 std::vector<double> values;
3310 double fSum = 0.0;
3311 double vSum = 0.0;
3312 double vMean = 0.0;
3313 double fVal = 0.0;
3314 rValCount = 0.0;
3315 ScAddress aAdr;
3316 ScRange aRange;
3317 size_t nRefInList = 0;
3318 while (nParamCount-- > 0)
3320 switch (GetStackType())
3322 case svDouble :
3324 fVal = GetDouble();
3325 values.push_back(fVal);
3326 fSum += fVal;
3327 rValCount++;
3329 break;
3330 case svSingleRef :
3332 PopSingleRef( aAdr );
3333 ScBaseCell* pCell = GetCell( aAdr );
3334 if (HasCellValueData(pCell))
3336 fVal = GetCellValue( aAdr, pCell );
3337 values.push_back(fVal);
3338 fSum += fVal;
3339 rValCount++;
3341 else if ( bTextAsZero && HasCellStringData( pCell ) )
3343 values.push_back(0.0);
3344 rValCount++;
3347 break;
3348 case svDoubleRef :
3349 case svRefList :
3351 USHORT nErr = 0;
3352 PopDoubleRef( aRange, nParamCount, nRefInList);
3353 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3354 if (aValIter.GetFirst(fVal, nErr))
3358 values.push_back(fVal);
3359 fSum += fVal;
3360 rValCount++;
3362 while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
3365 break;
3366 case svMatrix :
3368 ScMatrixRef pMat = PopMatrix();
3369 if (pMat)
3371 SCSIZE nC, nR;
3372 pMat->GetDimensions(nC, nR);
3373 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3375 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3377 if (!pMat->IsString(nMatCol,nMatRow))
3379 fVal= pMat->GetDouble(nMatCol,nMatRow);
3380 values.push_back(fVal);
3381 fSum += fVal;
3382 rValCount++;
3384 else if ( bTextAsZero )
3386 values.push_back(0.0);
3387 rValCount++;
3393 break;
3394 case svString :
3396 Pop();
3397 if ( bTextAsZero )
3399 values.push_back(0.0);
3400 rValCount++;
3402 else
3403 SetError(errIllegalParameter);
3405 break;
3406 default :
3407 Pop();
3408 SetError(errIllegalParameter);
3412 ::std::vector<double>::size_type n = values.size();
3413 vMean = fSum / n;
3414 for (::std::vector<double>::size_type i = 0; i < n; i++)
3415 vSum += (values[i] - vMean) * (values[i] - vMean);
3417 rVal = vSum;
3421 void ScInterpreter::ScVar( BOOL bTextAsZero )
3423 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVar" );
3424 double nVal;
3425 double nValCount;
3426 GetStVarParams( nVal, nValCount, bTextAsZero );
3428 if (nValCount <= 1.0)
3429 PushError( errDivisionByZero );
3430 else
3431 PushDouble( nVal / (nValCount - 1.0));
3435 void ScInterpreter::ScVarP( BOOL bTextAsZero )
3437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVarP" );
3438 double nVal;
3439 double nValCount;
3440 GetStVarParams( nVal, nValCount, bTextAsZero );
3442 PushDouble( div( nVal, nValCount));
3446 void ScInterpreter::ScStDev( BOOL bTextAsZero )
3448 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStDev" );
3449 double nVal;
3450 double nValCount;
3451 GetStVarParams( nVal, nValCount, bTextAsZero );
3452 if (nValCount <= 1.0)
3453 PushError( errDivisionByZero );
3454 else
3455 PushDouble( sqrt( nVal / (nValCount - 1.0)));
3459 void ScInterpreter::ScStDevP( BOOL bTextAsZero )
3461 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStDevP" );
3462 double nVal;
3463 double nValCount;
3464 GetStVarParams( nVal, nValCount, bTextAsZero );
3465 if (nValCount == 0.0)
3466 PushError( errDivisionByZero );
3467 else
3468 PushDouble( sqrt( nVal / nValCount));
3470 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3472 * Besides that the special NAN gets lost in the call through sqrt(),
3473 * unxlngi6.pro then looped back and forth somewhere between div() and
3474 * ::rtl::math::setNan(). Tests showed that
3476 * sqrt( div( 1, 0));
3478 * produced a loop, but
3480 * double f1 = div( 1, 0);
3481 * sqrt( f1 );
3483 * was fine. There seems to be some compiler optimization problem. It does
3484 * not occur when compiled with debug=t.
3489 void ScInterpreter::ScColumns()
3491 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScColumns" );
3492 BYTE nParamCount = GetByte();
3493 ULONG nVal = 0;
3494 SCCOL nCol1;
3495 SCROW nRow1;
3496 SCTAB nTab1;
3497 SCCOL nCol2;
3498 SCROW nRow2;
3499 SCTAB nTab2;
3500 while (nParamCount-- > 0)
3502 switch ( GetStackType() )
3504 case svSingleRef:
3505 PopError();
3506 nVal++;
3507 break;
3508 case svDoubleRef:
3509 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3510 nVal += static_cast<ULONG>(nTab2 - nTab1 + 1) *
3511 static_cast<ULONG>(nCol2 - nCol1 + 1);
3512 break;
3513 case svMatrix:
3515 ScMatrixRef pMat = PopMatrix();
3516 if (pMat)
3518 SCSIZE nC, nR;
3519 pMat->GetDimensions(nC, nR);
3520 nVal += nC;
3523 break;
3524 default:
3525 PopError();
3526 SetError(errIllegalParameter);
3529 PushDouble((double)nVal);
3533 void ScInterpreter::ScRows()
3535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRows" );
3536 BYTE nParamCount = GetByte();
3537 ULONG nVal = 0;
3538 SCCOL nCol1;
3539 SCROW nRow1;
3540 SCTAB nTab1;
3541 SCCOL nCol2;
3542 SCROW nRow2;
3543 SCTAB nTab2;
3544 while (nParamCount-- > 0)
3546 switch ( GetStackType() )
3548 case svSingleRef:
3549 PopError();
3550 nVal++;
3551 break;
3552 case svDoubleRef:
3553 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3554 nVal += static_cast<ULONG>(nTab2 - nTab1 + 1) *
3555 static_cast<ULONG>(nRow2 - nRow1 + 1);
3556 break;
3557 case svMatrix:
3559 ScMatrixRef pMat = PopMatrix();
3560 if (pMat)
3562 SCSIZE nC, nR;
3563 pMat->GetDimensions(nC, nR);
3564 nVal += nR;
3567 break;
3568 default:
3569 PopError();
3570 SetError(errIllegalParameter);
3573 PushDouble((double)nVal);
3576 void ScInterpreter::ScTables()
3578 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTables" );
3579 BYTE nParamCount = GetByte();
3580 ULONG nVal;
3581 if ( nParamCount == 0 )
3582 nVal = pDok->GetTableCount();
3583 else
3585 nVal = 0;
3586 SCCOL nCol1;
3587 SCROW nRow1;
3588 SCTAB nTab1;
3589 SCCOL nCol2;
3590 SCROW nRow2;
3591 SCTAB nTab2;
3592 while (nParamCount-- > 0)
3594 switch ( GetStackType() )
3596 case svSingleRef:
3597 PopError();
3598 nVal++;
3599 break;
3600 case svDoubleRef:
3601 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3602 nVal += static_cast<ULONG>(nTab2 - nTab1 + 1);
3603 break;
3604 case svMatrix:
3605 PopError();
3606 nVal++;
3607 break;
3608 default:
3609 PopError();
3610 SetError( errIllegalParameter );
3614 PushDouble( (double) nVal );
3618 void ScInterpreter::ScColumn()
3620 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScColumn" );
3621 BYTE nParamCount = GetByte();
3622 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
3624 double nVal = 0;
3625 if (nParamCount == 0)
3627 nVal = aPos.Col() + 1;
3628 if (bMatrixFormula)
3630 SCCOL nCols;
3631 SCROW nRows;
3632 pMyFormulaCell->GetMatColsRows( nCols, nRows);
3633 ScMatrixRef pResMat = GetNewMat( static_cast<SCSIZE>(nCols), 1);
3634 if (pResMat)
3636 for (SCCOL i=0; i < nCols; ++i)
3637 pResMat->PutDouble( nVal + i, static_cast<SCSIZE>(i), 0);
3638 PushMatrix( pResMat);
3639 return;
3643 else
3645 switch ( GetStackType() )
3647 case svSingleRef :
3649 SCCOL nCol1;
3650 SCROW nRow1;
3651 SCTAB nTab1;
3652 PopSingleRef( nCol1, nRow1, nTab1 );
3653 nVal = (double) (nCol1 + 1);
3655 break;
3656 case svDoubleRef :
3658 SCCOL nCol1;
3659 SCROW nRow1;
3660 SCTAB nTab1;
3661 SCCOL nCol2;
3662 SCROW nRow2;
3663 SCTAB nTab2;
3664 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
3665 if (nCol2 > nCol1)
3667 ScMatrixRef pResMat = GetNewMat(
3668 static_cast<SCSIZE>(nCol2-nCol1+1), 1);
3669 if (pResMat)
3671 for (SCCOL i = nCol1; i <= nCol2; i++)
3672 pResMat->PutDouble((double)(i+1),
3673 static_cast<SCSIZE>(i-nCol1), 0);
3674 PushMatrix(pResMat);
3675 return;
3677 else
3678 nVal = 0.0;
3680 else
3681 nVal = (double) (nCol1 + 1);
3683 break;
3684 default:
3685 SetError( errIllegalParameter );
3686 nVal = 0.0;
3689 PushDouble( nVal );
3694 void ScInterpreter::ScRow()
3696 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRow" );
3697 BYTE nParamCount = GetByte();
3698 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
3700 double nVal = 0;
3701 if (nParamCount == 0)
3703 nVal = aPos.Row() + 1;
3704 if (bMatrixFormula)
3706 SCCOL nCols;
3707 SCROW nRows;
3708 pMyFormulaCell->GetMatColsRows( nCols, nRows);
3709 ScMatrixRef pResMat = GetNewMat( 1, static_cast<SCSIZE>(nRows));
3710 if (pResMat)
3712 for (SCROW i=0; i < nRows; i++)
3713 pResMat->PutDouble( nVal + i, 0, static_cast<SCSIZE>(i));
3714 PushMatrix( pResMat);
3715 return;
3719 else
3721 switch ( GetStackType() )
3723 case svSingleRef :
3725 SCCOL nCol1;
3726 SCROW nRow1;
3727 SCTAB nTab1;
3728 PopSingleRef( nCol1, nRow1, nTab1 );
3729 nVal = (double) (nRow1 + 1);
3731 break;
3732 case svDoubleRef :
3734 SCCOL nCol1;
3735 SCROW nRow1;
3736 SCTAB nTab1;
3737 SCCOL nCol2;
3738 SCROW nRow2;
3739 SCTAB nTab2;
3740 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
3741 if (nRow2 > nRow1)
3743 ScMatrixRef pResMat = GetNewMat( 1,
3744 static_cast<SCSIZE>(nRow2-nRow1+1));
3745 if (pResMat)
3747 for (SCROW i = nRow1; i <= nRow2; i++)
3748 pResMat->PutDouble((double)(i+1), 0,
3749 static_cast<SCSIZE>(i-nRow1));
3750 PushMatrix(pResMat);
3751 return;
3753 else
3754 nVal = 0.0;
3756 else
3757 nVal = (double) (nRow1 + 1);
3759 break;
3760 default:
3761 SetError( errIllegalParameter );
3762 nVal = 0.0;
3765 PushDouble( nVal );
3769 void ScInterpreter::ScTable()
3771 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTable" );
3772 BYTE nParamCount = GetByte();
3773 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
3775 SCTAB nVal = 0;
3776 if ( nParamCount == 0 )
3777 nVal = aPos.Tab() + 1;
3778 else
3780 switch ( GetStackType() )
3782 case svString :
3784 String aStr( PopString() );
3785 if ( pDok->GetTable( aStr, nVal ) )
3786 ++nVal;
3787 else
3788 SetError( errIllegalArgument );
3790 break;
3791 case svSingleRef :
3793 SCCOL nCol1;
3794 SCROW nRow1;
3795 SCTAB nTab1;
3796 PopSingleRef( nCol1, nRow1, nTab1 );
3797 nVal = nTab1 + 1;
3799 break;
3800 case svDoubleRef :
3802 SCCOL nCol1;
3803 SCROW nRow1;
3804 SCTAB nTab1;
3805 SCCOL nCol2;
3806 SCROW nRow2;
3807 SCTAB nTab2;
3808 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
3809 nVal = nTab1 + 1;
3811 break;
3812 default:
3813 SetError( errIllegalParameter );
3815 if ( nGlobalError )
3816 nVal = 0;
3818 PushDouble( (double) nVal );
3822 /** returns -1 when the matrix value is smaller than the query value, 0 when
3823 they are equal, and 1 when the matrix value is larger than the query
3824 value. */
3825 static sal_Int32 lcl_CompareMatrix2Query( SCSIZE i, const ScMatrix& rMat,
3826 const ScQueryEntry& rEntry)
3828 if (rMat.IsEmpty(i))
3830 /* TODO: in case we introduced query for real empty this would have to
3831 * be changed! */
3832 return -1; // empty always less than anything else
3835 /* FIXME: what is an empty path (result of IF(false;true_path) in
3836 * comparisons? */
3838 if (rMat.IsValue(i))
3840 if (rEntry.bQueryByString)
3841 return -1; // numeric always less than string
3843 const double nVal1 = rMat.GetDouble(i);
3844 const double nVal2 = rEntry.nVal;
3845 if (nVal1 == nVal2)
3846 return 0;
3848 return nVal1 < nVal2 ? -1 : 1;
3851 if (!rEntry.bQueryByString)
3852 return 1; // string always greater than numeric
3854 if (!rEntry.pStr)
3855 // this should not happen!
3856 return 1;
3858 const String& rStr1 = rMat.GetString(i);
3859 const String& rStr2 = *rEntry.pStr;
3861 return ScGlobal::pCollator->compareString( rStr1, rStr2); // case-insensitive
3864 /** returns the last item with the identical value as the original item
3865 value. */
3866 static void lcl_GetLastMatch( SCSIZE& rIndex, const ScMatrix& rMat,
3867 SCSIZE nMatCount, bool bReverse)
3869 if (rMat.IsValue(rIndex))
3871 double nVal = rMat.GetDouble(rIndex);
3872 if (bReverse)
3873 while (rIndex > 0 && rMat.IsValue(rIndex-1) &&
3874 nVal == rMat.GetDouble(rIndex-1))
3875 --rIndex;
3876 else
3877 while (rIndex < nMatCount-1 && rMat.IsValue(rIndex+1) &&
3878 nVal == rMat.GetDouble(rIndex+1))
3879 ++rIndex;
3881 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
3882 else if (rMat.IsEmptyPath(rIndex))
3884 if (bReverse)
3885 while (rIndex > 0 && rMat.IsEmptyPath(rIndex-1))
3886 --rIndex;
3887 else
3888 while (rIndex < nMatCount-1 && rMat.IsEmptyPath(rIndex+1))
3889 ++rIndex;
3891 else if (rMat.IsEmpty(rIndex))
3893 if (bReverse)
3894 while (rIndex > 0 && rMat.IsEmpty(rIndex-1))
3895 --rIndex;
3896 else
3897 while (rIndex < nMatCount-1 && rMat.IsEmpty(rIndex+1))
3898 ++rIndex;
3900 else if (rMat.IsString(rIndex))
3902 String aStr( rMat.GetString(rIndex));
3903 if (bReverse)
3904 while (rIndex > 0 && rMat.IsString(rIndex-1) &&
3905 aStr == rMat.GetString(rIndex-1))
3906 --rIndex;
3907 else
3908 while (rIndex < nMatCount-1 && rMat.IsString(rIndex+1) &&
3909 aStr == rMat.GetString(rIndex+1))
3910 ++rIndex;
3912 else
3914 DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
3918 void ScInterpreter::ScMatch()
3920 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMatch" );
3921 ScMatrixRef pMatSrc = NULL;
3923 BYTE nParamCount = GetByte();
3924 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
3926 double fTyp;
3927 if (nParamCount == 3)
3928 fTyp = GetDouble();
3929 else
3930 fTyp = 1.0;
3931 SCCOL nCol1 = 0;
3932 SCROW nRow1 = 0;
3933 SCTAB nTab1 = 0;
3934 SCCOL nCol2 = 0;
3935 SCROW nRow2 = 0;
3936 SCTAB nTab2 = 0;
3937 if (GetStackType() == svDoubleRef)
3939 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3940 if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
3942 PushIllegalParameter();
3943 return;
3946 else if (GetStackType() == svMatrix)
3948 pMatSrc = PopMatrix();
3949 if (!pMatSrc)
3951 PushIllegalParameter();
3952 return;
3955 else
3957 PushIllegalParameter();
3958 return;
3960 if (nGlobalError == 0)
3962 double fVal;
3963 String sStr;
3964 ScQueryParam rParam;
3965 rParam.nCol1 = nCol1;
3966 rParam.nRow1 = nRow1;
3967 rParam.nCol2 = nCol2;
3968 rParam.nTab = nTab1;
3969 rParam.bMixedComparison = TRUE;
3971 ScQueryEntry& rEntry = rParam.GetEntry(0);
3972 rEntry.bDoQuery = TRUE;
3973 if (fTyp < 0.0)
3974 rEntry.eOp = SC_GREATER_EQUAL;
3975 else if (fTyp > 0.0)
3976 rEntry.eOp = SC_LESS_EQUAL;
3977 switch ( GetStackType() )
3979 case svDouble:
3981 fVal = GetDouble();
3982 rEntry.bQueryByString = FALSE;
3983 rEntry.nVal = fVal;
3985 break;
3986 case svString:
3988 sStr = GetString();
3989 rEntry.bQueryByString = TRUE;
3990 *rEntry.pStr = sStr;
3992 break;
3993 case svDoubleRef :
3994 case svSingleRef :
3996 ScAddress aAdr;
3997 if ( !PopDoubleRefOrSingleRef( aAdr ) )
3999 PushInt(0);
4000 return ;
4002 ScBaseCell* pCell = GetCell( aAdr );
4003 if (HasCellValueData(pCell))
4005 fVal = GetCellValue( aAdr, pCell );
4006 rEntry.bQueryByString = FALSE;
4007 rEntry.nVal = fVal;
4009 else
4011 GetCellString(sStr, pCell);
4012 rEntry.bQueryByString = TRUE;
4013 *rEntry.pStr = sStr;
4016 break;
4017 case svMatrix :
4019 ScMatValType nType = GetDoubleOrStringFromMatrix(
4020 rEntry.nVal, *rEntry.pStr);
4021 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
4023 break;
4024 default:
4026 PushIllegalParameter();
4027 return;
4030 if ( rEntry.bQueryByString )
4032 BOOL bIsVBAMode = FALSE;
4033 if ( pDok )
4035 SfxObjectShell* pDocSh = pDok->GetDocumentShell();
4036 if ( pDocSh )
4037 bIsVBAMode = pDocSh->GetBasic()->isVBAEnabled();
4039 // #TODO handle MSO wildcards
4040 if ( bIsVBAMode )
4041 rParam.bRegExp = FALSE;
4042 else
4043 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4046 if (pMatSrc) // The source data is matrix array.
4048 SCSIZE nC, nR;
4049 pMatSrc->GetDimensions( nC, nR);
4050 if (nC > 1 && nR > 1)
4052 // The source matrix must be a vector.
4053 PushIllegalParameter();
4054 return;
4056 SCSIZE nMatCount = (nC == 1) ? nR : nC;
4058 // simple serial search for equality mode (source data doesn't
4059 // need to be sorted).
4061 if (rEntry.eOp == SC_EQUAL)
4063 for (SCSIZE i = 0; i < nMatCount; ++i)
4065 if (lcl_CompareMatrix2Query( i, *pMatSrc, rEntry) == 0)
4067 PushDouble(i+1); // found !
4068 return;
4071 PushNA(); // not found
4072 return;
4075 // binary search for non-equality mode (the source data is
4076 // assumed to be sorted).
4078 bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL);
4079 SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0;
4080 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
4082 SCSIZE nMid = nFirst + nLen/2;
4083 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry);
4084 if (nCmp == 0)
4086 // exact match. find the last item with the same value.
4087 lcl_GetLastMatch( nMid, *pMatSrc, nMatCount, !bAscOrder);
4088 PushDouble( nMid+1);
4089 return;
4092 if (nLen == 1) // first and last items are next to each other.
4094 if (nCmp < 0)
4095 nHitIndex = bAscOrder ? nLast : nFirst;
4096 else
4097 nHitIndex = bAscOrder ? nFirst : nLast;
4098 break;
4101 if (nCmp < 0)
4103 if (bAscOrder)
4104 nFirst = nMid;
4105 else
4106 nLast = nMid;
4108 else
4110 if (bAscOrder)
4111 nLast = nMid;
4112 else
4113 nFirst = nMid;
4117 if (nHitIndex == nMatCount-1) // last item
4119 sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry);
4120 if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
4122 // either the last item is an exact match or the real
4123 // hit is beyond the last item.
4124 PushDouble( nHitIndex+1);
4125 return;
4129 if (nHitIndex > 0) // valid hit must be 2nd item or higher
4131 PushDouble( nHitIndex); // non-exact match
4132 return;
4135 PushNA();
4136 return;
4139 SCCOLROW nDelta = 0;
4140 if (nCol1 == nCol2)
4141 { // search row in column
4142 rParam.nRow2 = nRow2;
4143 rEntry.nField = nCol1;
4144 ScAddress aResultPos( nCol1, nRow1, nTab1);
4145 if (!LookupQueryWithCache( aResultPos, rParam))
4147 PushNA();
4148 return;
4150 nDelta = aResultPos.Row() - nRow1;
4152 else
4153 { // search column in row
4154 SCCOL nC;
4155 rParam.bByRow = FALSE;
4156 rParam.nRow2 = nRow1;
4157 rEntry.nField = nCol1;
4158 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
4159 // Advance Entry.nField in Iterator if column changed
4160 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
4161 if (fTyp == 0.0)
4162 { // EQUAL
4163 if ( aCellIter.GetFirst() )
4164 nC = aCellIter.GetCol();
4165 else
4167 PushNA();
4168 return;
4171 else
4172 { // <= or >=
4173 SCROW nR;
4174 if ( !aCellIter.FindEqualOrSortedLastInRange( nC, nR ) )
4176 PushNA();
4177 return;
4180 nDelta = nC - nCol1;
4182 PushDouble((double) (nDelta + 1));
4184 else
4185 PushIllegalParameter();
4190 void ScInterpreter::ScCountEmptyCells()
4192 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCountEmptyCells" );
4193 if ( MustHaveParamCount( GetByte(), 1 ) )
4195 ULONG nMaxCount = 0, nCount = 0;
4196 CellType eCellType;
4197 switch (GetStackType())
4199 case svSingleRef :
4201 nMaxCount = 1;
4202 ScAddress aAdr;
4203 PopSingleRef( aAdr );
4204 eCellType = GetCellType( GetCell( aAdr ) );
4205 if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
4206 nCount = 1;
4208 break;
4209 case svDoubleRef :
4210 case svRefList :
4212 ScRange aRange;
4213 short nParam = 1;
4214 size_t nRefInList = 0;
4215 while (nParam-- > 0)
4217 PopDoubleRef( aRange, nParam, nRefInList);
4218 nMaxCount +=
4219 static_cast<ULONG>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) *
4220 static_cast<ULONG>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) *
4221 static_cast<ULONG>(aRange.aEnd.Tab() - aRange.aStart.Tab() + 1);
4222 ScBaseCell* pCell;
4223 ScCellIterator aDocIter( pDok, aRange, glSubTotal);
4224 if ( (pCell = aDocIter.GetFirst()) != NULL )
4228 if ((eCellType = pCell->GetCellType()) != CELLTYPE_NONE
4229 && eCellType != CELLTYPE_NOTE)
4230 nCount++;
4231 } while ( (pCell = aDocIter.GetNext()) != NULL );
4235 break;
4236 default : SetError(errIllegalParameter); break;
4238 PushDouble(nMaxCount - nCount);
4243 void ScInterpreter::ScCountIf()
4245 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCountIf" );
4246 if ( MustHaveParamCount( GetByte(), 2 ) )
4248 String rString;
4249 double fVal = 0.0;
4250 BOOL bIsString = TRUE;
4251 switch ( GetStackType() )
4253 case svDoubleRef :
4254 case svSingleRef :
4256 ScAddress aAdr;
4257 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4259 PushInt(0);
4260 return ;
4262 ScBaseCell* pCell = GetCell( aAdr );
4263 switch ( GetCellType( pCell ) )
4265 case CELLTYPE_VALUE :
4266 fVal = GetCellValue( aAdr, pCell );
4267 bIsString = FALSE;
4268 break;
4269 case CELLTYPE_FORMULA :
4270 if( ((ScFormulaCell*)pCell)->IsValue() )
4272 fVal = GetCellValue( aAdr, pCell );
4273 bIsString = FALSE;
4275 else
4276 GetCellString(rString, pCell);
4277 break;
4278 case CELLTYPE_STRING :
4279 case CELLTYPE_EDIT :
4280 GetCellString(rString, pCell);
4281 break;
4282 default:
4283 fVal = 0.0;
4284 bIsString = FALSE;
4287 break;
4288 case svMatrix :
4290 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
4291 rString);
4292 bIsString = ScMatrix::IsNonValueType( nType);
4294 break;
4295 case svString:
4296 rString = GetString();
4297 break;
4298 default:
4300 fVal = GetDouble();
4301 bIsString = FALSE;
4304 double fSum = 0.0;
4305 short nParam = 1;
4306 size_t nRefInList = 0;
4307 while (nParam-- > 0)
4309 SCCOL nCol1;
4310 SCROW nRow1;
4311 SCTAB nTab1;
4312 SCCOL nCol2;
4313 SCROW nRow2;
4314 SCTAB nTab2;
4315 switch ( GetStackType() )
4317 case svDoubleRef :
4318 case svRefList :
4320 ScRange aRange;
4321 PopDoubleRef( aRange, nParam, nRefInList);
4322 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4324 break;
4325 case svSingleRef :
4326 PopSingleRef( nCol1, nRow1, nTab1 );
4327 nCol2 = nCol1;
4328 nRow2 = nRow1;
4329 nTab2 = nTab1;
4330 break;
4331 default:
4332 PushIllegalParameter();
4333 return ;
4335 if ( nTab1 != nTab2 )
4337 PushIllegalParameter();
4338 return;
4340 if (nCol1 > nCol2)
4342 PushIllegalParameter();
4343 return;
4345 if (nGlobalError == 0)
4347 ScQueryParam rParam;
4348 rParam.nRow1 = nRow1;
4349 rParam.nRow2 = nRow2;
4351 ScQueryEntry& rEntry = rParam.GetEntry(0);
4352 rEntry.bDoQuery = TRUE;
4353 if (!bIsString)
4355 rEntry.bQueryByString = FALSE;
4356 rEntry.nVal = fVal;
4357 rEntry.eOp = SC_EQUAL;
4359 else
4361 rParam.FillInExcelSyntax(rString, 0);
4362 sal_uInt32 nIndex = 0;
4363 rEntry.bQueryByString =
4364 !(pFormatter->IsNumberFormat(
4365 *rEntry.pStr, nIndex, rEntry.nVal));
4366 if ( rEntry.bQueryByString )
4367 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4369 rParam.nCol1 = nCol1;
4370 rParam.nCol2 = nCol2;
4371 rEntry.nField = nCol1;
4372 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
4373 // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
4374 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
4375 if ( aCellIter.GetFirst() )
4379 fSum++;
4380 } while ( aCellIter.GetNext() );
4383 else
4385 PushIllegalParameter();
4386 return;
4389 PushDouble(fSum);
4394 void ScInterpreter::ScSumIf()
4396 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumIf" );
4397 BYTE nParamCount = GetByte();
4398 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
4400 SCCOL nCol3 = 0;
4401 SCROW nRow3 = 0;
4402 SCTAB nTab3 = 0;
4404 bool bSumExtraRange = (nParamCount == 3);
4405 if (bSumExtraRange)
4407 // Save only the upperleft cell in case of cell range. The geometry
4408 // of the 3rd parameter is taken from the 1st parameter.
4410 switch ( GetStackType() )
4412 case svDoubleRef :
4414 SCCOL nColJunk = 0;
4415 SCROW nRowJunk = 0;
4416 SCTAB nTabJunk = 0;
4417 PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
4418 if ( nTabJunk != nTab3 )
4420 PushIllegalParameter();
4421 return;
4424 break;
4425 case svSingleRef :
4426 PopSingleRef( nCol3, nRow3, nTab3 );
4427 break;
4428 default:
4429 PushIllegalParameter();
4430 return ;
4433 String rString;
4434 double fVal = 0.0;
4435 BOOL bIsString = TRUE;
4436 switch ( GetStackType() )
4438 case svDoubleRef :
4439 case svSingleRef :
4441 ScAddress aAdr;
4442 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4444 PushInt(0);
4445 return ;
4447 ScBaseCell* pCell = GetCell( aAdr );
4448 switch ( GetCellType( pCell ) )
4450 case CELLTYPE_VALUE :
4451 fVal = GetCellValue( aAdr, pCell );
4452 bIsString = FALSE;
4453 break;
4454 case CELLTYPE_FORMULA :
4455 if( ((ScFormulaCell*)pCell)->IsValue() )
4457 fVal = GetCellValue( aAdr, pCell );
4458 bIsString = FALSE;
4460 else
4461 GetCellString(rString, pCell);
4462 break;
4463 case CELLTYPE_STRING :
4464 case CELLTYPE_EDIT :
4465 GetCellString(rString, pCell);
4466 break;
4467 default:
4468 fVal = 0.0;
4469 bIsString = FALSE;
4472 break;
4473 case svString:
4474 rString = GetString();
4475 break;
4476 case svMatrix :
4478 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
4479 rString);
4480 bIsString = ScMatrix::IsNonValueType( nType);
4482 break;
4483 default:
4485 fVal = GetDouble();
4486 bIsString = FALSE;
4490 double fSum = 0.0;
4491 double fMem = 0.0;
4492 BOOL bNull = TRUE;
4493 short nParam = 1;
4494 size_t nRefInList = 0;
4495 while (nParam-- > 0)
4497 SCCOL nCol1;
4498 SCROW nRow1;
4499 SCTAB nTab1;
4500 SCCOL nCol2;
4501 SCROW nRow2;
4502 SCTAB nTab2;
4503 switch ( GetStackType() )
4505 case svRefList :
4506 if (bSumExtraRange)
4508 PushIllegalParameter();
4509 return;
4511 else
4513 ScRange aRange;
4514 PopDoubleRef( aRange, nParam, nRefInList);
4515 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4517 break;
4518 case svDoubleRef :
4519 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
4520 break;
4521 case svSingleRef :
4522 PopSingleRef( nCol1, nRow1, nTab1 );
4523 nCol2 = nCol1;
4524 nRow2 = nRow1;
4525 nTab2 = nTab1;
4526 break;
4527 default:
4528 PushIllegalParameter();
4529 return ;
4531 if ( nTab1 != nTab2 )
4533 PushIllegalParameter();
4534 return;
4537 if (bSumExtraRange)
4539 // Take the range geometry of the 1st parameter and apply it to
4540 // the 3rd. If parts of the resulting range would point outside
4541 // the sheet, don't complain but silently ignore and simply cut
4542 // them away, this is what Xcl does :-/
4544 // For the cut-away part we also don't need to determine the
4545 // criteria match, so shrink the source range accordingly,
4546 // instead of the result range.
4547 SCCOL nColDelta = nCol2 - nCol1;
4548 SCROW nRowDelta = nRow2 - nRow1;
4549 if (nCol3 + nColDelta > MAXCOL)
4551 SCCOL nNewDelta = MAXCOL - nCol3;
4552 nCol2 = nCol1 + nNewDelta;
4555 if (nRow3 + nRowDelta > MAXROW)
4557 SCROW nNewDelta = MAXROW - nRow3;
4558 nRow2 = nRow1 + nNewDelta;
4561 else
4563 nCol3 = nCol1;
4564 nRow3 = nRow1;
4565 nTab3 = nTab1;
4568 if (nGlobalError == 0)
4570 ScQueryParam rParam;
4571 rParam.nRow1 = nRow1;
4572 rParam.nRow2 = nRow2;
4574 ScQueryEntry& rEntry = rParam.GetEntry(0);
4575 rEntry.bDoQuery = TRUE;
4576 if (!bIsString)
4578 rEntry.bQueryByString = FALSE;
4579 rEntry.nVal = fVal;
4580 rEntry.eOp = SC_EQUAL;
4582 else
4584 rParam.FillInExcelSyntax(rString, 0);
4585 sal_uInt32 nIndex = 0;
4586 rEntry.bQueryByString =
4587 !(pFormatter->IsNumberFormat(
4588 *rEntry.pStr, nIndex, rEntry.nVal));
4589 if ( rEntry.bQueryByString )
4590 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4592 ScAddress aAdr;
4593 aAdr.SetTab( nTab3 );
4594 rParam.nCol1 = nCol1;
4595 rParam.nCol2 = nCol2;
4596 rEntry.nField = nCol1;
4597 SCCOL nColDiff = nCol3 - nCol1;
4598 SCROW nRowDiff = nRow3 - nRow1;
4599 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
4600 // Increment Entry.nField in iterator when switching to next column.
4601 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
4602 if ( aCellIter.GetFirst() )
4606 aAdr.SetCol( aCellIter.GetCol() + nColDiff);
4607 aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
4608 ScBaseCell* pCell = GetCell( aAdr );
4609 if ( HasCellValueData(pCell) )
4611 fVal = GetCellValue( aAdr, pCell );
4612 if ( bNull && fVal != 0.0 )
4614 bNull = FALSE;
4615 fMem = fVal;
4617 else
4618 fSum += fVal;
4620 } while ( aCellIter.GetNext() );
4623 else
4625 PushIllegalParameter();
4626 return;
4629 PushDouble( ::rtl::math::approxAdd( fSum, fMem ) );
4634 void ScInterpreter::ScLookup()
4636 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLookup" );
4637 BYTE nParamCount = GetByte();
4638 if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
4639 return ;
4641 ScMatrixRef pDataMat = NULL, pResMat = NULL;
4642 SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
4643 SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
4644 SCTAB nTab1 = 0, nResTab = 0;
4645 SCSIZE nLenMajor = 0; // length of major direction
4646 bool bVertical = true; // whether to lookup vertically or horizontally
4648 if (nParamCount == 3)
4650 switch (GetStackType())
4652 case svDoubleRef:
4654 SCTAB nTabJunk;
4655 PopDoubleRef(nResCol1, nResRow1, nResTab,
4656 nResCol2, nResRow2, nTabJunk);
4657 if (nResTab != nTabJunk ||
4658 ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
4660 // The result array must be a vector.
4661 PushIllegalParameter();
4662 return;
4665 break;
4666 case svMatrix:
4668 pResMat = PopMatrix();
4669 if (!pResMat)
4671 PushIllegalParameter();
4672 return;
4674 SCSIZE nC, nR;
4675 pResMat->GetDimensions(nC, nR);
4676 if (nC != 1 && nR != 1)
4678 // Result matrix must be a vector.
4679 PushIllegalParameter();
4680 return;
4683 break;
4684 default:
4685 PushIllegalParameter();
4686 return;
4690 // Get the data-result range and also determine whether this is vertical
4691 // lookup or horizontal lookup.
4693 switch (GetStackType())
4695 case svDoubleRef:
4697 SCTAB nTabJunk;
4698 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
4699 if (nTab1 != nTabJunk)
4701 PushIllegalParameter();
4702 return;
4704 bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
4705 nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
4707 break;
4708 case svMatrix:
4710 pDataMat = PopMatrix();
4711 if (!pDataMat)
4713 PushIllegalParameter();
4714 return;
4717 SCSIZE nC, nR;
4718 pDataMat->GetDimensions(nC, nR);
4719 bVertical = (nR >= nC);
4720 nLenMajor = bVertical ? nR : nC;
4722 break;
4723 default:
4724 PushIllegalParameter();
4725 return;
4729 if (nGlobalError)
4731 PushIllegalParameter();
4732 return;
4735 // Get the lookup value.
4737 ScQueryParam aParam;
4738 ScQueryEntry& rEntry = aParam.GetEntry(0);
4739 if ( !FillEntry(rEntry) )
4740 return;
4742 // Now, perform the search to compute the delta position (nDelta).
4744 if (pDataMat)
4746 // Data array is given as a matrix.
4747 rEntry.bDoQuery = true;
4748 rEntry.eOp = SC_LESS_EQUAL;
4749 bool bFound = false;
4751 SCSIZE nC, nR;
4752 pDataMat->GetDimensions(nC, nR);
4754 // In case of non-vector matrix, only search the first row or column.
4755 ScMatrixRef pDataMat2;
4756 if (bVertical)
4758 ScMatrixRef pTempMat(new ScMatrix(1, nR));
4759 for (SCSIZE i = 0; i < nR; ++i)
4760 if (pDataMat->IsValue(0, i))
4761 pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
4762 else
4763 pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
4764 pDataMat2 = pTempMat;
4766 else
4768 ScMatrixRef pTempMat(new ScMatrix(nC, 1));
4769 for (SCSIZE i = 0; i < nC; ++i)
4770 if (pDataMat->IsValue(i, 0))
4771 pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
4772 else
4773 pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
4774 pDataMat2 = pTempMat;
4777 // binary search for non-equality mode (the source data is
4778 // assumed to be sorted in ascending order).
4780 SCCOLROW nDelta = -1;
4782 SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
4783 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
4785 SCSIZE nMid = nFirst + nLen/2;
4786 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry);
4787 if (nCmp == 0)
4789 // exact match. find the last item with the same value.
4790 lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false);
4791 nDelta = nMid;
4792 bFound = true;
4793 break;
4796 if (nLen == 1) // first and last items are next to each other.
4798 nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
4799 // If already the 1st item is greater there's nothing found.
4800 bFound = (nDelta >= 0);
4801 break;
4804 if (nCmp < 0)
4805 nFirst = nMid;
4806 else
4807 nLast = nMid;
4810 if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
4812 sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry);
4813 if (nCmp <= 0)
4815 // either the last item is an exact match or the real
4816 // hit is beyond the last item.
4817 nDelta += 1;
4818 bFound = true;
4821 else if (nDelta > 0) // valid hit must be 2nd item or higher
4823 // non-exact match
4824 bFound = true;
4827 if (!bFound)
4829 PushNA();
4830 return;
4833 // Now that we've found the delta, push the result back to the cell.
4835 if (pResMat)
4837 // result array is matrix.
4838 if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount())
4840 PushNA();
4841 return;
4843 if (pResMat->IsValue(nDelta))
4844 PushDouble(pResMat->GetDouble(nDelta));
4845 else
4846 PushString(pResMat->GetString(nDelta));
4848 else if (nParamCount == 3)
4850 // result array is cell range.
4851 ScAddress aAdr;
4852 aAdr.SetTab(nResTab);
4853 bool bResVertical = (nResRow2 - nResRow1) > 0;
4854 if (bResVertical)
4856 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
4857 if (nTempRow > MAXROW)
4859 PushDouble(0);
4860 return;
4862 aAdr.SetCol(nResCol1);
4863 aAdr.SetRow(nTempRow);
4865 else
4867 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
4868 if (nTempCol > MAXCOL)
4870 PushDouble(0);
4871 return;
4873 aAdr.SetCol(nTempCol);
4874 aAdr.SetRow(nResRow1);
4876 PushCellResultToken(true, aAdr, NULL, NULL);
4878 else
4880 // no result array. Use the data array to get the final value from.
4881 if (bVertical)
4883 if (pDataMat->IsValue(nC-1, nDelta))
4884 PushDouble(pDataMat->GetDouble(nC-1, nDelta));
4885 else
4886 PushString(pDataMat->GetString(nC-1, nDelta));
4888 else
4890 if (pDataMat->IsValue(nDelta, nR-1))
4891 PushDouble(pDataMat->GetDouble(nDelta, nR-1));
4892 else
4893 PushString(pDataMat->GetString(nDelta, nR-1));
4897 return;
4900 // Perform cell range search.
4902 aParam.nCol1 = nCol1;
4903 aParam.nRow1 = nRow1;
4904 aParam.nCol2 = bVertical ? nCol1 : nCol2;
4905 aParam.nRow2 = bVertical ? nRow2 : nRow1;
4906 aParam.bByRow = bVertical;
4907 aParam.bMixedComparison = true;
4909 rEntry.bDoQuery = TRUE;
4910 rEntry.eOp = SC_LESS_EQUAL;
4911 rEntry.nField = nCol1;
4912 if ( rEntry.bQueryByString )
4913 aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4915 ScQueryCellIterator aCellIter(pDok, nTab1, aParam, FALSE);
4916 SCCOL nC;
4917 SCROW nR;
4918 // Advance Entry.nField in iterator upon switching columns if
4919 // lookup in row.
4920 aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
4921 if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
4923 PushNA();
4924 return;
4927 SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
4929 if (pResMat)
4931 // Use the matrix result array.
4932 if (pResMat->IsValue(nDelta))
4933 PushDouble(pResMat->GetDouble(nDelta));
4934 else
4935 PushString(pResMat->GetString(nDelta));
4937 else if (nParamCount == 3)
4939 // Use the result array vector. Note that the result array is assumed
4940 // to be a vector (i.e. 1-dimensinoal array).
4942 ScAddress aAdr;
4943 aAdr.SetTab(nResTab);
4944 bool bResVertical = (nResRow2 - nResRow1) > 0;
4945 if (bResVertical)
4947 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
4948 if (nTempRow > MAXROW)
4950 PushDouble(0);
4951 return;
4953 aAdr.SetCol(nResCol1);
4954 aAdr.SetRow(nTempRow);
4956 else
4958 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
4959 if (nTempCol > MAXCOL)
4961 PushDouble(0);
4962 return;
4964 aAdr.SetCol(nTempCol);
4965 aAdr.SetRow(nResRow1);
4967 PushCellResultToken(true, aAdr, NULL, NULL);
4969 else
4971 // Regardless of whether or not the result array exists, the last
4972 // array is always used as the "result" array.
4974 ScAddress aAdr;
4975 aAdr.SetTab(nTab1);
4976 if (bVertical)
4978 SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
4979 if (nTempRow > MAXROW)
4981 PushDouble(0);
4982 return;
4984 aAdr.SetCol(nCol2);
4985 aAdr.SetRow(nTempRow);
4987 else
4989 SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
4990 if (nTempCol > MAXCOL)
4992 PushDouble(0);
4993 return;
4995 aAdr.SetCol(nTempCol);
4996 aAdr.SetRow(nRow2);
4998 PushCellResultToken(true, aAdr, NULL, NULL);
5003 void ScInterpreter::ScHLookup()
5005 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHLookup" );
5006 CalculateLookup(TRUE);
5008 void ScInterpreter::CalculateLookup(BOOL HLookup)
5010 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateLookup" );
5011 BYTE nParamCount = GetByte();
5012 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
5014 BOOL bSorted;
5015 if (nParamCount == 4)
5016 bSorted = GetBool();
5017 else
5018 bSorted = TRUE;
5019 double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
5020 ScMatrixRef pMat = NULL;
5021 SCSIZE nC = 0, nR = 0;
5022 SCCOL nCol1 = 0;
5023 SCROW nRow1 = 0;
5024 SCTAB nTab1 = 0;
5025 SCCOL nCol2 = 0;
5026 SCROW nRow2 = 0;
5027 SCTAB nTab2;
5028 if (GetStackType() == svDoubleRef)
5030 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
5031 if (nTab1 != nTab2)
5033 PushIllegalParameter();
5034 return;
5037 else if (GetStackType() == svMatrix)
5039 pMat = PopMatrix();
5040 if (pMat)
5041 pMat->GetDimensions(nC, nR);
5042 else
5044 PushIllegalParameter();
5045 return;
5048 else
5050 PushIllegalParameter();
5051 return;
5053 if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
5055 PushIllegalArgument();
5056 return;
5058 SCROW nZIndex = static_cast<SCROW>(fIndex);
5059 SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
5061 if (!pMat)
5063 nZIndex += nRow1; // Wertzeile
5064 nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 ); // value column
5067 if (nGlobalError == 0)
5069 ScQueryParam rParam;
5070 rParam.nCol1 = nCol1;
5071 rParam.nRow1 = nRow1;
5072 if ( HLookup )
5074 rParam.nCol2 = nCol2;
5075 rParam.nRow2 = nRow1; // nur in der ersten Zeile suchen
5076 rParam.bByRow = FALSE;
5077 } // if ( HLookup )
5078 else
5080 rParam.nCol2 = nCol1; // nur in der ersten Spalte suchen
5081 rParam.nRow2 = nRow2;
5082 rParam.nTab = nTab1;
5084 rParam.bMixedComparison = TRUE;
5086 ScQueryEntry& rEntry = rParam.GetEntry(0);
5087 rEntry.bDoQuery = TRUE;
5088 if ( bSorted )
5089 rEntry.eOp = SC_LESS_EQUAL;
5090 if ( !FillEntry(rEntry) )
5091 return;
5092 if ( rEntry.bQueryByString )
5093 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5094 if (pMat)
5096 SCSIZE nMatCount = HLookup ? nC : nR;
5097 SCSIZE nDelta = SCSIZE_MAX;
5098 if (rEntry.bQueryByString)
5100 //!!!!!!!
5101 //! TODO: enable regex on matrix strings
5102 //!!!!!!!
5103 String aParamStr = *rEntry.pStr;
5104 if ( bSorted )
5106 for (SCSIZE i = 0; i < nMatCount; i++)
5108 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
5110 sal_Int32 nRes =
5111 ScGlobal::pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr);
5112 if (nRes <= 0)
5113 nDelta = i;
5114 else if (i>0) // #i2168# ignore first mismatch
5115 i = nMatCount+1;
5117 else
5118 nDelta = i;
5121 else
5123 for (SCSIZE i = 0; i < nMatCount; i++)
5125 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
5127 if ( ScGlobal::pTransliteration->isEqual(
5128 HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr ) )
5130 nDelta = i;
5131 i = nMatCount + 1;
5137 else
5139 if ( bSorted )
5141 // #i2168# ignore strings
5142 for (SCSIZE i = 0; i < nMatCount; i++)
5144 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
5146 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rEntry.nVal)
5147 nDelta = i;
5148 else
5149 i = nMatCount+1;
5153 else
5155 for (SCSIZE i = 0; i < nMatCount; i++)
5157 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
5159 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) == rEntry.nVal)
5161 nDelta = i;
5162 i = nMatCount + 1;
5168 if ( nDelta != SCSIZE_MAX )
5170 SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
5171 SCSIZE nY = nDelta;
5172 if ( HLookup )
5174 nX = nDelta;
5175 nY = static_cast<SCSIZE>(nZIndex);
5177 if ( pMat->IsString( nX, nY) )
5178 PushString(pMat->GetString( nX,nY));
5179 else
5180 PushDouble(pMat->GetDouble( nX,nY));
5182 else
5183 PushNA();
5185 else
5187 rEntry.nField = nCol1;
5188 BOOL bFound = FALSE;
5189 SCCOL nCol = 0;
5190 SCROW nRow = 0;
5191 if ( bSorted )
5192 rEntry.eOp = SC_LESS_EQUAL;
5193 if ( HLookup )
5195 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, FALSE);
5196 // advance Entry.nField in Iterator upon switching columns
5197 aCellIter.SetAdvanceQueryParamEntryField( TRUE );
5198 if ( bSorted )
5200 SCROW nRow1_temp;
5201 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
5203 else if ( aCellIter.GetFirst() )
5205 bFound = TRUE;
5206 nCol = aCellIter.GetCol();
5208 nRow = nZIndex;
5209 } // if ( HLookup )
5210 else
5212 ScAddress aResultPos( nCol1, nRow1, nTab1);
5213 bFound = LookupQueryWithCache( aResultPos, rParam);
5214 nRow = aResultPos.Row();
5215 nCol = nSpIndex;
5217 if ( bFound )
5219 ScAddress aAdr( nCol, nRow, nTab1 );
5220 PushCellResultToken( true, aAdr, NULL, NULL);
5222 else
5223 PushNA();
5226 else
5227 PushIllegalParameter();
5231 bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
5233 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::FillEntry" );
5234 switch ( GetStackType() )
5236 case svDouble:
5238 rEntry.bQueryByString = FALSE;
5239 rEntry.nVal = GetDouble();
5241 break;
5242 case svString:
5244 const String sStr = GetString();
5245 rEntry.bQueryByString = TRUE;
5246 *rEntry.pStr = sStr;
5248 break;
5249 case svDoubleRef :
5250 case svSingleRef :
5252 ScAddress aAdr;
5253 if ( !PopDoubleRefOrSingleRef( aAdr ) )
5255 PushInt(0);
5256 return false;
5258 ScBaseCell* pCell = GetCell( aAdr );
5259 if (HasCellValueData(pCell))
5261 rEntry.bQueryByString = FALSE;
5262 rEntry.nVal = GetCellValue( aAdr, pCell );
5264 else
5266 if ( GetCellType( pCell ) == CELLTYPE_NOTE )
5268 rEntry.bQueryByString = FALSE;
5269 rEntry.nVal = 0.0;
5271 else
5273 String sStr;
5274 GetCellString(sStr, pCell);
5275 rEntry.bQueryByString = TRUE;
5276 *rEntry.pStr = sStr;
5280 break;
5281 case svMatrix :
5283 const ScMatValType nType = GetDoubleOrStringFromMatrix(rEntry.nVal, *rEntry.pStr);
5284 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
5286 break;
5287 default:
5289 PushIllegalParameter();
5290 return false;
5292 } // switch ( GetStackType() )
5293 return true;
5295 void ScInterpreter::ScVLookup()
5297 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVLookup" );
5298 CalculateLookup(FALSE);
5301 #if defined(WIN) && defined(MSC)
5302 #pragma optimize("",off)
5303 #endif
5305 void ScInterpreter::ScSubTotal()
5307 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSubTotal" );
5308 BYTE nParamCount = GetByte();
5309 if ( MustHaveParamCountMin( nParamCount, 2 ) )
5311 // We must fish the 1st parameter deep from the stack! And push it on top.
5312 const FormulaToken* p = pStack[ sp - nParamCount ];
5313 PushTempToken( *p );
5314 int nFunc = (int) ::rtl::math::approxFloor( GetDouble() );
5315 if( nFunc < 1 || nFunc > 11 )
5316 PushIllegalArgument(); // simulate return on stack, not SetError(...)
5317 else
5319 cPar = nParamCount - 1;
5320 glSubTotal = TRUE;
5321 switch( nFunc )
5323 case SUBTOTAL_FUNC_AVE : ScAverage(); break;
5324 case SUBTOTAL_FUNC_CNT : ScCount(); break;
5325 case SUBTOTAL_FUNC_CNT2 : ScCount2(); break;
5326 case SUBTOTAL_FUNC_MAX : ScMax(); break;
5327 case SUBTOTAL_FUNC_MIN : ScMin(); break;
5328 case SUBTOTAL_FUNC_PROD : ScProduct(); break;
5329 case SUBTOTAL_FUNC_STD : ScStDev(); break;
5330 case SUBTOTAL_FUNC_STDP : ScStDevP(); break;
5331 case SUBTOTAL_FUNC_SUM : ScSum(); break;
5332 case SUBTOTAL_FUNC_VAR : ScVar(); break;
5333 case SUBTOTAL_FUNC_VARP : ScVarP(); break;
5334 default : PushIllegalArgument(); break;
5336 glSubTotal = FALSE;
5338 // Get rid of the 1st (fished) parameter.
5339 double nVal = GetDouble();
5340 Pop();
5341 PushDouble( nVal );
5344 #if defined(WIN) && defined(MSC)
5345 #pragma optimize("",on)
5346 #endif
5349 BOOL ScInterpreter::GetDBParams(SCTAB& rTab, ScQueryParam& rParam,
5350 BOOL& rMissingField )
5352 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDBParams" );
5353 BOOL bRet = FALSE;
5354 BOOL bAllowMissingField = FALSE;
5355 if ( rMissingField )
5357 bAllowMissingField = TRUE;
5358 rMissingField = FALSE;
5360 if ( GetByte() == 3 )
5363 SCCOL nQCol1;
5364 SCROW nQRow1;
5365 SCTAB nQTab1;
5366 SCCOL nQCol2;
5367 SCROW nQRow2;
5368 SCTAB nQTab2;
5369 PopDoubleRef(nQCol1, nQRow1, nQTab1, nQCol2, nQRow2, nQTab2);
5371 BOOL bByVal = TRUE;
5372 double nVal = 0.0;
5373 String aStr;
5374 ScRange aMissingRange;
5375 BOOL bRangeFake = FALSE;
5376 switch (GetStackType())
5378 case svDouble :
5379 nVal = ::rtl::math::approxFloor( GetDouble() );
5380 if ( bAllowMissingField && nVal == 0.0 )
5381 rMissingField = TRUE; // fake missing parameter
5382 break;
5383 case svString :
5384 bByVal = FALSE;
5385 aStr = GetString();
5386 break;
5387 case svSingleRef :
5389 ScAddress aAdr;
5390 PopSingleRef( aAdr );
5391 ScBaseCell* pCell = GetCell( aAdr );
5392 if (HasCellValueData(pCell))
5393 nVal = GetCellValue( aAdr, pCell );
5394 else
5396 bByVal = FALSE;
5397 GetCellString(aStr, pCell);
5400 break;
5401 case svDoubleRef :
5402 if ( bAllowMissingField )
5403 { // fake missing parameter for old SO compatibility
5404 bRangeFake = TRUE;
5405 PopDoubleRef( aMissingRange );
5407 else
5409 PopError();
5410 SetError( errIllegalParameter );
5412 break;
5413 case svMissing :
5414 PopError();
5415 if ( bAllowMissingField )
5416 rMissingField = TRUE;
5417 else
5418 SetError( errIllegalParameter );
5419 break;
5420 default:
5421 PopError();
5422 SetError( errIllegalParameter );
5425 SCCOL nDBCol1;
5426 SCROW nDBRow1;
5427 SCTAB nDBTab1;
5428 SCCOL nDBCol2;
5429 SCROW nDBRow2;
5430 SCTAB nDBTab2;
5431 PopDoubleRef(nDBCol1, nDBRow1, nDBTab1, nDBCol2, nDBRow2, nDBTab2);
5433 if ( nGlobalError == 0 && bRangeFake )
5435 // range parameter must match entire database range
5436 if ( aMissingRange == ScRange( nDBCol1, nDBRow1, nDBTab1, nDBCol2,
5437 nDBRow2, nDBTab2) )
5438 rMissingField = TRUE;
5439 else
5440 SetError( errIllegalParameter );
5443 if (nGlobalError == 0)
5445 SCCOL nField = nDBCol1;
5446 BOOL bFound = TRUE;
5447 if ( rMissingField )
5448 ; // special case
5449 else if ( bByVal )
5451 if ( nVal <= 0 || nVal > (nDBCol2 - nDBCol1 + 1) )
5452 bFound = FALSE;
5453 else
5454 nField = Min(nDBCol2, (SCCOL)(nDBCol1 + (SCCOL)nVal - 1));
5456 else
5458 bFound = FALSE;
5459 String aCellStr;
5460 ScAddress aLook( nDBCol1, nDBRow1, nDBTab1 );
5461 while (!bFound && (aLook.Col() <= nDBCol2))
5463 ScBaseCell* pCell = GetCell( aLook );
5464 GetCellString( aCellStr, pCell );
5465 bFound = ScGlobal::pTransliteration->isEqual( aCellStr, aStr );
5466 if (!bFound)
5467 aLook.IncCol();
5469 nField = aLook.Col();
5471 if (bFound)
5473 rParam.nCol1 = nDBCol1;
5474 rParam.nRow1 = nDBRow1;
5475 rParam.nCol2 = nDBCol2;
5476 rParam.nRow2 = nDBRow2;
5477 rParam.nTab = nDBTab1;
5478 rParam.bHasHeader = TRUE;
5479 rParam.bByRow = TRUE;
5480 rParam.bInplace = TRUE;
5481 rParam.bCaseSens = FALSE;
5482 rParam.bRegExp = FALSE;
5483 rParam.bDuplicate = TRUE;
5484 if (pDok->CreateQueryParam(nQCol1, nQRow1, nQCol2, nQRow2, nQTab1, rParam))
5486 // An allowed missing field parameter sets the result field
5487 // to any of the query fields, just to be able to return
5488 // some cell from the iterator.
5489 if ( rMissingField )
5490 nField = static_cast<SCCOL>(rParam.GetEntry(0).nField);
5492 rParam.nCol1 = nField;
5493 rParam.nCol2 = nField;
5494 rTab = nDBTab1;
5495 bRet = TRUE;
5496 SCSIZE nCount = rParam.GetEntryCount();
5497 for ( SCSIZE i=0; i < nCount; i++ )
5499 ScQueryEntry& rEntry = rParam.GetEntry(i);
5500 if ( rEntry.bDoQuery )
5502 sal_uInt32 nIndex = 0;
5503 rEntry.bQueryByString = !pFormatter->IsNumberFormat(
5504 *rEntry.pStr, nIndex, rEntry.nVal );
5505 if ( rEntry.bQueryByString && !rParam.bRegExp )
5506 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5508 else
5509 break; // for
5515 return bRet;
5519 void ScInterpreter::DBIterator( ScIterFunc eFunc )
5521 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::DBIterator" );
5522 SCTAB nTab1;
5523 double nErg = 0.0;
5524 double fMem = 0.0;
5525 BOOL bNull = TRUE;
5526 ULONG nCount = 0;
5527 ScQueryParam aQueryParam;
5528 BOOL bMissingField = FALSE;
5529 if ( GetDBParams( nTab1, aQueryParam, bMissingField) )
5531 double nVal;
5532 USHORT nErr;
5533 ScQueryValueIterator aValIter(pDok, nTab1, aQueryParam);
5534 if ( aValIter.GetFirst(nVal, nErr) && !nErr )
5536 switch( eFunc )
5538 case ifPRODUCT: nErg = 1; break;
5539 case ifMAX: nErg = -MAXDOUBLE; break;
5540 case ifMIN: nErg = MAXDOUBLE; break;
5541 default: ; // nothing
5545 nCount++;
5546 switch( eFunc )
5548 case ifAVERAGE:
5549 case ifSUM:
5550 if ( bNull && nVal != 0.0 )
5552 bNull = FALSE;
5553 fMem = nVal;
5555 else
5556 nErg += nVal;
5557 break;
5558 case ifSUMSQ: nErg += nVal * nVal; break;
5559 case ifPRODUCT: nErg *= nVal; break;
5560 case ifMAX: if( nVal > nErg ) nErg = nVal; break;
5561 case ifMIN: if( nVal < nErg ) nErg = nVal; break;
5562 default: ; // nothing
5565 while ( aValIter.GetNext(nVal, nErr) && !nErr );
5567 SetError(nErr);
5569 else
5570 SetError( errIllegalParameter);
5571 switch( eFunc )
5573 case ifCOUNT: nErg = nCount; break;
5574 case ifSUM: nErg = ::rtl::math::approxAdd( nErg, fMem ); break;
5575 case ifAVERAGE: nErg = ::rtl::math::approxAdd( nErg, fMem ) / nCount; break;
5576 default: ; // nothing
5578 PushDouble( nErg );
5582 void ScInterpreter::ScDBSum()
5584 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBSum" );
5585 DBIterator( ifSUM );
5589 void ScInterpreter::ScDBCount()
5591 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBCount" );
5592 SCTAB nTab;
5593 ScQueryParam aQueryParam;
5594 BOOL bMissingField = TRUE;
5595 if ( GetDBParams( nTab, aQueryParam, bMissingField) )
5597 ULONG nCount = 0;
5598 if ( bMissingField )
5599 { // count all matching records
5600 // TODO: currently the QueryIterators only return cell pointers of
5601 // existing cells, so if a query matches an empty cell there's
5602 // nothing returned, and therefor not counted!
5603 // Since this has ever been the case and this code here only came
5604 // into existance to fix #i6899 and it never worked before we'll
5605 // have to live with it until we reimplement the iterators to also
5606 // return empty cells, which would mean to adapt all callers of
5607 // iterators.
5608 ScQueryCellIterator aCellIter( pDok, nTab, aQueryParam);
5609 if ( aCellIter.GetFirst() )
5613 nCount++;
5614 } while ( aCellIter.GetNext() );
5617 else
5618 { // count only matching records with a value in the "result" field
5619 double nVal;
5620 USHORT nErr = 0;
5621 ScQueryValueIterator aValIter( pDok, nTab, aQueryParam);
5622 if ( aValIter.GetFirst( nVal, nErr) && !nErr )
5626 nCount++;
5627 } while ( aValIter.GetNext( nVal, nErr) && !nErr );
5629 SetError( nErr );
5631 PushDouble( nCount );
5633 else
5634 PushIllegalParameter();
5638 void ScInterpreter::ScDBCount2()
5640 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBCount2" );
5641 SCTAB nTab;
5642 ScQueryParam aQueryParam;
5643 BOOL bMissingField = TRUE;
5644 if (GetDBParams( nTab, aQueryParam, bMissingField))
5646 ULONG nCount = 0;
5647 ScQueryCellIterator aCellIter(pDok, nTab, aQueryParam);
5648 if ( aCellIter.GetFirst() )
5652 nCount++;
5653 } while ( aCellIter.GetNext() );
5655 PushDouble(nCount);
5657 else
5658 PushIllegalParameter();
5662 void ScInterpreter::ScDBAverage()
5664 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBAverage" );
5665 DBIterator( ifAVERAGE );
5669 void ScInterpreter::ScDBMax()
5671 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBMax" );
5672 DBIterator( ifMAX );
5676 void ScInterpreter::ScDBMin()
5678 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBMin" );
5679 DBIterator( ifMIN );
5683 void ScInterpreter::ScDBProduct()
5685 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBProduct" );
5686 DBIterator( ifPRODUCT );
5690 void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
5692 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDBStVarParams" );
5693 std::vector<double> values;
5694 double vSum = 0.0;
5695 double vMean = 0.0;
5697 rValCount = 0.0;
5698 double fSum = 0.0;
5699 SCTAB nTab;
5700 ScQueryParam aQueryParam;
5701 BOOL bMissingField = FALSE;
5702 if (GetDBParams( nTab, aQueryParam, bMissingField))
5704 double fVal;
5705 USHORT nErr;
5706 ScQueryValueIterator aValIter(pDok, nTab, aQueryParam);
5707 if (aValIter.GetFirst(fVal, nErr) && !nErr)
5711 rValCount++;
5712 values.push_back(fVal);
5713 fSum += fVal;
5715 while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
5717 SetError(nErr);
5719 else
5720 SetError( errIllegalParameter);
5722 vMean = fSum / values.size();
5724 for (size_t i = 0; i < values.size(); i++)
5725 vSum += (values[i] - vMean) * (values[i] - vMean);
5727 rVal = vSum;
5731 void ScInterpreter::ScDBStdDev()
5733 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBStdDev" );
5734 double fVal, fCount;
5735 GetDBStVarParams( fVal, fCount );
5736 PushDouble( sqrt(fVal/(fCount-1)));
5740 void ScInterpreter::ScDBStdDevP()
5742 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBStdDevP" );
5743 double fVal, fCount;
5744 GetDBStVarParams( fVal, fCount );
5745 PushDouble( sqrt(fVal/fCount));
5749 void ScInterpreter::ScDBVar()
5751 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBVar" );
5752 double fVal, fCount;
5753 GetDBStVarParams( fVal, fCount );
5754 PushDouble(fVal/(fCount-1));
5758 void ScInterpreter::ScDBVarP()
5760 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBVarP" );
5761 double fVal, fCount;
5762 GetDBStVarParams( fVal, fCount );
5763 PushDouble(fVal/fCount);
5767 void ScInterpreter::ScIndirect()
5769 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndirect" );
5770 BYTE nParamCount = GetByte();
5771 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
5773 bool bTryXlA1 = true; // whether to try XL_A1 style as well.
5774 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;
5775 if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
5777 eConv = FormulaGrammar::CONV_XL_R1C1;
5778 bTryXlA1 = false;
5780 const ScAddress::Details aDetails( eConv, aPos );
5781 const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos );
5782 SCTAB nTab = aPos.Tab();
5783 String sRefStr( GetString() );
5784 ScRefAddress aRefAd, aRefAd2;
5785 if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails) ||
5786 (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd,
5787 aRefAd2, aDetailsXlA1)))
5788 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
5789 aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() );
5790 else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails) ||
5791 (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd,
5792 aDetailsXlA1)))
5793 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
5794 else
5798 ScRangeName* pNames = pDok->GetRangeName();
5799 if (!pNames)
5800 break;
5802 USHORT nPos = 0;
5803 if (!pNames->SearchName( sRefStr, nPos))
5804 break;
5806 ScRangeData* rData = (*pNames)[nPos];
5807 if (!rData)
5808 break;
5810 // We need this in order to obtain a good range.
5811 rData->ValidateTabRefs();
5813 ScRange aRange;
5814 #if 0
5815 // This is some really odd Excel behavior and renders named
5816 // ranges containing relative references totally useless.
5817 if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0)))
5818 break;
5819 #else
5820 // This is the usual way to treat named ranges containing
5821 // relative references.
5822 if (!rData->IsReference( aRange, aPos))
5823 break;
5824 #endif
5826 if (aRange.aStart == aRange.aEnd)
5827 PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
5828 aRange.aStart.Tab());
5829 else
5830 PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(),
5831 aRange.aStart.Tab(), aRange.aEnd.Col(),
5832 aRange.aEnd.Row(), aRange.aEnd.Tab());
5834 // success!
5835 return;
5837 while (false);
5839 PushIllegalArgument();
5845 void ScInterpreter::ScAddressFunc()
5847 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAddressFunc" );
5848 String sTabStr;
5850 BYTE nParamCount = GetByte();
5851 if( !MustHaveParamCount( nParamCount, 2, 5 ) )
5852 return;
5854 if( nParamCount >= 5 )
5855 sTabStr = GetString();
5857 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO; // default
5858 if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
5859 eConv = FormulaGrammar::CONV_XL_R1C1;
5861 USHORT nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE; // default
5862 if( nParamCount >= 3 )
5864 USHORT n = (USHORT) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
5865 switch ( n )
5867 default :
5868 PushNoValue();
5869 return;
5871 case 5:
5872 case 1 : break; // default
5873 case 6:
5874 case 2 : nFlags = SCA_ROW_ABSOLUTE; break;
5875 case 7:
5876 case 3 : nFlags = SCA_COL_ABSOLUTE; break;
5877 case 8:
5878 case 4 : nFlags = 0; break; // both relative
5881 nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL;
5883 SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
5884 SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
5885 if( eConv == FormulaGrammar::CONV_XL_R1C1 )
5887 // YUCK! The XL interface actually treats rel R1C1 refs differently
5888 // than A1
5889 if( !(nFlags & SCA_COL_ABSOLUTE) )
5890 nCol += aPos.Col() + 1;
5891 if( !(nFlags & SCA_ROW_ABSOLUTE) )
5892 nRow += aPos.Row() + 1;
5895 --nCol;
5896 --nRow;
5897 if(!ValidCol( nCol) || !ValidRow( nRow))
5899 PushIllegalArgument();
5900 return;
5903 String aRefStr;
5904 const ScAddress::Details aDetails( eConv, aPos );
5905 const ScAddress aAdr( nCol, nRow, 0);
5906 aAdr.Format( aRefStr, nFlags, pDok, aDetails );
5908 if( nParamCount >= 5 )
5910 ScCompiler::CheckTabQuotes( sTabStr, eConv);
5911 sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.');
5912 sTabStr += aRefStr;
5913 PushString( sTabStr );
5915 else
5916 PushString( aRefStr );
5920 void ScInterpreter::ScOffset()
5922 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOffset" );
5923 BYTE nParamCount = GetByte();
5924 if ( MustHaveParamCount( nParamCount, 3, 5 ) )
5926 long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus;
5927 if (nParamCount == 5)
5928 nColNew = (long) ::rtl::math::approxFloor(GetDouble());
5929 if (nParamCount >= 4)
5930 nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
5931 nColPlus = (long) ::rtl::math::approxFloor(GetDouble());
5932 nRowPlus = (long) ::rtl::math::approxFloor(GetDouble());
5933 SCCOL nCol1;
5934 SCROW nRow1;
5935 SCTAB nTab1;
5936 SCCOL nCol2;
5937 SCROW nRow2;
5938 SCTAB nTab2;
5939 if (nColNew == 0 || nRowNew == 0)
5941 PushIllegalArgument();
5942 return;
5944 if (GetStackType() == svSingleRef)
5946 PopSingleRef(nCol1, nRow1, nTab1);
5947 if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
5949 nCol1 = (SCCOL)((long) nCol1 + nColPlus);
5950 nRow1 = (SCROW)((long) nRow1 + nRowPlus);
5951 if (!ValidCol(nCol1) || !ValidRow(nRow1))
5952 PushIllegalArgument();
5953 else
5954 PushSingleRef(nCol1, nRow1, nTab1);
5956 else
5958 if (nColNew < 0)
5959 nColNew = 1;
5960 if (nRowNew < 0)
5961 nRowNew = 1;
5962 nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 wird veraendert!
5963 nRow1 = (SCROW)((long)nRow1+nRowPlus);
5964 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
5965 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
5966 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
5967 !ValidCol(nCol2) || !ValidRow(nRow2))
5968 PushIllegalArgument();
5969 else
5970 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
5973 else if (GetStackType() == svDoubleRef)
5975 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
5976 if (nColNew < 0)
5977 nColNew = nCol2 - nCol1 + 1;
5978 if (nRowNew < 0)
5979 nRowNew = nRow2 - nRow1 + 1;
5980 nCol1 = (SCCOL)((long)nCol1+nColPlus);
5981 nRow1 = (SCROW)((long)nRow1+nRowPlus);
5982 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
5983 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
5984 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
5985 !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
5986 PushIllegalArgument();
5987 else
5988 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
5990 else
5991 PushIllegalParameter();
5996 void ScInterpreter::ScIndex()
5998 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndex" );
5999 BYTE nParamCount = GetByte();
6000 if ( MustHaveParamCount( nParamCount, 1, 4 ) )
6002 long nArea;
6003 size_t nAreaCount;
6004 SCCOL nCol;
6005 SCROW nRow;
6006 if (nParamCount == 4)
6007 nArea = (long) ::rtl::math::approxFloor(GetDouble());
6008 else
6009 nArea = 1;
6010 if (nParamCount >= 3)
6011 nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
6012 else
6013 nCol = 0;
6014 if (nParamCount >= 2)
6015 nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
6016 else
6017 nRow = 0;
6018 if (GetStackType() == svRefList)
6019 nAreaCount = (sp ? static_cast<ScToken*>(pStack[sp-1])->GetRefList()->size() : 0);
6020 else
6021 nAreaCount = 1; // one reference or array or whatever
6022 if (nAreaCount == 0 || (size_t)nArea > nAreaCount)
6024 PushError( errNoRef);
6025 return;
6027 else if (nArea < 1 || nCol < 0 || nRow < 0)
6029 PushIllegalArgument();
6030 return;
6032 switch (GetStackType())
6034 case svMatrix:
6036 if (nArea != 1)
6037 SetError(errIllegalArgument);
6038 USHORT nOldSp = sp;
6039 ScMatrixRef pMat = GetMatrix();
6040 if (pMat)
6042 SCSIZE nC, nR;
6043 pMat->GetDimensions(nC, nR);
6044 // Access one element of a vector independent of col/row
6045 // orientation?
6046 bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1));
6047 SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol),
6048 static_cast<SCSIZE>(nRow));
6049 if (nC == 0 || nR == 0 ||
6050 (!bVector && (static_cast<SCSIZE>(nCol) > nC ||
6051 static_cast<SCSIZE>(nRow) > nR)) ||
6052 (bVector && nElement > nC * nR))
6053 PushIllegalArgument();
6054 else if (nCol == 0 && nRow == 0)
6055 sp = nOldSp;
6056 else if (bVector)
6058 --nElement;
6059 if (pMat->IsString( nElement))
6060 PushString( pMat->GetString( nElement));
6061 else
6062 PushDouble( pMat->GetDouble( nElement));
6064 else if (nCol == 0)
6066 ScMatrixRef pResMat = GetNewMat(nC, 1);
6067 if (pResMat)
6069 SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
6070 for (SCSIZE i = 0; i < nC; i++)
6071 if (!pMat->IsString(i, nRowMinus1))
6072 pResMat->PutDouble(pMat->GetDouble(i,
6073 nRowMinus1), i, 0);
6074 else
6075 pResMat->PutString(pMat->GetString(i,
6076 nRowMinus1), i, 0);
6077 PushMatrix(pResMat);
6079 else
6080 PushIllegalArgument();
6082 else if (nRow == 0)
6084 ScMatrixRef pResMat = GetNewMat(1, nR);
6085 if (pResMat)
6087 SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
6088 for (SCSIZE i = 0; i < nR; i++)
6089 if (!pMat->IsString(nColMinus1, i))
6090 pResMat->PutDouble(pMat->GetDouble(nColMinus1,
6091 i), i);
6092 else
6093 pResMat->PutString(pMat->GetString(nColMinus1,
6094 i), i);
6095 PushMatrix(pResMat);
6097 else
6098 PushIllegalArgument();
6100 else
6102 if (!pMat->IsString( static_cast<SCSIZE>(nCol-1),
6103 static_cast<SCSIZE>(nRow-1)))
6104 PushDouble( pMat->GetDouble(
6105 static_cast<SCSIZE>(nCol-1),
6106 static_cast<SCSIZE>(nRow-1)));
6107 else
6108 PushString( pMat->GetString(
6109 static_cast<SCSIZE>(nCol-1),
6110 static_cast<SCSIZE>(nRow-1)));
6114 break;
6115 case svSingleRef:
6117 SCCOL nCol1 = 0;
6118 SCROW nRow1 = 0;
6119 SCTAB nTab1 = 0;
6120 PopSingleRef( nCol1, nRow1, nTab1);
6121 if (nCol > 1 || nRow > 1)
6122 PushIllegalArgument();
6123 else
6124 PushSingleRef( nCol1, nRow1, nTab1);
6126 break;
6127 case svDoubleRef:
6128 case svRefList:
6130 SCCOL nCol1 = 0;
6131 SCROW nRow1 = 0;
6132 SCTAB nTab1 = 0;
6133 SCCOL nCol2 = 0;
6134 SCROW nRow2 = 0;
6135 SCTAB nTab2 = 0;
6136 BOOL bRowArray = FALSE;
6137 if (GetStackType() == svRefList)
6139 FormulaTokenRef xRef = PopToken();
6140 if (nGlobalError || !xRef)
6142 PushIllegalParameter();
6143 return;
6145 ScRange aRange( ScAddress::UNINITIALIZED);
6146 DoubleRefToRange( (*(static_cast<ScToken*>(xRef.get())->GetRefList()))[nArea-1], aRange);
6147 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6148 if ( nParamCount == 2 && nRow1 == nRow2 )
6149 bRowArray = TRUE;
6151 else
6153 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6154 if ( nParamCount == 2 && nRow1 == nRow2 )
6155 bRowArray = TRUE;
6157 if ( nTab1 != nTab2 ||
6158 (nCol > 0 && nCol1+nCol-1 > nCol2) ||
6159 (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
6160 ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
6161 PushIllegalArgument();
6162 else if (nCol == 0 && nRow == 0)
6164 if ( nCol1 == nCol2 && nRow1 == nRow2 )
6165 PushSingleRef( nCol1, nRow1, nTab1 );
6166 else
6167 PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 );
6169 else if (nRow == 0)
6171 if ( nRow1 == nRow2 )
6172 PushSingleRef( nCol1+nCol-1, nRow1, nTab1 );
6173 else
6174 PushDoubleRef( nCol1+nCol-1, nRow1, nTab1,
6175 nCol1+nCol-1, nRow2, nTab1 );
6177 else if (nCol == 0)
6179 if ( nCol1 == nCol2 )
6180 PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
6181 else if ( bRowArray )
6183 nCol =(SCCOL) nRow;
6184 nRow = 1;
6185 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
6187 else
6188 PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
6189 nCol2, nRow1+nRow-1, nTab1);
6191 else
6192 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
6194 break;
6195 default:
6196 PushIllegalParameter();
6202 void ScInterpreter::ScMultiArea()
6204 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMultiArea" );
6205 // Legacy support, convert to RefList
6206 BYTE nParamCount = GetByte();
6207 if (MustHaveParamCountMin( nParamCount, 1))
6209 while (!nGlobalError && nParamCount-- > 1)
6211 ScUnionFunc();
6217 void ScInterpreter::ScAreas()
6219 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAreas" );
6220 BYTE nParamCount = GetByte();
6221 if (MustHaveParamCount( nParamCount, 1))
6223 size_t nCount = 0;
6224 switch (GetStackType())
6226 case svSingleRef:
6228 FormulaTokenRef xT = PopToken();
6229 ValidateRef( static_cast<ScToken*>(xT.get())->GetSingleRef());
6230 ++nCount;
6232 break;
6233 case svDoubleRef:
6235 FormulaTokenRef xT = PopToken();
6236 ValidateRef( static_cast<ScToken*>(xT.get())->GetDoubleRef());
6237 ++nCount;
6239 break;
6240 case svRefList:
6242 FormulaTokenRef xT = PopToken();
6243 ValidateRef( *(static_cast<ScToken*>(xT.get())->GetRefList()));
6244 nCount += static_cast<ScToken*>(xT.get())->GetRefList()->size();
6246 break;
6247 default:
6248 SetError( errIllegalParameter);
6250 PushDouble( double(nCount));
6255 void ScInterpreter::ScCurrency()
6257 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCurrency" );
6258 BYTE nParamCount = GetByte();
6259 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6261 String aStr;
6262 double fDec;
6263 if (nParamCount == 2)
6265 fDec = ::rtl::math::approxFloor(GetDouble());
6266 if (fDec < -15.0 || fDec > 15.0)
6268 PushIllegalArgument();
6269 return;
6272 else
6273 fDec = 2.0;
6274 double fVal = GetDouble();
6275 double fFac;
6276 if ( fDec != 0.0 )
6277 fFac = pow( (double)10, fDec );
6278 else
6279 fFac = 1.0;
6280 if (fVal < 0.0)
6281 fVal = ceil(fVal*fFac-0.5)/fFac;
6282 else
6283 fVal = floor(fVal*fFac+0.5)/fFac;
6284 Color* pColor = NULL;
6285 if ( fDec < 0.0 )
6286 fDec = 0.0;
6287 ULONG nIndex = pFormatter->GetStandardFormat(
6288 NUMBERFORMAT_CURRENCY,
6289 ScGlobal::eLnge);
6290 if ( (USHORT) fDec != pFormatter->GetFormatPrecision( nIndex ) )
6292 String sFormatString;
6293 pFormatter->GenerateFormat(sFormatString,
6294 nIndex,
6295 ScGlobal::eLnge,
6296 TRUE, // mit Tausenderpunkt
6297 FALSE, // nicht rot
6298 (USHORT) fDec,// Nachkommastellen
6299 1); // 1 Vorkommanull
6300 if (!pFormatter->GetPreviewString(sFormatString,
6301 fVal,
6302 aStr,
6303 &pColor,
6304 ScGlobal::eLnge))
6305 SetError(errIllegalArgument);
6307 else
6309 pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor);
6311 PushString(aStr);
6316 void ScInterpreter::ScReplace()
6318 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScReplace" );
6319 if ( MustHaveParamCount( GetByte(), 4 ) )
6321 String aNewStr( GetString() );
6322 short nCount = (short) GetDouble();
6323 short nPos = (short) GetDouble();
6324 String aOldStr( GetString() );
6325 if( nPos < 1 || nCount < 1 )
6326 PushIllegalArgument();
6327 else
6329 aOldStr.Erase( nPos-1, nCount );
6330 if ( CheckStringResultLen( aOldStr, aNewStr ) )
6331 aOldStr.Insert( aNewStr, nPos-1 );
6332 PushString( aOldStr );
6338 void ScInterpreter::ScFixed()
6340 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFixed" );
6341 BYTE nParamCount = GetByte();
6342 if ( MustHaveParamCount( nParamCount, 1, 3 ) )
6344 String aStr;
6345 double fDec;
6346 BOOL bThousand;
6347 if (nParamCount == 3)
6348 bThousand = !GetBool(); // Param TRUE: keine Tausenderpunkte
6349 else
6350 bThousand = TRUE;
6351 if (nParamCount >= 2)
6353 fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
6354 if (fDec < -15.0 || fDec > 15.0)
6356 PushIllegalArgument();
6357 return;
6360 else
6361 fDec = 2.0;
6362 double fVal = GetDouble();
6363 double fFac;
6364 if ( fDec != 0.0 )
6365 fFac = pow( (double)10, fDec );
6366 else
6367 fFac = 1.0;
6368 if (fVal < 0.0)
6369 fVal = ceil(fVal*fFac-0.5)/fFac;
6370 else
6371 fVal = floor(fVal*fFac+0.5)/fFac;
6372 Color* pColor = NULL;
6373 String sFormatString;
6374 if (fDec < 0.0)
6375 fDec = 0.0;
6376 ULONG nIndex = pFormatter->GetStandardFormat(
6377 NUMBERFORMAT_NUMBER,
6378 ScGlobal::eLnge);
6379 pFormatter->GenerateFormat(sFormatString,
6380 nIndex,
6381 ScGlobal::eLnge,
6382 bThousand, // mit Tausenderpunkt
6383 FALSE, // nicht rot
6384 (USHORT) fDec,// Nachkommastellen
6385 1); // 1 Vorkommanull
6386 if (!pFormatter->GetPreviewString(sFormatString,
6387 fVal,
6388 aStr,
6389 &pColor,
6390 ScGlobal::eLnge))
6391 PushIllegalArgument();
6392 else
6393 PushString(aStr);
6398 void ScInterpreter::ScFind()
6400 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFind" );
6401 BYTE nParamCount = GetByte();
6402 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
6404 double fAnz;
6405 if (nParamCount == 3)
6406 fAnz = GetDouble();
6407 else
6408 fAnz = 1.0;
6409 String sStr = GetString();
6410 if( fAnz < 1.0 || fAnz > (double) sStr.Len() )
6411 PushNoValue();
6412 else
6414 xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 );
6415 if (nPos == STRING_NOTFOUND)
6416 PushNoValue();
6417 else
6418 PushDouble((double)(nPos + 1));
6424 void ScInterpreter::ScExact()
6426 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExact" );
6427 nFuncFmtType = NUMBERFORMAT_LOGICAL;
6428 if ( MustHaveParamCount( GetByte(), 2 ) )
6430 String s1( GetString() );
6431 String s2( GetString() );
6432 PushInt( s1 == s2 );
6437 void ScInterpreter::ScLeft()
6439 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLeft" );
6440 BYTE nParamCount = GetByte();
6441 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6443 xub_StrLen n;
6444 if (nParamCount == 2)
6446 double nVal = ::rtl::math::approxFloor(GetDouble());
6447 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
6449 PushIllegalArgument();
6450 return ;
6452 else
6453 n = (xub_StrLen) nVal;
6455 else
6456 n = 1;
6457 String aStr( GetString() );
6458 aStr.Erase( n );
6459 PushString( aStr );
6464 void ScInterpreter::ScRight()
6466 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRight" );
6467 BYTE nParamCount = GetByte();
6468 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6470 xub_StrLen n;
6471 if (nParamCount == 2)
6473 double nVal = ::rtl::math::approxFloor(GetDouble());
6474 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
6476 PushIllegalArgument();
6477 return ;
6479 else
6480 n = (xub_StrLen) nVal;
6482 else
6483 n = 1;
6484 String aStr( GetString() );
6485 if( n < aStr.Len() )
6486 aStr.Erase( 0, aStr.Len() - n );
6487 PushString( aStr );
6492 void ScInterpreter::ScSearch()
6494 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSearch" );
6495 double fAnz;
6496 BYTE nParamCount = GetByte();
6497 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
6499 if (nParamCount == 3)
6501 fAnz = ::rtl::math::approxFloor(GetDouble());
6502 if (fAnz > double(STRING_MAXLEN))
6504 PushIllegalArgument();
6505 return;
6508 else
6509 fAnz = 1.0;
6510 String sStr = GetString();
6511 String SearchStr = GetString();
6512 xub_StrLen nPos = (xub_StrLen) fAnz - 1;
6513 xub_StrLen nEndPos = sStr.Len();
6514 if( nPos >= nEndPos )
6515 PushNoValue();
6516 else
6518 utl::SearchParam::SearchType eSearchType =
6519 (MayBeRegExp( SearchStr, pDok ) ?
6520 utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL);
6521 utl::SearchParam sPar(SearchStr, eSearchType, FALSE, FALSE, FALSE);
6522 utl::TextSearch sT( sPar, *ScGlobal::pCharClass );
6523 int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos);
6524 if (!nBool)
6525 PushNoValue();
6526 else
6527 PushDouble((double)(nPos) + 1);
6533 void ScInterpreter::ScMid()
6535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMid" );
6536 if ( MustHaveParamCount( GetByte(), 3 ) )
6538 double fAnz = ::rtl::math::approxFloor(GetDouble());
6539 double fAnfang = ::rtl::math::approxFloor(GetDouble());
6540 const String& rStr = GetString();
6541 if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
6542 PushIllegalArgument();
6543 else
6544 PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
6549 void ScInterpreter::ScText()
6551 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScText" );
6552 if ( MustHaveParamCount( GetByte(), 2 ) )
6554 String sFormatString = GetString();
6555 double fVal = GetDouble();
6556 String aStr;
6557 Color* pColor = NULL;
6558 LanguageType eCellLang;
6559 const ScPatternAttr* pPattern = pDok->GetPattern(
6560 aPos.Col(), aPos.Row(), aPos.Tab() );
6561 if ( pPattern )
6562 eCellLang = ((const SvxLanguageItem&)
6563 pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue();
6564 else
6565 eCellLang = ScGlobal::eLnge;
6566 if ( !pFormatter->GetPreviewStringGuess( sFormatString, fVal, aStr,
6567 &pColor, eCellLang ) )
6568 PushIllegalArgument();
6569 else
6570 PushString(aStr);
6575 void ScInterpreter::ScSubstitute()
6577 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSubstitute" );
6578 BYTE nParamCount = GetByte();
6579 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
6581 xub_StrLen nAnz;
6582 if (nParamCount == 4)
6584 double fAnz = ::rtl::math::approxFloor(GetDouble());
6585 if( fAnz < 1 || fAnz > STRING_MAXLEN )
6587 PushIllegalArgument();
6588 return;
6590 else
6591 nAnz = (xub_StrLen) fAnz;
6593 else
6594 nAnz = 0;
6595 String sNewStr = GetString();
6596 String sOldStr = GetString();
6597 String sStr = GetString();
6598 xub_StrLen nPos = 0;
6599 xub_StrLen nCount = 0;
6600 xub_StrLen nNewLen = sNewStr.Len();
6601 xub_StrLen nOldLen = sOldStr.Len();
6602 while( TRUE )
6604 nPos = sStr.Search( sOldStr, nPos );
6605 if (nPos != STRING_NOTFOUND)
6607 nCount++;
6608 if( !nAnz || nCount == nAnz )
6610 sStr.Erase(nPos,nOldLen);
6611 if ( CheckStringResultLen( sStr, sNewStr ) )
6613 sStr.Insert(sNewStr,nPos);
6614 nPos = sal::static_int_cast<xub_StrLen>( nPos + nNewLen );
6616 else
6617 break;
6619 else
6620 nPos++;
6622 else
6623 break;
6625 PushString( sStr );
6630 void ScInterpreter::ScRept()
6632 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRept" );
6633 if ( MustHaveParamCount( GetByte(), 2 ) )
6635 double fAnz = ::rtl::math::approxFloor(GetDouble());
6636 String aStr( GetString() );
6637 if ( fAnz < 0.0 )
6638 PushIllegalArgument();
6639 else if ( fAnz * aStr.Len() > STRING_MAXLEN )
6641 PushError( errStringOverflow );
6643 else if ( fAnz == 0.0 )
6644 PushString( EMPTY_STRING );
6645 else
6647 xub_StrLen n = (xub_StrLen) fAnz;
6648 const xub_StrLen nLen = aStr.Len();
6649 String aRes;
6650 const sal_Unicode* const pSrc = aStr.GetBuffer();
6651 sal_Unicode* pDst = aRes.AllocBuffer( n * nLen );
6652 while( n-- )
6654 memcpy( pDst, pSrc, nLen * sizeof(sal_Unicode) );
6655 pDst += nLen;
6657 PushString( aRes );
6663 void ScInterpreter::ScConcat()
6665 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScConcat" );
6666 BYTE nParamCount = GetByte();
6667 String aRes;
6668 while( nParamCount-- > 0)
6670 const String& rStr = GetString();
6671 aRes.Insert( rStr, 0 );
6673 PushString( aRes );
6677 void ScInterpreter::ScErrorType()
6679 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScErrorType" );
6680 USHORT nErr;
6681 USHORT nOldError = nGlobalError;
6682 nGlobalError = 0;
6683 switch ( GetStackType() )
6685 case svRefList :
6687 FormulaTokenRef x = PopToken();
6688 if (nGlobalError)
6689 nErr = nGlobalError;
6690 else
6692 const ScRefList* pRefList = static_cast<ScToken*>(x.get())->GetRefList();
6693 size_t n = pRefList->size();
6694 if (!n)
6695 nErr = errNoRef;
6696 else if (n > 1)
6697 nErr = errNoValue;
6698 else
6700 ScRange aRange;
6701 DoubleRefToRange( (*pRefList)[0], aRange);
6702 if (nGlobalError)
6703 nErr = nGlobalError;
6704 else
6706 ScAddress aAdr;
6707 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
6708 nErr = pDok->GetErrCode( aAdr );
6709 else
6710 nErr = nGlobalError;
6715 break;
6716 case svDoubleRef :
6718 ScRange aRange;
6719 PopDoubleRef( aRange );
6720 if ( nGlobalError )
6721 nErr = nGlobalError;
6722 else
6724 ScAddress aAdr;
6725 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
6726 nErr = pDok->GetErrCode( aAdr );
6727 else
6728 nErr = nGlobalError;
6731 break;
6732 case svSingleRef :
6734 ScAddress aAdr;
6735 PopSingleRef( aAdr );
6736 if ( nGlobalError )
6737 nErr = nGlobalError;
6738 else
6739 nErr = pDok->GetErrCode( aAdr );
6741 break;
6742 default:
6743 PopError();
6744 nErr = nGlobalError;
6746 if ( nErr )
6748 nGlobalError = 0;
6749 PushDouble( nErr );
6751 else
6753 nGlobalError = nOldError;
6754 PushNA();
6759 BOOL ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc )
6761 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::MayBeRegExp" );
6762 if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
6763 return FALSE;
6764 if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') )
6765 return FALSE; // einzelnes Metazeichen kann keine RegExp sein
6766 static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
6767 const sal_Unicode* p1 = rStr.GetBuffer();
6768 sal_Unicode c1;
6769 while ( ( c1 = *p1++ ) != 0 )
6771 const sal_Unicode* p2 = cre;
6772 while ( *p2 )
6774 if ( c1 == *p2++ )
6775 return TRUE;
6778 return FALSE;
6781 static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
6782 const ScQueryParam & rParam, const ScQueryEntry & rEntry )
6784 bool bFound = false;
6785 ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, FALSE);
6786 if (rEntry.eOp != SC_EQUAL)
6788 // range lookup <= or >=
6789 SCCOL nCol;
6790 SCROW nRow;
6791 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow);
6792 if (bFound)
6794 o_rResultPos.SetCol( nCol);
6795 o_rResultPos.SetRow( nRow);
6798 else if (aCellIter.GetFirst())
6800 // EQUAL
6801 bFound = true;
6802 o_rResultPos.SetCol( aCellIter.GetCol());
6803 o_rResultPos.SetRow( aCellIter.GetRow());
6805 return bFound;
6808 #define erDEBUG_LOOKUPCACHE 0
6809 #if erDEBUG_LOOKUPCACHE
6810 #include <cstdio>
6811 using ::std::fprintf;
6812 using ::std::fflush;
6813 static struct LookupCacheDebugCounter
6815 unsigned long nMiss;
6816 unsigned long nHit;
6817 LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
6818 ~LookupCacheDebugCounter()
6820 fprintf( stderr, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
6821 nMiss, nHit, nHit+nMiss, (nMiss>0 ? nHit/nMiss : 0),
6822 ((nHit+nMiss)>0 ? (100*nHit)/(nHit+nMiss) : 0));
6823 fflush( stderr);
6825 } aLookupCacheDebugCounter;
6826 #endif
6828 bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
6829 const ScQueryParam & rParam ) const
6831 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "Eike.Rathke@sun.com", "ScInterpreter::LookupQueryWithCache" );
6832 bool bFound = false;
6833 const ScQueryEntry& rEntry = rParam.GetEntry(0);
6834 bool bColumnsMatch = (rParam.nCol1 == rEntry.nField);
6835 DBG_ASSERT( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match");
6836 if (!bColumnsMatch)
6837 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
6838 else
6840 ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
6841 rParam.nCol2, rParam.nRow2, rParam.nTab);
6842 ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange);
6843 ScLookupCache::QueryCriteria aCriteria( rEntry);
6844 ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos,
6845 aCriteria, aPos);
6846 switch (eCacheResult)
6848 case ScLookupCache::NOT_CACHED :
6849 case ScLookupCache::CRITERIA_DIFFERENT :
6850 #if erDEBUG_LOOKUPCACHE
6851 ++aLookupCacheDebugCounter.nMiss;
6852 #if erDEBUG_LOOKUPCACHE > 1
6853 fprintf( stderr, "miss %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
6854 #endif
6855 #endif
6856 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
6857 if (eCacheResult == ScLookupCache::NOT_CACHED)
6858 rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
6859 break;
6860 case ScLookupCache::FOUND :
6861 #if erDEBUG_LOOKUPCACHE
6862 ++aLookupCacheDebugCounter.nHit;
6863 #if erDEBUG_LOOKUPCACHE > 1
6864 fprintf( stderr, "hit %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
6865 #endif
6866 #endif
6867 bFound = true;
6868 break;
6869 case ScLookupCache::NOT_AVAILABLE :
6870 ; // nothing, bFound remains FALSE
6871 break;
6874 return bFound;