1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
20 #include "interpre.hxx"
22 #include "scitems.hxx"
23 #include <editeng/langitem.hxx>
24 #include <editeng/justifyitem.hxx>
25 #include <formula/random.hxx>
26 #include <osl/thread.h>
27 #include <svx/algitem.hxx>
28 #include <unotools/textsearch.hxx>
29 #include <svl/zforlist.hxx>
30 #include <svl/zformat.hxx>
31 #include <tools/urlobj.hxx>
32 #include <unotools/charclass.hxx>
33 #include <sfx2/docfile.hxx>
34 #include <sfx2/printer.hxx>
35 #include <unotools/collatorwrapper.hxx>
36 #include <unotools/transliterationwrapper.hxx>
37 #include <rtl/ustring.hxx>
38 #include <unicode/uchar.h>
40 #include "patattr.hxx"
42 #include "document.hxx"
43 #include "dociter.hxx"
44 #include "formulacell.hxx"
45 #include "scmatrix.hxx"
46 #include "docoptio.hxx"
47 #include "globstr.hrc"
49 #include "jumpmatrix.hxx"
50 #include "cellkeytranslator.hxx"
51 #include "lookupcache.hxx"
52 #include "rangenam.hxx"
53 #include "rangeutl.hxx"
54 #include "compiler.hxx"
55 #include "externalrefmgr.hxx"
56 #include <basic/sbstar.hxx>
57 #include "doubleref.hxx"
58 #include "queryparam.hxx"
59 #include "queryentry.hxx"
60 #include "tokenarray.hxx"
61 #include "compare.hxx"
63 #include <comphelper/processfactory.hxx>
64 #include <comphelper/random.hxx>
65 #include <comphelper/string.hxx>
66 #include <svl/sharedstringpool.hxx>
75 static const sal_uInt64 n2power48
= SAL_CONST_UINT64( 281474976710656); // 2^48
77 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack
)
78 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter
)
80 ScCalcConfig
ScInterpreter::maGlobalConfig
;
81 ScTokenStack
* ScInterpreter::pGlobalStack
= NULL
;
82 bool ScInterpreter::bGlobalStackInUse
= false;
84 using namespace formula
;
85 using ::std::unique_ptr
;
87 void ScInterpreter::ScIfJump()
89 const short* pJump
= pCur
->GetJump();
90 short nJumpCount
= pJump
[ 0 ];
91 MatrixDoubleRefToMatrix();
92 switch ( GetStackType() )
96 ScMatrixRef pMat
= PopMatrix();
98 PushIllegalParameter();
101 FormulaTokenRef xNew
;
102 ScTokenMatrixMap::const_iterator aMapIter
;
103 // DoubleError handled by JumpMatrix
104 pMat
->SetErrorInterpreter( NULL
);
106 pMat
->GetDimensions( nCols
, nRows
);
107 if ( nCols
== 0 || nRows
== 0 )
109 PushIllegalArgument();
112 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
113 pCur
)) != pTokenMatrixMap
->end()))
114 xNew
= (*aMapIter
).second
;
117 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
118 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
120 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
124 bool bIsValue
= pMat
->IsValue(nC
, nR
);
127 fVal
= pMat
->GetDouble(nC
, nR
);
128 bIsValue
= ::rtl::math::isFinite(fVal
);
129 bTrue
= bIsValue
&& (fVal
!= 0.0);
135 // Treat empty and empty path as 0, but string
137 bIsValue
= (!pMat
->IsString(nC
, nR
) || pMat
->IsEmpty(nC
, nR
));
139 fVal
= (bIsValue
? 0.0 : CreateDoubleError( errNoValue
));
143 if( nJumpCount
>= 2 )
145 pJumpMat
->SetJump( nC
, nR
, fVal
,
147 pJump
[ nJumpCount
]);
150 { // no parameter given for THEN
151 pJumpMat
->SetJump( nC
, nR
, fVal
,
153 pJump
[ nJumpCount
]);
158 if( nJumpCount
== 3 && bIsValue
)
160 pJumpMat
->SetJump( nC
, nR
, fVal
,
162 pJump
[ nJumpCount
]);
165 { // no parameter given for ELSE,
167 pJumpMat
->SetJump( nC
, nR
, fVal
,
169 pJump
[ nJumpCount
]);
174 xNew
= new ScJumpMatrixToken( pJumpMat
);
175 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur
, xNew
));
179 PushIllegalArgument();
182 PushTempToken( xNew
.get());
183 // set endpoint of path for main code line
184 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
192 if( nJumpCount
>= 2 )
194 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
197 { // no parameter given for THEN
198 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
200 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
205 if( nJumpCount
== 3 )
207 aCode
.Jump( pJump
[ 2 ], pJump
[ nJumpCount
] );
210 { // no parameter given for ELSE
211 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
213 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
220 /** Store a matrix value in another matrix in the context of that other matrix
221 is the result matrix of a jump matrix. All arguments must be valid and are
223 static void lcl_storeJumpMatResult(
224 const ScMatrix
* pMat
, ScJumpMatrix
* pJumpMat
, SCSIZE nC
, SCSIZE nR
)
226 if ( pMat
->IsValue( nC
, nR
) )
228 double fVal
= pMat
->GetDouble( nC
, nR
);
229 pJumpMat
->PutResultDouble( fVal
, nC
, nR
);
231 else if ( pMat
->IsEmpty( nC
, nR
) )
233 pJumpMat
->PutResultEmpty( nC
, nR
);
237 pJumpMat
->PutResultString(pMat
->GetString(nC
, nR
), nC
, nR
);
241 void ScInterpreter::ScIfError( bool bNAonly
)
243 const short* pJump
= pCur
->GetJump();
244 short nJumpCount
= pJump
[ 0 ];
245 if (!sp
|| nJumpCount
!= 2)
247 // Reset nGlobalError here to not propagate the old error, if any.
248 nGlobalError
= (sp
? errParameterExpected
: errUnknownStackVariable
);
249 PushError( nGlobalError
);
250 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
254 FormulaTokenRef
xToken( pStack
[ sp
- 1 ] );
256 sal_uInt16 nOldGlobalError
= nGlobalError
;
259 MatrixDoubleRefToMatrix();
260 switch (GetStackType())
264 // Act on implicitly propagated error, if any.
266 nGlobalError
= nOldGlobalError
;
278 if (!PopDoubleRefOrSingleRef( aAdr
))
283 ScRefCellValue aCell
;
284 aCell
.assign(*pDok
, aAdr
);
285 nGlobalError
= GetCellErrCode(aCell
);
291 case svExternalSingleRef
:
292 case svExternalDoubleRef
:
295 svl::SharedString aStr
;
296 // Handles also existing jump matrix case and sets error on
298 GetDoubleOrStringFromMatrix( fVal
, aStr
);
305 const ScMatrixRef pMat
= PopMatrix();
306 if (!pMat
|| (nGlobalError
&& (!bNAonly
|| nGlobalError
== NOTAVAILABLE
)))
311 // If the matrix has no queried error at all we can simply use
312 // it as result and don't need to bother with jump matrix.
313 SCSIZE nErrorCol
= ::std::numeric_limits
<SCSIZE
>::max(),
314 nErrorRow
= ::std::numeric_limits
<SCSIZE
>::max();
316 pMat
->GetDimensions( nCols
, nRows
);
317 if (nCols
== 0 || nRows
== 0)
322 for (SCSIZE nC
=0; nC
< nCols
&& !bError
; ++nC
)
324 for (SCSIZE nR
=0; nR
< nRows
&& !bError
; ++nR
)
326 sal_uInt16 nErr
= pMat
->GetError( nC
, nR
);
327 if (nErr
&& (!bNAonly
|| nErr
== NOTAVAILABLE
))
336 break; // switch, we're done and have the result
338 FormulaTokenRef xNew
;
339 ScTokenMatrixMap::const_iterator aMapIter
;
340 if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find( pCur
)) != pTokenMatrixMap
->end()))
342 xNew
= (*aMapIter
).second
;
346 const ScMatrix
* pMatPtr
= pMat
.get();
347 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
348 // Init all jumps to no error to save single calls. Error
349 // is the exceptional condition.
350 const double fFlagResult
= CreateDoubleError( errJumpMatHasResult
);
351 pJumpMat
->SetAllJumps( fFlagResult
, pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
352 // Up to first error position simply store results, no need
353 // to evaluate error conditions again.
354 SCSIZE nC
= 0, nR
= 0;
355 for ( ; nC
< nCols
&& (nC
!= nErrorCol
|| nR
!= nErrorRow
); /*nop*/ )
357 for (nR
= 0 ; nR
< nRows
&& (nC
!= nErrorCol
|| nR
!= nErrorRow
); ++nR
)
359 lcl_storeJumpMatResult(pMatPtr
, pJumpMat
, nC
, nR
);
361 if (nC
!= nErrorCol
&& nR
!= nErrorRow
)
364 // Now the mixed cases.
365 for ( ; nC
< nCols
; ++nC
)
367 for ( ; nR
< nRows
; ++nR
)
369 sal_uInt16 nErr
= pMat
->GetError( nC
, nR
);
370 if (nErr
&& (!bNAonly
|| nErr
== NOTAVAILABLE
))
372 pJumpMat
->SetJump( nC
, nR
, 1.0, pJump
[ 1 ], pJump
[ nJumpCount
] );
375 { // FALSE, EMPTY path, store result instead
376 lcl_storeJumpMatResult(pMatPtr
, pJumpMat
, nC
, nR
);
381 xNew
= new ScJumpMatrixToken( pJumpMat
);
382 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type( pCur
, xNew
));
384 nGlobalError
= nOldGlobalError
;
385 PushTempToken( xNew
.get() );
386 // set endpoint of path for main code line
387 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
393 if (bError
&& (!bNAonly
|| nGlobalError
== NOTAVAILABLE
))
395 // error, calculate 2nd argument
397 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
401 // no error, push 1st argument and continue
402 nGlobalError
= nOldGlobalError
;
403 PushTempToken( xToken
.get());
404 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
408 void ScInterpreter::ScChooseJump()
410 // We have to set a jump, if there was none chosen because of an error set
412 bool bHaveJump
= false;
413 const short* pJump
= pCur
->GetJump();
414 short nJumpCount
= pJump
[ 0 ];
415 MatrixDoubleRefToMatrix();
416 switch ( GetStackType() )
420 ScMatrixRef pMat
= PopMatrix();
422 PushIllegalParameter();
425 FormulaTokenRef xNew
;
426 ScTokenMatrixMap::const_iterator aMapIter
;
427 // DoubleError handled by JumpMatrix
428 pMat
->SetErrorInterpreter( NULL
);
430 pMat
->GetDimensions( nCols
, nRows
);
431 if ( nCols
== 0 || nRows
== 0 )
432 PushIllegalParameter();
433 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
434 pCur
)) != pTokenMatrixMap
->end()))
435 xNew
= (*aMapIter
).second
;
438 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
439 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
441 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
444 bool bIsValue
= pMat
->IsValue(nC
, nR
);
447 fVal
= pMat
->GetDouble(nC
, nR
);
448 bIsValue
= ::rtl::math::isFinite( fVal
);
451 fVal
= ::rtl::math::approxFloor( fVal
);
452 if ( (fVal
< 1) || (fVal
>= nJumpCount
))
455 fVal
= CreateDoubleError(
462 fVal
= CreateDoubleError( errNoValue
);
466 pJumpMat
->SetJump( nC
, nR
, fVal
,
467 pJump
[ (short)fVal
],
468 pJump
[ nJumpCount
]);
472 pJumpMat
->SetJump( nC
, nR
, fVal
,
474 pJump
[ nJumpCount
]);
478 xNew
= new ScJumpMatrixToken( pJumpMat
);
479 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
484 PushTempToken( xNew
.get());
485 // set endpoint of path for main code line
486 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
494 double nJumpIndex
= ::rtl::math::approxFloor( GetDouble() );
495 if (!nGlobalError
&& (nJumpIndex
>= 1) && (nJumpIndex
< nJumpCount
))
497 aCode
.Jump( pJump
[ (short) nJumpIndex
], pJump
[ nJumpCount
] );
501 PushIllegalArgument();
505 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
508 static void lcl_AdjustJumpMatrix( ScJumpMatrix
* pJumpM
, SCSIZE nParmCols
, SCSIZE nParmRows
)
510 SCSIZE nJumpCols
, nJumpRows
;
511 SCSIZE nResCols
, nResRows
;
512 SCSIZE nAdjustCols
, nAdjustRows
;
513 pJumpM
->GetDimensions( nJumpCols
, nJumpRows
);
514 pJumpM
->GetResMatDimensions( nResCols
, nResRows
);
515 if (( nJumpCols
== 1 && nParmCols
> nResCols
) ||
516 ( nJumpRows
== 1 && nParmRows
> nResRows
))
518 if ( nJumpCols
== 1 && nJumpRows
== 1 )
520 nAdjustCols
= nParmCols
> nResCols
? nParmCols
: nResCols
;
521 nAdjustRows
= nParmRows
> nResRows
? nParmRows
: nResRows
;
523 else if ( nJumpCols
== 1 )
525 nAdjustCols
= nParmCols
;
526 nAdjustRows
= nResRows
;
530 nAdjustCols
= nResCols
;
531 nAdjustRows
= nParmRows
;
533 pJumpM
->SetNewResMat( nAdjustCols
, nAdjustRows
);
537 bool ScInterpreter::JumpMatrix( short nStackLevel
)
539 pJumpMatrix
= pStack
[sp
-nStackLevel
]->GetJumpMatrix();
540 bool bHasResMat
= pJumpMatrix
->HasResultMatrix();
542 if ( nStackLevel
== 2 )
544 if ( aCode
.HasStacked() )
545 aCode
.Pop(); // pop what Jump() pushed
548 OSL_FAIL( "ScInterpreter::JumpMatrix: pop goes the weasel" );
554 SetError( errUnknownStackVariable
);
558 pJumpMatrix
->GetPos( nC
, nR
);
559 switch ( GetStackType() )
563 double fVal
= GetDouble();
566 fVal
= CreateDoubleError( nGlobalError
);
569 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
574 svl::SharedString aStr
= GetString();
577 pJumpMatrix
->PutResultDouble( CreateDoubleError( nGlobalError
),
582 pJumpMatrix
->PutResultString(aStr
, nC
, nR
);
588 PopSingleRef( aAdr
);
591 pJumpMatrix
->PutResultDouble( CreateDoubleError( nGlobalError
),
597 ScRefCellValue aCell
;
598 aCell
.assign(*pDok
, aAdr
);
599 if (aCell
.hasEmptyValue())
600 pJumpMatrix
->PutResultEmpty( nC
, nR
);
601 else if (aCell
.hasNumeric())
603 double fVal
= GetCellValue(aAdr
, aCell
);
606 fVal
= CreateDoubleError(
610 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
614 svl::SharedString aStr
;
615 GetCellString(aStr
, aCell
);
618 pJumpMatrix
->PutResultDouble( CreateDoubleError(
619 nGlobalError
), nC
, nR
);
623 pJumpMatrix
->PutResultString(aStr
, nC
, nR
);
629 { // upper left plus offset within matrix
632 PopDoubleRef( aRange
);
635 fVal
= CreateDoubleError( nGlobalError
);
637 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
641 // Do not modify the original range because we use it
642 // to adjust the size of the result matrix if necessary.
643 ScAddress
aAdr( aRange
.aStart
);
644 sal_uLong nCol
= (sal_uLong
)aAdr
.Col() + nC
;
645 sal_uLong nRow
= (sal_uLong
)aAdr
.Row() + nR
;
646 if ((nCol
> static_cast<sal_uLong
>(aRange
.aEnd
.Col()) &&
647 aRange
.aEnd
.Col() != aRange
.aStart
.Col())
648 || (nRow
> static_cast<sal_uLong
>(aRange
.aEnd
.Row()) &&
649 aRange
.aEnd
.Row() != aRange
.aStart
.Row()))
651 fVal
= CreateDoubleError( NOTAVAILABLE
);
652 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
656 // Replicate column and/or row of a vector if it is
657 // one. Note that this could be a range reference
658 // that in fact consists of only one cell, e.g. A1:A1
659 if (aRange
.aEnd
.Col() == aRange
.aStart
.Col())
660 nCol
= aRange
.aStart
.Col();
661 if (aRange
.aEnd
.Row() == aRange
.aStart
.Row())
662 nRow
= aRange
.aStart
.Row();
663 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) );
664 aAdr
.SetRow( static_cast<SCROW
>(nRow
) );
665 ScRefCellValue aCell
;
666 aCell
.assign(*pDok
, aAdr
);
667 if (aCell
.hasEmptyValue())
668 pJumpMatrix
->PutResultEmpty( nC
, nR
);
669 else if (aCell
.hasNumeric())
671 double fCellVal
= GetCellValue(aAdr
, aCell
);
674 fCellVal
= CreateDoubleError(
678 pJumpMatrix
->PutResultDouble( fCellVal
, nC
, nR
);
682 svl::SharedString aStr
;
683 GetCellString(aStr
, aCell
);
686 pJumpMatrix
->PutResultDouble( CreateDoubleError(
687 nGlobalError
), nC
, nR
);
691 pJumpMatrix
->PutResultString(aStr
, nC
, nR
);
694 SCSIZE nParmCols
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
695 SCSIZE nParmRows
= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
696 lcl_AdjustJumpMatrix( pJumpMatrix
, nParmCols
, nParmRows
);
701 { // match matrix offsets
703 ScMatrixRef pMat
= PopMatrix();
706 fVal
= CreateDoubleError( nGlobalError
);
708 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
712 fVal
= CreateDoubleError( errUnknownVariable
);
713 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
718 pMat
->GetDimensions( nCols
, nRows
);
719 if ((nCols
<= nC
&& nCols
!= 1) ||
720 (nRows
<= nR
&& nRows
!= 1))
722 fVal
= CreateDoubleError( NOTAVAILABLE
);
723 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
727 lcl_storeJumpMatResult(pMat
.get(), pJumpMatrix
, nC
, nR
);
729 lcl_AdjustJumpMatrix( pJumpMatrix
, nCols
, nRows
);
736 double fVal
= CreateDoubleError( nGlobalError
);
738 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
744 double fVal
= CreateDoubleError( errIllegalArgument
);
745 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
750 bool bCont
= pJumpMatrix
->Next( nC
, nR
);
754 short nStart
, nNext
, nStop
;
755 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
756 while ( bCont
&& nStart
== nNext
)
757 { // push all results that have no jump path
758 if ( bHasResMat
&& (GetDoubleErrorValue( fBool
) != errJumpMatHasResult
) )
760 // a false without path results in an empty path value
762 pJumpMatrix
->PutResultEmptyPath( nC
, nR
);
764 pJumpMatrix
->PutResultDouble( fBool
, nC
, nR
);
766 bCont
= pJumpMatrix
->Next( nC
, nR
);
768 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
770 if ( bCont
&& nStart
!= nNext
)
772 const ScTokenVec
* pParams
= pJumpMatrix
->GetJumpParameters();
775 for ( ScTokenVec::const_iterator i
= pParams
->begin();
776 i
!= pParams
->end(); ++i
)
778 // This is not the current state of the interpreter, so
779 // push without error, and elements' errors are coded into
781 PushWithoutError( *(*i
));
784 aCode
.Jump( nStart
, nNext
, nStop
);
788 { // we're done with it, throw away jump matrix, keep result
789 ScMatrix
* pResMat
= pJumpMatrix
->GetResultMatrix();
792 PushMatrix( pResMat
);
793 // Remove jump matrix from map and remember result matrix in case it
794 // could be reused in another path of the same condition.
797 pTokenMatrixMap
->erase( pCur
);
798 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type( pCur
,
806 double ScInterpreter::Compare( ScQueryOp eOp
)
810 aComp
.mbIgnoreCase
= pDok
->GetDocOptions().IsIgnoreCase();
811 for( short i
= 1; i
>= 0; i
-- )
813 sc::Compare::Cell
& rCell
= aComp
.maCells
[i
];
815 switch ( GetRawStackType() )
819 rCell
.mbEmpty
= true;
823 rCell
.mfValue
= GetDouble();
824 rCell
.mbValue
= true;
827 rCell
.maStr
= GetString();
828 rCell
.mbValue
= false;
834 if ( !PopDoubleRefOrSingleRef( aAdr
) )
836 ScRefCellValue aCell
;
837 aCell
.assign(*pDok
, aAdr
);
838 if (aCell
.hasEmptyValue())
839 rCell
.mbEmpty
= true;
840 else if (aCell
.hasString())
842 svl::SharedString aStr
;
843 GetCellString(aStr
, aCell
);
845 rCell
.mbValue
= false;
849 rCell
.mfValue
= GetCellValue(aAdr
, aCell
);
850 rCell
.mbValue
= true;
854 case svExternalSingleRef
:
856 ScMatrixRef pMat
= GetMatrix();
859 SetError( errIllegalParameter
);
864 pMat
->GetDimensions(nC
, nR
);
867 SetError( errIllegalParameter
);
870 if (pMat
->IsEmpty(0, 0))
871 rCell
.mbEmpty
= true;
872 else if (pMat
->IsString(0, 0))
874 rCell
.maStr
= pMat
->GetString(0, 0);
875 rCell
.mbValue
= false;
879 rCell
.mfValue
= pMat
->GetDouble(0, 0);
880 rCell
.mbValue
= true;
884 case svExternalDoubleRef
:
885 // TODO: Find out how to handle this...
887 SetError( errIllegalParameter
);
893 nCurFmtType
= nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
894 return sc::CompareFunc(aComp
);
897 sc::RangeMatrix
ScInterpreter::CompareMat( ScQueryOp eOp
, sc::CompareOptions
* pOptions
)
901 aComp
.mbIgnoreCase
= pDok
->GetDocOptions().IsIgnoreCase();
902 sc::RangeMatrix aMat
[2];
904 for( short i
= 1; i
>= 0; i
-- )
906 sc::Compare::Cell
& rCell
= aComp
.maCells
[i
];
908 switch (GetRawStackType())
912 rCell
.mbEmpty
= true;
916 rCell
.mfValue
= GetDouble();
917 rCell
.mbValue
= true;
920 rCell
.maStr
= GetString();
921 rCell
.mbValue
= false;
925 PopSingleRef( aAdr
);
926 ScRefCellValue aCell
;
927 aCell
.assign(*pDok
, aAdr
);
928 if (aCell
.hasEmptyValue())
929 rCell
.mbEmpty
= true;
930 else if (aCell
.hasString())
932 svl::SharedString aStr
;
933 GetCellString(aStr
, aCell
);
935 rCell
.mbValue
= false;
939 rCell
.mfValue
= GetCellValue(aAdr
, aCell
);
940 rCell
.mbValue
= true;
946 aMat
[i
] = GetRangeMatrix();
948 SetError( errIllegalParameter
);
950 aMat
[i
].mpMat
->SetErrorInterpreter(NULL
);
951 // errors are transported as DoubleError inside matrix
954 SetError( errIllegalParameter
);
959 sc::RangeMatrix aRes
;
963 nCurFmtType
= nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
967 if (aMat
[0].mpMat
&& aMat
[1].mpMat
)
971 aMat
[0].mpMat
->GetDimensions(nC0
, nR0
);
972 aMat
[1].mpMat
->GetDimensions(nC1
, nR1
);
973 SCSIZE nC
= std::max( nC0
, nC1
);
974 SCSIZE nR
= std::max( nR0
, nR1
);
975 aRes
.mpMat
= GetNewMat( nC
, nR
);
978 for ( SCSIZE j
=0; j
<nC
; j
++ )
980 for ( SCSIZE k
=0; k
<nR
; k
++ )
982 SCSIZE nCol
= j
, nRow
= k
;
983 if (aMat
[0].mpMat
->ValidColRowOrReplicated(nCol
, nRow
) &&
984 aMat
[1].mpMat
->ValidColRowOrReplicated(nCol
, nRow
))
986 for ( short i
=1; i
>=0; i
-- )
988 sc::Compare::Cell
& rCell
= aComp
.maCells
[i
];
990 if (aMat
[i
].mpMat
->IsString(j
, k
))
992 rCell
.mbValue
= false;
993 rCell
.maStr
= aMat
[i
].mpMat
->GetString(j
, k
);
994 rCell
.mbEmpty
= aMat
[i
].mpMat
->IsEmpty(j
, k
);
998 rCell
.mbValue
= true;
999 rCell
.mfValue
= aMat
[i
].mpMat
->GetDouble(j
, k
);
1000 rCell
.mbEmpty
= false;
1003 aRes
.mpMat
->PutDouble( sc::CompareFunc( aComp
, pOptions
), j
, k
);
1006 aRes
.mpMat
->PutError( errNoValue
, j
, k
);
1013 aRes
.mpMat
->CompareEqual();
1016 aRes
.mpMat
->CompareLess();
1019 aRes
.mpMat
->CompareGreater();
1022 aRes
.mpMat
->CompareLessEqual();
1024 case SC_GREATER_EQUAL
:
1025 aRes
.mpMat
->CompareGreaterEqual();
1028 aRes
.mpMat
->CompareNotEqual();
1031 OSL_TRACE( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)eOp
);
1036 else if (aMat
[0].mpMat
|| aMat
[1].mpMat
)
1038 size_t i
= ( aMat
[0].mpMat
? 0 : 1);
1040 aRes
.mnCol1
= aMat
[i
].mnCol1
;
1041 aRes
.mnRow1
= aMat
[i
].mnRow1
;
1042 aRes
.mnTab1
= aMat
[i
].mnTab1
;
1043 aRes
.mnCol2
= aMat
[i
].mnCol2
;
1044 aRes
.mnRow2
= aMat
[i
].mnRow2
;
1045 aRes
.mnTab2
= aMat
[i
].mnTab2
;
1047 ScMatrix
& rMat
= *aMat
[i
].mpMat
;
1048 aRes
.mpMat
= rMat
.CompareMatrix(aComp
, i
, pOptions
);
1053 nCurFmtType
= nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1057 ScMatrixRef
ScInterpreter::QueryMat( const ScMatrixRef
& pMat
, sc::CompareOptions
& rOptions
)
1059 short nSaveCurFmtType
= nCurFmtType
;
1060 short nSaveFuncFmtType
= nFuncFmtType
;
1062 const ScQueryEntry::Item
& rItem
= rOptions
.aQueryEntry
.GetQueryItem();
1063 if (rItem
.meType
== ScQueryEntry::ByString
)
1064 PushString(rItem
.maString
.getString());
1066 PushDouble(rItem
.mfVal
);
1067 ScMatrixRef pResultMatrix
= CompareMat(rOptions
.aQueryEntry
.eOp
, &rOptions
).mpMat
;
1068 nCurFmtType
= nSaveCurFmtType
;
1069 nFuncFmtType
= nSaveFuncFmtType
;
1070 if (nGlobalError
|| !pResultMatrix
)
1072 SetError( errIllegalParameter
);
1073 return pResultMatrix
;
1076 return pResultMatrix
;
1079 void ScInterpreter::ScEqual()
1081 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1083 sc::RangeMatrix aMat
= CompareMat(SC_EQUAL
);
1086 PushIllegalParameter();
1093 PushInt( int(Compare( SC_EQUAL
) == 0) );
1096 void ScInterpreter::ScNotEqual()
1098 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1100 sc::RangeMatrix aMat
= CompareMat(SC_NOT_EQUAL
);
1103 PushIllegalParameter();
1110 PushInt( int(Compare( SC_NOT_EQUAL
) != 0) );
1113 void ScInterpreter::ScLess()
1115 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1117 sc::RangeMatrix aMat
= CompareMat(SC_LESS
);
1120 PushIllegalParameter();
1127 PushInt( int(Compare( SC_LESS
) < 0) );
1130 void ScInterpreter::ScGreater()
1132 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1134 sc::RangeMatrix aMat
= CompareMat(SC_GREATER
);
1137 PushIllegalParameter();
1144 PushInt( int(Compare( SC_GREATER
) > 0) );
1147 void ScInterpreter::ScLessEqual()
1149 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1151 sc::RangeMatrix aMat
= CompareMat(SC_LESS_EQUAL
);
1154 PushIllegalParameter();
1161 PushInt( int(Compare( SC_LESS_EQUAL
) <= 0) );
1164 void ScInterpreter::ScGreaterEqual()
1166 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1168 sc::RangeMatrix aMat
= CompareMat(SC_GREATER_EQUAL
);
1171 PushIllegalParameter();
1178 PushInt( int(Compare( SC_GREATER_EQUAL
) >= 0) );
1181 void ScInterpreter::ScAnd()
1183 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1184 short nParamCount
= GetByte();
1185 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1187 bool bHaveValue
= false;
1189 size_t nRefInList
= 0;
1190 while( nParamCount
-- > 0)
1192 if ( !nGlobalError
)
1194 switch ( GetStackType() )
1198 nRes
&= ( PopDouble() != 0.0 );
1202 SetError( errNoValue
);
1207 PopSingleRef( aAdr
);
1208 if ( !nGlobalError
)
1210 ScRefCellValue aCell
;
1211 aCell
.assign(*pDok
, aAdr
);
1212 if (aCell
.hasNumeric())
1215 nRes
&= ( GetCellValue(aAdr
, aCell
) != 0.0 );
1217 // else: Xcl raises no error here
1225 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1226 if ( !nGlobalError
)
1229 sal_uInt16 nErr
= 0;
1230 ScValueIterator
aValIter( pDok
, aRange
);
1231 if ( aValIter
.GetFirst( fVal
, nErr
) && nErr
== 0 )
1236 nRes
&= ( fVal
!= 0.0 );
1237 } while ( (nErr
== 0) &&
1238 aValIter
.GetNext( fVal
, nErr
) );
1244 case svExternalSingleRef
:
1245 case svExternalDoubleRef
:
1248 ScMatrixRef pMat
= GetMatrix();
1252 double fVal
= pMat
->And();
1253 sal_uInt16 nErr
= GetDoubleErrorValue( fVal
);
1260 nRes
&= (fVal
!= 0.0);
1262 // else: GetMatrix did set errIllegalParameter
1267 SetError( errIllegalParameter
);
1274 PushInt( int(nRes
) );
1280 void ScInterpreter::ScOr()
1282 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1283 short nParamCount
= GetByte();
1284 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1286 bool bHaveValue
= false;
1288 size_t nRefInList
= 0;
1289 while( nParamCount
-- > 0)
1291 if ( !nGlobalError
)
1293 switch ( GetStackType() )
1297 nRes
|= ( PopDouble() != 0.0 );
1301 SetError( errNoValue
);
1306 PopSingleRef( aAdr
);
1307 if ( !nGlobalError
)
1309 ScRefCellValue aCell
;
1310 aCell
.assign(*pDok
, aAdr
);
1311 if (aCell
.hasNumeric())
1314 nRes
|= ( GetCellValue(aAdr
, aCell
) != 0.0 );
1316 // else: Xcl raises no error here
1324 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1325 if ( !nGlobalError
)
1328 sal_uInt16 nErr
= 0;
1329 ScValueIterator
aValIter( pDok
, aRange
);
1330 if ( aValIter
.GetFirst( fVal
, nErr
) )
1335 nRes
|= ( fVal
!= 0.0 );
1336 } while ( (nErr
== 0) &&
1337 aValIter
.GetNext( fVal
, nErr
) );
1343 case svExternalSingleRef
:
1344 case svExternalDoubleRef
:
1348 ScMatrixRef pMat
= GetMatrix();
1352 double fVal
= pMat
->Or();
1353 sal_uInt16 nErr
= GetDoubleErrorValue( fVal
);
1360 nRes
|= (fVal
!= 0.0);
1362 // else: GetMatrix did set errIllegalParameter
1367 SetError( errIllegalParameter
);
1374 PushInt( int(nRes
) );
1380 void ScInterpreter::ScXor()
1383 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1384 short nParamCount
= GetByte();
1385 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1387 bool bHaveValue
= false;
1389 size_t nRefInList
= 0;
1390 while( nParamCount
-- > 0)
1392 if ( !nGlobalError
)
1394 switch ( GetStackType() )
1398 nRes
^= ( PopDouble() != 0.0 );
1402 SetError( errNoValue
);
1407 PopSingleRef( aAdr
);
1408 if ( !nGlobalError
)
1410 ScRefCellValue aCell
;
1411 aCell
.assign(*pDok
, aAdr
);
1412 if (aCell
.hasNumeric())
1415 nRes
^= ( GetCellValue(aAdr
, aCell
) != 0.0 );
1417 /* TODO: set error? Excel doesn't have XOR, but
1418 * doesn't set an error in this case for AND and
1427 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1428 if ( !nGlobalError
)
1431 sal_uInt16 nErr
= 0;
1432 ScValueIterator
aValIter( pDok
, aRange
);
1433 if ( aValIter
.GetFirst( fVal
, nErr
) )
1438 nRes
^= ( fVal
!= 0.0 );
1439 } while ( (nErr
== 0) &&
1440 aValIter
.GetNext( fVal
, nErr
) );
1446 case svExternalSingleRef
:
1447 case svExternalDoubleRef
:
1451 ScMatrixRef pMat
= GetMatrix();
1455 double fVal
= pMat
->Xor();
1456 sal_uInt16 nErr
= GetDoubleErrorValue( fVal
);
1463 nRes
^= ( fVal
!= 0.0 );
1465 // else: GetMatrix did set errIllegalParameter
1470 SetError( errIllegalParameter
);
1477 PushInt( int(nRes
) );
1483 void ScInterpreter::ScNeg()
1485 // Simple negation doesn't change current format type to number, keep
1487 nFuncFmtType
= nCurFmtType
;
1488 switch ( GetStackType() )
1492 ScMatrixRef pMat
= GetMatrix();
1494 PushIllegalParameter();
1498 pMat
->GetDimensions( nC
, nR
);
1499 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1501 PushIllegalArgument();
1504 pMat
->NegOp( *pResMat
);
1505 PushMatrix( pResMat
);
1511 PushDouble( -GetDouble() );
1515 void ScInterpreter::ScPercentSign()
1517 nFuncFmtType
= css::util::NumberFormat::PERCENT
;
1518 const FormulaToken
* pSaveCur
= pCur
;
1519 sal_uInt8 nSavePar
= cPar
;
1522 FormulaByteToken
aDivOp( ocDiv
, cPar
);
1529 void ScInterpreter::ScNot()
1531 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1532 switch ( GetStackType() )
1536 ScMatrixRef pMat
= GetMatrix();
1538 PushIllegalParameter();
1542 pMat
->GetDimensions( nC
, nR
);
1543 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1545 PushIllegalArgument();
1548 pMat
->NotOp( *pResMat
);
1549 PushMatrix( pResMat
);
1555 PushInt( int(GetDouble() == 0.0) );
1559 void ScInterpreter::ScBitAnd()
1562 if ( !MustHaveParamCount( GetByte(), 2 ) )
1565 double num1
= ::rtl::math::approxFloor( GetDouble());
1566 double num2
= ::rtl::math::approxFloor( GetDouble());
1567 if ( (num1
>= n2power48
) || (num1
< 0) ||
1568 (num2
>= n2power48
) || (num2
< 0))
1569 PushIllegalArgument();
1571 PushDouble ((sal_uInt64
) num1
& (sal_uInt64
) num2
);
1574 void ScInterpreter::ScBitOr()
1577 if ( !MustHaveParamCount( GetByte(), 2 ) )
1580 double num1
= ::rtl::math::approxFloor( GetDouble());
1581 double num2
= ::rtl::math::approxFloor( GetDouble());
1582 if ( (num1
>= n2power48
) || (num1
< 0) ||
1583 (num2
>= n2power48
) || (num2
< 0))
1584 PushIllegalArgument();
1586 PushDouble ((sal_uInt64
) num1
| (sal_uInt64
) num2
);
1589 void ScInterpreter::ScBitXor()
1592 if ( !MustHaveParamCount( GetByte(), 2 ) )
1595 double num1
= ::rtl::math::approxFloor( GetDouble());
1596 double num2
= ::rtl::math::approxFloor( GetDouble());
1597 if ( (num1
>= n2power48
) || (num1
< 0) ||
1598 (num2
>= n2power48
) || (num2
< 0))
1599 PushIllegalArgument();
1601 PushDouble ((sal_uInt64
) num1
^ (sal_uInt64
) num2
);
1604 void ScInterpreter::ScBitLshift()
1607 if ( !MustHaveParamCount( GetByte(), 2 ) )
1610 double fShift
= ::rtl::math::approxFloor( GetDouble());
1611 double num
= ::rtl::math::approxFloor( GetDouble());
1612 if ((num
>= n2power48
) || (num
< 0))
1613 PushIllegalArgument();
1618 fRes
= ::rtl::math::approxFloor( num
/ pow( 2.0, -fShift
));
1619 else if (fShift
== 0)
1622 fRes
= num
* pow( 2.0, fShift
);
1627 void ScInterpreter::ScBitRshift()
1630 if ( !MustHaveParamCount( GetByte(), 2 ) )
1633 double fShift
= ::rtl::math::approxFloor( GetDouble());
1634 double num
= ::rtl::math::approxFloor( GetDouble());
1635 if ((num
>= n2power48
) || (num
< 0))
1636 PushIllegalArgument();
1641 fRes
= num
* pow( 2.0, -fShift
);
1642 else if (fShift
== 0)
1645 fRes
= ::rtl::math::approxFloor( num
/ pow( 2.0, fShift
));
1650 void ScInterpreter::ScPi()
1655 void ScInterpreter::ScRandom()
1657 PushDouble(formula::rng::fRandom(0, 1));
1660 void ScInterpreter::ScTrue()
1662 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1666 void ScInterpreter::ScFalse()
1668 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1672 void ScInterpreter::ScDeg()
1674 PushDouble((GetDouble() / F_PI
) * 180.0);
1677 void ScInterpreter::ScRad()
1679 PushDouble(GetDouble() * (F_PI
/ 180));
1682 void ScInterpreter::ScSin()
1684 PushDouble(::rtl::math::sin(GetDouble()));
1687 void ScInterpreter::ScCos()
1689 PushDouble(::rtl::math::cos(GetDouble()));
1692 void ScInterpreter::ScTan()
1694 PushDouble(::rtl::math::tan(GetDouble()));
1697 void ScInterpreter::ScCot()
1699 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1702 void ScInterpreter::ScArcSin()
1704 PushDouble(asin(GetDouble()));
1707 void ScInterpreter::ScArcCos()
1709 PushDouble(acos(GetDouble()));
1712 void ScInterpreter::ScArcTan()
1714 PushDouble(atan(GetDouble()));
1717 void ScInterpreter::ScArcCot()
1719 PushDouble((F_PI2
) - atan(GetDouble()));
1722 void ScInterpreter::ScSinHyp()
1724 PushDouble(sinh(GetDouble()));
1727 void ScInterpreter::ScCosHyp()
1729 PushDouble(cosh(GetDouble()));
1732 void ScInterpreter::ScTanHyp()
1734 PushDouble(tanh(GetDouble()));
1737 void ScInterpreter::ScCotHyp()
1739 PushDouble(1.0 / tanh(GetDouble()));
1742 void ScInterpreter::ScArcSinHyp()
1744 PushDouble( ::rtl::math::asinh( GetDouble()));
1747 void ScInterpreter::ScArcCosHyp()
1749 double fVal
= GetDouble();
1751 PushIllegalArgument();
1753 PushDouble( ::rtl::math::acosh( fVal
));
1756 void ScInterpreter::ScArcTanHyp()
1758 double fVal
= GetDouble();
1759 if (fabs(fVal
) >= 1.0)
1760 PushIllegalArgument();
1762 PushDouble( ::rtl::math::atanh( fVal
));
1765 void ScInterpreter::ScArcCotHyp()
1767 double nVal
= GetDouble();
1768 if (fabs(nVal
) <= 1.0)
1769 PushIllegalArgument();
1771 PushDouble(0.5 * log((nVal
+ 1.0) / (nVal
- 1.0)));
1774 void ScInterpreter::ScCosecant()
1776 PushDouble(1.0 / ::rtl::math::sin(GetDouble()));
1779 void ScInterpreter::ScSecant()
1781 PushDouble(1.0 / ::rtl::math::cos(GetDouble()));
1784 void ScInterpreter::ScCosecantHyp()
1786 PushDouble(1.0 / sinh(GetDouble()));
1789 void ScInterpreter::ScSecantHyp()
1791 PushDouble(1.0 / cosh(GetDouble()));
1794 void ScInterpreter::ScExp()
1796 PushDouble(exp(GetDouble()));
1799 void ScInterpreter::ScSqrt()
1801 double fVal
= GetDouble();
1803 PushDouble(sqrt(fVal
));
1805 PushIllegalArgument();
1808 void ScInterpreter::ScIsEmpty()
1811 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1812 switch ( GetRawStackType() )
1816 FormulaTokenRef p
= PopToken();
1817 if (!static_cast<const ScEmptyCellToken
*>(p
.get())->IsInherited())
1825 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1827 // NOTE: this differs from COUNTBLANK() ScCountEmptyCells() that
1828 // may treat ="" in the referenced cell as blank for Excel
1829 // interoperability.
1830 ScRefCellValue aCell
;
1831 aCell
.assign(*pDok
, aAdr
);
1832 if (aCell
.meType
== CELLTYPE_NONE
)
1836 case svExternalSingleRef
:
1837 case svExternalDoubleRef
:
1840 ScMatrixRef pMat
= GetMatrix();
1843 else if ( !pJumpMatrix
)
1844 nRes
= pMat
->IsEmptyCell( 0, 0) ? 1 : 0;
1847 SCSIZE nCols
, nRows
, nC
, nR
;
1848 pMat
->GetDimensions( nCols
, nRows
);
1849 pJumpMatrix
->GetPos( nC
, nR
);
1850 if ( nC
< nCols
&& nR
< nRows
)
1851 nRes
= pMat
->IsEmptyCell( nC
, nR
) ? 1 : 0;
1852 // else: false, not empty (which is what Xcl does)
1863 bool ScInterpreter::IsString()
1865 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1867 switch ( GetRawStackType() )
1877 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1880 ScRefCellValue aCell
;
1881 aCell
.assign(*pDok
, aAdr
);
1882 if (GetCellErrCode(aCell
) == 0)
1884 switch (aCell
.meType
)
1886 case CELLTYPE_STRING
:
1887 case CELLTYPE_EDIT
:
1890 case CELLTYPE_FORMULA
:
1891 nRes
= (!aCell
.mpFormula
->IsValue() && !aCell
.mpFormula
->IsEmpty());
1901 ScMatrixRef pMat
= PopMatrix();
1904 else if ( !pJumpMatrix
)
1905 nRes
= pMat
->IsString(0, 0) && !pMat
->IsEmpty(0, 0);
1908 SCSIZE nCols
, nRows
, nC
, nR
;
1909 pMat
->GetDimensions( nCols
, nRows
);
1910 pJumpMatrix
->GetPos( nC
, nR
);
1911 if ( nC
< nCols
&& nR
< nRows
)
1912 nRes
= pMat
->IsString( nC
, nR
) && !pMat
->IsEmpty( nC
, nR
);
1923 void ScInterpreter::ScIsString()
1925 PushInt( int(IsString()) );
1928 void ScInterpreter::ScIsNonString()
1930 PushInt( int(!IsString()) );
1933 void ScInterpreter::ScIsLogical()
1936 switch ( GetStackType() )
1942 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1945 ScRefCellValue aCell
;
1946 aCell
.assign(*pDok
, aAdr
);
1947 if (GetCellErrCode(aCell
) == 0)
1949 if (aCell
.hasNumeric())
1951 sal_uLong nFormat
= GetCellNumberFormat(aAdr
, aCell
);
1952 nRes
= (pFormatter
->GetType(nFormat
) == css::util::NumberFormat::LOGICAL
);
1958 // TODO: we don't have type information for arrays except
1959 // numerical/string.
1963 if ( !nGlobalError
)
1964 nRes
= ( nCurFmtType
== css::util::NumberFormat::LOGICAL
);
1966 nCurFmtType
= nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
1968 PushInt( int(nRes
) );
1971 void ScInterpreter::ScType()
1974 switch ( GetStackType() )
1980 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1983 ScRefCellValue aCell
;
1984 aCell
.assign(*pDok
, aAdr
);
1985 if (GetCellErrCode(aCell
) == 0)
1987 switch (aCell
.meType
)
1989 // NOTE: this is Xcl nonsense!
1990 case CELLTYPE_STRING
:
1991 case CELLTYPE_EDIT
:
1994 case CELLTYPE_VALUE
:
1996 sal_uLong nFormat
= GetCellNumberFormat(aAdr
, aCell
);
1997 if (pFormatter
->GetType(nFormat
) == css::util::NumberFormat::LOGICAL
)
2003 case CELLTYPE_FORMULA
:
2007 PushIllegalArgument();
2033 // we could return the type of one element if in JumpMatrix or
2034 // ForceArray mode, but Xcl doesn't ...
2049 static inline bool lcl_FormatHasNegColor( const SvNumberformat
* pFormat
)
2051 return pFormat
&& pFormat
->GetColor( 1 );
2054 static inline bool lcl_FormatHasOpenPar( const SvNumberformat
* pFormat
)
2056 return pFormat
&& (pFormat
->GetFormatstring().indexOf('(') != -1);
2061 void getFormatString(SvNumberFormatter
* pFormatter
, sal_uLong nFormat
, OUString
& rFmtStr
)
2063 bool bAppendPrec
= true;
2064 sal_uInt16 nPrec
, nLeading
;
2065 bool bThousand
, bIsRed
;
2066 pFormatter
->GetFormatSpecialInfo( nFormat
, bThousand
, bIsRed
, nPrec
, nLeading
);
2068 switch( pFormatter
->GetType( nFormat
) )
2070 case css::util::NumberFormat::NUMBER
: if(bThousand
) rFmtStr
= ","; else rFmtStr
= "F"; break;
2071 case css::util::NumberFormat::CURRENCY
: rFmtStr
= "C"; break;
2072 case css::util::NumberFormat::SCIENTIFIC
: rFmtStr
= "S"; break;
2073 case css::util::NumberFormat::PERCENT
: rFmtStr
= "P"; break;
2076 bAppendPrec
= false;
2077 switch( pFormatter
->GetIndexTableOffset( nFormat
) )
2079 case NF_DATE_SYSTEM_SHORT
:
2080 case NF_DATE_SYS_DMMMYY
:
2081 case NF_DATE_SYS_DDMMYY
:
2082 case NF_DATE_SYS_DDMMYYYY
:
2083 case NF_DATE_SYS_DMMMYYYY
:
2084 case NF_DATE_DIN_DMMMYYYY
:
2085 case NF_DATE_SYS_DMMMMYYYY
:
2086 case NF_DATE_DIN_DMMMMYYYY
: rFmtStr
= "D1"; break;
2087 case NF_DATE_SYS_DDMMM
: rFmtStr
= "D2"; break;
2088 case NF_DATE_SYS_MMYY
: rFmtStr
= "D3"; break;
2089 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
2090 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
2091 rFmtStr
= "D4"; break;
2092 case NF_DATE_DIN_MMDD
: rFmtStr
= "D5"; break;
2093 case NF_TIME_HHMMSSAMPM
: rFmtStr
= "D6"; break;
2094 case NF_TIME_HHMMAMPM
: rFmtStr
= "D7"; break;
2095 case NF_TIME_HHMMSS
: rFmtStr
= "D8"; break;
2096 case NF_TIME_HHMM
: rFmtStr
= "D9"; break;
2097 default: rFmtStr
= "G";
2102 rFmtStr
+= OUString::number(nPrec
);
2103 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( nFormat
);
2104 if( lcl_FormatHasNegColor( pFormat
) )
2106 if( lcl_FormatHasOpenPar( pFormat
) )
2112 void ScInterpreter::ScCell()
2113 { // ATTRIBUTE ; [REF]
2114 sal_uInt8 nParamCount
= GetByte();
2115 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
2117 ScAddress
aCellPos( aPos
);
2118 bool bError
= false;
2119 if( nParamCount
== 2 )
2121 switch (GetStackType())
2123 case svExternalSingleRef
:
2124 case svExternalDoubleRef
:
2126 // Let's handle external reference separately...
2133 bError
= !PopDoubleRefOrSingleRef( aCellPos
);
2135 OUString aInfoType
= GetString().getString();
2136 if( bError
|| nGlobalError
)
2137 PushIllegalParameter();
2140 ScRefCellValue aCell
;
2141 aCell
.assign(*pDok
, aCellPos
);
2143 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::GetLocale(), ocCell
);
2145 // *** ADDRESS INFO ***
2146 if( aInfoType
== "COL" )
2147 { // column number (1-based)
2148 PushInt( aCellPos
.Col() + 1 );
2150 else if( aInfoType
== "ROW" )
2151 { // row number (1-based)
2152 PushInt( aCellPos
.Row() + 1 );
2154 else if( aInfoType
== "SHEET" )
2155 { // table number (1-based)
2156 PushInt( aCellPos
.Tab() + 1 );
2158 else if( aInfoType
== "ADDRESS" )
2159 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
2160 sal_uInt16 nFlags
= (aCellPos
.Tab() == aPos
.Tab()) ? (SCA_ABS
) : (SCA_ABS_3D
);
2161 OUString
aStr(aCellPos
.Format(nFlags
, pDok
, pDok
->GetAddressConvention()));
2164 else if( aInfoType
== "FILENAME" )
2165 { // file name and table name: 'FILENAME'#$TABLE
2166 SCTAB nTab
= aCellPos
.Tab();
2167 OUString aFuncResult
;
2168 if( nTab
< pDok
->GetTableCount() )
2170 if( pDok
->GetLinkMode( nTab
) == SC_LINK_VALUE
)
2171 pDok
->GetName( nTab
, aFuncResult
);
2174 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
2175 if( pShell
&& pShell
->GetMedium() )
2177 OUStringBuffer aBuf
;
2179 const INetURLObject
& rURLObj
= pShell
->GetMedium()->GetURLObject();
2180 aBuf
.append(rURLObj
.GetMainURL(INetURLObject::DECODE_UNAMBIGUOUS
));
2181 aBuf
.appendAscii("'#$");
2183 pDok
->GetName( nTab
, aTabName
);
2184 aBuf
.append(aTabName
);
2185 aFuncResult
= aBuf
.makeStringAndClear();
2189 PushString( aFuncResult
);
2191 else if( aInfoType
== "COORD" )
2192 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
2193 // Yes, passing tab as col is intentional!
2194 OUStringBuffer aFuncResult
;
2196 ScAddress( static_cast<SCCOL
>(aCellPos
.Tab()), 0, 0 ).Format(
2197 (SCA_COL_ABSOLUTE
|SCA_VALID_COL
), NULL
, pDok
->GetAddressConvention() );
2198 aFuncResult
.append(aCellStr
);
2199 aFuncResult
.append(':');
2200 aCellStr
= aCellPos
.Format((SCA_COL_ABSOLUTE
|SCA_VALID_COL
|SCA_ROW_ABSOLUTE
|SCA_VALID_ROW
),
2201 NULL
, pDok
->GetAddressConvention());
2202 aFuncResult
.append(aCellStr
);
2203 PushString( aFuncResult
.makeStringAndClear() );
2206 // *** CELL PROPERTIES ***
2207 else if( aInfoType
== "CONTENTS" )
2208 { // contents of the cell, no formatting
2209 if (aCell
.hasString())
2211 svl::SharedString aStr
;
2212 GetCellString(aStr
, aCell
);
2216 PushDouble(GetCellValue(aCellPos
, aCell
));
2218 else if( aInfoType
== "TYPE" )
2219 { // b = blank; l = string (label); v = otherwise (value)
2221 if (aCell
.hasString())
2224 c
= aCell
.hasNumeric() ? 'v' : 'b';
2225 PushString( OUString(c
) );
2227 else if( aInfoType
== "WIDTH" )
2228 { // column width (rounded off as count of zero characters in standard font and size)
2229 Printer
* pPrinter
= pDok
->GetPrinter();
2230 MapMode
aOldMode( pPrinter
->GetMapMode() );
2231 vcl::Font
aOldFont( pPrinter
->GetFont() );
2234 pPrinter
->SetMapMode( MAP_TWIP
);
2235 // font color doesn't matter here
2236 pDok
->GetDefPattern()->GetFont( aDefFont
, SC_AUTOCOL_BLACK
, pPrinter
);
2237 pPrinter
->SetFont( aDefFont
);
2238 long nZeroWidth
= pPrinter
->GetTextWidth( OUString( '0' ) );
2239 pPrinter
->SetFont( aOldFont
);
2240 pPrinter
->SetMapMode( aOldMode
);
2241 int nZeroCount
= (int)(pDok
->GetColWidth( aCellPos
.Col(), aCellPos
.Tab() ) / nZeroWidth
);
2242 PushInt( nZeroCount
);
2244 else if( aInfoType
== "PREFIX" )
2245 { // ' = left; " = right; ^ = centered
2247 if (aCell
.hasString())
2249 const SvxHorJustifyItem
* pJustAttr
= static_cast<const SvxHorJustifyItem
*>(
2250 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_HOR_JUSTIFY
));
2251 switch( pJustAttr
->GetValue() )
2253 case SVX_HOR_JUSTIFY_STANDARD
:
2254 case SVX_HOR_JUSTIFY_LEFT
:
2255 case SVX_HOR_JUSTIFY_BLOCK
: c
= '\''; break;
2256 case SVX_HOR_JUSTIFY_CENTER
: c
= '^'; break;
2257 case SVX_HOR_JUSTIFY_RIGHT
: c
= '"'; break;
2258 case SVX_HOR_JUSTIFY_REPEAT
: c
= '\\'; break;
2261 PushString( OUString(c
) );
2263 else if( aInfoType
== "PROTECT" )
2264 { // 1 = cell locked
2265 const ScProtectionAttr
* pProtAttr
= static_cast<const ScProtectionAttr
*>(
2266 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_PROTECTION
));
2267 PushInt( pProtAttr
->GetProtection() ? 1 : 0 );
2270 // *** FORMATTING ***
2271 else if( aInfoType
== "FORMAT" )
2272 { // specific format code for standard formats
2273 OUString aFuncResult
;
2274 sal_uLong nFormat
= pDok
->GetNumberFormat( aCellPos
);
2275 getFormatString(pFormatter
, nFormat
, aFuncResult
);
2276 PushString( aFuncResult
);
2278 else if( aInfoType
== "COLOR" )
2279 { // 1 = negative values are colored, otherwise 0
2280 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2281 PushInt( lcl_FormatHasNegColor( pFormat
) ? 1 : 0 );
2283 else if( aInfoType
== "PARENTHESES" )
2284 { // 1 = format string contains a '(' character, otherwise 0
2285 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2286 PushInt( lcl_FormatHasOpenPar( pFormat
) ? 1 : 0 );
2289 PushIllegalArgument();
2294 void ScInterpreter::ScCellExternal()
2298 ScSingleRefData aRef
;
2299 ScExternalRefCache::TokenRef pToken
;
2300 ScExternalRefCache::CellFormat aFmt
;
2301 PopExternalSingleRef(nFileId
, aTabName
, aRef
, pToken
, &aFmt
);
2304 PushIllegalParameter();
2308 OUString aInfoType
= GetString().getString();
2311 PushIllegalParameter();
2318 aRef
.SetAbsTab(0); // external ref has a tab index of -1, which SingleRefToVars() don't like.
2319 SingleRefToVars(aRef
, nCol
, nRow
, nTab
);
2322 PushIllegalParameter();
2325 aRef
.SetAbsTab(-1); // revert the value.
2327 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::GetLocale(), ocCell
);
2328 ScExternalRefManager
* pRefMgr
= pDok
->GetExternalRefManager();
2330 if ( aInfoType
== "COL" )
2332 else if ( aInfoType
== "ROW" )
2334 else if ( aInfoType
== "SHEET" )
2336 // For SHEET, No idea what number we should set, but let's always set
2337 // 1 if the external sheet exists, no matter what sheet. Excel does
2339 if (pRefMgr
->getCacheTable(nFileId
, aTabName
, false, NULL
).get())
2342 SetError(errNoName
);
2344 else if ( aInfoType
== "ADDRESS" )
2346 // ODF 1.2 says we need to always display address using the ODF A1 grammar.
2347 ScTokenArray aArray
;
2348 aArray
.AddExternalSingleReference(nFileId
, aTabName
, aRef
);
2349 ScCompiler
aComp(pDok
, aPos
, aArray
);
2350 aComp
.SetGrammar(formula::FormulaGrammar::GRAM_ODFF_A1
);
2352 aComp
.CreateStringFromTokenArray(aStr
);
2355 else if ( aInfoType
== "FILENAME" )
2357 // 'file URI'#$SheetName
2359 const OUString
* p
= pRefMgr
->getExternalFileName(nFileId
);
2362 // In theory this should never happen...
2363 SetError(errNoName
);
2367 OUStringBuffer aBuf
;
2370 aBuf
.appendAscii("'#$");
2371 aBuf
.append(aTabName
);
2372 PushString(aBuf
.makeStringAndClear());
2374 else if ( aInfoType
== "CONTENTS" )
2376 switch (pToken
->GetType())
2379 PushString(pToken
->GetString());
2382 PushString(OUString::number(pToken
->GetDouble()));
2385 PushString(ScGlobal::GetErrorString(pToken
->GetError()));
2388 PushString(ScGlobal::GetEmptyOUString());
2391 else if ( aInfoType
== "TYPE" )
2393 sal_Unicode c
= 'v';
2394 switch (pToken
->GetType())
2405 PushString(OUString(c
));
2407 else if ( aInfoType
== "FORMAT" )
2410 sal_uLong nFmt
= aFmt
.mbIsSet
? aFmt
.mnIndex
: 0;
2411 getFormatString(pFormatter
, nFmt
, aFmtStr
);
2412 PushString(aFmtStr
);
2414 else if ( aInfoType
== "COLOR" )
2416 // 1 = negative values are colored, otherwise 0
2420 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(aFmt
.mnIndex
);
2421 nVal
= lcl_FormatHasNegColor(pFormat
) ? 1 : 0;
2425 else if ( aInfoType
== "PARENTHESES" )
2427 // 1 = format string contains a '(' character, otherwise 0
2431 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(aFmt
.mnIndex
);
2432 nVal
= lcl_FormatHasOpenPar(pFormat
) ? 1 : 0;
2437 PushIllegalParameter();
2440 void ScInterpreter::ScIsRef()
2442 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2444 switch ( GetStackType() )
2449 PopSingleRef( aAdr
);
2450 if ( !nGlobalError
)
2457 PopDoubleRef( aRange
);
2458 if ( !nGlobalError
)
2464 FormulaTokenRef x
= PopToken();
2465 if ( !nGlobalError
)
2466 nRes
= !x
.get()->GetRefList()->empty();
2473 PushInt( int(nRes
) );
2476 void ScInterpreter::ScIsValue()
2478 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2480 switch ( GetRawStackType() )
2490 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2493 ScRefCellValue aCell
;
2494 aCell
.assign(*pDok
, aAdr
);
2495 if (GetCellErrCode(aCell
) == 0)
2497 switch (aCell
.meType
)
2499 case CELLTYPE_VALUE
:
2502 case CELLTYPE_FORMULA
:
2503 nRes
= (aCell
.mpFormula
->IsValue() && !aCell
.mpFormula
->IsEmpty());
2513 ScMatrixRef pMat
= PopMatrix();
2516 else if ( !pJumpMatrix
)
2518 if (pMat
->GetErrorIfNotString( 0, 0) == 0)
2519 nRes
= pMat
->IsValue( 0, 0);
2523 SCSIZE nCols
, nRows
, nC
, nR
;
2524 pMat
->GetDimensions( nCols
, nRows
);
2525 pJumpMatrix
->GetPos( nC
, nR
);
2526 if ( nC
< nCols
&& nR
< nRows
)
2527 if (pMat
->GetErrorIfNotString( nC
, nR
) == 0)
2528 nRes
= pMat
->IsValue( nC
, nR
);
2536 PushInt( int(nRes
) );
2539 void ScInterpreter::ScIsFormula()
2541 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2543 switch ( GetStackType() )
2549 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2552 nRes
= (pDok
->GetCellType(aAdr
) == CELLTYPE_FORMULA
);
2559 PushInt( int(nRes
) );
2562 void ScInterpreter::ScFormula()
2565 switch ( GetStackType() )
2571 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2574 ScRefCellValue aCell
;
2575 aCell
.assign(*pDok
, aAdr
);
2576 switch (aCell
.meType
)
2578 case CELLTYPE_FORMULA
:
2579 aCell
.mpFormula
->GetFormula(aFormula
);
2582 SetError( NOTAVAILABLE
);
2588 SetError( NOTAVAILABLE
);
2590 PushString( aFormula
);
2593 void ScInterpreter::ScIsNV()
2595 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2597 switch ( GetStackType() )
2603 bool bOk
= PopDoubleRefOrSingleRef( aAdr
);
2604 if ( nGlobalError
== NOTAVAILABLE
)
2608 ScRefCellValue aCell
;
2609 aCell
.assign(*pDok
, aAdr
);
2610 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2611 nRes
= (nErr
== NOTAVAILABLE
);
2617 ScMatrixRef pMat
= PopMatrix();
2620 else if ( !pJumpMatrix
)
2621 nRes
= (pMat
->GetErrorIfNotString( 0, 0) == NOTAVAILABLE
);
2624 SCSIZE nCols
, nRows
, nC
, nR
;
2625 pMat
->GetDimensions( nCols
, nRows
);
2626 pJumpMatrix
->GetPos( nC
, nR
);
2627 if ( nC
< nCols
&& nR
< nRows
)
2628 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) == NOTAVAILABLE
);
2634 if ( nGlobalError
== NOTAVAILABLE
)
2638 PushInt( int(nRes
) );
2641 void ScInterpreter::ScIsErr()
2643 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2645 switch ( GetStackType() )
2651 bool bOk
= PopDoubleRefOrSingleRef( aAdr
);
2652 if ( !bOk
|| (nGlobalError
&& nGlobalError
!= NOTAVAILABLE
) )
2656 ScRefCellValue aCell
;
2657 aCell
.assign(*pDok
, aAdr
);
2658 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2659 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2665 ScMatrixRef pMat
= PopMatrix();
2666 if ( nGlobalError
|| !pMat
)
2667 nRes
= ((nGlobalError
&& nGlobalError
!= NOTAVAILABLE
) || !pMat
);
2668 else if ( !pJumpMatrix
)
2670 sal_uInt16 nErr
= pMat
->GetErrorIfNotString( 0, 0);
2671 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2675 SCSIZE nCols
, nRows
, nC
, nR
;
2676 pMat
->GetDimensions( nCols
, nRows
);
2677 pJumpMatrix
->GetPos( nC
, nR
);
2678 if ( nC
< nCols
&& nR
< nRows
)
2680 sal_uInt16 nErr
= pMat
->GetErrorIfNotString( nC
, nR
);
2681 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2688 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2692 PushInt( int(nRes
) );
2695 void ScInterpreter::ScIsError()
2697 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2699 switch ( GetStackType() )
2705 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2714 ScRefCellValue aCell
;
2715 aCell
.assign(*pDok
, aAdr
);
2716 nRes
= (GetCellErrCode(aCell
) != 0);
2722 ScMatrixRef pMat
= PopMatrix();
2723 if ( nGlobalError
|| !pMat
)
2725 else if ( !pJumpMatrix
)
2726 nRes
= (pMat
->GetErrorIfNotString( 0, 0) != 0);
2729 SCSIZE nCols
, nRows
, nC
, nR
;
2730 pMat
->GetDimensions( nCols
, nRows
);
2731 pJumpMatrix
->GetPos( nC
, nR
);
2732 if ( nC
< nCols
&& nR
< nRows
)
2733 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) != 0);
2743 PushInt( int(nRes
) );
2746 bool ScInterpreter::IsEven()
2748 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
2751 switch ( GetStackType() )
2757 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2760 ScRefCellValue aCell
;
2761 aCell
.assign(*pDok
, aAdr
);
2762 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2767 switch (aCell
.meType
)
2769 case CELLTYPE_VALUE
:
2770 fVal
= GetCellValue(aAdr
, aCell
);
2773 case CELLTYPE_FORMULA
:
2774 if (aCell
.mpFormula
->IsValue())
2776 fVal
= GetCellValue(aAdr
, aCell
);
2794 ScMatrixRef pMat
= PopMatrix();
2797 else if ( !pJumpMatrix
)
2799 nRes
= pMat
->IsValue( 0, 0);
2801 fVal
= pMat
->GetDouble( 0, 0);
2805 SCSIZE nCols
, nRows
, nC
, nR
;
2806 pMat
->GetDimensions( nCols
, nRows
);
2807 pJumpMatrix
->GetPos( nC
, nR
);
2808 if ( nC
< nCols
&& nR
< nRows
)
2810 nRes
= pMat
->IsValue( nC
, nR
);
2812 fVal
= pMat
->GetDouble( nC
, nR
);
2815 SetError( errNoValue
);
2823 SetError( errIllegalParameter
);
2825 nRes
= ( fmod( ::rtl::math::approxFloor( fabs( fVal
) ), 2.0 ) < 0.5 );
2829 void ScInterpreter::ScIsEven()
2831 PushInt( int(IsEven()) );
2834 void ScInterpreter::ScIsOdd()
2836 PushInt( int(!IsEven()) );
2839 void ScInterpreter::ScN()
2841 sal_uInt16 nErr
= nGlobalError
;
2843 // Temporarily override the ConvertStringToValue() error for
2844 // GetCellValue() / GetCellValueOrZero()
2845 sal_uInt16 nSErr
= mnStringNoValueError
;
2846 mnStringNoValueError
= errCellNoValue
;
2847 double fVal
= GetDouble();
2848 mnStringNoValueError
= nSErr
;
2850 nGlobalError
= nErr
; // preserve previous error if any
2851 else if (nGlobalError
== errCellNoValue
)
2852 nGlobalError
= 0; // reset temporary detection error
2856 void ScInterpreter::ScTrim()
2858 // Doesn't only trim but also removes duplicated blanks within!
2859 OUString aVal
= comphelper::string::strip(GetString().getString(), ' ');
2860 OUStringBuffer aStr
;
2861 const sal_Unicode
* p
= aVal
.getStr();
2862 const sal_Unicode
* const pEnd
= p
+ aVal
.getLength();
2865 if ( *p
!= ' ' || p
[-1] != ' ' ) // first can't be ' ', so -1 is fine
2869 PushString(aStr
.makeStringAndClear());
2872 void ScInterpreter::ScUpper()
2874 OUString aString
= ScGlobal::pCharClass
->uppercase(GetString().getString());
2875 PushString(aString
);
2878 void ScInterpreter::ScProper()
2880 //2do: what to do with I18N-CJK ?!?
2881 OUStringBuffer
aStr(GetString().getString());
2882 const sal_Int32 nLen
= aStr
.getLength();
2885 OUString
aUpr(ScGlobal::pCharClass
->uppercase(aStr
.toString()));
2886 OUString
aLwr(ScGlobal::pCharClass
->lowercase(aStr
.toString()));
2889 while( nPos
< nLen
)
2891 OUString
aTmpStr( aStr
[nPos
-1] );
2892 if ( !ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 ) )
2893 aStr
[nPos
] = aUpr
[nPos
];
2895 aStr
[nPos
] = aLwr
[nPos
];
2899 PushString(aStr
.makeStringAndClear());
2902 void ScInterpreter::ScLower()
2904 OUString aString
= ScGlobal::pCharClass
->lowercase(GetString().getString());
2905 PushString(aString
);
2908 void ScInterpreter::ScLen()
2910 PushDouble(GetString().getLength());
2913 void ScInterpreter::ScT()
2915 switch ( GetStackType() )
2921 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2926 bool bValue
= false;
2927 ScRefCellValue aCell
;
2928 aCell
.assign(*pDok
, aAdr
);
2929 if (GetCellErrCode(aCell
) == 0)
2931 switch (aCell
.meType
)
2933 case CELLTYPE_VALUE
:
2936 case CELLTYPE_FORMULA
:
2937 bValue
= aCell
.mpFormula
->IsValue();
2944 PushString(EMPTY_OUSTRING
);
2948 svl::SharedString aStr
;
2949 GetCellString(aStr
, aCell
);
2955 case svExternalSingleRef
:
2956 case svExternalDoubleRef
:
2959 svl::SharedString aStr
;
2960 ScMatValType nMatValType
= GetDoubleOrStringFromMatrix( fVal
, aStr
);
2961 if (ScMatrix::IsValueType( nMatValType
))
2962 PushString(svl::SharedString::getEmptyString());
2970 PushString( EMPTY_OUSTRING
);
2977 PushError( errUnknownOpCode
);
2981 void ScInterpreter::ScValue()
2983 OUString aInputString
;
2986 switch ( GetRawStackType() )
2994 return; // leave on stack
3000 if ( !PopDoubleRefOrSingleRef( aAdr
) )
3005 ScRefCellValue aCell
;
3006 aCell
.assign(*pDok
, aAdr
);
3007 if (aCell
.hasString())
3009 svl::SharedString aSS
;
3010 GetCellString(aSS
, aCell
);
3011 aInputString
= aSS
.getString();
3013 else if (aCell
.hasNumeric())
3015 PushDouble( GetCellValue(aAdr
, aCell
) );
3027 svl::SharedString aSS
;
3028 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
3030 aInputString
= aSS
.getString();
3033 case SC_MATVAL_EMPTY
:
3036 case SC_MATVAL_VALUE
:
3037 case SC_MATVAL_BOOLEAN
:
3040 case SC_MATVAL_STRING
:
3044 PushIllegalArgument();
3049 aInputString
= GetString().getString();
3053 sal_uInt32 nFIndex
= 0; // 0 for default locale
3054 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
3057 PushIllegalArgument();
3061 void ScInterpreter::ScNumberValue()
3064 sal_uInt8 nParamCount
= GetByte();
3065 if ( !MustHaveParamCount( nParamCount
, 1, 3 ) )
3068 OUString aInputString
;
3069 OUString aDecimalSeparator
, aGroupSeparator
;
3070 sal_Unicode cDecimalSeparator
= 0;
3072 if ( nParamCount
== 3 )
3073 aGroupSeparator
= GetString().getString();
3075 if ( nParamCount
>= 2 )
3077 aDecimalSeparator
= GetString().getString();
3078 if ( aDecimalSeparator
.getLength() == 1 )
3079 cDecimalSeparator
= aDecimalSeparator
[ 0 ];
3082 PushIllegalArgument(); //if given, separator length must be 1
3087 if ( cDecimalSeparator
&& aGroupSeparator
.indexOf( cDecimalSeparator
) != -1 )
3089 PushIllegalArgument(); //decimal separator cannot appear in group separator
3093 switch (GetStackType())
3096 return; // leave on stack
3098 aInputString
= GetString().getString();
3102 PushError( nGlobalError
);
3105 if ( aInputString
.isEmpty() )
3107 if ( maCalcConfig
.mbEmptyStringAsZero
)
3114 sal_Int32 nDecSep
= aInputString
.indexOf( cDecimalSeparator
);
3117 OUString
aTemporary( nDecSep
>= 0 ? aInputString
.copy( 0, nDecSep
) : aInputString
);
3118 sal_Int32 nIndex
= 0;
3119 while (nIndex
< aGroupSeparator
.getLength())
3121 sal_uInt32 nChar
= aGroupSeparator
.iterateCodePoints( &nIndex
);
3122 aTemporary
= aTemporary
.replaceAll( OUString( &nChar
, 1 ), "" );
3125 aInputString
= aTemporary
+ aInputString
.copy( nDecSep
);
3127 aInputString
= aTemporary
;
3130 for ( sal_Int32 i
= aInputString
.getLength(); --i
>= 0; )
3132 sal_Unicode c
= aInputString
[ i
];
3133 if ( c
== 0x0020 || c
== 0x0009 || c
== 0x000A || c
== 0x000D )
3134 aInputString
= aInputString
.replaceAt( i
, 1, "" ); // remove spaces etc.
3136 sal_Int32 nPercentCount
= 0;
3137 for ( sal_Int32 i
= aInputString
.getLength() - 1; i
>= 0 && aInputString
[ i
] == 0x0025; i
-- )
3139 aInputString
= aInputString
.replaceAt( i
, 1, "" ); // remove and count trailing '%'
3143 rtl_math_ConversionStatus eStatus
;
3144 sal_Int32 nParseEnd
;
3145 double fVal
= ::rtl::math::stringToDouble( aInputString
, cDecimalSeparator
, 0, &eStatus
, &nParseEnd
);
3146 if ( eStatus
== rtl_math_ConversionStatus_Ok
&& nParseEnd
== aInputString
.getLength() )
3149 fVal
*= pow( 10.0, -(nPercentCount
* 2)); // process '%' from input string
3156 //2do: this should be a proper unicode string method
3157 static inline bool lcl_ScInterpreter_IsPrintable( sal_Unicode c
)
3159 return 0x20 <= c
&& c
!= 0x7f;
3162 void ScInterpreter::ScClean()
3164 OUString aStr
= GetString().getString();
3165 for ( sal_Int32 i
= 0; i
< aStr
.getLength(); i
++ )
3167 if ( !lcl_ScInterpreter_IsPrintable( aStr
[i
] ) )
3168 aStr
= aStr
.replaceAt(i
,1,"");
3173 void ScInterpreter::ScCode()
3175 //2do: make it full range unicode?
3176 OUString aStr
= GetString().getString();
3181 //"classic" ByteString conversion flags
3182 const sal_uInt32 convertFlags
=
3183 RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE
|
3184 RTL_UNICODETOTEXT_FLAGS_CONTROL_IGNORE
|
3185 RTL_UNICODETOTEXT_FLAGS_FLUSH
|
3186 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT
|
3187 RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT
|
3188 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
;
3189 PushInt( (unsigned char) OUStringToOString(OUString(aStr
[0]), osl_getThreadTextEncoding(), convertFlags
).toChar() );
3193 void ScInterpreter::ScChar()
3195 //2do: make it full range unicode?
3196 double fVal
= GetDouble();
3197 if (fVal
< 0.0 || fVal
>= 256.0)
3198 PushIllegalArgument();
3201 //"classic" ByteString conversion flags
3202 const sal_uInt32 convertFlags
=
3203 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT
|
3204 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
|
3205 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
;
3207 sal_Char cEncodedChar
= static_cast<sal_Char
>(fVal
);
3208 OUString
aStr(&cEncodedChar
, 1, osl_getThreadTextEncoding(), convertFlags
);
3213 /* #i70213# fullwidth/halfwidth conversion provided by
3214 * Takashi Nakamoto <bluedwarf@ooo>
3215 * erAck: added Excel compatibility conversions as seen in issue's test case. */
3217 static OUString
lcl_convertIntoHalfWidth( const OUString
& rStr
)
3219 static bool bFirstASCCall
= true;
3220 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessComponentContext(), 0 );
3224 aTrans
.loadModuleByImplName( OUString( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM
);
3225 bFirstASCCall
= false;
3228 return aTrans
.transliterate( rStr
, 0, sal_uInt16( rStr
.getLength() ), NULL
);
3231 static OUString
lcl_convertIntoFullWidth( const OUString
& rStr
)
3233 static bool bFirstJISCall
= true;
3234 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessComponentContext(), 0 );
3238 aTrans
.loadModuleByImplName( OUString( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM
);
3239 bFirstJISCall
= false;
3242 return aTrans
.transliterate( rStr
, 0, sal_uInt16( rStr
.getLength() ), NULL
);
3246 * Summary: Converts half-width to full-width ASCII and katakana characters.
3247 * Semantics: Conversion is done for half-width ASCII and katakana characters,
3248 * other characters are simply copied from T to the result. This is the
3249 * complementary function to ASC.
3250 * For references regarding halfwidth and fullwidth characters see
3251 * http://www.unicode.org/reports/tr11/
3252 * http://www.unicode.org/charts/charindex2.html#H
3253 * http://www.unicode.org/charts/charindex2.html#F
3255 void ScInterpreter::ScJis()
3257 if (MustHaveParamCount( GetByte(), 1))
3258 PushString( lcl_convertIntoFullWidth( GetString().getString()));
3262 * Summary: Converts full-width to half-width ASCII and katakana characters.
3263 * Semantics: Conversion is done for full-width ASCII and katakana characters,
3264 * other characters are simply copied from T to the result. This is the
3265 * complementary function to JIS.
3267 void ScInterpreter::ScAsc()
3269 if (MustHaveParamCount( GetByte(), 1))
3270 PushString( lcl_convertIntoHalfWidth( GetString().getString()));
3273 void ScInterpreter::ScUnicode()
3275 if ( MustHaveParamCount( GetByte(), 1 ) )
3277 OUString aStr
= GetString().getString();
3279 PushIllegalParameter();
3283 PushDouble(aStr
.iterateCodePoints(&i
));
3288 void ScInterpreter::ScUnichar()
3290 if ( MustHaveParamCount( GetByte(), 1 ) )
3292 double dVal
= ::rtl::math::approxFloor( GetDouble() );
3293 if ((dVal
< 0x000000) || (dVal
> 0x10FFFF))
3294 PushIllegalArgument();
3297 sal_uInt32 nCodePoint
= static_cast<sal_uInt32
>( dVal
);
3298 OUString
aStr( &nCodePoint
, 1 );
3304 void ScInterpreter::ScMin( bool bTextAsZero
)
3306 short nParamCount
= GetByte();
3307 if (!MustHaveParamCountMin( nParamCount
, 1))
3309 double nMin
= ::std::numeric_limits
<double>::max();
3313 size_t nRefInList
= 0;
3314 while (nParamCount
-- > 0)
3316 switch (GetStackType())
3321 if (nMin
> nVal
) nMin
= nVal
;
3322 nFuncFmtType
= css::util::NumberFormat::NUMBER
;
3327 PopSingleRef( aAdr
);
3328 ScRefCellValue aCell
;
3329 aCell
.assign(*pDok
, aAdr
);
3330 if (aCell
.hasNumeric())
3332 nVal
= GetCellValue(aAdr
, aCell
);
3334 if (nMin
> nVal
) nMin
= nVal
;
3336 else if (bTextAsZero
&& aCell
.hasString())
3346 sal_uInt16 nErr
= 0;
3347 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3348 ScValueIterator
aValIter( pDok
, aRange
, mnSubTotalFlags
, bTextAsZero
);
3349 if (aValIter
.GetFirst(nVal
, nErr
))
3353 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3354 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
3364 case svExternalSingleRef
:
3365 case svExternalDoubleRef
:
3367 ScMatrixRef pMat
= GetMatrix();
3370 nFuncFmtType
= css::util::NumberFormat::NUMBER
;
3371 nVal
= pMat
->GetMinValue(bTextAsZero
);
3386 SetError(errIllegalParameter
);
3391 SetError(errIllegalParameter
);
3400 void ScInterpreter::ScMax( bool bTextAsZero
)
3402 short nParamCount
= GetByte();
3403 if (!MustHaveParamCountMin( nParamCount
, 1))
3405 double nMax
= -(::std::numeric_limits
<double>::max());
3409 size_t nRefInList
= 0;
3410 while (nParamCount
-- > 0)
3412 switch (GetStackType())
3417 if (nMax
< nVal
) nMax
= nVal
;
3418 nFuncFmtType
= css::util::NumberFormat::NUMBER
;
3423 PopSingleRef( aAdr
);
3424 ScRefCellValue aCell
;
3425 aCell
.assign(*pDok
, aAdr
);
3426 if (aCell
.hasNumeric())
3428 nVal
= GetCellValue(aAdr
, aCell
);
3430 if (nMax
< nVal
) nMax
= nVal
;
3432 else if (bTextAsZero
&& aCell
.hasString())
3442 sal_uInt16 nErr
= 0;
3443 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3444 ScValueIterator
aValIter( pDok
, aRange
, mnSubTotalFlags
, bTextAsZero
);
3445 if (aValIter
.GetFirst(nVal
, nErr
))
3449 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3450 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
3460 case svExternalSingleRef
:
3461 case svExternalDoubleRef
:
3463 ScMatrixRef pMat
= GetMatrix();
3466 nFuncFmtType
= css::util::NumberFormat::NUMBER
;
3467 nVal
= pMat
->GetMaxValue(bTextAsZero
);
3482 SetError(errIllegalParameter
);
3487 SetError(errIllegalParameter
);
3496 void ScInterpreter::GetStVarParams( double& rVal
, double& rValCount
,
3499 short nParamCount
= GetByte();
3501 std::vector
<double> values
;
3509 size_t nRefInList
= 0;
3510 while (nParamCount
-- > 0)
3512 switch (GetStackType())
3517 values
.push_back(fVal
);
3524 PopSingleRef( aAdr
);
3525 ScRefCellValue aCell
;
3526 aCell
.assign(*pDok
, aAdr
);
3527 if (aCell
.hasNumeric())
3529 fVal
= GetCellValue(aAdr
, aCell
);
3530 values
.push_back(fVal
);
3534 else if (bTextAsZero
&& aCell
.hasString())
3536 values
.push_back(0.0);
3544 sal_uInt16 nErr
= 0;
3545 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3546 ScValueIterator
aValIter( pDok
, aRange
, mnSubTotalFlags
, bTextAsZero
);
3547 if (aValIter
.GetFirst(fVal
, nErr
))
3551 values
.push_back(fVal
);
3555 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
3561 ScMatrixRef pMat
= PopMatrix();
3565 pMat
->GetDimensions(nC
, nR
);
3566 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3568 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3570 if (!pMat
->IsString(nMatCol
,nMatRow
))
3572 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3573 values
.push_back(fVal
);
3577 else if ( bTextAsZero
)
3579 values
.push_back(0.0);
3592 values
.push_back(0.0);
3596 SetError(errIllegalParameter
);
3601 SetError(errIllegalParameter
);
3605 ::std::vector
<double>::size_type n
= values
.size();
3607 for (::std::vector
<double>::size_type i
= 0; i
< n
; i
++)
3608 vSum
+= ::rtl::math::approxSub( values
[i
], vMean
) * ::rtl::math::approxSub( values
[i
], vMean
);
3612 void ScInterpreter::ScVar( bool bTextAsZero
)
3616 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3618 if (nValCount
<= 1.0)
3619 PushError( errDivisionByZero
);
3621 PushDouble( nVal
/ (nValCount
- 1.0));
3624 void ScInterpreter::ScVarP( bool bTextAsZero
)
3628 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3630 PushDouble( div( nVal
, nValCount
));
3633 void ScInterpreter::ScStDev( bool bTextAsZero
)
3637 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3638 if (nValCount
<= 1.0)
3639 PushError( errDivisionByZero
);
3641 PushDouble( sqrt( nVal
/ (nValCount
- 1.0)));
3644 void ScInterpreter::ScStDevP( bool bTextAsZero
)
3648 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3649 if (nValCount
== 0.0)
3650 PushError( errDivisionByZero
);
3652 PushDouble( sqrt( nVal
/ nValCount
));
3654 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3656 * Besides that the special NAN gets lost in the call through sqrt(),
3657 * unxlngi6.pro then looped back and forth somewhere between div() and
3658 * ::rtl::math::setNan(). Tests showed that
3660 * sqrt( div( 1, 0));
3662 * produced a loop, but
3664 * double f1 = div( 1, 0);
3667 * was fine. There seems to be some compiler optimization problem. It does
3668 * not occur when compiled with debug=t.
3672 void ScInterpreter::ScColumns()
3674 sal_uInt8 nParamCount
= GetByte();
3682 while (nParamCount
-- > 0)
3684 switch ( GetStackType() )
3691 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3692 nVal
+= static_cast<sal_uLong
>(nTab2
- nTab1
+ 1) *
3693 static_cast<sal_uLong
>(nCol2
- nCol1
+ 1);
3697 ScMatrixRef pMat
= PopMatrix();
3701 pMat
->GetDimensions(nC
, nR
);
3706 case svExternalSingleRef
:
3710 case svExternalDoubleRef
:
3714 ScComplexRefData aRef
;
3715 PopExternalDoubleRef( nFileId
, aTabName
, aRef
);
3716 ScRange aAbs
= aRef
.toAbs(aPos
);
3717 nVal
+= static_cast<sal_uLong
>(aAbs
.aEnd
.Tab() - aAbs
.aStart
.Tab() + 1) *
3718 static_cast<sal_uLong
>(aAbs
.aEnd
.Col() - aAbs
.aStart
.Col() + 1);
3723 SetError(errIllegalParameter
);
3726 PushDouble((double)nVal
);
3729 void ScInterpreter::ScRows()
3731 sal_uInt8 nParamCount
= GetByte();
3739 while (nParamCount
-- > 0)
3741 switch ( GetStackType() )
3748 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3749 nVal
+= static_cast<sal_uLong
>(nTab2
- nTab1
+ 1) *
3750 static_cast<sal_uLong
>(nRow2
- nRow1
+ 1);
3754 ScMatrixRef pMat
= PopMatrix();
3758 pMat
->GetDimensions(nC
, nR
);
3763 case svExternalSingleRef
:
3767 case svExternalDoubleRef
:
3771 ScComplexRefData aRef
;
3772 PopExternalDoubleRef( nFileId
, aTabName
, aRef
);
3773 ScRange aAbs
= aRef
.toAbs(aPos
);
3774 nVal
+= static_cast<sal_uLong
>(aAbs
.aEnd
.Tab() - aAbs
.aStart
.Tab() + 1) *
3775 static_cast<sal_uLong
>(aAbs
.aEnd
.Row() - aAbs
.aStart
.Row() + 1);
3780 SetError(errIllegalParameter
);
3783 PushDouble((double)nVal
);
3786 void ScInterpreter::ScSheets()
3788 sal_uInt8 nParamCount
= GetByte();
3790 if ( nParamCount
== 0 )
3791 nVal
= pDok
->GetTableCount();
3801 while (nParamCount
-- > 0)
3803 switch ( GetStackType() )
3810 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3811 nVal
+= static_cast<sal_uLong
>(nTab2
- nTab1
+ 1);
3817 case svExternalSingleRef
:
3821 case svExternalDoubleRef
:
3825 ScComplexRefData aRef
;
3826 PopExternalDoubleRef( nFileId
, aTabName
, aRef
);
3827 ScRange aAbs
= aRef
.toAbs(aPos
);
3828 nVal
+= static_cast<sal_uLong
>(aAbs
.aEnd
.Tab() - aAbs
.aStart
.Tab() + 1);
3833 SetError( errIllegalParameter
);
3837 PushDouble( (double) nVal
);
3840 void ScInterpreter::ScColumn()
3842 sal_uInt8 nParamCount
= GetByte();
3843 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3846 if (nParamCount
== 0)
3848 nVal
= aPos
.Col() + 1;
3853 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3856 // Happens if called via ScViewFunc::EnterMatrix()
3857 // ScFormulaCell::GetResultDimensions() as of course a
3858 // matrix result is not available yet.
3861 ScMatrixRef pResMat
= GetNewMat( static_cast<SCSIZE
>(nCols
), 1);
3864 for (SCCOL i
=0; i
< nCols
; ++i
)
3865 pResMat
->PutDouble( nVal
+ i
, static_cast<SCSIZE
>(i
), 0);
3866 PushMatrix( pResMat
);
3873 switch ( GetStackType() )
3880 PopSingleRef( nCol1
, nRow1
, nTab1
);
3881 nVal
= (double) (nCol1
+ 1);
3892 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3895 ScMatrixRef pResMat
= GetNewMat(
3896 static_cast<SCSIZE
>(nCol2
-nCol1
+1), 1);
3899 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
3900 pResMat
->PutDouble((double)(i
+1),
3901 static_cast<SCSIZE
>(i
-nCol1
), 0);
3902 PushMatrix(pResMat
);
3909 nVal
= (double) (nCol1
+ 1);
3913 SetError( errIllegalParameter
);
3921 void ScInterpreter::ScRow()
3923 sal_uInt8 nParamCount
= GetByte();
3924 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3927 if (nParamCount
== 0)
3929 nVal
= aPos
.Row() + 1;
3934 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3937 // Happens if called via ScViewFunc::EnterMatrix()
3938 // ScFormulaCell::GetResultDimensions() as of course a
3939 // matrix result is not available yet.
3942 ScMatrixRef pResMat
= GetNewMat( 1, static_cast<SCSIZE
>(nRows
));
3945 for (SCROW i
=0; i
< nRows
; i
++)
3946 pResMat
->PutDouble( nVal
+ i
, 0, static_cast<SCSIZE
>(i
));
3947 PushMatrix( pResMat
);
3954 switch ( GetStackType() )
3961 PopSingleRef( nCol1
, nRow1
, nTab1
);
3962 nVal
= (double) (nRow1
+ 1);
3973 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3976 ScMatrixRef pResMat
= GetNewMat( 1,
3977 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
3980 for (SCROW i
= nRow1
; i
<= nRow2
; i
++)
3981 pResMat
->PutDouble((double)(i
+1), 0,
3982 static_cast<SCSIZE
>(i
-nRow1
));
3983 PushMatrix(pResMat
);
3990 nVal
= (double) (nRow1
+ 1);
3994 SetError( errIllegalParameter
);
4002 void ScInterpreter::ScSheet()
4004 sal_uInt8 nParamCount
= GetByte();
4005 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
4008 if ( nParamCount
== 0 )
4009 nVal
= aPos
.Tab() + 1;
4012 switch ( GetStackType() )
4016 svl::SharedString aStr
= PopString();
4017 if ( pDok
->GetTable(aStr
.getString(), nVal
))
4020 SetError( errIllegalArgument
);
4028 PopSingleRef( nCol1
, nRow1
, nTab1
);
4040 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4045 SetError( errIllegalParameter
);
4050 PushDouble( (double) nVal
);
4056 class VectorMatrixAccessor
4059 VectorMatrixAccessor(const ScMatrix
& rMat
, bool bColVec
) :
4060 mrMat(rMat
), mbColVec(bColVec
) {}
4062 bool IsEmpty(SCSIZE i
) const
4064 return mbColVec
? mrMat
.IsEmpty(0, i
) : mrMat
.IsEmpty(i
, 0);
4067 bool IsEmptyPath(SCSIZE i
) const
4069 return mbColVec
? mrMat
.IsEmptyPath(0, i
) : mrMat
.IsEmptyPath(i
, 0);
4072 bool IsValue(SCSIZE i
) const
4074 return mbColVec
? mrMat
.IsValue(0, i
) : mrMat
.IsValue(i
, 0);
4077 bool IsString(SCSIZE i
) const
4079 return mbColVec
? mrMat
.IsString(0, i
) : mrMat
.IsString(i
, 0);
4082 double GetDouble(SCSIZE i
) const
4084 return mbColVec
? mrMat
.GetDouble(0, i
) : mrMat
.GetDouble(i
, 0);
4087 OUString
GetString(SCSIZE i
) const
4089 return mbColVec
? mrMat
.GetString(0, i
).getString() : mrMat
.GetString(i
, 0).getString();
4092 SCSIZE
GetElementCount() const
4095 mrMat
.GetDimensions(nC
, nR
);
4096 return mbColVec
? nR
: nC
;
4100 const ScMatrix
& mrMat
;
4104 /** returns -1 when the matrix value is smaller than the query value, 0 when
4105 they are equal, and 1 when the matrix value is larger than the query
4107 static sal_Int32
lcl_CompareMatrix2Query(
4108 SCSIZE i
, const VectorMatrixAccessor
& rMat
, const ScQueryEntry
& rEntry
)
4110 if (rMat
.IsEmpty(i
))
4112 /* TODO: in case we introduced query for real empty this would have to
4114 return -1; // empty always less than anything else
4117 /* FIXME: what is an empty path (result of IF(false;true_path) in
4120 bool bByString
= rEntry
.GetQueryItem().meType
== ScQueryEntry::ByString
;
4121 if (rMat
.IsValue(i
))
4124 return -1; // numeric always less than string
4126 const double nVal1
= rMat
.GetDouble(i
);
4127 const double nVal2
= rEntry
.GetQueryItem().mfVal
;
4131 return nVal1
< nVal2
? -1 : 1;
4135 return 1; // string always greater than numeric
4137 OUString aStr1
= rMat
.GetString(i
);
4138 OUString aStr2
= rEntry
.GetQueryItem().maString
.getString();
4140 return ScGlobal::GetCollator()->compareString(aStr1
, aStr2
); // case-insensitive
4143 /** returns the last item with the identical value as the original item
4145 static void lcl_GetLastMatch( SCSIZE
& rIndex
, const VectorMatrixAccessor
& rMat
,
4146 SCSIZE nMatCount
, bool bReverse
)
4148 if (rMat
.IsValue(rIndex
))
4150 double nVal
= rMat
.GetDouble(rIndex
);
4152 while (rIndex
> 0 && rMat
.IsValue(rIndex
-1) &&
4153 nVal
== rMat
.GetDouble(rIndex
-1))
4156 while (rIndex
< nMatCount
-1 && rMat
.IsValue(rIndex
+1) &&
4157 nVal
== rMat
.GetDouble(rIndex
+1))
4160 // Order of IsEmptyPath, IsEmpty, IsString is significant!
4161 else if (rMat
.IsEmptyPath(rIndex
))
4164 while (rIndex
> 0 && rMat
.IsEmptyPath(rIndex
-1))
4167 while (rIndex
< nMatCount
-1 && rMat
.IsEmptyPath(rIndex
+1))
4170 else if (rMat
.IsEmpty(rIndex
))
4173 while (rIndex
> 0 && rMat
.IsEmpty(rIndex
-1))
4176 while (rIndex
< nMatCount
-1 && rMat
.IsEmpty(rIndex
+1))
4179 else if (rMat
.IsString(rIndex
))
4181 OUString
aStr( rMat
.GetString(rIndex
));
4183 while (rIndex
> 0 && rMat
.IsString(rIndex
-1) &&
4184 aStr
== rMat
.GetString(rIndex
-1))
4187 while (rIndex
< nMatCount
-1 && rMat
.IsString(rIndex
+1) &&
4188 aStr
== rMat
.GetString(rIndex
+1))
4193 OSL_FAIL("lcl_GetLastMatch: unhandled matrix type");
4199 void ScInterpreter::ScMatch()
4202 sal_uInt8 nParamCount
= GetByte();
4203 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4206 if (nParamCount
== 3)
4216 ScMatrixRef pMatSrc
= NULL
;
4218 switch (GetStackType())
4221 PopSingleRef( nCol1
, nRow1
, nTab1
);
4228 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4229 if (nTab1
!= nTab2
|| (nCol1
!= nCol2
&& nRow1
!= nRow2
))
4231 PushIllegalParameter();
4237 case svExternalDoubleRef
:
4239 if (GetStackType() == svMatrix
)
4240 pMatSrc
= PopMatrix();
4242 PopExternalDoubleRef(pMatSrc
);
4246 PushIllegalParameter();
4252 PushIllegalParameter();
4256 if (nGlobalError
== 0)
4259 ScQueryParam rParam
;
4260 rParam
.nCol1
= nCol1
;
4261 rParam
.nRow1
= nRow1
;
4262 rParam
.nCol2
= nCol2
;
4263 rParam
.nTab
= nTab1
;
4265 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4266 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
4267 rEntry
.bDoQuery
= true;
4269 rEntry
.eOp
= SC_GREATER_EQUAL
;
4270 else if (fTyp
> 0.0)
4271 rEntry
.eOp
= SC_LESS_EQUAL
;
4272 switch ( GetStackType() )
4278 rItem
.meType
= ScQueryEntry::ByValue
;
4283 rItem
.meType
= ScQueryEntry::ByString
;
4284 rItem
.maString
= GetString();
4291 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4296 ScRefCellValue aCell
;
4297 aCell
.assign(*pDok
, aAdr
);
4298 if (aCell
.hasNumeric())
4300 fVal
= GetCellValue(aAdr
, aCell
);
4301 rItem
.meType
= ScQueryEntry::ByValue
;
4306 GetCellString(rItem
.maString
, aCell
);
4307 rItem
.meType
= ScQueryEntry::ByString
;
4311 case svExternalSingleRef
:
4313 ScExternalRefCache::TokenRef pToken
;
4314 PopExternalSingleRef(pToken
);
4320 if (pToken
->GetType() == svDouble
)
4322 rItem
.meType
= ScQueryEntry::ByValue
;
4323 rItem
.mfVal
= pToken
->GetDouble();
4327 rItem
.meType
= ScQueryEntry::ByString
;
4328 rItem
.maString
= pToken
->GetString();
4332 case svExternalDoubleRef
:
4333 // TODO: Implement this.
4334 PushIllegalParameter();
4339 svl::SharedString aStr
;
4340 ScMatValType nType
= GetDoubleOrStringFromMatrix(
4342 rItem
.maString
= aStr
;
4343 rItem
.meType
= ScMatrix::IsNonValueType(nType
) ?
4344 ScQueryEntry::ByString
: ScQueryEntry::ByValue
;
4349 PushIllegalParameter();
4353 if (rItem
.meType
== ScQueryEntry::ByString
)
4355 bool bIsVBAMode
= pDok
->IsInVBAMode();
4357 // #TODO handle MSO wildcards
4359 rParam
.bRegExp
= false;
4361 rParam
.bRegExp
= MayBeRegExp(rEntry
.GetQueryItem().maString
.getString(), pDok
);
4364 if (pMatSrc
) // The source data is matrix array.
4367 pMatSrc
->GetDimensions( nC
, nR
);
4368 if (nC
> 1 && nR
> 1)
4370 // The source matrix must be a vector.
4371 PushIllegalParameter();
4374 SCSIZE nMatCount
= (nC
== 1) ? nR
: nC
;
4375 VectorMatrixAccessor
aMatAcc(*pMatSrc
, nC
== 1);
4377 // simple serial search for equality mode (source data doesn't
4378 // need to be sorted).
4380 if (rEntry
.eOp
== SC_EQUAL
)
4382 for (SCSIZE i
= 0; i
< nMatCount
; ++i
)
4384 if (lcl_CompareMatrix2Query( i
, aMatAcc
, rEntry
) == 0)
4386 PushDouble(i
+1); // found !
4390 PushNA(); // not found
4394 // binary search for non-equality mode (the source data is
4395 // assumed to be sorted).
4397 bool bAscOrder
= (rEntry
.eOp
== SC_LESS_EQUAL
);
4398 SCSIZE nFirst
= 0, nLast
= nMatCount
-1, nHitIndex
= 0;
4399 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
4401 SCSIZE nMid
= nFirst
+ nLen
/2;
4402 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, aMatAcc
, rEntry
);
4405 // exact match. find the last item with the same value.
4406 lcl_GetLastMatch( nMid
, aMatAcc
, nMatCount
, !bAscOrder
);
4407 PushDouble( nMid
+1);
4411 if (nLen
== 1) // first and last items are next to each other.
4414 nHitIndex
= bAscOrder
? nLast
: nFirst
;
4416 nHitIndex
= bAscOrder
? nFirst
: nLast
;
4436 if (nHitIndex
== nMatCount
-1) // last item
4438 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nHitIndex
, aMatAcc
, rEntry
);
4439 if ((bAscOrder
&& nCmp
<= 0) || (!bAscOrder
&& nCmp
>= 0))
4441 // either the last item is an exact match or the real
4442 // hit is beyond the last item.
4443 PushDouble( nHitIndex
+1);
4448 if (nHitIndex
> 0) // valid hit must be 2nd item or higher
4450 PushDouble( nHitIndex
); // non-exact match
4458 SCCOLROW nDelta
= 0;
4460 { // search row in column
4461 rParam
.nRow2
= nRow2
;
4462 rEntry
.nField
= nCol1
;
4463 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
4464 if (!LookupQueryWithCache( aResultPos
, rParam
))
4469 nDelta
= aResultPos
.Row() - nRow1
;
4472 { // search column in row
4474 rParam
.bByRow
= false;
4475 rParam
.nRow2
= nRow1
;
4476 rEntry
.nField
= nCol1
;
4477 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
4478 // Advance Entry.nField in Iterator if column changed
4479 aCellIter
.SetAdvanceQueryParamEntryField( true );
4482 if ( aCellIter
.GetFirst() )
4483 nC
= aCellIter
.GetCol();
4493 if ( !aCellIter
.FindEqualOrSortedLastInRange( nC
, nR
) )
4499 nDelta
= nC
- nCol1
;
4501 PushDouble((double) (nDelta
+ 1));
4504 PushIllegalParameter();
4510 bool isCellContentEmpty( const ScRefCellValue
& rCell
)
4512 switch (rCell
.meType
)
4514 case CELLTYPE_VALUE
:
4515 case CELLTYPE_STRING
:
4518 case CELLTYPE_FORMULA
:
4520 // NOTE: Excel treats ="" in a referenced cell as blank in
4521 // COUNTBLANK() but not in ISBLANK(), which is inconsistent.
4522 // COUNTBLANK() tests the (display) result whereas ISBLANK() tests
4523 // the cell content.
4524 // ODFF allows both for COUNTBLANK().
4525 // OOo and LibreOffice prior to 4.4 did not treat ="" as blank in
4526 // COUNTBLANK(), we now do for Excel interoperability.
4527 /* TODO: introduce yet another compatibility option? */
4528 sc::FormulaResultValue aRes
= rCell
.mpFormula
->GetResult();
4529 if (aRes
.meType
!= sc::FormulaResultValue::String
)
4531 if (!aRes
.maString
.isEmpty())
4544 void ScInterpreter::ScCountEmptyCells()
4546 if ( MustHaveParamCount( GetByte(), 1 ) )
4548 sal_uLong nMaxCount
= 0, nCount
= 0;
4549 switch (GetStackType())
4555 PopSingleRef( aAdr
);
4556 ScRefCellValue aCell
;
4557 aCell
.assign(*pDok
, aAdr
);
4558 if (!isCellContentEmpty(aCell
))
4567 size_t nRefInList
= 0;
4568 while (nParam
-- > 0)
4570 PopDoubleRef( aRange
, nParam
, nRefInList
);
4572 static_cast<sal_uLong
>(aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1) *
4573 static_cast<sal_uLong
>(aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1) *
4574 static_cast<sal_uLong
>(aRange
.aEnd
.Tab() - aRange
.aStart
.Tab() + 1);
4576 ScCellIterator
aIter( pDok
, aRange
, mnSubTotalFlags
);
4577 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
4579 const ScRefCellValue
& rCell
= aIter
.getRefCellValue();
4580 if (!isCellContentEmpty(rCell
))
4586 default : SetError(errIllegalParameter
); break;
4588 PushDouble(nMaxCount
- nCount
);
4592 double ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc
)
4594 sal_uInt8 nParamCount
= GetByte();
4595 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
4602 ScMatrixRef pSumExtraMatrix
;
4603 bool bSumExtraRange
= (nParamCount
== 3);
4606 // Save only the upperleft cell in case of cell range. The geometry
4607 // of the 3rd parameter is taken from the 1st parameter.
4609 switch ( GetStackType() )
4616 PopDoubleRef( nCol3
, nRow3
, nTab3
, nColJunk
, nRowJunk
, nTabJunk
);
4617 if ( nTabJunk
!= nTab3
)
4619 SetError( errIllegalParameter
);
4625 PopSingleRef( nCol3
, nRow3
, nTab3
);
4628 pSumExtraMatrix
= PopMatrix();
4629 // nCol3, nRow3, nTab3 remain 0
4631 case svExternalSingleRef
:
4633 pSumExtraMatrix
= new ScMatrix(1, 1, 0.0);
4634 ScExternalRefCache::TokenRef pToken
;
4635 PopExternalSingleRef(pToken
);
4638 SetError( errIllegalParameter
);
4642 if (pToken
->GetType() == svDouble
)
4643 pSumExtraMatrix
->PutDouble(pToken
->GetDouble(), 0, 0);
4645 pSumExtraMatrix
->PutString(pToken
->GetString(), 0, 0);
4648 case svExternalDoubleRef
:
4649 PopExternalDoubleRef(pSumExtraMatrix
);
4652 SetError( errIllegalParameter
);
4657 svl::SharedString aString
;
4659 bool bIsString
= true;
4660 switch ( GetStackType() )
4666 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4669 ScRefCellValue aCell
;
4670 aCell
.assign(*pDok
, aAdr
);
4671 switch (aCell
.meType
)
4673 case CELLTYPE_VALUE
:
4674 fVal
= GetCellValue(aAdr
, aCell
);
4677 case CELLTYPE_FORMULA
:
4678 if (aCell
.mpFormula
->IsValue())
4680 fVal
= GetCellValue(aAdr
, aCell
);
4684 GetCellString(aString
, aCell
);
4686 case CELLTYPE_STRING
:
4687 case CELLTYPE_EDIT
:
4688 GetCellString(aString
, aCell
);
4697 aString
= GetString();
4700 case svExternalDoubleRef
:
4702 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
, aString
);
4703 bIsString
= ScMatrix::IsNonValueType( nType
);
4706 case svExternalSingleRef
:
4708 ScExternalRefCache::TokenRef pToken
;
4709 PopExternalSingleRef(pToken
);
4712 if (pToken
->GetType() == svDouble
)
4714 fVal
= pToken
->GetDouble();
4718 aString
= pToken
->GetString();
4732 double fCount
= 0.0;
4735 size_t nRefInList
= 0;
4736 while (nParam
-- > 0)
4744 ScMatrixRef pQueryMatrix
;
4745 switch ( GetStackType() )
4750 SetError( errIllegalParameter
);
4755 PopDoubleRef( aRange
, nParam
, nRefInList
);
4756 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4760 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4763 PopSingleRef( nCol1
, nRow1
, nTab1
);
4769 case svExternalSingleRef
:
4770 case svExternalDoubleRef
:
4772 pQueryMatrix
= GetMatrix();
4775 SetError( errIllegalParameter
);
4782 pQueryMatrix
->GetDimensions( nC
, nR
);
4783 nCol2
= static_cast<SCCOL
>(nC
- 1);
4784 nRow2
= static_cast<SCROW
>(nR
- 1);
4789 SetError( errIllegalParameter
);
4791 if ( nTab1
!= nTab2
)
4793 SetError( errIllegalParameter
);
4798 // Take the range geometry of the 1st parameter and apply it to
4799 // the 3rd. If parts of the resulting range would point outside
4800 // the sheet, don't complain but silently ignore and simply cut
4801 // them away, this is what Xcl does :-/
4803 // For the cut-away part we also don't need to determine the
4804 // criteria match, so shrink the source range accordingly,
4805 // instead of the result range.
4806 SCCOL nColDelta
= nCol2
- nCol1
;
4807 SCROW nRowDelta
= nRow2
- nRow1
;
4810 if (pSumExtraMatrix
)
4813 pSumExtraMatrix
->GetDimensions( nC
, nR
);
4814 nMaxCol
= static_cast<SCCOL
>(nC
- 1);
4815 nMaxRow
= static_cast<SCROW
>(nR
- 1);
4822 if (nCol3
+ nColDelta
> nMaxCol
)
4824 SCCOL nNewDelta
= nMaxCol
- nCol3
;
4825 nCol2
= nCol1
+ nNewDelta
;
4828 if (nRow3
+ nRowDelta
> nMaxRow
)
4830 SCROW nNewDelta
= nMaxRow
- nRow3
;
4831 nRow2
= nRow1
+ nNewDelta
;
4841 if (nGlobalError
== 0)
4843 ScQueryParam rParam
;
4844 rParam
.nRow1
= nRow1
;
4845 rParam
.nRow2
= nRow2
;
4847 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4848 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
4849 rEntry
.bDoQuery
= true;
4852 rItem
.meType
= ScQueryEntry::ByValue
;
4854 rEntry
.eOp
= SC_EQUAL
;
4858 rParam
.FillInExcelSyntax(pDok
->GetSharedStringPool(), aString
.getString(), 0, pFormatter
);
4859 if (rItem
.meType
== ScQueryEntry::ByString
)
4860 rParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
4863 aAdr
.SetTab( nTab3
);
4864 rParam
.nCol1
= nCol1
;
4865 rParam
.nCol2
= nCol2
;
4866 rEntry
.nField
= nCol1
;
4867 SCsCOL nColDiff
= nCol3
- nCol1
;
4868 SCsROW nRowDiff
= nRow3
- nRow1
;
4871 // Never case-sensitive.
4872 sc::CompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
4873 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
4874 if (nGlobalError
|| !pResultMatrix
)
4876 SetError( errIllegalParameter
);
4879 if (pSumExtraMatrix
)
4881 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4883 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4885 if (pResultMatrix
->IsValue( nCol
, nRow
) &&
4886 pResultMatrix
->GetDouble( nCol
, nRow
))
4888 SCSIZE nC
= nCol
+ nColDiff
;
4889 SCSIZE nR
= nRow
+ nRowDiff
;
4890 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4892 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4894 if ( bNull
&& fVal
!= 0.0 )
4908 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4910 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4912 if (pResultMatrix
->GetDouble( nCol
, nRow
))
4914 aAdr
.SetCol( nCol
+ nColDiff
);
4915 aAdr
.SetRow( nRow
+ nRowDiff
);
4916 ScRefCellValue aCell
;
4917 aCell
.assign(*pDok
, aAdr
);
4918 if (aCell
.hasNumeric())
4920 fVal
= GetCellValue(aAdr
, aCell
);
4922 if ( bNull
&& fVal
!= 0.0 )
4937 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
4938 // Increment Entry.nField in iterator when switching to next column.
4939 aCellIter
.SetAdvanceQueryParamEntryField( true );
4940 if ( aCellIter
.GetFirst() )
4942 if (pSumExtraMatrix
)
4946 SCSIZE nC
= aCellIter
.GetCol() + nColDiff
;
4947 SCSIZE nR
= aCellIter
.GetRow() + nRowDiff
;
4948 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4950 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4952 if ( bNull
&& fVal
!= 0.0 )
4960 } while ( aCellIter
.GetNext() );
4966 aAdr
.SetCol( aCellIter
.GetCol() + nColDiff
);
4967 aAdr
.SetRow( aCellIter
.GetRow() + nRowDiff
);
4968 ScRefCellValue aCell
;
4969 aCell
.assign(*pDok
, aAdr
);
4970 if (aCell
.hasNumeric())
4972 fVal
= GetCellValue(aAdr
, aCell
);
4974 if ( bNull
&& fVal
!= 0.0 )
4982 } while ( aCellIter
.GetNext() );
4989 SetError( errIllegalParameter
);
4996 case ifSUMIF
: fRes
= ::rtl::math::approxAdd( fSum
, fMem
); break;
4997 case ifAVERAGEIF
: fRes
= div( ::rtl::math::approxAdd( fSum
, fMem
), fCount
); break;
5002 void ScInterpreter::ScSumIf()
5004 PushDouble( IterateParametersIf( ifSUMIF
));
5007 void ScInterpreter::ScAverageIf()
5009 PushDouble( IterateParametersIf( ifAVERAGEIF
));
5012 void ScInterpreter::ScCountIf()
5014 if ( MustHaveParamCount( GetByte(), 2 ) )
5016 svl::SharedString aString
;
5018 bool bIsString
= true;
5019 switch ( GetStackType() )
5025 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5030 ScRefCellValue aCell
;
5031 aCell
.assign(*pDok
, aAdr
);
5032 switch (aCell
.meType
)
5034 case CELLTYPE_VALUE
:
5035 fVal
= GetCellValue(aAdr
, aCell
);
5038 case CELLTYPE_FORMULA
:
5039 if (aCell
.mpFormula
->IsValue())
5041 fVal
= GetCellValue(aAdr
, aCell
);
5045 GetCellString(aString
, aCell
);
5047 case CELLTYPE_STRING
:
5048 case CELLTYPE_EDIT
:
5049 GetCellString(aString
, aCell
);
5058 case svExternalSingleRef
:
5059 case svExternalDoubleRef
:
5061 ScMatValType nType
= GetDoubleOrStringFromMatrix(fVal
, aString
);
5062 bIsString
= ScMatrix::IsNonValueType( nType
);
5066 aString
= GetString();
5074 double fCount
= 0.0;
5076 size_t nRefInList
= 0;
5077 while (nParam
-- > 0)
5085 ScMatrixRef pQueryMatrix
;
5086 switch ( GetStackType() )
5092 PopDoubleRef( aRange
, nParam
, nRefInList
);
5093 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5097 PopSingleRef( nCol1
, nRow1
, nTab1
);
5103 case svExternalSingleRef
:
5104 case svExternalDoubleRef
:
5106 pQueryMatrix
= GetMatrix();
5109 PushIllegalParameter();
5116 pQueryMatrix
->GetDimensions( nC
, nR
);
5117 nCol2
= static_cast<SCCOL
>(nC
- 1);
5118 nRow2
= static_cast<SCROW
>(nR
- 1);
5123 PushIllegalParameter();
5126 if ( nTab1
!= nTab2
)
5128 PushIllegalParameter();
5133 PushIllegalParameter();
5136 if (nGlobalError
== 0)
5138 ScQueryParam rParam
;
5139 rParam
.nRow1
= nRow1
;
5140 rParam
.nRow2
= nRow2
;
5142 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5143 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
5144 rEntry
.bDoQuery
= true;
5147 rItem
.meType
= ScQueryEntry::ByValue
;
5149 rEntry
.eOp
= SC_EQUAL
;
5153 rParam
.FillInExcelSyntax(pDok
->GetSharedStringPool(), aString
.getString(), 0, pFormatter
);
5154 if (rItem
.meType
== ScQueryEntry::ByString
)
5155 rParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
5157 rParam
.nCol1
= nCol1
;
5158 rParam
.nCol2
= nCol2
;
5159 rEntry
.nField
= nCol1
;
5162 // Never case-sensitive.
5163 sc::CompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
5164 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
5165 if (nGlobalError
|| !pResultMatrix
)
5167 PushIllegalParameter();
5171 SCSIZE nSize
= pResultMatrix
->GetElementCount();
5172 for (SCSIZE nIndex
= 0; nIndex
< nSize
; ++nIndex
)
5174 if (pResultMatrix
->IsValue( nIndex
) &&
5175 pResultMatrix
->GetDouble( nIndex
))
5181 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
5182 // Keep Entry.nField in iterator on column change
5183 aCellIter
.SetAdvanceQueryParamEntryField( true );
5184 if ( aCellIter
.GetFirst() )
5189 } while ( aCellIter
.GetNext() );
5195 PushIllegalParameter();
5203 double ScInterpreter::IterateParametersIfs( ScIterFuncIfs eFunc
)
5205 sal_uInt8 nParamCount
= GetByte();
5206 sal_uInt8 nQueryCount
= nParamCount
/ 2;
5209 if ( eFunc
== ifCOUNTIFS
)
5210 bCheck
= (nParamCount
>= 2) && (nParamCount
% 2 == 0);
5212 bCheck
= (nParamCount
>= 3) && (nParamCount
% 2 == 1);
5216 SetError( errParameterExpected
);
5220 std::vector
<sal_uInt8
> aResArray
;
5221 size_t nRowSize
= 0;
5222 size_t nColSize
= 0;
5227 double fCount
= 0.0;
5229 size_t nRefInList
= 0;
5230 SCCOL nDimensionCols
= 0;
5231 SCROW nDimensionRows
= 0;
5233 while (nParamCount
> 1 && !nGlobalError
)
5236 svl::SharedString aString
;
5238 bool bIsString
= true;
5239 switch ( GetStackType() )
5245 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5248 ScRefCellValue aCell
;
5249 aCell
.assign(*pDok
, aAdr
);
5250 switch (aCell
.meType
)
5252 case CELLTYPE_VALUE
:
5253 fVal
= GetCellValue(aAdr
, aCell
);
5256 case CELLTYPE_FORMULA
:
5257 if (aCell
.mpFormula
->IsValue())
5259 fVal
= GetCellValue(aAdr
, aCell
);
5263 GetCellString(aString
, aCell
);
5265 case CELLTYPE_STRING
:
5266 case CELLTYPE_EDIT
:
5267 GetCellString(aString
, aCell
);
5276 aString
= GetString();
5279 case svExternalDoubleRef
:
5281 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
, aString
);
5282 bIsString
= ScMatrix::IsNonValueType( nType
);
5285 case svExternalSingleRef
:
5287 ScExternalRefCache::TokenRef pToken
;
5288 PopExternalSingleRef(pToken
);
5291 if (pToken
->GetType() == svDouble
)
5293 fVal
= pToken
->GetDouble();
5297 aString
= pToken
->GetString();
5309 return 0; // and bail out, no need to evaluate other arguments
5320 ScMatrixRef pQueryMatrix
;
5321 switch ( GetStackType() )
5326 PopDoubleRef( aRange
, nParam
, nRefInList
);
5327 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5331 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5334 PopSingleRef( nCol1
, nRow1
, nTab1
);
5340 case svExternalSingleRef
:
5341 case svExternalDoubleRef
:
5343 pQueryMatrix
= PopMatrix();
5346 SetError( errIllegalParameter
);
5353 pQueryMatrix
->GetDimensions( nC
, nR
);
5354 nCol2
= static_cast<SCCOL
>(nC
- 1);
5355 nRow2
= static_cast<SCROW
>(nR
- 1);
5360 SetError( errIllegalParameter
);
5363 if ( nTab1
!= nTab2
)
5365 SetError( errIllegalArgument
);
5369 // All reference ranges must be of same dimension and size.
5370 if (!nDimensionCols
)
5371 nDimensionCols
= nCol2
- nCol1
+ 1;
5372 if (!nDimensionRows
)
5373 nDimensionRows
= nRow2
- nRow1
+ 1;
5374 if ((nDimensionCols
!= (nCol2
- nCol1
+ 1)) || (nDimensionRows
!= (nRow2
- nRow1
+ 1)))
5376 SetError ( errIllegalArgument
);
5380 // recalculate matrix values
5384 // initialize temporary result matrix
5385 if (aResArray
.empty())
5387 nColSize
= nCol2
- nCol1
+ 1;
5388 nRowSize
= nRow2
- nRow1
+ 1;
5389 aResArray
.resize(nColSize
*nRowSize
, 0);
5392 ScQueryParam rParam
;
5393 rParam
.nRow1
= nRow1
;
5394 rParam
.nRow2
= nRow2
;
5396 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5397 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
5398 rEntry
.bDoQuery
= true;
5401 rItem
.meType
= ScQueryEntry::ByValue
;
5403 rEntry
.eOp
= SC_EQUAL
;
5407 rParam
.FillInExcelSyntax(pDok
->GetSharedStringPool(), aString
.getString(), 0, pFormatter
);
5408 if (rItem
.meType
== ScQueryEntry::ByString
)
5409 rParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
5412 aAdr
.SetTab( nTab1
);
5413 rParam
.nCol1
= nCol1
;
5414 rParam
.nCol2
= nCol2
;
5415 rEntry
.nField
= nCol1
;
5416 SCsCOL nColDiff
= -nCol1
;
5417 SCsROW nRowDiff
= -nRow1
;
5420 // Never case-sensitive.
5421 sc::CompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
5422 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
5423 if (nGlobalError
|| !pResultMatrix
)
5425 SetError( errIllegalParameter
);
5429 // result matrix is filled with boolean values.
5430 std::vector
<double> aResValues
;
5431 pResultMatrix
->GetDoubleArray(aResValues
, true);
5432 if (aResArray
.size() != aResValues
.size())
5434 SetError( errIllegalParameter
);
5438 std::vector
<sal_uInt8
>::iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5439 std::vector
<double>::const_iterator itThisRes
= aResValues
.begin();
5440 for (; itRes
!= itResEnd
; ++itRes
, ++itThisRes
)
5441 *itRes
+= *itThisRes
;
5445 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
5446 // Increment Entry.nField in iterator when switching to next column.
5447 aCellIter
.SetAdvanceQueryParamEntryField( true );
5448 if ( aCellIter
.GetFirst() )
5452 size_t nC
= aCellIter
.GetCol() + nColDiff
;
5453 size_t nR
= aCellIter
.GetRow() + nRowDiff
;
5454 ++aResArray
[nC
*nRowSize
+nR
];
5455 } while ( aCellIter
.GetNext() );
5462 return 0; // bail out
5464 // main range - only for AVERAGEIFS and SUMIFS
5465 if (nParamCount
== 1)
5470 SCCOL nMainCol1
= 0;
5471 SCROW nMainRow1
= 0;
5472 SCTAB nMainTab1
= 0;
5473 SCCOL nMainCol2
= 0;
5474 SCROW nMainRow2
= 0;
5475 SCTAB nMainTab2
= 0;
5476 ScMatrixRef pMainMatrix
;
5477 switch ( GetStackType() )
5482 PopDoubleRef( aRange
, nParam
, nRefInList
);
5483 aRange
.GetVars( nMainCol1
, nMainRow1
, nMainTab1
, nMainCol2
, nMainRow2
, nMainTab2
);
5487 PopDoubleRef( nMainCol1
, nMainRow1
, nMainTab1
, nMainCol2
, nMainRow2
, nMainTab2
);
5490 PopSingleRef( nMainCol1
, nMainRow1
, nMainTab1
);
5491 nMainCol2
= nMainCol1
;
5492 nMainRow2
= nMainRow1
;
5493 nMainTab2
= nMainTab1
;
5496 case svExternalSingleRef
:
5497 case svExternalDoubleRef
:
5499 pMainMatrix
= PopMatrix();
5502 SetError( errIllegalParameter
);
5509 pMainMatrix
->GetDimensions( nC
, nR
);
5510 nMainCol2
= static_cast<SCCOL
>(nC
- 1);
5511 nMainRow2
= static_cast<SCROW
>(nR
- 1);
5516 SetError( errIllegalParameter
);
5519 if ( nMainTab1
!= nMainTab2
)
5521 SetError( errIllegalArgument
);
5525 // All reference ranges must be of same dimension and size.
5526 if ((nDimensionCols
!= (nMainCol2
- nMainCol1
+ 1)) || (nDimensionRows
!= (nMainRow2
- nMainRow1
+ 1)))
5528 SetError ( errIllegalArgument
);
5533 return 0; // bail out
5535 // end-result calculation
5537 aAdr
.SetTab( nMainTab1
);
5540 std::vector
<double> aMainValues
;
5541 pMainMatrix
->GetDoubleArray(aMainValues
, false); // Map empty values to NaN's.
5542 if (aResArray
.size() != aMainValues
.size())
5544 SetError( errIllegalArgument
);
5548 std::vector
<sal_uInt8
>::const_iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5549 std::vector
<double>::const_iterator itMain
= aMainValues
.begin();
5550 for (; itRes
!= itResEnd
; ++itRes
, ++itMain
)
5552 if (*itRes
!= nQueryCount
)
5556 if (GetDoubleErrorValue(fVal
) == errElementNaN
)
5560 if (bNull
&& fVal
!= 0.0)
5571 std::vector
<sal_uInt8
>::const_iterator itRes
= aResArray
.begin();
5572 for (size_t nCol
= 0; nCol
< nColSize
; ++nCol
)
5574 for (size_t nRow
= 0; nRow
< nRowSize
; ++nRow
, ++itRes
)
5576 if (*itRes
== nQueryCount
)
5578 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) + nMainCol1
);
5579 aAdr
.SetRow( static_cast<SCROW
>(nRow
) + nMainRow1
);
5580 ScRefCellValue aCell
;
5581 aCell
.assign(*pDok
, aAdr
);
5582 if (aCell
.hasNumeric())
5584 fVal
= GetCellValue(aAdr
, aCell
);
5586 if ( bNull
&& fVal
!= 0.0 )
5601 std::vector
<sal_uInt8
>::const_iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5602 for (; itRes
!= itResEnd
; ++itRes
)
5603 if (*itRes
== nQueryCount
)
5609 case ifSUMIFS
: fRes
= ::rtl::math::approxAdd( fSum
, fMem
); break;
5610 case ifAVERAGEIFS
: fRes
= div( ::rtl::math::approxAdd( fSum
, fMem
), fCount
); break;
5611 case ifCOUNTIFS
: fRes
= fCount
; break;
5612 default: ; // nothing
5619 void ScInterpreter::ScSumIfs()
5621 PushDouble( IterateParametersIfs( ifSUMIFS
));
5624 void ScInterpreter::ScAverageIfs()
5626 PushDouble( IterateParametersIfs( ifAVERAGEIFS
));
5629 void ScInterpreter::ScCountIfs()
5631 PushDouble( IterateParametersIfs( ifCOUNTIFS
));
5634 void ScInterpreter::ScLookup()
5636 sal_uInt8 nParamCount
= GetByte();
5637 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
5640 ScMatrixRef pDataMat
= NULL
, pResMat
= NULL
;
5641 SCCOL nCol1
= 0, nCol2
= 0, nResCol1
= 0, nResCol2
= 0;
5642 SCROW nRow1
= 0, nRow2
= 0, nResRow1
= 0, nResRow2
= 0;
5643 SCTAB nTab1
= 0, nResTab
= 0;
5644 SCSIZE nLenMajor
= 0; // length of major direction
5645 bool bVertical
= true; // whether to lookup vertically or horizontally
5647 // The third parameter, result array, for double, string and single reference.
5648 double fResVal
= 0.0;
5649 svl::SharedString aResStr
;
5651 StackVar eResArrayType
= svUnknown
;
5653 if (nParamCount
== 3)
5655 eResArrayType
= GetStackType();
5656 switch (eResArrayType
)
5661 PopDoubleRef(nResCol1
, nResRow1
, nResTab
,
5662 nResCol2
, nResRow2
, nTabJunk
);
5663 if (nResTab
!= nTabJunk
||
5664 ((nResRow2
- nResRow1
) > 0 && (nResCol2
- nResCol1
) > 0))
5666 // The result array must be a vector.
5667 PushIllegalParameter();
5673 case svExternalSingleRef
:
5674 case svExternalDoubleRef
:
5676 pResMat
= GetMatrix();
5679 PushIllegalParameter();
5683 pResMat
->GetDimensions(nC
, nR
);
5684 if (nC
!= 1 && nR
!= 1)
5686 // Result matrix must be a vector.
5687 PushIllegalParameter();
5693 fResVal
= GetDouble();
5696 aResStr
= GetString();
5699 PopSingleRef( aResAdr
);
5702 PushIllegalParameter();
5707 // For double, string and single reference.
5708 double fDataVal
= 0.0;
5709 svl::SharedString aDataStr
;
5711 bool bValueData
= false;
5713 // Get the data-result range and also determine whether this is vertical
5714 // lookup or horizontal lookup.
5716 StackVar eDataArrayType
= GetStackType();
5717 switch (eDataArrayType
)
5722 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTabJunk
);
5723 if (nTab1
!= nTabJunk
)
5725 PushIllegalParameter();
5728 bVertical
= (nRow2
- nRow1
) >= (nCol2
- nCol1
);
5729 nLenMajor
= bVertical
? nRow2
- nRow1
+ 1 : nCol2
- nCol1
+ 1;
5733 case svExternalSingleRef
:
5734 case svExternalDoubleRef
:
5736 pDataMat
= GetMatrix();
5739 PushIllegalParameter();
5744 pDataMat
->GetDimensions(nC
, nR
);
5745 bVertical
= (nR
>= nC
);
5746 nLenMajor
= bVertical
? nR
: nC
;
5751 fDataVal
= GetDouble();
5757 aDataStr
= GetString();
5762 PopSingleRef( aDataAdr
);
5763 ScRefCellValue aCell
;
5764 aCell
.assign(*pDok
, aDataAdr
);
5765 if (aCell
.hasEmptyValue())
5767 // Empty cells aren't found anywhere, bail out early.
5768 SetError( NOTAVAILABLE
);
5770 else if (aCell
.hasNumeric())
5772 fDataVal
= GetCellValue(aDataAdr
, aCell
);
5776 GetCellString(aDataStr
, aCell
);
5780 SetError( errIllegalParameter
);
5785 PushError( nGlobalError
);
5789 // Get the lookup value.
5791 ScQueryParam aParam
;
5792 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
5793 if ( !FillEntry(rEntry
) )
5796 if ( eDataArrayType
== svDouble
|| eDataArrayType
== svString
||
5797 eDataArrayType
== svSingleRef
)
5799 // Delta position for a single value is always 0.
5801 // Found if data <= query, but not if query is string and found data is
5802 // numeric or vice versa. This is how Excel does it but doesn't
5805 bool bFound
= false;
5806 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
5810 if (rItem
.meType
== ScQueryEntry::ByString
)
5813 bFound
= (fDataVal
<= rItem
.mfVal
);
5817 if (rItem
.meType
!= ScQueryEntry::ByString
)
5820 bFound
= (ScGlobal::GetCollator()->compareString(aDataStr
.getString(), rItem
.maString
.getString()) <= 0);
5831 if (pResMat
->IsValue( 0, 0 ))
5832 PushDouble(pResMat
->GetDouble( 0, 0 ));
5834 PushString(pResMat
->GetString(0, 0));
5836 else if (nParamCount
== 3)
5838 switch (eResArrayType
)
5841 PushDouble( fResVal
);
5844 PushString( aResStr
);
5847 aResAdr
.Set( nResCol1
, nResRow1
, nResTab
);
5850 PushCellResultToken( true, aResAdr
, NULL
, NULL
);
5853 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
5858 switch (eDataArrayType
)
5861 PushDouble( fDataVal
);
5864 PushString( aDataStr
);
5867 PushCellResultToken( true, aDataAdr
, NULL
, NULL
);
5870 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
5876 // Now, perform the search to compute the delta position (nDelta).
5880 // Data array is given as a matrix.
5881 rEntry
.bDoQuery
= true;
5882 rEntry
.eOp
= SC_LESS_EQUAL
;
5883 bool bFound
= false;
5886 pDataMat
->GetDimensions(nC
, nR
);
5888 // In case of non-vector matrix, only search the first row or column.
5889 ScMatrixRef pDataMat2
;
5892 ScMatrixRef
pTempMat(new ScMatrix(1, nR
, 0.0));
5893 for (SCSIZE i
= 0; i
< nR
; ++i
)
5894 if (pDataMat
->IsValue(0, i
))
5895 pTempMat
->PutDouble(pDataMat
->GetDouble(0, i
), 0, i
);
5897 pTempMat
->PutString(pDataMat
->GetString(0, i
), 0, i
);
5898 pDataMat2
= pTempMat
;
5902 ScMatrixRef
pTempMat(new ScMatrix(nC
, 1, 0.0));
5903 for (SCSIZE i
= 0; i
< nC
; ++i
)
5904 if (pDataMat
->IsValue(i
, 0))
5905 pTempMat
->PutDouble(pDataMat
->GetDouble(i
, 0), i
, 0);
5907 pTempMat
->PutString(pDataMat
->GetString(i
, 0), i
, 0);
5908 pDataMat2
= pTempMat
;
5911 VectorMatrixAccessor
aMatAcc2(*pDataMat2
, bVertical
);
5913 // binary search for non-equality mode (the source data is
5914 // assumed to be sorted in ascending order).
5916 SCCOLROW nDelta
= -1;
5918 SCSIZE nFirst
= 0, nLast
= nLenMajor
-1; //, nHitIndex = 0;
5919 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
5921 SCSIZE nMid
= nFirst
+ nLen
/2;
5922 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, aMatAcc2
, rEntry
);
5925 // exact match. find the last item with the same value.
5926 lcl_GetLastMatch( nMid
, aMatAcc2
, nLenMajor
, false);
5932 if (nLen
== 1) // first and last items are next to each other.
5934 nDelta
= nCmp
< 0 ? nLast
- 1 : nFirst
- 1;
5935 // If already the 1st item is greater there's nothing found.
5936 bFound
= (nDelta
>= 0);
5946 if (nDelta
== static_cast<SCCOLROW
>(nLenMajor
-2)) // last item
5948 sal_Int32 nCmp
= lcl_CompareMatrix2Query(nDelta
+1, aMatAcc2
, rEntry
);
5951 // either the last item is an exact match or the real
5952 // hit is beyond the last item.
5957 else if (nDelta
> 0) // valid hit must be 2nd item or higher
5963 // With 0-9 < A-Z, if query is numeric and data found is string, or
5964 // vice versa, the (yet another undocumented) Excel behavior is to
5965 // return #N/A instead.
5969 VectorMatrixAccessor
aMatAcc(*pDataMat
, bVertical
);
5970 SCCOLROW i
= nDelta
;
5971 SCSIZE n
= aMatAcc
.GetElementCount();
5972 if (static_cast<SCSIZE
>(i
) >= n
)
5973 i
= static_cast<SCCOLROW
>(n
);
5974 bool bByString
= rEntry
.GetQueryItem().meType
== ScQueryEntry::ByString
;
5975 if (bByString
== aMatAcc
.IsValue(i
))
5985 // Now that we've found the delta, push the result back to the cell.
5989 VectorMatrixAccessor
aResMatAcc(*pResMat
, bVertical
);
5990 // result array is matrix.
5991 if (static_cast<SCSIZE
>(nDelta
) >= aResMatAcc
.GetElementCount())
5996 if (aResMatAcc
.IsValue(nDelta
))
5997 PushDouble(aResMatAcc
.GetDouble(nDelta
));
5999 PushString(aResMatAcc
.GetString(nDelta
));
6001 else if (nParamCount
== 3)
6003 // result array is cell range.
6005 aAdr
.SetTab(nResTab
);
6006 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
6009 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
6010 if (nTempRow
> MAXROW
)
6015 aAdr
.SetCol(nResCol1
);
6016 aAdr
.SetRow(nTempRow
);
6020 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
6021 if (nTempCol
> MAXCOL
)
6026 aAdr
.SetCol(nTempCol
);
6027 aAdr
.SetRow(nResRow1
);
6029 PushCellResultToken(true, aAdr
, NULL
, NULL
);
6033 // no result array. Use the data array to get the final value from.
6036 if (pDataMat
->IsValue(nC
-1, nDelta
))
6037 PushDouble(pDataMat
->GetDouble(nC
-1, nDelta
));
6039 PushString(pDataMat
->GetString(nC
-1, nDelta
));
6043 if (pDataMat
->IsValue(nDelta
, nR
-1))
6044 PushDouble(pDataMat
->GetDouble(nDelta
, nR
-1));
6046 PushString(pDataMat
->GetString(nDelta
, nR
-1));
6053 // Perform cell range search.
6055 aParam
.nCol1
= nCol1
;
6056 aParam
.nRow1
= nRow1
;
6057 aParam
.nCol2
= bVertical
? nCol1
: nCol2
;
6058 aParam
.nRow2
= bVertical
? nRow2
: nRow1
;
6059 aParam
.bByRow
= bVertical
;
6061 rEntry
.bDoQuery
= true;
6062 rEntry
.eOp
= SC_LESS_EQUAL
;
6063 rEntry
.nField
= nCol1
;
6064 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6065 if (rItem
.meType
== ScQueryEntry::ByString
)
6066 aParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
6068 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, false);
6071 // Advance Entry.nField in iterator upon switching columns if
6073 aCellIter
.SetAdvanceQueryParamEntryField(!bVertical
);
6074 if ( !aCellIter
.FindEqualOrSortedLastInRange(nC
, nR
) )
6080 SCCOLROW nDelta
= bVertical
? static_cast<SCSIZE
>(nR
-nRow1
) : static_cast<SCSIZE
>(nC
-nCol1
);
6084 VectorMatrixAccessor
aResMatAcc(*pResMat
, bVertical
);
6085 // Use the matrix result array.
6086 if (aResMatAcc
.IsValue(nDelta
))
6087 PushDouble(aResMatAcc
.GetDouble(nDelta
));
6089 PushString(aResMatAcc
.GetString(nDelta
));
6091 else if (nParamCount
== 3)
6093 switch (eResArrayType
)
6097 // Use the result array vector. Note that the result array is assumed
6098 // to be a vector (i.e. 1-dimensinoal array).
6101 aAdr
.SetTab(nResTab
);
6102 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
6105 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
6106 if (nTempRow
> MAXROW
)
6111 aAdr
.SetCol(nResCol1
);
6112 aAdr
.SetRow(nTempRow
);
6116 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
6117 if (nTempCol
> MAXCOL
)
6122 aAdr
.SetCol(nTempCol
);
6123 aAdr
.SetRow(nResRow1
);
6125 PushCellResultToken( true, aAdr
, NULL
, NULL
);
6136 switch (eResArrayType
)
6139 PushDouble( fResVal
);
6142 PushString( aResStr
);
6145 PushCellResultToken( true, aResAdr
, NULL
, NULL
);
6154 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
6159 // Regardless of whether or not the result array exists, the last
6160 // array is always used as the "result" array.
6166 SCROW nTempRow
= static_cast<SCROW
>(nRow1
+ nDelta
);
6167 if (nTempRow
> MAXROW
)
6173 aAdr
.SetRow(nTempRow
);
6177 SCCOL nTempCol
= static_cast<SCCOL
>(nCol1
+ nDelta
);
6178 if (nTempCol
> MAXCOL
)
6183 aAdr
.SetCol(nTempCol
);
6186 PushCellResultToken(true, aAdr
, NULL
, NULL
);
6190 void ScInterpreter::ScHLookup()
6192 CalculateLookup(true);
6195 void ScInterpreter::CalculateLookup(bool bHLookup
)
6197 sal_uInt8 nParamCount
= GetByte();
6198 if (!MustHaveParamCount(nParamCount
, 3, 4))
6201 // Optional 4th argument to declare whether or not the range is sorted.
6202 bool bSorted
= true;
6203 if (nParamCount
== 4)
6204 bSorted
= GetBool();
6206 // Index of column to search.
6207 double fIndex
= ::rtl::math::approxFloor( GetDouble() ) - 1.0;
6209 ScMatrixRef pMat
= NULL
;
6210 SCSIZE nC
= 0, nR
= 0;
6217 StackVar eType
= GetStackType();
6218 if (eType
== svDoubleRef
)
6220 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6223 PushIllegalParameter();
6227 else if (eType
== svSingleRef
)
6229 PopSingleRef(nCol1
, nRow1
, nTab1
);
6233 else if (eType
== svMatrix
|| eType
== svExternalDoubleRef
|| eType
== svExternalSingleRef
)
6238 pMat
->GetDimensions(nC
, nR
);
6241 PushIllegalParameter();
6247 PushIllegalParameter();
6251 if ( fIndex
< 0.0 || (bHLookup
? (pMat
? (fIndex
>= nR
) : (fIndex
+nRow1
> nRow2
)) : (pMat
? (fIndex
>= nC
) : (fIndex
+nCol1
> nCol2
)) ) )
6253 PushIllegalArgument();
6257 SCROW nZIndex
= static_cast<SCROW
>(fIndex
);
6258 SCCOL nSpIndex
= static_cast<SCCOL
>(fIndex
);
6262 nZIndex
+= nRow1
; // Wertzeile
6263 nSpIndex
= sal::static_int_cast
<SCCOL
>( nSpIndex
+ nCol1
); // value column
6268 PushIllegalParameter();
6272 ScQueryParam aParam
;
6273 aParam
.nCol1
= nCol1
;
6274 aParam
.nRow1
= nRow1
;
6277 aParam
.nCol2
= nCol2
;
6278 aParam
.nRow2
= nRow1
; // nur in der ersten Zeile suchen
6279 aParam
.bByRow
= false;
6283 aParam
.nCol2
= nCol1
; // nur in der ersten Spalte suchen
6284 aParam
.nRow2
= nRow2
;
6285 aParam
.nTab
= nTab1
;
6288 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
6289 rEntry
.bDoQuery
= true;
6291 rEntry
.eOp
= SC_LESS_EQUAL
;
6292 if ( !FillEntry(rEntry
) )
6295 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6296 if (rItem
.meType
== ScQueryEntry::ByString
)
6297 aParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
6300 SCSIZE nMatCount
= bHLookup
? nC
: nR
;
6301 SCSIZE nDelta
= SCSIZE_MAX
;
6302 if (rItem
.meType
== ScQueryEntry::ByString
)
6305 //TODO: enable regex on matrix strings
6307 svl::SharedString aParamStr
= rItem
.maString
;
6310 static CollatorWrapper
* pCollator
= ScGlobal::GetCollator();
6311 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6313 if (bHLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
6316 pCollator
->compareString(
6317 bHLookup
? pMat
->GetString(i
,0).getString() : pMat
->GetString(0,i
).getString(), aParamStr
.getString());
6320 else if (i
>0) // #i2168# ignore first mismatch
6331 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6333 if (pMat
->IsString(i
, 0))
6335 if (pMat
->GetString(i
,0).getDataIgnoreCase() == aParamStr
.getDataIgnoreCase())
6345 nDelta
= pMat
->MatchStringInColumns(aParamStr
, 0, 0);
6353 // #i2168# ignore strings
6354 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6356 if (!(bHLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
6358 if ((bHLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) <= rItem
.mfVal
)
6369 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6371 if (! pMat
->IsString(i
, 0) )
6373 if ( pMat
->GetDouble(i
,0) == rItem
.mfVal
)
6383 nDelta
= pMat
->MatchDoubleInColumns(rItem
.mfVal
, 0, 0);
6387 if ( nDelta
!= SCSIZE_MAX
)
6389 SCSIZE nX
= static_cast<SCSIZE
>(nSpIndex
);
6394 nY
= static_cast<SCSIZE
>(nZIndex
);
6396 if ( pMat
->IsString( nX
, nY
) )
6397 PushString(pMat
->GetString( nX
,nY
).getString());
6399 PushDouble(pMat
->GetDouble( nX
,nY
));
6406 rEntry
.nField
= nCol1
;
6407 bool bFound
= false;
6411 rEntry
.eOp
= SC_LESS_EQUAL
;
6414 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, false);
6415 // advance Entry.nField in Iterator upon switching columns
6416 aCellIter
.SetAdvanceQueryParamEntryField( true );
6420 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow1_temp
);
6422 else if ( aCellIter
.GetFirst() )
6425 nCol
= aCellIter
.GetCol();
6431 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
6432 bFound
= LookupQueryWithCache( aResultPos
, aParam
);
6433 nRow
= aResultPos
.Row();
6439 ScAddress
aAdr( nCol
, nRow
, nTab1
);
6440 PushCellResultToken( true, aAdr
, NULL
, NULL
);
6447 bool ScInterpreter::FillEntry(ScQueryEntry
& rEntry
)
6449 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6450 switch ( GetStackType() )
6454 rItem
.meType
= ScQueryEntry::ByValue
;
6455 rItem
.mfVal
= GetDouble();
6460 rItem
.meType
= ScQueryEntry::ByString
;
6461 rItem
.maString
= GetString();
6468 if ( !PopDoubleRefOrSingleRef( aAdr
) )
6473 ScRefCellValue aCell
;
6474 aCell
.assign(*pDok
, aAdr
);
6475 if (aCell
.hasNumeric())
6477 rItem
.meType
= ScQueryEntry::ByValue
;
6478 rItem
.mfVal
= GetCellValue(aAdr
, aCell
);
6482 GetCellString(rItem
.maString
, aCell
);
6483 rItem
.meType
= ScQueryEntry::ByString
;
6489 svl::SharedString aStr
;
6490 const ScMatValType nType
= GetDoubleOrStringFromMatrix(rItem
.mfVal
, aStr
);
6491 rItem
.maString
= aStr
;
6492 rItem
.meType
= ScMatrix::IsNonValueType(nType
) ?
6493 ScQueryEntry::ByString
: ScQueryEntry::ByValue
;
6498 PushIllegalParameter();
6501 } // switch ( GetStackType() )
6504 void ScInterpreter::ScVLookup()
6506 CalculateLookup(false);
6509 void ScInterpreter::ScSubTotal()
6511 sal_uInt8 nParamCount
= GetByte();
6512 if ( MustHaveParamCountMin( nParamCount
, 2 ) )
6514 // We must fish the 1st parameter deep from the stack! And push it on top.
6515 const FormulaToken
* p
= pStack
[ sp
- nParamCount
];
6516 PushTempToken( *p
);
6517 int nFunc
= (int) ::rtl::math::approxFloor( GetDouble() );
6518 mnSubTotalFlags
|= SUBTOTAL_IGN_NESTED_ST_AG
| SUBTOTAL_IGN_FILTERED
;
6521 // For opcodes 101 through 111, we need to skip hidden cells.
6522 // Other than that these opcodes are identical to 1 through 11.
6523 mnSubTotalFlags
|= SUBTOTAL_IGN_HIDDEN
;
6527 if ( nFunc
< 1 || nFunc
> 11 )
6528 PushIllegalArgument(); // simulate return on stack, not SetError(...)
6531 cPar
= nParamCount
- 1;
6534 case SUBTOTAL_FUNC_AVE
: ScAverage(); break;
6535 case SUBTOTAL_FUNC_CNT
: ScCount(); break;
6536 case SUBTOTAL_FUNC_CNT2
: ScCount2(); break;
6537 case SUBTOTAL_FUNC_MAX
: ScMax(); break;
6538 case SUBTOTAL_FUNC_MIN
: ScMin(); break;
6539 case SUBTOTAL_FUNC_PROD
: ScProduct(); break;
6540 case SUBTOTAL_FUNC_STD
: ScStDev(); break;
6541 case SUBTOTAL_FUNC_STDP
: ScStDevP(); break;
6542 case SUBTOTAL_FUNC_SUM
: ScSum(); break;
6543 case SUBTOTAL_FUNC_VAR
: ScVar(); break;
6544 case SUBTOTAL_FUNC_VARP
: ScVarP(); break;
6545 default : PushIllegalArgument(); break;
6548 mnSubTotalFlags
= 0x00;
6549 // Get rid of the 1st (fished) parameter.
6550 double nVal
= GetDouble();
6556 void ScInterpreter::ScAggregate()
6558 sal_uInt8 nParamCount
= GetByte();
6559 if ( MustHaveParamCountMin( nParamCount
, 3 ) )
6561 // fish the 1st parameter from the stack and push it on top.
6562 const FormulaToken
* p
= pStack
[ sp
- nParamCount
];
6563 PushTempToken( *p
);
6564 int nFunc
= ( int ) ::rtl::math::approxFloor( GetDouble() );
6565 // fish the 2nd parameter from the stack and push it on top.
6566 const FormulaToken
* p2
= pStack
[ sp
- ( nParamCount
- 1 ) ];
6567 PushTempToken( *p2
);
6568 int nOption
= ( int ) ::rtl::math::approxFloor( GetDouble() );
6570 if ( nFunc
< 1 || nFunc
> 19 )
6571 PushIllegalArgument();
6576 case 0 : // ignore nested SUBTOTAL and AGGREGATE functions
6577 mnSubTotalFlags
= SUBTOTAL_IGN_NESTED_ST_AG
;
6579 case 1 : // ignore hidden rows, nested SUBTOTAL and AGGREGATE functions
6580 mnSubTotalFlags
= SUBTOTAL_IGN_HIDDEN
| SUBTOTAL_IGN_NESTED_ST_AG
;
6582 case 2 : // ignore error values, nested SUBTOTAL and AGGREGATE functions
6583 mnSubTotalFlags
= SUBTOTAL_IGN_ERR_VAL
| SUBTOTAL_IGN_NESTED_ST_AG
;
6585 case 3 : // ignore hidden rows, error values, nested SUBTOTAL and AGGREGATE functions
6586 mnSubTotalFlags
= SUBTOTAL_IGN_HIDDEN
| SUBTOTAL_IGN_ERR_VAL
| SUBTOTAL_IGN_NESTED_ST_AG
;
6588 case 4 : // ignore nothing
6589 mnSubTotalFlags
= 0x00;
6591 case 5 : // ignore hidden rows
6592 mnSubTotalFlags
= SUBTOTAL_IGN_HIDDEN
;
6594 case 6 : // ignore error values
6595 mnSubTotalFlags
= SUBTOTAL_IGN_ERR_VAL
;
6597 case 7 : // ignore hidden rows and error values
6598 mnSubTotalFlags
= SUBTOTAL_IGN_HIDDEN
| SUBTOTAL_IGN_ERR_VAL
;
6601 PushIllegalArgument();
6605 cPar
= nParamCount
- 2;
6608 case SUBTOTAL_FUNC_AVE
: ScAverage(); break;
6609 case SUBTOTAL_FUNC_CNT
: ScCount(); break;
6610 case SUBTOTAL_FUNC_CNT2
: ScCount2(); break;
6611 case SUBTOTAL_FUNC_MAX
: ScMax(); break;
6612 case SUBTOTAL_FUNC_MIN
: ScMin(); break;
6613 case SUBTOTAL_FUNC_PROD
: ScProduct(); break;
6614 case SUBTOTAL_FUNC_STD
: ScStDev(); break;
6615 case SUBTOTAL_FUNC_STDP
: ScStDevP(); break;
6616 case SUBTOTAL_FUNC_SUM
: ScSum(); break;
6617 case SUBTOTAL_FUNC_VAR
: ScVar(); break;
6618 case SUBTOTAL_FUNC_VARP
: ScVarP(); break;
6619 case AGGREGATE_FUNC_MEDIAN
: ScMedian(); break;
6620 case AGGREGATE_FUNC_MODSNGL
: ScModalValue(); break;
6621 case AGGREGATE_FUNC_LARGE
: ScLarge(); break;
6622 case AGGREGATE_FUNC_SMALL
: ScSmall(); break;
6623 case AGGREGATE_FUNC_PERCINC
: ScPercentile( true ); break;
6624 case AGGREGATE_FUNC_QRTINC
: ScQuartile( true ); break;
6625 case AGGREGATE_FUNC_PERCEXC
: ScPercentile( false ); break;
6626 case AGGREGATE_FUNC_QRTEXC
: ScQuartile( false ); break;
6627 default : PushIllegalArgument(); break;
6629 mnSubTotalFlags
= 0x00;
6631 double nVal
= GetDouble();
6632 // Get rid of the 1st and 2nd (fished) parameters.
6639 ScDBQueryParamBase
* ScInterpreter::GetDBParams( bool& rMissingField
)
6641 bool bAllowMissingField
= false;
6642 if ( rMissingField
)
6644 bAllowMissingField
= true;
6645 rMissingField
= false;
6647 if ( GetByte() == 3 )
6649 // First, get the query criteria range.
6650 ::std::unique_ptr
<ScDBRangeBase
> pQueryRef( PopDBDoubleRef() );
6651 if (!pQueryRef
.get())
6656 svl::SharedString aStr
;
6657 ScRange aMissingRange
;
6658 bool bRangeFake
= false;
6659 switch (GetStackType())
6662 nVal
= ::rtl::math::approxFloor( GetDouble() );
6663 if ( bAllowMissingField
&& nVal
== 0.0 )
6664 rMissingField
= true; // fake missing parameter
6673 PopSingleRef( aAdr
);
6674 ScRefCellValue aCell
;
6675 aCell
.assign(*pDok
, aAdr
);
6676 if (aCell
.hasNumeric())
6677 nVal
= GetCellValue(aAdr
, aCell
);
6681 GetCellString(aStr
, aCell
);
6686 if ( bAllowMissingField
)
6687 { // fake missing parameter for old SO compatibility
6689 PopDoubleRef( aMissingRange
);
6694 SetError( errIllegalParameter
);
6699 if ( bAllowMissingField
)
6700 rMissingField
= true;
6702 SetError( errIllegalParameter
);
6706 SetError( errIllegalParameter
);
6712 unique_ptr
<ScDBRangeBase
> pDBRef( PopDBDoubleRef() );
6714 if (nGlobalError
|| !pDBRef
.get())
6719 // range parameter must match entire database range
6720 if (pDBRef
->isRangeEqual(aMissingRange
))
6721 rMissingField
= true;
6723 SetError( errIllegalParameter
);
6729 SCCOL nField
= pDBRef
->getFirstFieldColumn();
6733 nField
= pDBRef
->findFieldColumn(static_cast<SCCOL
>(nVal
));
6736 sal_uInt16 nErr
= 0;
6737 nField
= pDBRef
->findFieldColumn(aStr
.getString(), &nErr
);
6741 if (!ValidCol(nField
))
6744 unique_ptr
<ScDBQueryParamBase
> pParam( pDBRef
->createQueryParam(pQueryRef
.get()) );
6748 // An allowed missing field parameter sets the result field
6749 // to any of the query fields, just to be able to return
6750 // some cell from the iterator.
6751 if ( rMissingField
)
6752 nField
= static_cast<SCCOL
>(pParam
->GetEntry(0).nField
);
6753 pParam
->mnField
= nField
;
6755 SCSIZE nCount
= pParam
->GetEntryCount();
6756 for ( SCSIZE i
=0; i
< nCount
; i
++ )
6758 ScQueryEntry
& rEntry
= pParam
->GetEntry(i
);
6759 if (!rEntry
.bDoQuery
)
6762 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6763 sal_uInt32 nIndex
= 0;
6764 OUString aQueryStr
= rItem
.maString
.getString();
6765 bool bNumber
= pFormatter
->IsNumberFormat(
6766 aQueryStr
, nIndex
, rItem
.mfVal
);
6767 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
6769 if (!bNumber
&& !pParam
->bRegExp
)
6770 pParam
->bRegExp
= MayBeRegExp(aQueryStr
, pDok
);
6772 return pParam
.release();
6778 void ScInterpreter::DBIterator( ScIterFunc eFunc
)
6783 sal_uLong nCount
= 0;
6784 bool bMissingField
= false;
6785 unique_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6786 if (pQueryParam
.get())
6788 if (!pQueryParam
->IsValidFieldIndex())
6790 SetError(errNoValue
);
6793 ScDBQueryDataIterator
aValIter(pDok
, pQueryParam
.release());
6794 ScDBQueryDataIterator::Value aValue
;
6795 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6799 case ifPRODUCT
: nErg
= 1; break;
6800 case ifMAX
: nErg
= -MAXDOUBLE
; break;
6801 case ifMIN
: nErg
= MAXDOUBLE
; break;
6802 default: ; // nothing
6811 if ( bNull
&& aValue
.mfValue
!= 0.0 )
6814 fMem
= aValue
.mfValue
;
6817 nErg
+= aValue
.mfValue
;
6819 case ifSUMSQ
: nErg
+= aValue
.mfValue
* aValue
.mfValue
; break;
6820 case ifPRODUCT
: nErg
*= aValue
.mfValue
; break;
6821 case ifMAX
: if( aValue
.mfValue
> nErg
) nErg
= aValue
.mfValue
; break;
6822 case ifMIN
: if( aValue
.mfValue
< nErg
) nErg
= aValue
.mfValue
; break;
6823 default: ; // nothing
6826 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6828 SetError(aValue
.mnError
);
6831 SetError( errIllegalParameter
);
6834 case ifCOUNT
: nErg
= nCount
; break;
6835 case ifSUM
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
); break;
6836 case ifAVERAGE
: nErg
= div(::rtl::math::approxAdd(nErg
, fMem
), nCount
); break;
6837 default: ; // nothing
6842 void ScInterpreter::ScDBSum()
6844 DBIterator( ifSUM
);
6847 void ScInterpreter::ScDBCount()
6849 bool bMissingField
= true;
6850 unique_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6851 if (pQueryParam
.get())
6853 sal_uLong nCount
= 0;
6854 if ( bMissingField
&& pQueryParam
->GetType() == ScDBQueryParamBase::INTERNAL
)
6855 { // count all matching records
6856 // TODO: currently the QueryIterators only return cell pointers of
6857 // existing cells, so if a query matches an empty cell there's
6858 // nothing returned, and therefore not counted!
6859 // Since this has ever been the case and this code here only came
6860 // into existence to fix #i6899 and it never worked before we'll
6861 // have to live with it until we reimplement the iterators to also
6862 // return empty cells, which would mean to adapt all callers of
6864 ScDBQueryParamInternal
* p
= static_cast<ScDBQueryParamInternal
*>(pQueryParam
.get());
6865 p
->nCol2
= p
->nCol1
; // Don't forget to select only one column.
6866 SCTAB nTab
= p
->nTab
;
6867 // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField,
6868 // so the source range has to be restricted, like before the introduction
6869 // of ScDBQueryParamBase.
6870 p
->nCol1
= p
->nCol2
= p
->mnField
;
6871 ScQueryCellIterator
aCellIter( pDok
, nTab
, *p
);
6872 if ( aCellIter
.GetFirst() )
6877 } while ( aCellIter
.GetNext() );
6881 { // count only matching records with a value in the "result" field
6882 if (!pQueryParam
->IsValidFieldIndex())
6884 SetError(errNoValue
);
6887 ScDBQueryDataIterator
aValIter( pDok
, pQueryParam
.release());
6888 ScDBQueryDataIterator::Value aValue
;
6889 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6895 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6897 SetError(aValue
.mnError
);
6899 PushDouble( nCount
);
6902 PushIllegalParameter();
6905 void ScInterpreter::ScDBCount2()
6907 bool bMissingField
= true;
6908 unique_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6909 if (pQueryParam
.get())
6911 if (!pQueryParam
->IsValidFieldIndex())
6913 SetError(errNoValue
);
6916 sal_uLong nCount
= 0;
6917 pQueryParam
->mbSkipString
= false;
6918 ScDBQueryDataIterator
aValIter( pDok
, pQueryParam
.release());
6919 ScDBQueryDataIterator::Value aValue
;
6920 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6926 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6928 SetError(aValue
.mnError
);
6929 PushDouble( nCount
);
6932 PushIllegalParameter();
6935 void ScInterpreter::ScDBAverage()
6937 DBIterator( ifAVERAGE
);
6940 void ScInterpreter::ScDBMax()
6942 DBIterator( ifMAX
);
6945 void ScInterpreter::ScDBMin()
6947 DBIterator( ifMIN
);
6950 void ScInterpreter::ScDBProduct()
6952 DBIterator( ifPRODUCT
);
6955 void ScInterpreter::GetDBStVarParams( double& rVal
, double& rValCount
)
6957 std::vector
<double> values
;
6963 bool bMissingField
= false;
6964 unique_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6965 if (pQueryParam
.get())
6967 if (!pQueryParam
->IsValidFieldIndex())
6969 SetError(errNoValue
);
6972 ScDBQueryDataIterator
aValIter(pDok
, pQueryParam
.release());
6973 ScDBQueryDataIterator::Value aValue
;
6974 if (aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6979 values
.push_back(aValue
.mfValue
);
6980 fSum
+= aValue
.mfValue
;
6982 while ((aValue
.mnError
== 0) && aValIter
.GetNext(aValue
));
6984 SetError(aValue
.mnError
);
6987 SetError( errIllegalParameter
);
6989 vMean
= fSum
/ values
.size();
6991 for (size_t i
= 0; i
< values
.size(); i
++)
6992 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
6997 void ScInterpreter::ScDBStdDev()
6999 double fVal
, fCount
;
7000 GetDBStVarParams( fVal
, fCount
);
7001 PushDouble( sqrt(fVal
/(fCount
-1)));
7004 void ScInterpreter::ScDBStdDevP()
7006 double fVal
, fCount
;
7007 GetDBStVarParams( fVal
, fCount
);
7008 PushDouble( sqrt(fVal
/fCount
));
7011 void ScInterpreter::ScDBVar()
7013 double fVal
, fCount
;
7014 GetDBStVarParams( fVal
, fCount
);
7015 PushDouble(fVal
/(fCount
-1));
7018 void ScInterpreter::ScDBVarP()
7020 double fVal
, fCount
;
7021 GetDBStVarParams( fVal
, fCount
);
7022 PushDouble(fVal
/fCount
);
7025 void ScInterpreter::ScIndirect()
7027 sal_uInt8 nParamCount
= GetByte();
7028 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7030 // Reference address syntax for INDIRECT is configurable.
7031 FormulaGrammar::AddressConvention eConv
= maCalcConfig
.meStringRefAddressSyntax
;
7032 if (eConv
== FormulaGrammar::CONV_UNSPECIFIED
)
7033 // Use the current address syntax if unspecified.
7034 eConv
= pDok
->GetAddressConvention();
7036 // either CONV_A1_XL_A1 was explicitly configured, or it wasn't possible
7037 // to determine which syntax to use during doc import
7038 bool bTryXlA1
= (eConv
== FormulaGrammar::CONV_A1_XL_A1
);
7040 if (nParamCount
== 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
7042 // Overwrite the config and try Excel R1C1.
7043 eConv
= FormulaGrammar::CONV_XL_R1C1
;
7047 const ScAddress::Details
aDetails( bTryXlA1
? FormulaGrammar::CONV_OOO
: eConv
, aPos
);
7048 const ScAddress::Details
aDetailsXlA1( FormulaGrammar::CONV_XL_A1
, aPos
);
7049 SCTAB nTab
= aPos
.Tab();
7050 OUString sRefStr
= GetString().getString();
7051 ScRefAddress aRefAd
, aRefAd2
;
7052 ScAddress::ExternalInfo aExtInfo
;
7053 if ( ConvertDoubleRef(pDok
, sRefStr
, nTab
, aRefAd
, aRefAd2
, aDetails
, &aExtInfo
) ||
7054 ( bTryXlA1
&& ConvertDoubleRef(pDok
, sRefStr
, nTab
, aRefAd
,
7055 aRefAd2
, aDetailsXlA1
, &aExtInfo
) ) )
7057 if (aExtInfo
.mbExternal
)
7059 PushExternalDoubleRef(
7060 aExtInfo
.mnFileId
, aExtInfo
.maTabName
,
7061 aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab(),
7062 aRefAd2
.Col(), aRefAd2
.Row(), aRefAd2
.Tab());
7065 PushDoubleRef( aRefAd
, aRefAd2
);
7067 else if ( ConvertSingleRef(pDok
, sRefStr
, nTab
, aRefAd
, aDetails
, &aExtInfo
) ||
7068 ( bTryXlA1
&& ConvertSingleRef (pDok
, sRefStr
, nTab
, aRefAd
,
7069 aDetailsXlA1
, &aExtInfo
) ) )
7071 if (aExtInfo
.mbExternal
)
7073 PushExternalSingleRef(
7074 aExtInfo
.mnFileId
, aExtInfo
.maTabName
, aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab());
7077 PushSingleRef( aRefAd
);
7083 ScRangeData
* pData
= ScRangeStringConverter::GetRangeDataFromString(sRefStr
, nTab
, pDok
);
7087 // We need this in order to obtain a good range.
7088 pData
->ValidateTabRefs();
7092 // This is the usual way to treat named ranges containing
7093 // relative references.
7094 if (!pData
->IsReference( aRange
, aPos
))
7097 if (aRange
.aStart
== aRange
.aEnd
)
7098 PushSingleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
7099 aRange
.aStart
.Tab());
7101 PushDoubleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
7102 aRange
.aStart
.Tab(), aRange
.aEnd
.Col(),
7103 aRange
.aEnd
.Row(), aRange
.aEnd
.Tab());
7112 OUString
aName( ScGlobal::pCharClass
->uppercase( sRefStr
));
7113 ScDBCollection::NamedDBs
& rDBs
= pDok
->GetDBCollection()->getNamedDBs();
7114 const ScDBData
* pData
= rDBs
.findByUpperName( aName
);
7119 pData
->GetArea( aRange
);
7121 // In Excel, specifying a table name without [] resolves to the
7122 // same as with [], a range that excludes header and totals
7123 // rows and contains only data rows. Do the same.
7124 if (pData
->HasHeader())
7125 aRange
.aStart
.IncRow();
7126 if (pData
->HasTotals())
7127 aRange
.aEnd
.IncRow(-1);
7129 if (aRange
.aStart
.Row() > aRange
.aEnd
.Row())
7132 if (aRange
.aStart
== aRange
.aEnd
)
7133 PushSingleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
7134 aRange
.aStart
.Tab());
7136 PushDoubleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
7137 aRange
.aStart
.Tab(), aRange
.aEnd
.Col(),
7138 aRange
.aEnd
.Row(), aRange
.aEnd
.Tab());
7145 // It may be even a TableRef.
7146 // Anything else that resolves to one reference could be added
7147 // here, but we don't want to compile every arbitrary string. This
7148 // is already nasty enough..
7149 sal_Int32 nIndex
= 0;
7150 if ((nIndex
= sRefStr
.indexOf('[')) >= 0 && sRefStr
.indexOf(']',nIndex
+1) > nIndex
)
7154 ScCompiler
aComp( pDok
, aPos
);
7155 aComp
.SetGrammar( pDok
->GetGrammar());
7156 aComp
.SetRefConvention( eConv
); // must be after grammar
7157 boost::scoped_ptr
<ScTokenArray
> pArr( aComp
.CompileString( sRefStr
));
7159 // Whatever.. use only the specific case.
7160 if (!pArr
->HasOpCode( ocTableRef
))
7163 aComp
.CompileTokenArray();
7165 // A syntactically valid reference will generate exactly
7166 // one RPN token, a reference or error. Discard everything
7168 if (pArr
->GetCodeLen() != 1)
7171 ScTokenRef
xTok( pArr
->FirstRPN());
7175 switch (xTok
->GetType())
7180 PushTempToken( xTok
.get());
7190 PushError( errNoRef
);
7195 void ScInterpreter::ScAddressFunc()
7199 sal_uInt8 nParamCount
= GetByte();
7200 if( !MustHaveParamCount( nParamCount
, 2, 5 ) )
7203 if( nParamCount
>= 5 )
7204 sTabStr
= GetString().getString();
7206 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
; // default
7207 if( nParamCount
>= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
7208 eConv
= FormulaGrammar::CONV_XL_R1C1
;
7210 sal_uInt16 nFlags
= SCA_COL_ABSOLUTE
| SCA_ROW_ABSOLUTE
; // default
7211 if( nParamCount
>= 3 )
7213 sal_uInt16 n
= (sal_uInt16
) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
7221 case 1 : break; // default
7223 case 2 : nFlags
= SCA_ROW_ABSOLUTE
; break;
7225 case 3 : nFlags
= SCA_COL_ABSOLUTE
; break;
7227 case 4 : nFlags
= 0; break; // both relative
7230 nFlags
|= SCA_VALID
| SCA_VALID_ROW
| SCA_VALID_COL
;
7232 SCCOL nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
7233 SCROW nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
7234 if( eConv
== FormulaGrammar::CONV_XL_R1C1
)
7236 // YUCK! The XL interface actually treats rel R1C1 refs differently
7238 if( !(nFlags
& SCA_COL_ABSOLUTE
) )
7239 nCol
+= aPos
.Col() + 1;
7240 if( !(nFlags
& SCA_ROW_ABSOLUTE
) )
7241 nRow
+= aPos
.Row() + 1;
7246 if(!ValidCol( nCol
) || !ValidRow( nRow
))
7248 PushIllegalArgument();
7252 const ScAddress::Details
aDetails( eConv
, aPos
);
7253 const ScAddress
aAdr( nCol
, nRow
, 0);
7254 OUString
aRefStr(aAdr
.Format(nFlags
, pDok
, aDetails
));
7256 if( nParamCount
>= 5 && !sTabStr
.isEmpty() )
7259 if (eConv
== FormulaGrammar::CONV_OOO
)
7261 // Isolate Tab from 'Doc'#Tab
7262 sal_Int32 nPos
= ScCompiler::GetDocTabPos( sTabStr
);
7265 if (sTabStr
[nPos
+1] == '$')
7266 ++nPos
; // also split 'Doc'#$Tab
7267 aDoc
= sTabStr
.copy( 0, nPos
+1);
7268 sTabStr
= sTabStr
.copy( nPos
+1);
7271 /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may
7272 * need some extra handling to isolate Tab from Doc. */
7273 if (sTabStr
[0] != '\'' || !sTabStr
.endsWith("'"))
7274 ScCompiler::CheckTabQuotes( sTabStr
, eConv
);
7275 if (!aDoc
.isEmpty())
7276 sTabStr
= aDoc
+ sTabStr
;
7277 sTabStr
+= eConv
== FormulaGrammar::CONV_XL_R1C1
? OUString("!") : OUString(".");
7279 PushString( sTabStr
);
7282 PushString( aRefStr
);
7285 void ScInterpreter::ScOffset()
7287 sal_uInt8 nParamCount
= GetByte();
7288 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
7290 long nColNew
= -1, nRowNew
= -1, nColPlus
, nRowPlus
;
7291 if (nParamCount
== 5)
7292 nColNew
= (long) ::rtl::math::approxFloor(GetDouble());
7293 if (nParamCount
>= 4)
7294 nRowNew
= (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
7295 nColPlus
= (long) ::rtl::math::approxFloor(GetDouble());
7296 nRowPlus
= (long) ::rtl::math::approxFloor(GetDouble());
7303 if (nColNew
== 0 || nRowNew
== 0)
7305 PushIllegalArgument();
7308 switch (GetStackType())
7312 PopSingleRef(nCol1
, nRow1
, nTab1
);
7313 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
7315 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
7316 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
7317 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
7318 PushIllegalArgument();
7320 PushSingleRef(nCol1
, nRow1
, nTab1
);
7328 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7329 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7330 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7331 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7332 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7333 !ValidCol(nCol2
) || !ValidRow(nRow2
))
7334 PushIllegalArgument();
7336 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
7340 case svExternalSingleRef
:
7344 ScSingleRefData aRef
;
7345 PopExternalSingleRef(nFileId
, aTabName
, aRef
);
7346 ScAddress aAbsRef
= aRef
.toAbs(aPos
);
7347 nCol1
= aAbsRef
.Col();
7348 nRow1
= aAbsRef
.Row();
7349 nTab1
= aAbsRef
.Tab();
7351 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
7353 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
7354 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
7355 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
7356 PushIllegalArgument();
7358 PushExternalSingleRef(nFileId
, aTabName
, nCol1
, nRow1
, nTab1
);
7366 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7367 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7368 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7369 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7371 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7372 !ValidCol(nCol2
) || !ValidRow(nRow2
))
7373 PushIllegalArgument();
7375 PushExternalDoubleRef(nFileId
, aTabName
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7381 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7383 nColNew
= nCol2
- nCol1
+ 1;
7385 nRowNew
= nRow2
- nRow1
+ 1;
7386 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7387 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7388 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7389 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7390 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7391 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
7392 PushIllegalArgument();
7394 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
7397 case svExternalDoubleRef
:
7401 ScComplexRefData aRef
;
7402 PopExternalDoubleRef(nFileId
, aTabName
, aRef
);
7403 ScRange aAbs
= aRef
.toAbs(aPos
);
7404 nCol1
= aAbs
.aStart
.Col();
7405 nRow1
= aAbs
.aStart
.Row();
7406 nTab1
= aAbs
.aStart
.Tab();
7407 nCol2
= aAbs
.aEnd
.Col();
7408 nRow2
= aAbs
.aEnd
.Row();
7409 nTab2
= aAbs
.aEnd
.Tab();
7411 nColNew
= nCol2
- nCol1
+ 1;
7413 nRowNew
= nRow2
- nRow1
+ 1;
7414 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7415 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7416 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7417 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7418 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7419 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
7420 PushIllegalArgument();
7422 PushExternalDoubleRef(nFileId
, aTabName
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7426 PushIllegalParameter();
7432 void ScInterpreter::ScIndex()
7434 sal_uInt8 nParamCount
= GetByte();
7435 if ( MustHaveParamCount( nParamCount
, 1, 4 ) )
7441 if (nParamCount
== 4)
7442 nArea
= (long) ::rtl::math::approxFloor(GetDouble());
7445 if (nParamCount
>= 3)
7446 nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
7449 if (nParamCount
>= 2)
7450 nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
7453 if (GetStackType() == svRefList
)
7454 nAreaCount
= (sp
? pStack
[sp
-1]->GetRefList()->size() : 0);
7456 nAreaCount
= 1; // one reference or array or whatever
7457 if (nAreaCount
== 0 || (size_t)nArea
> nAreaCount
)
7459 PushError( errNoRef
);
7462 else if (nArea
< 1 || nCol
< 0 || nRow
< 0)
7464 PushIllegalArgument();
7467 switch (GetStackType())
7470 case svExternalSingleRef
:
7471 case svExternalDoubleRef
:
7474 SetError(errIllegalArgument
);
7475 sal_uInt16 nOldSp
= sp
;
7476 ScMatrixRef pMat
= GetMatrix();
7480 pMat
->GetDimensions(nC
, nR
);
7481 // Access one element of a vector independent of col/row
7483 bool bVector
= ((nCol
== 0 || nRow
== 0) && (nC
== 1 || nR
== 1));
7484 SCSIZE nElement
= ::std::max( static_cast<SCSIZE
>(nCol
),
7485 static_cast<SCSIZE
>(nRow
));
7486 if (nC
== 0 || nR
== 0 ||
7487 (!bVector
&& (static_cast<SCSIZE
>(nCol
) > nC
||
7488 static_cast<SCSIZE
>(nRow
) > nR
)) ||
7489 (bVector
&& nElement
> nC
* nR
))
7490 PushIllegalArgument();
7491 else if (nCol
== 0 && nRow
== 0)
7496 if (pMat
->IsString( nElement
))
7497 PushString( pMat
->GetString(nElement
).getString());
7499 PushDouble( pMat
->GetDouble( nElement
));
7503 ScMatrixRef pResMat
= GetNewMat(nC
, 1);
7506 SCSIZE nRowMinus1
= static_cast<SCSIZE
>(nRow
- 1);
7507 for (SCSIZE i
= 0; i
< nC
; i
++)
7508 if (!pMat
->IsString(i
, nRowMinus1
))
7509 pResMat
->PutDouble(pMat
->GetDouble(i
,
7512 pResMat
->PutString(pMat
->GetString(i
, nRowMinus1
), i
, 0);
7514 PushMatrix(pResMat
);
7517 PushIllegalArgument();
7521 ScMatrixRef pResMat
= GetNewMat(1, nR
);
7524 SCSIZE nColMinus1
= static_cast<SCSIZE
>(nCol
- 1);
7525 for (SCSIZE i
= 0; i
< nR
; i
++)
7526 if (!pMat
->IsString(nColMinus1
, i
))
7527 pResMat
->PutDouble(pMat
->GetDouble(nColMinus1
,
7530 pResMat
->PutString(pMat
->GetString(nColMinus1
, i
), i
);
7531 PushMatrix(pResMat
);
7534 PushIllegalArgument();
7538 if (!pMat
->IsString( static_cast<SCSIZE
>(nCol
-1),
7539 static_cast<SCSIZE
>(nRow
-1)))
7540 PushDouble( pMat
->GetDouble(
7541 static_cast<SCSIZE
>(nCol
-1),
7542 static_cast<SCSIZE
>(nRow
-1)));
7544 PushString( pMat
->GetString(
7545 static_cast<SCSIZE
>(nCol
-1),
7546 static_cast<SCSIZE
>(nRow
-1)).getString());
7556 PopSingleRef( nCol1
, nRow1
, nTab1
);
7557 if (nCol
> 1 || nRow
> 1)
7558 PushIllegalArgument();
7560 PushSingleRef( nCol1
, nRow1
, nTab1
);
7572 bool bRowArray
= false;
7573 if (GetStackType() == svRefList
)
7575 FormulaTokenRef xRef
= PopToken();
7576 if (nGlobalError
|| !xRef
)
7578 PushIllegalParameter();
7581 ScRange
aRange( ScAddress::UNINITIALIZED
);
7582 DoubleRefToRange( (*(xRef
.get()->GetRefList()))[nArea
-1], aRange
);
7583 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7584 if ( nParamCount
== 2 && nRow1
== nRow2
)
7589 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7590 if ( nParamCount
== 2 && nRow1
== nRow2
)
7593 if ( nTab1
!= nTab2
||
7594 (nCol
> 0 && nCol1
+nCol
-1 > nCol2
) ||
7595 (nRow
> 0 && nRow1
+nRow
-1 > nRow2
&& !bRowArray
) ||
7596 ( nRow
> nCol2
- nCol1
+ 1 && bRowArray
))
7597 PushIllegalArgument();
7598 else if (nCol
== 0 && nRow
== 0)
7600 if ( nCol1
== nCol2
&& nRow1
== nRow2
)
7601 PushSingleRef( nCol1
, nRow1
, nTab1
);
7603 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
7607 if ( nRow1
== nRow2
)
7608 PushSingleRef( nCol1
+nCol
-1, nRow1
, nTab1
);
7610 PushDoubleRef( nCol1
+nCol
-1, nRow1
, nTab1
,
7611 nCol1
+nCol
-1, nRow2
, nTab1
);
7615 if ( nCol1
== nCol2
)
7616 PushSingleRef( nCol1
, nRow1
+nRow
-1, nTab1
);
7617 else if ( bRowArray
)
7621 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
7624 PushDoubleRef( nCol1
, nRow1
+nRow
-1, nTab1
,
7625 nCol2
, nRow1
+nRow
-1, nTab1
);
7628 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
7632 PushIllegalParameter();
7637 void ScInterpreter::ScMultiArea()
7639 // Legacy support, convert to RefList
7640 sal_uInt8 nParamCount
= GetByte();
7641 if (MustHaveParamCountMin( nParamCount
, 1))
7643 while (!nGlobalError
&& nParamCount
-- > 1)
7650 void ScInterpreter::ScAreas()
7652 sal_uInt8 nParamCount
= GetByte();
7653 if (MustHaveParamCount( nParamCount
, 1))
7656 switch (GetStackType())
7660 FormulaTokenRef xT
= PopToken();
7661 ValidateRef( *xT
.get()->GetSingleRef());
7667 FormulaTokenRef xT
= PopToken();
7668 ValidateRef( *xT
.get()->GetDoubleRef());
7674 FormulaTokenRef xT
= PopToken();
7675 ValidateRef( *(xT
.get()->GetRefList()));
7676 nCount
+= xT
.get()->GetRefList()->size();
7680 SetError( errIllegalParameter
);
7682 PushDouble( double(nCount
));
7686 void ScInterpreter::ScCurrency()
7688 sal_uInt8 nParamCount
= GetByte();
7689 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7693 if (nParamCount
== 2)
7695 fDec
= ::rtl::math::approxFloor(GetDouble());
7696 if (fDec
< -15.0 || fDec
> 15.0)
7698 PushIllegalArgument();
7704 double fVal
= GetDouble();
7707 fFac
= pow( (double)10, fDec
);
7711 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
7713 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
7714 Color
* pColor
= NULL
;
7717 sal_uLong nIndex
= pFormatter
->GetStandardFormat(
7718 css::util::NumberFormat::CURRENCY
,
7720 if ( (sal_uInt16
) fDec
!= pFormatter
->GetFormatPrecision( nIndex
) )
7722 OUString sFormatString
= pFormatter
->GenerateFormat(
7725 true, // mit Tausenderpunkt
7727 (sal_uInt16
) fDec
,// Nachkommastellen
7728 1); // 1 Vorkommanull
7729 if (!pFormatter
->GetPreviewString(sFormatString
,
7734 SetError(errIllegalArgument
);
7738 pFormatter
->GetOutputString(fVal
, nIndex
, aStr
, &pColor
);
7744 void ScInterpreter::ScReplace()
7746 if ( MustHaveParamCount( GetByte(), 4 ) )
7748 OUString aNewStr
= GetString().getString();
7749 double fCount
= GetStringPositionArgument();
7750 double fPos
= GetStringPositionArgument();
7751 OUString aOldStr
= GetString().getString();
7752 if (fPos
< 1.0 || fCount
< 0.0)
7753 PushIllegalArgument();
7756 sal_Int32 nCount
= static_cast<sal_Int32
>(fCount
);
7757 sal_Int32 nPos
= static_cast<sal_Int32
>(fPos
);
7758 sal_Int32 nLen
= aOldStr
.getLength();
7759 if (nPos
> nLen
+ 1)
7761 if (nCount
> nLen
- nPos
+ 1)
7762 nCount
= nLen
- nPos
+ 1;
7763 aOldStr
= aOldStr
.replaceAt( nPos
-1, nCount
, "" );
7764 if ( CheckStringResultLen( aOldStr
, aNewStr
) )
7765 aOldStr
= aOldStr
.replaceAt( nPos
-1, 0, aNewStr
);
7766 PushString( aOldStr
);
7771 void ScInterpreter::ScFixed()
7773 sal_uInt8 nParamCount
= GetByte();
7774 if ( MustHaveParamCount( nParamCount
, 1, 3 ) )
7779 if (nParamCount
== 3)
7780 bThousand
= !GetBool(); // Param TRUE: keine Tausenderpunkte
7783 if (nParamCount
>= 2)
7785 fDec
= ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
7786 if (fDec
< -15.0 || fDec
> 15.0)
7788 PushIllegalArgument();
7794 double fVal
= GetDouble();
7797 fFac
= pow( (double)10, fDec
);
7801 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
7803 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
7804 Color
* pColor
= NULL
;
7807 sal_uLong nIndex
= pFormatter
->GetStandardFormat(
7808 css::util::NumberFormat::NUMBER
,
7810 OUString sFormatString
= pFormatter
->GenerateFormat(
7813 bThousand
, // mit Tausenderpunkt
7815 (sal_uInt16
) fDec
,// Nachkommastellen
7816 1); // 1 Vorkommanull
7817 if (!pFormatter
->GetPreviewString(sFormatString
,
7822 PushIllegalArgument();
7828 void ScInterpreter::ScFind()
7830 sal_uInt8 nParamCount
= GetByte();
7831 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
7834 if (nParamCount
== 3)
7838 OUString sStr
= GetString().getString();
7839 if (nAnz
< 1 || nAnz
> sStr
.getLength())
7843 sal_Int32 nPos
= sStr
.indexOf(GetString().getString(), nAnz
- 1);
7847 PushDouble((double)(nPos
+ 1));
7852 void ScInterpreter::ScExact()
7854 nFuncFmtType
= css::util::NumberFormat::LOGICAL
;
7855 if ( MustHaveParamCount( GetByte(), 2 ) )
7857 svl::SharedString s1
= GetString();
7858 svl::SharedString s2
= GetString();
7859 PushInt( int(s1
.getData() == s2
.getData()) );
7863 void ScInterpreter::ScLeft()
7865 sal_uInt8 nParamCount
= GetByte();
7866 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7869 if (nParamCount
== 2)
7871 double nVal
= GetStringPositionArgument();
7874 PushIllegalArgument();
7878 n
= (sal_Int32
) nVal
;
7882 OUString aStr
= GetString().getString();
7883 n
= std::min(n
, aStr
.getLength());
7884 aStr
= aStr
.copy( 0, n
);
7894 static const UBlockScript scriptList
[] = {
7895 {UBLOCK_HANGUL_JAMO
, UBLOCK_HANGUL_JAMO
},
7896 {UBLOCK_CJK_RADICALS_SUPPLEMENT
, UBLOCK_HANGUL_SYLLABLES
},
7897 {UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
,UBLOCK_CJK_RADICALS_SUPPLEMENT
},
7898 {UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS
,UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
},
7899 {UBLOCK_CJK_COMPATIBILITY_FORMS
, UBLOCK_CJK_COMPATIBILITY_FORMS
},
7900 {UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
, UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
},
7901 {UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
, UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
},
7902 {UBLOCK_CJK_STROKES
, UBLOCK_CJK_STROKES
}
7904 #define scriptListCount sizeof (scriptList) / sizeof (UBlockScript)
7905 bool SAL_CALL
lcl_getScriptClass(sal_uInt32 currentChar
)
7907 // for the locale of ja-JP, character U+0x005c and U+0x20ac should be ScriptType::Asian
7908 if( (currentChar
== 0x005c || currentChar
== 0x20ac) &&
7909 (MsLangId::getSystemLanguage() == LANGUAGE_JAPANESE
) )
7912 static bool nRet
= false;
7913 UBlockCode block
= (UBlockCode
)ublock_getCode((sal_uInt32
)currentChar
);
7914 for ( i
= 0; i
< scriptListCount
; i
++) {
7915 if (block
<= scriptList
[i
].to
) break;
7917 nRet
= (i
< scriptListCount
&& block
>= scriptList
[i
].from
);
7920 bool IsDBCS(sal_Unicode ch
)
7922 return lcl_getScriptClass(ch
);
7924 sal_Int32
getLengthB(const OUString
&str
)
7928 sal_Int32 index
= 0;
7929 sal_Int32 length
= 0;
7930 while(index
< str
.getLength()){
7931 if(IsDBCS(str
[index
]))
7939 void ScInterpreter::ScLenB()
7941 PushDouble( getLengthB(GetString().getString()) );
7943 OUString
lcl_RightB(const OUString
&rStr
, sal_Int32 n
)
7945 if( n
< getLengthB(rStr
) )
7947 OUStringBuffer
aBuf(rStr
);
7948 sal_Int32 index
= aBuf
.getLength();
7953 aBuf
.remove( 0, index
+ 1);
7958 aBuf
.remove( 0, index
+ 2 );
7959 aBuf
.insert( 0, " ");
7962 if(IsDBCS(aBuf
[index
]))
7967 return aBuf
.makeStringAndClear();
7971 void ScInterpreter::ScRightB()
7973 sal_uInt8 nParamCount
= GetByte();
7974 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7977 if (nParamCount
== 2)
7979 double nVal
= GetStringPositionArgument();
7982 PushIllegalArgument();
7986 n
= (sal_Int32
) nVal
;
7990 OUString
aStr(lcl_RightB(GetString().getString(), n
));
7994 OUString
lcl_LeftB(const OUString
&rStr
, sal_Int32 n
)
7996 if( n
< getLengthB(rStr
) )
7998 OUStringBuffer
aBuf(rStr
);
7999 sal_Int32 index
= -1;
8000 while(index
++ < aBuf
.getLength())
8004 aBuf
.truncate(index
);
8009 aBuf
.truncate( index
- 1 );
8013 if(IsDBCS(aBuf
[index
]))
8018 return aBuf
.makeStringAndClear();
8022 void ScInterpreter::ScLeftB()
8024 sal_uInt8 nParamCount
= GetByte();
8025 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
8028 if (nParamCount
== 2)
8030 double nVal
= GetStringPositionArgument();
8033 PushIllegalArgument();
8037 n
= (sal_Int32
) nVal
;
8041 OUString
aStr(lcl_LeftB(GetString().getString(), n
));
8045 void ScInterpreter::ScMidB()
8047 if ( MustHaveParamCount( GetByte(), 3 ) )
8049 double fAnz
= GetStringPositionArgument();
8050 double fAnfang
= GetStringPositionArgument();
8051 OUString aStr
= GetString().getString();
8052 if (fAnfang
< 1.0 || fAnz
< 0.0)
8053 PushIllegalArgument();
8057 aStr
= lcl_LeftB(aStr
, (sal_Int32
)fAnfang
+ (sal_Int32
)fAnz
- 1);
8058 sal_Int32 nCnt
= getLengthB(aStr
) - (sal_Int32
)fAnfang
+ 1;
8059 aStr
= lcl_RightB(aStr
, nCnt
>0 ? nCnt
:0);
8065 void ScInterpreter::ScRight()
8067 sal_uInt8 nParamCount
= GetByte();
8068 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
8071 if (nParamCount
== 2)
8073 double nVal
= GetStringPositionArgument();
8076 PushIllegalArgument();
8080 n
= (sal_Int32
) nVal
;
8084 OUString aStr
= GetString().getString();
8085 if( n
< aStr
.getLength() )
8086 aStr
= aStr
.copy( aStr
.getLength() - n
);
8091 void ScInterpreter::ScSearch()
8093 sal_uInt8 nParamCount
= GetByte();
8094 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
8097 if (nParamCount
== 3)
8099 // This should use GetStringPositionArgument() but old versions up
8100 // to LibreOffice 4.2.5 allowed and ignored 0 and negative values.
8101 // It is unnecessary to break existing documents that "rely" on
8102 // that behavior. Though ODFF constrains Start to be >=1.
8103 /* TODO: fix this and possibly break those broken documents? */
8104 fAnz
= rtl::math::approxFloor( GetDouble());
8107 else if (!CheckStringPositionArgument( fAnz
))
8109 PushIllegalArgument();
8115 OUString sStr
= GetString().getString();
8116 OUString SearchStr
= GetString().getString();
8117 sal_Int32 nPos
= fAnz
- 1;
8118 sal_Int32 nEndPos
= sStr
.getLength();
8119 if( nPos
>= nEndPos
)
8123 utl::SearchParam::SearchType eSearchType
=
8124 (MayBeRegExp( SearchStr
, pDok
) ?
8125 utl::SearchParam::SRCH_REGEXP
: utl::SearchParam::SRCH_NORMAL
);
8126 utl::SearchParam
sPar(SearchStr
, eSearchType
, false, false, false);
8127 utl::TextSearch
sT( sPar
, *ScGlobal::pCharClass
);
8128 bool nBool
= sT
.SearchForward(sStr
, &nPos
, &nEndPos
);
8132 PushDouble((double)(nPos
) + 1);
8137 void ScInterpreter::ScMid()
8139 if ( MustHaveParamCount( GetByte(), 3 ) )
8141 double fAnz
= GetStringPositionArgument();
8142 double fAnfang
= GetStringPositionArgument();
8143 OUString aStr
= GetString().getString();
8144 if (fAnfang
< 1.0 || fAnz
< 0.0)
8145 PushIllegalArgument();
8148 sal_Int32 nCharacters
= std::min
<sal_Int32
>(static_cast<sal_Int32
>(fAnz
), aStr
.getLength() - fAnfang
+ 1);
8150 if (nCharacters
> 0)
8151 sRes
= aStr
.copy(static_cast<sal_Int32
>(fAnfang
-1), nCharacters
);
8157 void ScInterpreter::ScText()
8159 if ( MustHaveParamCount( GetByte(), 2 ) )
8161 OUString sFormatString
= GetString().getString();
8162 svl::SharedString aStr
;
8163 bool bString
= false;
8165 switch (GetStackType())
8175 FormulaTokenRef
xTok( PopToken());
8178 PushTempToken( xTok
.get());
8179 // Temporarily override the ConvertStringToValue()
8180 // error for GetCellValue() / GetCellValueOrZero()
8181 sal_uInt16 nSErr
= mnStringNoValueError
;
8182 mnStringNoValueError
= errNotNumericString
;
8184 mnStringNoValueError
= nSErr
;
8185 if (nGlobalError
== errNotNumericString
)
8189 PushTempToken( xTok
.get());
8197 PushError( nGlobalError
);
8201 Color
* pColor
= NULL
;
8202 LanguageType eCellLang
;
8203 const ScPatternAttr
* pPattern
= pDok
->GetPattern(
8204 aPos
.Col(), aPos
.Row(), aPos
.Tab() );
8206 eCellLang
= static_cast<const SvxLanguageItem
&>(
8207 pPattern
->GetItem( ATTR_LANGUAGE_FORMAT
)).GetValue();
8209 eCellLang
= ScGlobal::eLnge
;
8212 if (!pFormatter
->GetPreviewString( sFormatString
, aStr
.getString(),
8213 aResult
, &pColor
, eCellLang
))
8214 PushIllegalArgument();
8216 PushString( aResult
);
8220 if (!pFormatter
->GetPreviewStringGuess( sFormatString
, fVal
,
8221 aResult
, &pColor
, eCellLang
))
8222 PushIllegalArgument();
8224 PushString( aResult
);
8230 void ScInterpreter::ScSubstitute()
8232 sal_uInt8 nParamCount
= GetByte();
8233 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
8236 if (nParamCount
== 4)
8238 double fAnz
= GetStringPositionArgument();
8241 PushIllegalArgument();
8245 nAnz
= (sal_Int32
) fAnz
;
8249 OUString sNewStr
= GetString().getString();
8250 OUString sOldStr
= GetString().getString();
8251 OUString sStr
= GetString().getString();
8253 sal_Int32 nCount
= 0;
8254 sal_Int32 nNewLen
= sNewStr
.getLength();
8255 sal_Int32 nOldLen
= sOldStr
.getLength();
8258 nPos
= sStr
.indexOf( sOldStr
, nPos
);
8262 if( !nAnz
|| nCount
== nAnz
)
8264 sStr
= sStr
.replaceAt(nPos
,nOldLen
, "");
8265 if ( CheckStringResultLen( sStr
, sNewStr
) )
8267 sStr
= sStr
.replaceAt(nPos
, 0, sNewStr
);
8268 nPos
= sal::static_int_cast
<sal_Int32
>( nPos
+ nNewLen
);
8283 void ScInterpreter::ScRept()
8285 if ( MustHaveParamCount( GetByte(), 2 ) )
8287 double fAnz
= GetStringPositionArgument();
8288 OUString aStr
= GetString().getString();
8290 PushIllegalArgument();
8291 else if ( fAnz
* aStr
.getLength() > SAL_MAX_UINT16
)
8293 PushError( errStringOverflow
);
8295 else if ( fAnz
== 0.0 )
8296 PushString( EMPTY_OUSTRING
);
8299 const sal_Int32 nLen
= aStr
.getLength();
8300 sal_Int32 n
= (sal_Int32
) fAnz
;
8301 OUStringBuffer
aRes(n
*nLen
);
8304 PushString( aRes
.makeStringAndClear() );
8309 void ScInterpreter::ScConcat()
8311 sal_uInt8 nParamCount
= GetByte();
8313 while( nParamCount
-- > 0)
8315 OUString aStr
= GetString().getString();
8321 sal_uInt16
ScInterpreter::GetErrorType()
8324 sal_uInt16 nOldError
= nGlobalError
;
8326 switch ( GetStackType() )
8330 FormulaTokenRef x
= PopToken();
8332 nErr
= nGlobalError
;
8335 const ScRefList
* pRefList
= x
.get()->GetRefList();
8336 size_t n
= pRefList
->size();
8344 DoubleRefToRange( (*pRefList
)[0], aRange
);
8346 nErr
= nGlobalError
;
8350 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
8351 nErr
= pDok
->GetErrCode( aAdr
);
8353 nErr
= nGlobalError
;
8362 PopDoubleRef( aRange
);
8364 nErr
= nGlobalError
;
8368 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
8369 nErr
= pDok
->GetErrCode( aAdr
);
8371 nErr
= nGlobalError
;
8378 PopSingleRef( aAdr
);
8380 nErr
= nGlobalError
;
8382 nErr
= pDok
->GetErrCode( aAdr
);
8387 nErr
= nGlobalError
;
8389 nGlobalError
= nOldError
;
8393 void ScInterpreter::ScErrorType()
8395 sal_uInt16 nErr
= GetErrorType();
8407 void ScInterpreter::ScErrorType_ODF()
8409 sal_uInt16 nErr
= GetErrorType();
8410 sal_uInt16 nErrType
;
8414 case errParameterExpected
: // #NULL!
8417 case errDivisionByZero
: // #DIV/0!
8420 case errNoValue
: // #VALUE!
8423 case errNoRef
: // #REF!
8426 case errNoName
: // #NAME?
8429 case errIllegalFPOperation
: // #NUM!
8432 case NOTAVAILABLE
: // #N/A
8436 #GETTING_DATA is a message that can appear in Excel when a large or
8437 complex worksheet is being calculated. In Excel 2007 and newer,
8438 operations are grouped so more complicated cells may finish after
8439 earlier ones do. While the calculations are still processing, the
8440 unfinished cells may display #GETTING_DATA.
8441 Because the message is temporary and disappears when the calculations
8442 complete, this isn’t a true error.
8443 No calc error code known (yet).
8445 case : // GETTING_DATA
8457 PushDouble( nErrType
);
8463 bool ScInterpreter::MayBeRegExp( const OUString
& rStr
, const ScDocument
* pDoc
)
8465 if ( pDoc
&& !pDoc
->GetDocOptions().IsFormulaRegexEnabled() )
8467 if ( rStr
.isEmpty() || (rStr
.getLength() == 1 && !rStr
.startsWith(".")) )
8468 return false; // single meta characters can not be a regexp
8469 static const sal_Unicode cre
[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
8470 const sal_Unicode
* p1
= rStr
.getStr();
8472 while ( ( c1
= *p1
++ ) != 0 )
8474 const sal_Unicode
* p2
= cre
;
8484 static bool lcl_LookupQuery( ScAddress
& o_rResultPos
, ScDocument
* pDoc
,
8485 const ScQueryParam
& rParam
, const ScQueryEntry
& rEntry
)
8487 bool bFound
= false;
8488 ScQueryCellIterator
aCellIter( pDoc
, rParam
.nTab
, rParam
, false);
8489 if (rEntry
.eOp
!= SC_EQUAL
)
8491 // range lookup <= or >=
8494 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow
);
8497 o_rResultPos
.SetCol( nCol
);
8498 o_rResultPos
.SetRow( nRow
);
8501 else if (aCellIter
.GetFirst())
8505 o_rResultPos
.SetCol( aCellIter
.GetCol());
8506 o_rResultPos
.SetRow( aCellIter
.GetRow());
8511 bool ScInterpreter::LookupQueryWithCache( ScAddress
& o_rResultPos
,
8512 const ScQueryParam
& rParam
) const
8514 bool bFound
= false;
8515 const ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
8516 bool bColumnsMatch
= (rParam
.nCol1
== rEntry
.nField
);
8517 OSL_ENSURE( bColumnsMatch
, "ScInterpreter::LookupQueryWithCache: columns don't match");
8518 // At least all volatile functions that generate indirect references have
8519 // to force non-cached lookup.
8520 /* TODO: We could further classify volatile functions into reference
8521 * generating and not reference generating functions to have to force less
8522 * direct lookups here. We could even further attribute volatility per
8523 * parameter so it would affect only the lookup range parameter. */
8524 if (!bColumnsMatch
|| GetVolatileType() != NOT_VOLATILE
)
8525 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
8528 ScRange
aLookupRange( rParam
.nCol1
, rParam
.nRow1
, rParam
.nTab
,
8529 rParam
.nCol2
, rParam
.nRow2
, rParam
.nTab
);
8530 ScLookupCache
& rCache
= pDok
->GetLookupCache( aLookupRange
);
8531 ScLookupCache::QueryCriteria
aCriteria( rEntry
);
8532 ScLookupCache::Result eCacheResult
= rCache
.lookup( o_rResultPos
,
8534 switch (eCacheResult
)
8536 case ScLookupCache::NOT_CACHED
:
8537 case ScLookupCache::CRITERIA_DIFFERENT
:
8538 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
8539 if (eCacheResult
== ScLookupCache::NOT_CACHED
)
8540 rCache
.insert( o_rResultPos
, aCriteria
, aPos
, bFound
);
8542 case ScLookupCache::FOUND
:
8545 case ScLookupCache::NOT_AVAILABLE
:
8546 ; // nothing, bFound remains FALSE
8553 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */