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 <osl/thread.h>
26 #include <svx/algitem.hxx>
27 #include <unotools/textsearch.hxx>
28 #include <svl/zforlist.hxx>
29 #include <svl/zformat.hxx>
30 #include <tools/urlobj.hxx>
31 #include <unotools/charclass.hxx>
32 #include <sfx2/docfile.hxx>
33 #include <sfx2/printer.hxx>
34 #include <unotools/collatorwrapper.hxx>
35 #include <unotools/transliterationwrapper.hxx>
36 #include <rtl/ustring.hxx>
37 #include <unicode/uchar.h>
39 #include "patattr.hxx"
41 #include "document.hxx"
42 #include "dociter.hxx"
43 #include "formulacell.hxx"
44 #include "scmatrix.hxx"
45 #include "docoptio.hxx"
46 #include "globstr.hrc"
48 #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/string.hxx>
65 #include "svl/sharedstringpool.hxx"
74 static const sal_uInt64 n2power48
= SAL_CONST_UINT64( 281474976710656); // 2^48
76 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack
)
77 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter
)
79 ScCalcConfig
ScInterpreter::maGlobalConfig
;
80 ScTokenStack
* ScInterpreter::pGlobalStack
= NULL
;
81 bool ScInterpreter::bGlobalStackInUse
= false;
83 using namespace formula
;
84 using ::std::auto_ptr
;
86 void ScInterpreter::ScIfJump()
88 const short* pJump
= pCur
->GetJump();
89 short nJumpCount
= pJump
[ 0 ];
90 MatrixDoubleRefToMatrix();
91 switch ( GetStackType() )
95 ScMatrixRef pMat
= PopMatrix();
97 PushIllegalParameter();
100 FormulaTokenRef xNew
;
101 ScTokenMatrixMap::const_iterator aMapIter
;
102 // DoubleError handled by JumpMatrix
103 pMat
->SetErrorInterpreter( NULL
);
105 pMat
->GetDimensions( nCols
, nRows
);
106 if ( nCols
== 0 || nRows
== 0 )
108 PushIllegalArgument();
111 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
112 pCur
)) != pTokenMatrixMap
->end()))
113 xNew
= (*aMapIter
).second
;
116 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
117 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
119 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
123 bool bIsValue
= pMat
->IsValue(nC
, nR
);
126 fVal
= pMat
->GetDouble(nC
, nR
);
127 bIsValue
= ::rtl::math::isFinite(fVal
);
128 bTrue
= bIsValue
&& (fVal
!= 0.0);
134 // Treat empty and empty path as 0, but string
136 bIsValue
= (!pMat
->IsString(nC
, nR
) || pMat
->IsEmpty(nC
, nR
));
138 fVal
= (bIsValue
? 0.0 : CreateDoubleError( errNoValue
));
142 if( nJumpCount
>= 2 )
144 pJumpMat
->SetJump( nC
, nR
, fVal
,
146 pJump
[ nJumpCount
]);
149 { // no parameter given for THEN
150 pJumpMat
->SetJump( nC
, nR
, fVal
,
152 pJump
[ nJumpCount
]);
157 if( nJumpCount
== 3 && bIsValue
)
159 pJumpMat
->SetJump( nC
, nR
, fVal
,
161 pJump
[ nJumpCount
]);
164 { // no parameter given for ELSE,
166 pJumpMat
->SetJump( nC
, nR
, fVal
,
168 pJump
[ nJumpCount
]);
173 xNew
= new ScJumpMatrixToken( pJumpMat
);
174 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur
, xNew
));
176 PushTempToken( xNew
.get());
177 // set endpoint of path for main code line
178 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
186 if( nJumpCount
>= 2 )
188 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
191 { // no parameter given for THEN
192 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
194 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
199 if( nJumpCount
== 3 )
201 aCode
.Jump( pJump
[ 2 ], pJump
[ nJumpCount
] );
204 { // no parameter given for ELSE
205 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
207 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
215 /** Store a matrix value in another matrix in the context of that other matrix
216 is the result matrix of a jump matrix. All arguments must be valid and are
218 static void lcl_storeJumpMatResult(
219 const ScMatrix
* pMat
, ScJumpMatrix
* pJumpMat
, SCSIZE nC
, SCSIZE nR
)
221 if ( pMat
->IsValue( nC
, nR
) )
223 double fVal
= pMat
->GetDouble( nC
, nR
);
224 pJumpMat
->PutResultDouble( fVal
, nC
, nR
);
226 else if ( pMat
->IsEmpty( nC
, nR
) )
228 pJumpMat
->PutResultEmpty( nC
, nR
);
232 pJumpMat
->PutResultString(pMat
->GetString(nC
, nR
), nC
, nR
);
237 void ScInterpreter::ScIfError( bool bNAonly
)
239 const short* pJump
= pCur
->GetJump();
240 short nJumpCount
= pJump
[ 0 ];
243 PushError( errUnknownStackVariable
);
244 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
248 FormulaTokenRef
xToken( pStack
[ sp
- 1 ] );
250 sal_uInt16 nOldGlobalError
= nGlobalError
;
253 MatrixDoubleRefToMatrix();
254 switch (GetStackType())
267 if (!PopDoubleRefOrSingleRef( aAdr
))
272 ScRefCellValue aCell
;
273 aCell
.assign(*pDok
, aAdr
);
274 nGlobalError
= GetCellErrCode(aCell
);
280 case svExternalSingleRef
:
281 case svExternalDoubleRef
:
284 svl::SharedString aStr
;
285 // Handles also existing jump matrix case and sets error on
287 GetDoubleOrStringFromMatrix( fVal
, aStr
);
294 const ScMatrixRef pMat
= PopMatrix();
295 if (!pMat
|| (nGlobalError
&& (!bNAonly
|| nGlobalError
== NOTAVAILABLE
)))
300 // If the matrix has no queried error at all we can simply use
301 // it as result and don't need to bother with jump matrix.
302 SCSIZE nErrorCol
= ::std::numeric_limits
<SCSIZE
>::max(),
303 nErrorRow
= ::std::numeric_limits
<SCSIZE
>::max();
305 pMat
->GetDimensions( nCols
, nRows
);
306 if (nCols
== 0 || nRows
== 0)
311 for (SCSIZE nC
=0; nC
< nCols
&& !bError
; ++nC
)
313 for (SCSIZE nR
=0; nR
< nRows
&& !bError
; ++nR
)
315 sal_uInt16 nErr
= pMat
->GetError( nC
, nR
);
316 if (nErr
&& (!bNAonly
|| nErr
== NOTAVAILABLE
))
325 break; // switch, we're done and have the result
327 FormulaTokenRef xNew
;
328 ScTokenMatrixMap::const_iterator aMapIter
;
329 if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find( pCur
)) != pTokenMatrixMap
->end()))
331 xNew
= (*aMapIter
).second
;
335 const ScMatrix
* pMatPtr
= pMat
.get();
336 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
337 // Init all jumps to no error to save single calls. Error
338 // is the exceptional condition.
339 const double fFlagResult
= CreateDoubleError( errJumpMatHasResult
);
340 pJumpMat
->SetAllJumps( fFlagResult
, pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
341 // Up to first error position simply store results, no need
342 // to evaluate error conditions again.
343 SCSIZE nC
= 0, nR
= 0;
344 for ( ; nC
< nCols
&& (nC
!= nErrorCol
|| nR
!= nErrorRow
); /*nop*/ )
346 for ( ; nR
< nRows
&& (nC
!= nErrorCol
|| nR
!= nErrorRow
); ++nR
)
348 lcl_storeJumpMatResult(pMatPtr
, pJumpMat
, nC
, nR
);
350 if (nC
!= nErrorCol
|| nR
!= nErrorRow
)
353 // Now the mixed cases.
354 for ( ; nC
< nCols
; ++nC
)
356 for ( ; nR
< nRows
; ++nR
)
358 sal_uInt16 nErr
= pMat
->GetError( nC
, nR
);
359 if (nErr
&& (!bNAonly
|| nErr
== NOTAVAILABLE
))
361 pJumpMat
->SetJump( nC
, nR
, 1.0, pJump
[ 1 ], pJump
[ nJumpCount
] );
364 { // FALSE, EMPTY path, store result instead
365 lcl_storeJumpMatResult(pMatPtr
, pJumpMat
, nC
, nR
);
369 xNew
= new ScJumpMatrixToken( pJumpMat
);
370 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type( pCur
, xNew
));
372 nGlobalError
= nOldGlobalError
;
373 PushTempToken( xNew
.get() );
374 // set endpoint of path for main code line
375 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
381 if (bError
&& (!bNAonly
|| nGlobalError
== NOTAVAILABLE
))
383 // error, calculate 2nd argument
385 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
389 // no error, push 1st argument and continue
390 nGlobalError
= nOldGlobalError
;
391 PushTempToken( xToken
.get());
392 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
397 void ScInterpreter::ScChoseJump()
399 // We have to set a jump, if there was none chosen because of an error set
401 bool bHaveJump
= false;
402 const short* pJump
= pCur
->GetJump();
403 short nJumpCount
= pJump
[ 0 ];
404 MatrixDoubleRefToMatrix();
405 switch ( GetStackType() )
409 ScMatrixRef pMat
= PopMatrix();
411 PushIllegalParameter();
414 FormulaTokenRef xNew
;
415 ScTokenMatrixMap::const_iterator aMapIter
;
416 // DoubleError handled by JumpMatrix
417 pMat
->SetErrorInterpreter( NULL
);
419 pMat
->GetDimensions( nCols
, nRows
);
420 if ( nCols
== 0 || nRows
== 0 )
421 PushIllegalParameter();
422 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
423 pCur
)) != pTokenMatrixMap
->end()))
424 xNew
= (*aMapIter
).second
;
427 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
428 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
430 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
433 bool bIsValue
= pMat
->IsValue(nC
, nR
);
436 fVal
= pMat
->GetDouble(nC
, nR
);
437 bIsValue
= ::rtl::math::isFinite( fVal
);
440 fVal
= ::rtl::math::approxFloor( fVal
);
441 if ( (fVal
< 1) || (fVal
>= nJumpCount
))
444 fVal
= CreateDoubleError(
451 fVal
= CreateDoubleError( errNoValue
);
455 pJumpMat
->SetJump( nC
, nR
, fVal
,
456 pJump
[ (short)fVal
],
457 pJump
[ nJumpCount
]);
461 pJumpMat
->SetJump( nC
, nR
, fVal
,
463 pJump
[ nJumpCount
]);
467 xNew
= new ScJumpMatrixToken( pJumpMat
);
468 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
471 PushTempToken( xNew
.get());
472 // set endpoint of path for main code line
473 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
480 double nJumpIndex
= ::rtl::math::approxFloor( GetDouble() );
481 if (!nGlobalError
&& (nJumpIndex
>= 1) && (nJumpIndex
< nJumpCount
))
483 aCode
.Jump( pJump
[ (short) nJumpIndex
], pJump
[ nJumpCount
] );
487 PushIllegalArgument();
491 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
494 static void lcl_AdjustJumpMatrix( ScJumpMatrix
* pJumpM
, SCSIZE nParmCols
, SCSIZE nParmRows
)
496 SCSIZE nJumpCols
, nJumpRows
;
497 SCSIZE nResCols
, nResRows
;
498 SCSIZE nAdjustCols
, nAdjustRows
;
499 pJumpM
->GetDimensions( nJumpCols
, nJumpRows
);
500 pJumpM
->GetResMatDimensions( nResCols
, nResRows
);
501 if (( nJumpCols
== 1 && nParmCols
> nResCols
) ||
502 ( nJumpRows
== 1 && nParmRows
> nResRows
))
504 if ( nJumpCols
== 1 && nJumpRows
== 1 )
506 nAdjustCols
= nParmCols
> nResCols
? nParmCols
: nResCols
;
507 nAdjustRows
= nParmRows
> nResRows
? nParmRows
: nResRows
;
509 else if ( nJumpCols
== 1 )
511 nAdjustCols
= nParmCols
;
512 nAdjustRows
= nResRows
;
516 nAdjustCols
= nResCols
;
517 nAdjustRows
= nParmRows
;
519 pJumpM
->SetNewResMat( nAdjustCols
, nAdjustRows
);
523 bool ScInterpreter::JumpMatrix( short nStackLevel
)
525 pJumpMatrix
= static_cast<ScToken
*>(pStack
[sp
-nStackLevel
])->GetJumpMatrix();
526 bool bHasResMat
= pJumpMatrix
->HasResultMatrix();
528 if ( nStackLevel
== 2 )
530 if ( aCode
.HasStacked() )
531 aCode
.Pop(); // pop what Jump() pushed
534 OSL_FAIL( "ScInterpreter::JumpMatrix: pop goes the weasel" );
540 SetError( errUnknownStackVariable
);
544 pJumpMatrix
->GetPos( nC
, nR
);
545 switch ( GetStackType() )
549 double fVal
= GetDouble();
552 fVal
= CreateDoubleError( nGlobalError
);
555 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
560 svl::SharedString aStr
= GetString();
563 pJumpMatrix
->PutResultDouble( CreateDoubleError( nGlobalError
),
568 pJumpMatrix
->PutResultString(aStr
, nC
, nR
);
574 PopSingleRef( aAdr
);
577 pJumpMatrix
->PutResultDouble( CreateDoubleError( nGlobalError
),
583 ScRefCellValue aCell
;
584 aCell
.assign(*pDok
, aAdr
);
585 if (aCell
.hasEmptyValue())
586 pJumpMatrix
->PutResultEmpty( nC
, nR
);
587 else if (aCell
.hasNumeric())
589 double fVal
= GetCellValue(aAdr
, aCell
);
592 fVal
= CreateDoubleError(
596 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
600 svl::SharedString aStr
;
601 GetCellString(aStr
, aCell
);
604 pJumpMatrix
->PutResultDouble( CreateDoubleError(
605 nGlobalError
), nC
, nR
);
609 pJumpMatrix
->PutResultString(aStr
, nC
, nR
);
615 { // upper left plus offset within matrix
618 PopDoubleRef( aRange
);
621 fVal
= CreateDoubleError( nGlobalError
);
623 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
627 // Do not modify the original range because we use it
628 // to adjust the size of the result matrix if necessary.
629 ScAddress
aAdr( aRange
.aStart
);
630 sal_uLong nCol
= (sal_uLong
)aAdr
.Col() + nC
;
631 sal_uLong nRow
= (sal_uLong
)aAdr
.Row() + nR
;
632 if ((nCol
> static_cast<sal_uLong
>(aRange
.aEnd
.Col()) &&
633 aRange
.aEnd
.Col() != aRange
.aStart
.Col())
634 || (nRow
> static_cast<sal_uLong
>(aRange
.aEnd
.Row()) &&
635 aRange
.aEnd
.Row() != aRange
.aStart
.Row()))
637 fVal
= CreateDoubleError( NOTAVAILABLE
);
638 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
642 // Replicate column and/or row of a vector if it is
643 // one. Note that this could be a range reference
644 // that in fact consists of only one cell, e.g. A1:A1
645 if (aRange
.aEnd
.Col() == aRange
.aStart
.Col())
646 nCol
= aRange
.aStart
.Col();
647 if (aRange
.aEnd
.Row() == aRange
.aStart
.Row())
648 nRow
= aRange
.aStart
.Row();
649 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) );
650 aAdr
.SetRow( static_cast<SCROW
>(nRow
) );
651 ScRefCellValue aCell
;
652 aCell
.assign(*pDok
, aAdr
);
653 if (aCell
.hasEmptyValue())
654 pJumpMatrix
->PutResultEmpty( nC
, nR
);
655 else if (aCell
.hasNumeric())
657 double fCellVal
= GetCellValue(aAdr
, aCell
);
660 fCellVal
= CreateDoubleError(
664 pJumpMatrix
->PutResultDouble( fCellVal
, nC
, nR
);
668 svl::SharedString aStr
;
669 GetCellString(aStr
, aCell
);
672 pJumpMatrix
->PutResultDouble( CreateDoubleError(
673 nGlobalError
), nC
, nR
);
677 pJumpMatrix
->PutResultString(aStr
, nC
, nR
);
680 SCSIZE nParmCols
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
681 SCSIZE nParmRows
= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
682 lcl_AdjustJumpMatrix( pJumpMatrix
, nParmCols
, nParmRows
);
687 { // match matrix offsets
689 ScMatrixRef pMat
= PopMatrix();
692 fVal
= CreateDoubleError( nGlobalError
);
694 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
698 fVal
= CreateDoubleError( errUnknownVariable
);
699 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
704 pMat
->GetDimensions( nCols
, nRows
);
705 if ((nCols
<= nC
&& nCols
!= 1) ||
706 (nRows
<= nR
&& nRows
!= 1))
708 fVal
= CreateDoubleError( NOTAVAILABLE
);
709 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
713 lcl_storeJumpMatResult(pMat
.get(), pJumpMatrix
, nC
, nR
);
715 lcl_AdjustJumpMatrix( pJumpMatrix
, nCols
, nRows
);
722 double fVal
= CreateDoubleError( nGlobalError
);
724 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
730 double fVal
= CreateDoubleError( errIllegalArgument
);
731 pJumpMatrix
->PutResultDouble( fVal
, nC
, nR
);
736 bool bCont
= pJumpMatrix
->Next( nC
, nR
);
740 short nStart
, nNext
, nStop
;
741 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
742 while ( bCont
&& nStart
== nNext
)
743 { // push all results that have no jump path
744 if ( bHasResMat
&& (GetDoubleErrorValue( fBool
) != errJumpMatHasResult
) )
746 // a false without path results in an empty path value
748 pJumpMatrix
->PutResultEmptyPath( nC
, nR
);
750 pJumpMatrix
->PutResultDouble( fBool
, nC
, nR
);
752 bCont
= pJumpMatrix
->Next( nC
, nR
);
754 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
756 if ( bCont
&& nStart
!= nNext
)
758 const ScTokenVec
* pParams
= pJumpMatrix
->GetJumpParameters();
761 for ( ScTokenVec::const_iterator i
= pParams
->begin();
762 i
!= pParams
->end(); ++i
)
764 // This is not the current state of the interpreter, so
765 // push without error, and elements' errors are coded into
767 PushWithoutError( *(*i
));
770 aCode
.Jump( nStart
, nNext
, nStop
);
774 { // we're done with it, throw away jump matrix, keep result
775 ScMatrix
* pResMat
= pJumpMatrix
->GetResultMatrix();
778 PushMatrix( pResMat
);
779 // Remove jump matrix from map and remember result matrix in case it
780 // could be reused in another path of the same condition.
783 pTokenMatrixMap
->erase( pCur
);
784 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type( pCur
,
792 double ScInterpreter::Compare()
795 aComp
.mbIgnoreCase
= pDok
->GetDocOptions().IsIgnoreCase();
796 for( short i
= 1; i
>= 0; i
-- )
798 sc::Compare::Cell
& rCell
= aComp
.maCells
[i
];
800 switch ( GetRawStackType() )
804 rCell
.mbEmpty
= true;
808 rCell
.mfValue
= GetDouble();
809 rCell
.mbValue
= true;
812 rCell
.maStr
= GetString();
813 rCell
.mbValue
= false;
819 if ( !PopDoubleRefOrSingleRef( aAdr
) )
821 ScRefCellValue aCell
;
822 aCell
.assign(*pDok
, aAdr
);
823 if (aCell
.hasEmptyValue())
824 rCell
.mbEmpty
= true;
825 else if (aCell
.hasString())
827 svl::SharedString aStr
;
828 GetCellString(aStr
, aCell
);
830 rCell
.mbValue
= false;
834 rCell
.mfValue
= GetCellValue(aAdr
, aCell
);
835 rCell
.mbValue
= true;
839 case svExternalSingleRef
:
841 ScMatrixRef pMat
= GetMatrix();
844 SetError( errIllegalParameter
);
849 pMat
->GetDimensions(nC
, nR
);
852 SetError( errIllegalParameter
);
855 if (pMat
->IsEmpty(0, 0))
856 rCell
.mbEmpty
= true;
857 else if (pMat
->IsString(0, 0))
859 rCell
.maStr
= pMat
->GetString(0, 0);
860 rCell
.mbValue
= false;
864 rCell
.mfValue
= pMat
->GetDouble(0, 0);
865 rCell
.mbValue
= true;
869 case svExternalDoubleRef
:
870 // TODO: Find out how to handle this...
872 SetError( errIllegalParameter
);
878 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
879 return sc::CompareFunc(aComp
.maCells
[0], aComp
.maCells
[1], aComp
.mbIgnoreCase
);
883 sc::RangeMatrix
ScInterpreter::CompareMat( ScQueryOp eOp
, sc::CompareOptions
* pOptions
)
887 aComp
.mbIgnoreCase
= pDok
->GetDocOptions().IsIgnoreCase();
888 sc::RangeMatrix aMat
[2];
890 for( short i
= 1; i
>= 0; i
-- )
892 sc::Compare::Cell
& rCell
= aComp
.maCells
[i
];
894 switch (GetRawStackType())
898 rCell
.mbEmpty
= true;
902 rCell
.mfValue
= GetDouble();
903 rCell
.mbValue
= true;
906 rCell
.maStr
= GetString();
907 rCell
.mbValue
= false;
911 PopSingleRef( aAdr
);
912 ScRefCellValue aCell
;
913 aCell
.assign(*pDok
, aAdr
);
914 if (aCell
.hasEmptyValue())
915 rCell
.mbEmpty
= true;
916 else if (aCell
.hasString())
918 svl::SharedString aStr
;
919 GetCellString(aStr
, aCell
);
921 rCell
.mbValue
= false;
925 rCell
.mfValue
= GetCellValue(aAdr
, aCell
);
926 rCell
.mbValue
= true;
932 aMat
[i
] = GetRangeMatrix();
934 SetError( errIllegalParameter
);
936 aMat
[i
].mpMat
->SetErrorInterpreter(NULL
);
937 // errors are transported as DoubleError inside matrix
940 SetError( errIllegalParameter
);
945 sc::RangeMatrix aRes
;
949 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
953 if (aMat
[0].mpMat
&& aMat
[1].mpMat
)
957 aMat
[0].mpMat
->GetDimensions(nC0
, nR0
);
958 aMat
[1].mpMat
->GetDimensions(nC1
, nR1
);
959 SCSIZE nC
= std::max( nC0
, nC1
);
960 SCSIZE nR
= std::max( nR0
, nR1
);
961 aRes
.mpMat
= GetNewMat( nC
, nR
);
964 for ( SCSIZE j
=0; j
<nC
; j
++ )
966 for ( SCSIZE k
=0; k
<nR
; k
++ )
968 SCSIZE nCol
= j
, nRow
= k
;
969 if (aMat
[0].mpMat
->ValidColRowOrReplicated(nCol
, nRow
) &&
970 aMat
[1].mpMat
->ValidColRowOrReplicated(nCol
, nRow
))
972 for ( short i
=1; i
>=0; i
-- )
974 sc::Compare::Cell
& rCell
= aComp
.maCells
[i
];
976 if (aMat
[i
].mpMat
->IsString(j
, k
))
978 rCell
.mbValue
= false;
979 rCell
.maStr
= aMat
[i
].mpMat
->GetString(j
, k
);
980 rCell
.mbEmpty
= aMat
[i
].mpMat
->IsEmpty(j
, k
);
984 rCell
.mbValue
= true;
985 rCell
.mfValue
= aMat
[i
].mpMat
->GetDouble(j
, k
);
986 rCell
.mbEmpty
= false;
989 aRes
.mpMat
->PutDouble(
990 sc::CompareFunc(aComp
.maCells
[0], aComp
.maCells
[1], aComp
.mbIgnoreCase
, pOptions
), j
, k
);
993 aRes
.mpMat
->PutString(mrStrPool
.intern(ScGlobal::GetRscString(STR_NO_VALUE
)), j
, k
);
1000 aRes
.mpMat
->CompareEqual();
1003 aRes
.mpMat
->CompareLess();
1006 aRes
.mpMat
->CompareGreater();
1009 aRes
.mpMat
->CompareLessEqual();
1011 case SC_GREATER_EQUAL
:
1012 aRes
.mpMat
->CompareGreaterEqual();
1015 aRes
.mpMat
->CompareNotEqual();
1018 OSL_TRACE( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)eOp
);
1023 else if (aMat
[0].mpMat
|| aMat
[1].mpMat
)
1025 size_t i
= ( aMat
[0].mpMat
? 0 : 1);
1027 aRes
.mnCol1
= aMat
[i
].mnCol1
;
1028 aRes
.mnRow1
= aMat
[i
].mnRow1
;
1029 aRes
.mnTab1
= aMat
[i
].mnTab1
;
1030 aRes
.mnCol2
= aMat
[i
].mnCol2
;
1031 aRes
.mnRow2
= aMat
[i
].mnRow2
;
1032 aRes
.mnTab2
= aMat
[i
].mnTab2
;
1034 ScMatrix
& rMat
= *aMat
[i
].mpMat
;
1035 aRes
.mpMat
= rMat
.CompareMatrix(aComp
, i
, pOptions
);
1040 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1045 ScMatrixRef
ScInterpreter::QueryMat( const ScMatrixRef
& pMat
, sc::CompareOptions
& rOptions
)
1047 short nSaveCurFmtType
= nCurFmtType
;
1048 short nSaveFuncFmtType
= nFuncFmtType
;
1050 const ScQueryEntry::Item
& rItem
= rOptions
.aQueryEntry
.GetQueryItem();
1051 if (rItem
.meType
== ScQueryEntry::ByString
)
1052 PushString(rItem
.maString
.getString());
1054 PushDouble(rItem
.mfVal
);
1055 ScMatrixRef pResultMatrix
= CompareMat(rOptions
.aQueryEntry
.eOp
, &rOptions
).mpMat
;
1056 nCurFmtType
= nSaveCurFmtType
;
1057 nFuncFmtType
= nSaveFuncFmtType
;
1058 if (nGlobalError
|| !pResultMatrix
)
1060 SetError( errIllegalParameter
);
1061 return pResultMatrix
;
1064 return pResultMatrix
;
1067 void ScInterpreter::ScEqual()
1069 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1071 sc::RangeMatrix aMat
= CompareMat(SC_EQUAL
);
1074 PushIllegalParameter();
1081 PushInt( Compare() == 0 );
1085 void ScInterpreter::ScNotEqual()
1087 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1089 sc::RangeMatrix aMat
= CompareMat(SC_NOT_EQUAL
);
1092 PushIllegalParameter();
1099 PushInt( Compare() != 0 );
1103 void ScInterpreter::ScLess()
1105 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1107 sc::RangeMatrix aMat
= CompareMat(SC_LESS
);
1110 PushIllegalParameter();
1117 PushInt( Compare() < 0 );
1121 void ScInterpreter::ScGreater()
1123 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1125 sc::RangeMatrix aMat
= CompareMat(SC_GREATER
);
1128 PushIllegalParameter();
1135 PushInt( Compare() > 0 );
1139 void ScInterpreter::ScLessEqual()
1141 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1143 sc::RangeMatrix aMat
= CompareMat(SC_LESS_EQUAL
);
1146 PushIllegalParameter();
1153 PushInt( Compare() <= 0 );
1157 void ScInterpreter::ScGreaterEqual()
1159 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1161 sc::RangeMatrix aMat
= CompareMat(SC_GREATER_EQUAL
);
1164 PushIllegalParameter();
1171 PushInt( Compare() >= 0 );
1175 void ScInterpreter::ScAnd()
1177 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1178 short nParamCount
= GetByte();
1179 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1181 bool bHaveValue
= false;
1183 size_t nRefInList
= 0;
1184 while( nParamCount
-- > 0)
1186 if ( !nGlobalError
)
1188 switch ( GetStackType() )
1192 nRes
&= ( PopDouble() != 0.0 );
1196 SetError( errNoValue
);
1201 PopSingleRef( aAdr
);
1202 if ( !nGlobalError
)
1204 ScRefCellValue aCell
;
1205 aCell
.assign(*pDok
, aAdr
);
1206 if (aCell
.hasNumeric())
1209 nRes
&= ( GetCellValue(aAdr
, aCell
) != 0.0 );
1211 // else: Xcl raises no error here
1219 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1220 if ( !nGlobalError
)
1223 sal_uInt16 nErr
= 0;
1224 ScValueIterator
aValIter( pDok
, aRange
);
1225 if ( aValIter
.GetFirst( fVal
, nErr
) )
1230 nRes
&= ( fVal
!= 0.0 );
1231 } while ( (nErr
== 0) &&
1232 aValIter
.GetNext( fVal
, nErr
) );
1238 case svExternalSingleRef
:
1239 case svExternalDoubleRef
:
1242 ScMatrixRef pMat
= GetMatrix();
1246 double fVal
= pMat
->And();
1247 sal_uInt16 nErr
= GetDoubleErrorValue( fVal
);
1254 nRes
&= (fVal
!= 0.0);
1256 // else: GetMatrix did set errIllegalParameter
1261 SetError( errIllegalParameter
);
1275 void ScInterpreter::ScOr()
1277 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1278 short nParamCount
= GetByte();
1279 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1281 bool bHaveValue
= false;
1283 size_t nRefInList
= 0;
1284 while( nParamCount
-- > 0)
1286 if ( !nGlobalError
)
1288 switch ( GetStackType() )
1292 nRes
|= ( PopDouble() != 0.0 );
1296 SetError( errNoValue
);
1301 PopSingleRef( aAdr
);
1302 if ( !nGlobalError
)
1304 ScRefCellValue aCell
;
1305 aCell
.assign(*pDok
, aAdr
);
1306 if (aCell
.hasNumeric())
1309 nRes
|= ( GetCellValue(aAdr
, aCell
) != 0.0 );
1311 // else: Xcl raises no error here
1319 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1320 if ( !nGlobalError
)
1323 sal_uInt16 nErr
= 0;
1324 ScValueIterator
aValIter( pDok
, aRange
);
1325 if ( aValIter
.GetFirst( fVal
, nErr
) )
1330 nRes
|= ( fVal
!= 0.0 );
1331 } while ( (nErr
== 0) &&
1332 aValIter
.GetNext( fVal
, nErr
) );
1338 case svExternalSingleRef
:
1339 case svExternalDoubleRef
:
1343 ScMatrixRef pMat
= GetMatrix();
1347 double fVal
= pMat
->Or();
1348 sal_uInt16 nErr
= GetDoubleErrorValue( fVal
);
1355 nRes
|= (fVal
!= 0.0);
1357 // else: GetMatrix did set errIllegalParameter
1362 SetError( errIllegalParameter
);
1376 void ScInterpreter::ScXor()
1379 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1380 short nParamCount
= GetByte();
1381 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1383 bool bHaveValue
= false;
1385 size_t nRefInList
= 0;
1386 while( nParamCount
-- > 0)
1388 if ( !nGlobalError
)
1390 switch ( GetStackType() )
1394 nRes
^= ( PopDouble() != 0.0 );
1398 SetError( errNoValue
);
1403 PopSingleRef( aAdr
);
1404 if ( !nGlobalError
)
1406 ScRefCellValue aCell
;
1407 aCell
.assign(*pDok
, aAdr
);
1408 if (aCell
.hasNumeric())
1411 nRes
^= ( GetCellValue(aAdr
, aCell
) != 0.0 );
1413 /* TODO: set error? Excel doesn't have XOR, but
1414 * doesn't set an error in this case for AND and
1423 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1424 if ( !nGlobalError
)
1427 sal_uInt16 nErr
= 0;
1428 ScValueIterator
aValIter( pDok
, aRange
);
1429 if ( aValIter
.GetFirst( fVal
, nErr
) )
1434 nRes
^= ( fVal
!= 0.0 );
1435 } while ( (nErr
== 0) &&
1436 aValIter
.GetNext( fVal
, nErr
) );
1442 case svExternalSingleRef
:
1443 case svExternalDoubleRef
:
1447 ScMatrixRef pMat
= GetMatrix();
1451 double fVal
= pMat
->Xor();
1452 sal_uInt16 nErr
= GetDoubleErrorValue( fVal
);
1459 nRes
^= ( fVal
!= 0.0 );
1461 // else: GetMatrix did set errIllegalParameter
1466 SetError( errIllegalParameter
);
1480 void ScInterpreter::ScNeg()
1482 // Simple negation doesn't change current format type to number, keep
1484 nFuncFmtType
= nCurFmtType
;
1485 switch ( GetStackType() )
1489 ScMatrixRef pMat
= GetMatrix();
1491 PushIllegalParameter();
1495 pMat
->GetDimensions( nC
, nR
);
1496 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1498 PushIllegalArgument();
1501 for (SCSIZE i
= 0; i
< nC
; ++i
)
1503 for (SCSIZE j
= 0; j
< nR
; ++j
)
1505 if ( pMat
->IsValueOrEmpty(i
,j
) )
1506 pResMat
->PutDouble( -pMat
->GetDouble(i
,j
), i
, j
);
1509 mrStrPool
.intern(ScGlobal::GetRscString(STR_NO_VALUE
)), i
, j
);
1512 PushMatrix( pResMat
);
1518 PushDouble( -GetDouble() );
1523 void ScInterpreter::ScPercentSign()
1525 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1526 const FormulaToken
* pSaveCur
= pCur
;
1527 sal_uInt8 nSavePar
= cPar
;
1530 FormulaByteToken
aDivOp( ocDiv
, cPar
);
1538 void ScInterpreter::ScNot()
1540 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1541 switch ( GetStackType() )
1545 ScMatrixRef pMat
= GetMatrix();
1547 PushIllegalParameter();
1551 pMat
->GetDimensions( nC
, nR
);
1552 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1554 PushIllegalArgument();
1557 for (SCSIZE i
= 0; i
< nC
; ++i
)
1559 for (SCSIZE j
= 0; j
< nR
; ++j
)
1561 if ( pMat
->IsValueOrEmpty(i
,j
) )
1562 pResMat
->PutDouble( (pMat
->GetDouble(i
,j
) == 0.0), i
, j
);
1565 mrStrPool
.intern(ScGlobal::GetRscString(STR_NO_VALUE
)), i
, j
);
1568 PushMatrix( pResMat
);
1574 PushInt( GetDouble() == 0.0 );
1579 void ScInterpreter::ScBitAnd()
1582 if ( !MustHaveParamCount( GetByte(), 2 ) )
1585 double num1
= ::rtl::math::approxFloor( GetDouble());
1586 double num2
= ::rtl::math::approxFloor( GetDouble());
1587 if ( (num1
>= n2power48
) || (num1
< 0) ||
1588 (num2
>= n2power48
) || (num2
< 0))
1589 PushIllegalArgument();
1591 PushDouble ((sal_uInt64
) num1
& (sal_uInt64
) num2
);
1595 void ScInterpreter::ScBitOr()
1598 if ( !MustHaveParamCount( GetByte(), 2 ) )
1601 double num1
= ::rtl::math::approxFloor( GetDouble());
1602 double num2
= ::rtl::math::approxFloor( GetDouble());
1603 if ( (num1
>= n2power48
) || (num1
< 0) ||
1604 (num2
>= n2power48
) || (num2
< 0))
1605 PushIllegalArgument();
1607 PushDouble ((sal_uInt64
) num1
| (sal_uInt64
) num2
);
1611 void ScInterpreter::ScBitXor()
1614 if ( !MustHaveParamCount( GetByte(), 2 ) )
1617 double num1
= ::rtl::math::approxFloor( GetDouble());
1618 double num2
= ::rtl::math::approxFloor( GetDouble());
1619 if ( (num1
>= n2power48
) || (num1
< 0) ||
1620 (num2
>= n2power48
) || (num2
< 0))
1621 PushIllegalArgument();
1623 PushDouble ((sal_uInt64
) num1
^ (sal_uInt64
) num2
);
1627 void ScInterpreter::ScBitLshift()
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
= ::rtl::math::approxFloor( num
/ pow( 2.0, -fShift
));
1642 else if (fShift
== 0)
1645 fRes
= num
* pow( 2.0, fShift
);
1651 void ScInterpreter::ScBitRshift()
1654 if ( !MustHaveParamCount( GetByte(), 2 ) )
1657 double fShift
= ::rtl::math::approxFloor( GetDouble());
1658 double num
= ::rtl::math::approxFloor( GetDouble());
1659 if ((num
>= n2power48
) || (num
< 0))
1660 PushIllegalArgument();
1665 fRes
= num
* pow( 2.0, -fShift
);
1666 else if (fShift
== 0)
1669 fRes
= ::rtl::math::approxFloor( num
/ pow( 2.0, fShift
));
1675 void ScInterpreter::ScPi()
1681 void ScInterpreter::ScRandom()
1683 PushDouble(sc::rng::uniform());
1687 void ScInterpreter::ScTrue()
1689 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1694 void ScInterpreter::ScFalse()
1696 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1701 void ScInterpreter::ScDeg()
1703 PushDouble((GetDouble() / F_PI
) * 180.0);
1707 void ScInterpreter::ScRad()
1709 PushDouble(GetDouble() * (F_PI
/ 180));
1713 void ScInterpreter::ScSin()
1715 PushDouble(::rtl::math::sin(GetDouble()));
1719 void ScInterpreter::ScCos()
1721 PushDouble(::rtl::math::cos(GetDouble()));
1725 void ScInterpreter::ScTan()
1727 PushDouble(::rtl::math::tan(GetDouble()));
1731 void ScInterpreter::ScCot()
1733 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1737 void ScInterpreter::ScArcSin()
1739 PushDouble(asin(GetDouble()));
1743 void ScInterpreter::ScArcCos()
1745 PushDouble(acos(GetDouble()));
1749 void ScInterpreter::ScArcTan()
1751 PushDouble(atan(GetDouble()));
1755 void ScInterpreter::ScArcCot()
1757 PushDouble((F_PI2
) - atan(GetDouble()));
1761 void ScInterpreter::ScSinHyp()
1763 PushDouble(sinh(GetDouble()));
1767 void ScInterpreter::ScCosHyp()
1769 PushDouble(cosh(GetDouble()));
1773 void ScInterpreter::ScTanHyp()
1775 PushDouble(tanh(GetDouble()));
1779 void ScInterpreter::ScCotHyp()
1781 PushDouble(1.0 / tanh(GetDouble()));
1785 void ScInterpreter::ScArcSinHyp()
1787 PushDouble( ::rtl::math::asinh( GetDouble()));
1790 void ScInterpreter::ScArcCosHyp()
1792 double fVal
= GetDouble();
1794 PushIllegalArgument();
1796 PushDouble( ::rtl::math::acosh( fVal
));
1799 void ScInterpreter::ScArcTanHyp()
1801 double fVal
= GetDouble();
1802 if (fabs(fVal
) >= 1.0)
1803 PushIllegalArgument();
1805 PushDouble( ::rtl::math::atanh( fVal
));
1809 void ScInterpreter::ScArcCotHyp()
1811 double nVal
= GetDouble();
1812 if (fabs(nVal
) <= 1.0)
1813 PushIllegalArgument();
1815 PushDouble(0.5 * log((nVal
+ 1.0) / (nVal
- 1.0)));
1818 void ScInterpreter::ScCosecant()
1820 PushDouble(1.0 / ::rtl::math::sin(GetDouble()));
1823 void ScInterpreter::ScSecant()
1825 PushDouble(1.0 / ::rtl::math::cos(GetDouble()));
1828 void ScInterpreter::ScCosecantHyp()
1830 PushDouble(1.0 / sinh(GetDouble()));
1833 void ScInterpreter::ScSecantHyp()
1835 PushDouble(1.0 / cosh(GetDouble()));
1839 void ScInterpreter::ScExp()
1841 PushDouble(exp(GetDouble()));
1845 void ScInterpreter::ScSqrt()
1847 double fVal
= GetDouble();
1849 PushDouble(sqrt(fVal
));
1851 PushIllegalArgument();
1855 void ScInterpreter::ScIsEmpty()
1858 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1859 switch ( GetRawStackType() )
1863 FormulaTokenRef p
= PopToken();
1864 if (!static_cast<const ScEmptyCellToken
*>(p
.get())->IsInherited())
1872 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1874 // NOTE: this could test also on inherited emptiness, but then the
1875 // cell tested wouldn't be empty. Must correspond with
1876 // ScCountEmptyCells().
1877 ScRefCellValue aCell
;
1878 aCell
.assign(*pDok
, aAdr
);
1879 if (aCell
.meType
== CELLTYPE_NONE
)
1883 case svExternalSingleRef
:
1884 case svExternalDoubleRef
:
1887 ScMatrixRef pMat
= GetMatrix();
1890 else if ( !pJumpMatrix
)
1891 nRes
= pMat
->IsEmpty( 0, 0);
1894 SCSIZE nCols
, nRows
, nC
, nR
;
1895 pMat
->GetDimensions( nCols
, nRows
);
1896 pJumpMatrix
->GetPos( nC
, nR
);
1897 if ( nC
< nCols
&& nR
< nRows
)
1898 nRes
= pMat
->IsEmpty( nC
, nR
);
1899 // else: false, not empty (which is what Xcl does)
1911 short ScInterpreter::IsString()
1913 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1915 switch ( GetRawStackType() )
1925 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1928 ScRefCellValue aCell
;
1929 aCell
.assign(*pDok
, aAdr
);
1930 if (GetCellErrCode(aCell
) == 0)
1932 switch (aCell
.meType
)
1934 case CELLTYPE_STRING
:
1935 case CELLTYPE_EDIT
:
1938 case CELLTYPE_FORMULA
:
1939 nRes
= (!aCell
.mpFormula
->IsValue() && !aCell
.mpFormula
->IsEmpty());
1949 ScMatrixRef pMat
= PopMatrix();
1952 else if ( !pJumpMatrix
)
1953 nRes
= pMat
->IsString(0, 0) && !pMat
->IsEmpty(0, 0);
1956 SCSIZE nCols
, nRows
, nC
, nR
;
1957 pMat
->GetDimensions( nCols
, nRows
);
1958 pJumpMatrix
->GetPos( nC
, nR
);
1959 if ( nC
< nCols
&& nR
< nRows
)
1960 nRes
= pMat
->IsString( nC
, nR
) && !pMat
->IsEmpty( nC
, nR
);
1972 void ScInterpreter::ScIsString()
1974 PushInt( IsString() );
1978 void ScInterpreter::ScIsNonString()
1980 PushInt( !IsString() );
1984 void ScInterpreter::ScIsLogical()
1987 switch ( GetStackType() )
1993 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1996 ScRefCellValue aCell
;
1997 aCell
.assign(*pDok
, aAdr
);
1998 if (GetCellErrCode(aCell
) == 0)
2000 if (aCell
.hasNumeric())
2002 sal_uLong nFormat
= GetCellNumberFormat(aAdr
, aCell
);
2003 nRes
= (pFormatter
->GetType(nFormat
) == NUMBERFORMAT_LOGICAL
);
2009 // TODO: we don't have type information for arrays except
2010 // numerical/string.
2014 if ( !nGlobalError
)
2015 nRes
= ( nCurFmtType
== NUMBERFORMAT_LOGICAL
);
2017 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2023 void ScInterpreter::ScType()
2026 switch ( GetStackType() )
2032 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2035 ScRefCellValue aCell
;
2036 aCell
.assign(*pDok
, aAdr
);
2037 if (GetCellErrCode(aCell
) == 0)
2039 switch (aCell
.meType
)
2041 // NOTE: this is Xcl nonsense!
2042 case CELLTYPE_STRING
:
2043 case CELLTYPE_EDIT
:
2046 case CELLTYPE_VALUE
:
2048 sal_uLong nFormat
= GetCellNumberFormat(aAdr
, aCell
);
2049 if (pFormatter
->GetType(nFormat
) == NUMBERFORMAT_LOGICAL
)
2055 case CELLTYPE_FORMULA
:
2059 PushIllegalArgument();
2085 // we could return the type of one element if in JumpMatrix or
2086 // ForceArray mode, but Xcl doesn't ...
2102 static inline bool lcl_FormatHasNegColor( const SvNumberformat
* pFormat
)
2104 return pFormat
&& pFormat
->GetColor( 1 );
2108 static inline bool lcl_FormatHasOpenPar( const SvNumberformat
* pFormat
)
2110 return pFormat
&& (pFormat
->GetFormatstring().indexOf('(') != -1);
2115 void getFormatString(SvNumberFormatter
* pFormatter
, sal_uLong nFormat
, OUString
& rFmtStr
)
2117 bool bAppendPrec
= true;
2118 sal_uInt16 nPrec
, nLeading
;
2119 bool bThousand
, bIsRed
;
2120 pFormatter
->GetFormatSpecialInfo( nFormat
, bThousand
, bIsRed
, nPrec
, nLeading
);
2122 switch( pFormatter
->GetType( nFormat
) )
2124 case NUMBERFORMAT_NUMBER
: if(bThousand
) rFmtStr
= ","; else rFmtStr
= "F"; break;
2125 case NUMBERFORMAT_CURRENCY
: rFmtStr
= "C"; break;
2126 case NUMBERFORMAT_SCIENTIFIC
: rFmtStr
= "S"; break;
2127 case NUMBERFORMAT_PERCENT
: rFmtStr
= "P"; break;
2130 bAppendPrec
= false;
2131 switch( pFormatter
->GetIndexTableOffset( nFormat
) )
2133 case NF_DATE_SYSTEM_SHORT
:
2134 case NF_DATE_SYS_DMMMYY
:
2135 case NF_DATE_SYS_DDMMYY
:
2136 case NF_DATE_SYS_DDMMYYYY
:
2137 case NF_DATE_SYS_DMMMYYYY
:
2138 case NF_DATE_DIN_DMMMYYYY
:
2139 case NF_DATE_SYS_DMMMMYYYY
:
2140 case NF_DATE_DIN_DMMMMYYYY
: rFmtStr
= "D1"; break;
2141 case NF_DATE_SYS_DDMMM
: rFmtStr
= "D2"; break;
2142 case NF_DATE_SYS_MMYY
: rFmtStr
= "D3"; break;
2143 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
2144 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
2145 rFmtStr
= "D4"; break;
2146 case NF_DATE_DIN_MMDD
: rFmtStr
= "D5"; break;
2147 case NF_TIME_HHMMSSAMPM
: rFmtStr
= "D6"; break;
2148 case NF_TIME_HHMMAMPM
: rFmtStr
= "D7"; break;
2149 case NF_TIME_HHMMSS
: rFmtStr
= "D8"; break;
2150 case NF_TIME_HHMM
: rFmtStr
= "D9"; break;
2151 default: rFmtStr
= "G";
2156 rFmtStr
+= OUString::number(nPrec
);
2157 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( nFormat
);
2158 if( lcl_FormatHasNegColor( pFormat
) )
2160 if( lcl_FormatHasOpenPar( pFormat
) )
2166 void ScInterpreter::ScCell()
2167 { // ATTRIBUTE ; [REF]
2168 sal_uInt8 nParamCount
= GetByte();
2169 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
2171 ScAddress
aCellPos( aPos
);
2172 bool bError
= false;
2173 if( nParamCount
== 2 )
2175 switch (GetStackType())
2177 case svExternalSingleRef
:
2178 case svExternalDoubleRef
:
2180 // Let's handle external reference separately...
2187 bError
= !PopDoubleRefOrSingleRef( aCellPos
);
2189 OUString aInfoType
= GetString().getString();
2190 if( bError
|| nGlobalError
)
2191 PushIllegalParameter();
2194 ScRefCellValue aCell
;
2195 aCell
.assign(*pDok
, aCellPos
);
2197 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::GetLocale(), ocCell
);
2199 // *** ADDRESS INFO ***
2200 if( aInfoType
.equalsAscii( "COL" ) )
2201 { // column number (1-based)
2202 PushInt( aCellPos
.Col() + 1 );
2204 else if( aInfoType
.equalsAscii( "ROW" ) )
2205 { // row number (1-based)
2206 PushInt( aCellPos
.Row() + 1 );
2208 else if( aInfoType
.equalsAscii( "SHEET" ) )
2209 { // table number (1-based)
2210 PushInt( aCellPos
.Tab() + 1 );
2212 else if( aInfoType
.equalsAscii( "ADDRESS" ) )
2213 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
2214 sal_uInt16 nFlags
= (aCellPos
.Tab() == aPos
.Tab()) ? (SCA_ABS
) : (SCA_ABS_3D
);
2215 OUString
aStr(aCellPos
.Format(nFlags
, pDok
, pDok
->GetAddressConvention()));
2218 else if( aInfoType
.equalsAscii( "FILENAME" ) )
2219 { // file name and table name: 'FILENAME'#$TABLE
2220 SCTAB nTab
= aCellPos
.Tab();
2221 OUString aFuncResult
;
2222 if( nTab
< pDok
->GetTableCount() )
2224 if( pDok
->GetLinkMode( nTab
) == SC_LINK_VALUE
)
2225 pDok
->GetName( nTab
, aFuncResult
);
2228 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
2229 if( pShell
&& pShell
->GetMedium() )
2231 OUStringBuffer aBuf
;
2233 const INetURLObject
& rURLObj
= pShell
->GetMedium()->GetURLObject();
2234 aBuf
.append(rURLObj
.GetMainURL(INetURLObject::DECODE_UNAMBIGUOUS
));
2235 aBuf
.appendAscii("'#$");
2237 pDok
->GetName( nTab
, aTabName
);
2238 aBuf
.append(aTabName
);
2239 aFuncResult
= aBuf
.makeStringAndClear();
2243 PushString( aFuncResult
);
2245 else if( aInfoType
.equalsAscii( "COORD" ) )
2246 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
2247 // Yes, passing tab as col is intentional!
2248 OUStringBuffer aFuncResult
;
2250 ScAddress( static_cast<SCCOL
>(aCellPos
.Tab()), 0, 0 ).Format(
2251 (SCA_COL_ABSOLUTE
|SCA_VALID_COL
), NULL
, pDok
->GetAddressConvention() );
2252 aFuncResult
.append(aCellStr
);
2253 aFuncResult
.append(':');
2254 aCellStr
= aCellPos
.Format((SCA_COL_ABSOLUTE
|SCA_VALID_COL
|SCA_ROW_ABSOLUTE
|SCA_VALID_ROW
),
2255 NULL
, pDok
->GetAddressConvention());
2256 aFuncResult
.append(aCellStr
);
2257 PushString( aFuncResult
.makeStringAndClear() );
2260 // *** CELL PROPERTIES ***
2261 else if( aInfoType
.equalsAscii( "CONTENTS" ) )
2262 { // contents of the cell, no formatting
2263 if (aCell
.hasString())
2265 svl::SharedString aStr
;
2266 GetCellString(aStr
, aCell
);
2270 PushDouble(GetCellValue(aCellPos
, aCell
));
2272 else if( aInfoType
.equalsAscii( "TYPE" ) )
2273 { // b = blank; l = string (label); v = otherwise (value)
2275 if (aCell
.hasString())
2278 c
= aCell
.hasNumeric() ? 'v' : 'b';
2279 PushString( OUString(c
) );
2281 else if( aInfoType
.equalsAscii( "WIDTH" ) )
2282 { // column width (rounded off as count of zero characters in standard font and size)
2283 Printer
* pPrinter
= pDok
->GetPrinter();
2284 MapMode
aOldMode( pPrinter
->GetMapMode() );
2285 Font
aOldFont( pPrinter
->GetFont() );
2288 pPrinter
->SetMapMode( MAP_TWIP
);
2289 // font color doesn't matter here
2290 pDok
->GetDefPattern()->GetFont( aDefFont
, SC_AUTOCOL_BLACK
, pPrinter
);
2291 pPrinter
->SetFont( aDefFont
);
2292 long nZeroWidth
= pPrinter
->GetTextWidth( OUString( '0' ) );
2293 pPrinter
->SetFont( aOldFont
);
2294 pPrinter
->SetMapMode( aOldMode
);
2295 int nZeroCount
= (int)(pDok
->GetColWidth( aCellPos
.Col(), aCellPos
.Tab() ) / nZeroWidth
);
2296 PushInt( nZeroCount
);
2298 else if( aInfoType
.equalsAscii( "PREFIX" ) )
2299 { // ' = left; " = right; ^ = centered
2301 if (aCell
.hasString())
2303 const SvxHorJustifyItem
* pJustAttr
= (const SvxHorJustifyItem
*)
2304 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_HOR_JUSTIFY
);
2305 switch( pJustAttr
->GetValue() )
2307 case SVX_HOR_JUSTIFY_STANDARD
:
2308 case SVX_HOR_JUSTIFY_LEFT
:
2309 case SVX_HOR_JUSTIFY_BLOCK
: c
= '\''; break;
2310 case SVX_HOR_JUSTIFY_CENTER
: c
= '^'; break;
2311 case SVX_HOR_JUSTIFY_RIGHT
: c
= '"'; break;
2312 case SVX_HOR_JUSTIFY_REPEAT
: c
= '\\'; break;
2315 PushString( OUString(c
) );
2317 else if( aInfoType
.equalsAscii( "PROTECT" ) )
2318 { // 1 = cell locked
2319 const ScProtectionAttr
* pProtAttr
= (const ScProtectionAttr
*)
2320 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_PROTECTION
);
2321 PushInt( pProtAttr
->GetProtection() ? 1 : 0 );
2324 // *** FORMATTING ***
2325 else if( aInfoType
.equalsAscii( "FORMAT" ) )
2326 { // specific format code for standard formats
2327 OUString aFuncResult
;
2328 sal_uLong nFormat
= pDok
->GetNumberFormat( aCellPos
);
2329 getFormatString(pFormatter
, nFormat
, aFuncResult
);
2330 PushString( aFuncResult
);
2332 else if( aInfoType
.equalsAscii( "COLOR" ) )
2333 { // 1 = negative values are colored, otherwise 0
2334 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2335 PushInt( lcl_FormatHasNegColor( pFormat
) ? 1 : 0 );
2337 else if( aInfoType
.equalsAscii( "PARENTHESES" ) )
2338 { // 1 = format string contains a '(' character, otherwise 0
2339 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2340 PushInt( lcl_FormatHasOpenPar( pFormat
) ? 1 : 0 );
2343 PushIllegalArgument();
2348 void ScInterpreter::ScCellExternal()
2352 ScSingleRefData aRef
;
2353 ScExternalRefCache::TokenRef pToken
;
2354 ScExternalRefCache::CellFormat aFmt
;
2355 PopExternalSingleRef(nFileId
, aTabName
, aRef
, pToken
, &aFmt
);
2358 PushIllegalParameter();
2362 OUString aInfoType
= GetString().getString();
2365 PushIllegalParameter();
2372 aRef
.SetAbsTab(0); // external ref has a tab index of -1, which SingleRefToVars() don't like.
2373 SingleRefToVars(aRef
, nCol
, nRow
, nTab
);
2376 PushIllegalParameter();
2379 aRef
.SetAbsTab(-1); // revert the value.
2381 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::GetLocale(), ocCell
);
2382 ScExternalRefManager
* pRefMgr
= pDok
->GetExternalRefManager();
2384 if ( aInfoType
== "COL" )
2386 else if ( aInfoType
== "ROW" )
2388 else if ( aInfoType
== "SHEET" )
2390 // For SHEET, No idea what number we should set, but let's always set
2391 // 1 if the external sheet exists, no matter what sheet. Excel does
2393 if (pRefMgr
->getCacheTable(nFileId
, aTabName
, false, NULL
).get())
2396 SetError(errNoName
);
2398 else if ( aInfoType
== "ADDRESS" )
2400 // ODF 1.2 says we need to always display address using the ODF A1 grammar.
2401 ScTokenArray aArray
;
2402 aArray
.AddExternalSingleReference(nFileId
, aTabName
, aRef
);
2403 ScCompiler
aComp(pDok
, aPos
, aArray
);
2404 aComp
.SetGrammar(formula::FormulaGrammar::GRAM_ODFF_A1
);
2406 aComp
.CreateStringFromTokenArray(aStr
);
2409 else if ( aInfoType
== "FILENAME" )
2411 // 'file URI'#$SheetName
2413 const OUString
* p
= pRefMgr
->getExternalFileName(nFileId
);
2416 // In theory this should never happen...
2417 SetError(errNoName
);
2421 OUStringBuffer aBuf
;
2424 aBuf
.appendAscii("'#$");
2425 aBuf
.append(aTabName
);
2426 PushString(aBuf
.makeStringAndClear());
2428 else if ( aInfoType
== "CONTENTS" )
2430 switch (pToken
->GetType())
2433 PushString(pToken
->GetString());
2436 PushString(OUString::number(pToken
->GetDouble()));
2439 PushString(ScGlobal::GetErrorString(pToken
->GetError()));
2442 PushString(ScGlobal::GetEmptyOUString());
2445 else if ( aInfoType
== "TYPE" )
2447 sal_Unicode c
= 'v';
2448 switch (pToken
->GetType())
2459 PushString(OUString(c
));
2461 else if ( aInfoType
== "FORMAT" )
2464 sal_uLong nFmt
= aFmt
.mbIsSet
? aFmt
.mnIndex
: 0;
2465 getFormatString(pFormatter
, nFmt
, aFmtStr
);
2466 PushString(aFmtStr
);
2468 else if ( aInfoType
== "COLOR" )
2470 // 1 = negative values are colored, otherwise 0
2474 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(aFmt
.mnIndex
);
2475 nVal
= lcl_FormatHasNegColor(pFormat
) ? 1 : 0;
2479 else if ( aInfoType
== "PARENTHESES" )
2481 // 1 = format string contains a '(' character, otherwise 0
2485 const SvNumberformat
* pFormat
= pFormatter
->GetEntry(aFmt
.mnIndex
);
2486 nVal
= lcl_FormatHasOpenPar(pFormat
) ? 1 : 0;
2491 PushIllegalParameter();
2494 void ScInterpreter::ScIsRef()
2496 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2498 switch ( GetStackType() )
2503 PopSingleRef( aAdr
);
2504 if ( !nGlobalError
)
2511 PopDoubleRef( aRange
);
2512 if ( !nGlobalError
)
2518 FormulaTokenRef x
= PopToken();
2519 if ( !nGlobalError
)
2520 nRes
= !static_cast<ScToken
*>(x
.get())->GetRefList()->empty();
2531 void ScInterpreter::ScIsValue()
2533 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2535 switch ( GetRawStackType() )
2545 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2548 ScRefCellValue aCell
;
2549 aCell
.assign(*pDok
, aAdr
);
2550 if (GetCellErrCode(aCell
) == 0)
2552 switch (aCell
.meType
)
2554 case CELLTYPE_VALUE
:
2557 case CELLTYPE_FORMULA
:
2558 nRes
= (aCell
.mpFormula
->IsValue() && !aCell
.mpFormula
->IsEmpty());
2568 ScMatrixRef pMat
= PopMatrix();
2571 else if ( !pJumpMatrix
)
2573 if (pMat
->GetErrorIfNotString( 0, 0) == 0)
2574 nRes
= pMat
->IsValue( 0, 0);
2578 SCSIZE nCols
, nRows
, nC
, nR
;
2579 pMat
->GetDimensions( nCols
, nRows
);
2580 pJumpMatrix
->GetPos( nC
, nR
);
2581 if ( nC
< nCols
&& nR
< nRows
)
2582 if (pMat
->GetErrorIfNotString( nC
, nR
) == 0)
2583 nRes
= pMat
->IsValue( nC
, nR
);
2595 void ScInterpreter::ScIsFormula()
2597 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2599 switch ( GetStackType() )
2605 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2608 nRes
= (pDok
->GetCellType(aAdr
) == CELLTYPE_FORMULA
);
2619 void ScInterpreter::ScFormula()
2622 switch ( GetStackType() )
2628 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2631 ScRefCellValue aCell
;
2632 aCell
.assign(*pDok
, aAdr
);
2633 switch (aCell
.meType
)
2635 case CELLTYPE_FORMULA
:
2636 aCell
.mpFormula
->GetFormula(aFormula
);
2639 SetError( NOTAVAILABLE
);
2645 SetError( NOTAVAILABLE
);
2647 PushString( aFormula
);
2652 void ScInterpreter::ScIsNV()
2654 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2656 switch ( GetStackType() )
2662 PopDoubleRefOrSingleRef( aAdr
);
2663 if ( nGlobalError
== NOTAVAILABLE
)
2667 ScRefCellValue aCell
;
2668 aCell
.assign(*pDok
, aAdr
);
2669 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2670 nRes
= (nErr
== NOTAVAILABLE
);
2676 ScMatrixRef pMat
= PopMatrix();
2679 else if ( !pJumpMatrix
)
2680 nRes
= (pMat
->GetErrorIfNotString( 0, 0) == NOTAVAILABLE
);
2683 SCSIZE nCols
, nRows
, nC
, nR
;
2684 pMat
->GetDimensions( nCols
, nRows
);
2685 pJumpMatrix
->GetPos( nC
, nR
);
2686 if ( nC
< nCols
&& nR
< nRows
)
2687 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) == NOTAVAILABLE
);
2693 if ( nGlobalError
== NOTAVAILABLE
)
2701 void ScInterpreter::ScIsErr()
2703 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2705 switch ( GetStackType() )
2711 PopDoubleRefOrSingleRef( aAdr
);
2712 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2716 ScRefCellValue aCell
;
2717 aCell
.assign(*pDok
, aAdr
);
2718 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2719 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2725 ScMatrixRef pMat
= PopMatrix();
2726 if ( nGlobalError
|| !pMat
)
2727 nRes
= ((nGlobalError
&& nGlobalError
!= NOTAVAILABLE
) || !pMat
);
2728 else if ( !pJumpMatrix
)
2730 sal_uInt16 nErr
= pMat
->GetErrorIfNotString( 0, 0);
2731 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2735 SCSIZE nCols
, nRows
, nC
, nR
;
2736 pMat
->GetDimensions( nCols
, nRows
);
2737 pJumpMatrix
->GetPos( nC
, nR
);
2738 if ( nC
< nCols
&& nR
< nRows
)
2740 sal_uInt16 nErr
= pMat
->GetErrorIfNotString( nC
, nR
);
2741 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2748 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2756 void ScInterpreter::ScIsError()
2758 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2760 switch ( GetStackType() )
2766 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2775 ScRefCellValue aCell
;
2776 aCell
.assign(*pDok
, aAdr
);
2777 nRes
= (GetCellErrCode(aCell
) != 0);
2783 ScMatrixRef pMat
= PopMatrix();
2784 if ( nGlobalError
|| !pMat
)
2786 else if ( !pJumpMatrix
)
2787 nRes
= (pMat
->GetErrorIfNotString( 0, 0) != 0);
2790 SCSIZE nCols
, nRows
, nC
, nR
;
2791 pMat
->GetDimensions( nCols
, nRows
);
2792 pJumpMatrix
->GetPos( nC
, nR
);
2793 if ( nC
< nCols
&& nR
< nRows
)
2794 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) != 0);
2808 short ScInterpreter::IsEven()
2810 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2813 switch ( GetStackType() )
2819 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2822 ScRefCellValue aCell
;
2823 aCell
.assign(*pDok
, aAdr
);
2824 sal_uInt16 nErr
= GetCellErrCode(aCell
);
2829 switch (aCell
.meType
)
2831 case CELLTYPE_VALUE
:
2832 fVal
= GetCellValue(aAdr
, aCell
);
2835 case CELLTYPE_FORMULA
:
2836 if (aCell
.mpFormula
->IsValue())
2838 fVal
= GetCellValue(aAdr
, aCell
);
2856 ScMatrixRef pMat
= PopMatrix();
2859 else if ( !pJumpMatrix
)
2861 nRes
= pMat
->IsValue( 0, 0);
2863 fVal
= pMat
->GetDouble( 0, 0);
2867 SCSIZE nCols
, nRows
, nC
, nR
;
2868 pMat
->GetDimensions( nCols
, nRows
);
2869 pJumpMatrix
->GetPos( nC
, nR
);
2870 if ( nC
< nCols
&& nR
< nRows
)
2872 nRes
= pMat
->IsValue( nC
, nR
);
2874 fVal
= pMat
->GetDouble( nC
, nR
);
2877 SetError( errNoValue
);
2885 SetError( errIllegalParameter
);
2887 nRes
= ( fmod( ::rtl::math::approxFloor( fabs( fVal
) ), 2.0 ) < 0.5 );
2892 void ScInterpreter::ScIsEven()
2894 PushInt( IsEven() );
2898 void ScInterpreter::ScIsOdd()
2900 PushInt( !IsEven() );
2903 void ScInterpreter::ScN()
2905 sal_uInt16 nErr
= nGlobalError
;
2907 // Temporarily override the ConvertStringToValue() error for
2908 // GetCellValue() / GetCellValueOrZero()
2909 sal_uInt16 nSErr
= mnStringNoValueError
;
2910 mnStringNoValueError
= errCellNoValue
;
2911 double fVal
= GetDouble();
2912 mnStringNoValueError
= nSErr
;
2914 nGlobalError
= nErr
; // preserve previous error if any
2915 else if (nGlobalError
== errCellNoValue
)
2916 nGlobalError
= 0; // reset temporary detection error
2920 void ScInterpreter::ScTrim()
2922 // Doesn't only trim but also removes duplicated blanks within!
2923 OUString aVal
= comphelper::string::strip(GetString().getString(), ' ');
2924 OUStringBuffer aStr
;
2925 const sal_Unicode
* p
= aVal
.getStr();
2926 const sal_Unicode
* const pEnd
= p
+ aVal
.getLength();
2929 if ( *p
!= ' ' || p
[-1] != ' ' ) // first can't be ' ', so -1 is fine
2933 PushString(aStr
.makeStringAndClear());
2937 void ScInterpreter::ScUpper()
2939 OUString aString
= ScGlobal::pCharClass
->uppercase(GetString().getString());
2940 PushString(aString
);
2944 void ScInterpreter::ScPropper()
2946 //2do: what to do with I18N-CJK ?!?
2947 OUStringBuffer
aStr(GetString().getString());
2948 const sal_Int32 nLen
= aStr
.getLength();
2951 OUString
aUpr(ScGlobal::pCharClass
->uppercase(aStr
.toString()));
2952 OUString
aLwr(ScGlobal::pCharClass
->lowercase(aStr
.toString()));
2955 while( nPos
< nLen
)
2957 OUString
aTmpStr( aStr
[nPos
-1] );
2958 if ( !ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 ) )
2959 aStr
[nPos
] = aUpr
[nPos
];
2961 aStr
[nPos
] = aLwr
[nPos
];
2965 PushString(aStr
.makeStringAndClear());
2969 void ScInterpreter::ScLower()
2971 OUString aString
= ScGlobal::pCharClass
->lowercase(GetString().getString());
2972 PushString(aString
);
2976 void ScInterpreter::ScLen()
2978 PushDouble(GetString().getLength());
2982 void ScInterpreter::ScT()
2984 switch ( GetStackType() )
2990 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2995 bool bValue
= false;
2996 ScRefCellValue aCell
;
2997 aCell
.assign(*pDok
, aAdr
);
2998 if (GetCellErrCode(aCell
) == 0)
3000 switch (aCell
.meType
)
3002 case CELLTYPE_VALUE
:
3005 case CELLTYPE_FORMULA
:
3006 bValue
= aCell
.mpFormula
->IsValue();
3013 PushString(EMPTY_OUSTRING
);
3017 svl::SharedString aStr
;
3018 GetCellString(aStr
, aCell
);
3024 case svExternalSingleRef
:
3025 case svExternalDoubleRef
:
3028 svl::SharedString aStr
;
3029 ScMatValType nMatValType
= GetDoubleOrStringFromMatrix( fVal
, aStr
);
3030 if (ScMatrix::IsValueType( nMatValType
))
3031 PushString(svl::SharedString::getEmptyString());
3039 PushString( EMPTY_OUSTRING
);
3046 PushError( errUnknownOpCode
);
3051 void ScInterpreter::ScValue()
3053 OUString aInputString
;
3056 switch ( GetRawStackType() )
3064 return; // leave on stack
3071 if ( !PopDoubleRefOrSingleRef( aAdr
) )
3076 ScRefCellValue aCell
;
3077 aCell
.assign(*pDok
, aAdr
);
3078 if (aCell
.hasString())
3080 svl::SharedString aSS
;
3081 GetCellString(aSS
, aCell
);
3082 aInputString
= aSS
.getString();
3084 else if (aCell
.hasNumeric())
3086 PushDouble( GetCellValue(aAdr
, aCell
) );
3098 svl::SharedString aSS
;
3099 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
3101 aInputString
= aSS
.getString();
3104 case SC_MATVAL_EMPTY
:
3107 case SC_MATVAL_VALUE
:
3108 case SC_MATVAL_BOOLEAN
:
3112 case SC_MATVAL_STRING
:
3116 PushIllegalArgument();
3121 aInputString
= GetString().getString();
3125 sal_uInt32 nFIndex
= 0; // 0 for default locale
3126 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
3129 PushIllegalArgument();
3134 void ScInterpreter::ScNumberValue()
3137 sal_uInt8 nParamCount
= GetByte();
3138 if ( !MustHaveParamCount( nParamCount
, 1, 3 ) )
3141 OUString aInputString
;
3142 OUString aDecimalSeparator
, aGroupSeparator
;
3143 sal_Unicode cDecimalSeparator
= 0;
3145 if ( nParamCount
== 3 )
3146 aGroupSeparator
= GetString().getString();
3148 if ( nParamCount
>= 2 )
3150 aDecimalSeparator
= GetString().getString();
3151 if ( aDecimalSeparator
.getLength() == 1 )
3152 cDecimalSeparator
= aDecimalSeparator
[ 0 ];
3155 PushIllegalArgument(); //if given, separator length must be 1
3160 if ( cDecimalSeparator
&& aGroupSeparator
.indexOf( cDecimalSeparator
) != -1 )
3162 PushIllegalArgument(); //decimal separator cannot appear in group separator
3166 switch (GetStackType())
3169 return; // leave on stack
3171 aInputString
= GetString().getString();
3175 PushError( nGlobalError
);
3178 if ( aInputString
.isEmpty() )
3180 if ( GetGlobalConfig().mbEmptyStringAsZero
)
3187 sal_Int32 nDecSep
= aInputString
.indexOf( cDecimalSeparator
);
3190 OUString
aTemporary( nDecSep
>= 0 ? aInputString
.copy( 0, nDecSep
) : aInputString
);
3191 sal_Int32 nIndex
= 0;
3192 while (nIndex
< aGroupSeparator
.getLength())
3194 sal_uInt32 nChar
= aGroupSeparator
.iterateCodePoints( &nIndex
);
3195 aTemporary
= aTemporary
.replaceAll( OUString( &nChar
, 1 ), "" );
3198 aInputString
= aTemporary
+ aInputString
.copy( nDecSep
);
3200 aInputString
= aTemporary
;
3203 for ( sal_Int32 i
= aInputString
.getLength(); --i
>= 0; )
3205 sal_Unicode c
= aInputString
[ i
];
3206 if ( c
== 0x0020 || c
== 0x0009 || c
== 0x000A || c
== 0x000D )
3207 aInputString
= aInputString
.replaceAt( i
, 1, "" ); // remove spaces etc.
3209 sal_Int32 nPercentCount
= 0;
3210 for ( sal_Int32 i
= aInputString
.getLength() - 1; i
>= 0 && aInputString
[ i
] == 0x0025; i
-- )
3212 aInputString
= aInputString
.replaceAt( i
, 1, "" ); // remove and count trailing '%'
3216 rtl_math_ConversionStatus eStatus
;
3217 sal_Int32 nParseEnd
;
3218 double fVal
= ::rtl::math::stringToDouble( aInputString
, cDecimalSeparator
, 0, &eStatus
, &nParseEnd
);
3219 if ( eStatus
== rtl_math_ConversionStatus_Ok
&& nParseEnd
== aInputString
.getLength() )
3222 fVal
*= pow( 10.0, -(nPercentCount
* 2)); // process '%' from input string
3230 //2do: this should be a proper unicode string method
3231 static inline bool lcl_ScInterpreter_IsPrintable( sal_Unicode c
)
3233 return 0x20 <= c
&& c
!= 0x7f;
3236 void ScInterpreter::ScClean()
3238 OUString aStr
= GetString().getString();
3239 for ( sal_Int32 i
= 0; i
< aStr
.getLength(); i
++ )
3241 if ( !lcl_ScInterpreter_IsPrintable( aStr
[i
] ) )
3242 aStr
= aStr
.replaceAt(i
,1,"");
3248 void ScInterpreter::ScCode()
3250 //2do: make it full range unicode?
3251 OUString aStr
= GetString().getString();
3252 //"classic" ByteString conversion flags
3253 const sal_uInt32 convertFlags
=
3254 RTL_UNICODETOTEXT_FLAGS_NONSPACING_IGNORE
|
3255 RTL_UNICODETOTEXT_FLAGS_CONTROL_IGNORE
|
3256 RTL_UNICODETOTEXT_FLAGS_FLUSH
|
3257 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_DEFAULT
|
3258 RTL_UNICODETOTEXT_FLAGS_INVALID_DEFAULT
|
3259 RTL_UNICODETOTEXT_FLAGS_UNDEFINED_REPLACE
;
3260 PushInt( (sal_uChar
) OUStringToOString(OUString(aStr
[0]), osl_getThreadTextEncoding(), convertFlags
).toChar() );
3264 void ScInterpreter::ScChar()
3266 //2do: make it full range unicode?
3267 double fVal
= GetDouble();
3268 if (fVal
< 0.0 || fVal
>= 256.0)
3269 PushIllegalArgument();
3272 //"classic" ByteString conversion flags
3273 const sal_uInt32 convertFlags
=
3274 RTL_TEXTTOUNICODE_FLAGS_UNDEFINED_DEFAULT
|
3275 RTL_TEXTTOUNICODE_FLAGS_MBUNDEFINED_DEFAULT
|
3276 RTL_TEXTTOUNICODE_FLAGS_INVALID_DEFAULT
;
3278 sal_Char cEncodedChar
= static_cast<sal_Char
>(fVal
);
3279 OUString
aStr(&cEncodedChar
, 1, osl_getThreadTextEncoding(), convertFlags
);
3285 /* #i70213# fullwidth/halfwidth conversion provided by
3286 * Takashi Nakamoto <bluedwarf@ooo>
3287 * erAck: added Excel compatibility conversions as seen in issue's test case. */
3289 static OUString
lcl_convertIntoHalfWidth( const OUString
& rStr
)
3291 static bool bFirstASCCall
= true;
3292 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessComponentContext(), 0 );
3296 aTrans
.loadModuleByImplName( OUString( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM
);
3297 bFirstASCCall
= false;
3300 return aTrans
.transliterate( rStr
, 0, sal_uInt16( rStr
.getLength() ), NULL
);
3304 static OUString
lcl_convertIntoFullWidth( const OUString
& rStr
)
3306 static bool bFirstJISCall
= true;
3307 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessComponentContext(), 0 );
3311 aTrans
.loadModuleByImplName( OUString( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM
);
3312 bFirstJISCall
= false;
3315 return aTrans
.transliterate( rStr
, 0, sal_uInt16( rStr
.getLength() ), NULL
);
3320 * Summary: Converts half-width to full-width ASCII and katakana characters.
3321 * Semantics: Conversion is done for half-width ASCII and katakana characters,
3322 * other characters are simply copied from T to the result. This is the
3323 * complementary function to ASC.
3324 * For references regarding halfwidth and fullwidth characters see
3325 * http://www.unicode.org/reports/tr11/
3326 * http://www.unicode.org/charts/charindex2.html#H
3327 * http://www.unicode.org/charts/charindex2.html#F
3329 void ScInterpreter::ScJis()
3331 if (MustHaveParamCount( GetByte(), 1))
3332 PushString( lcl_convertIntoFullWidth( GetString().getString()));
3337 * Summary: Converts full-width to half-width ASCII and katakana characters.
3338 * Semantics: Conversion is done for full-width ASCII and katakana characters,
3339 * other characters are simply copied from T to the result. This is the
3340 * complementary function to JIS.
3342 void ScInterpreter::ScAsc()
3344 if (MustHaveParamCount( GetByte(), 1))
3345 PushString( lcl_convertIntoHalfWidth( GetString().getString()));
3348 void ScInterpreter::ScUnicode()
3350 if ( MustHaveParamCount( GetByte(), 1 ) )
3352 OUString aStr
= GetString().getString();
3354 PushIllegalParameter();
3358 PushDouble(aStr
.iterateCodePoints(&i
));
3363 void ScInterpreter::ScUnichar()
3365 if ( MustHaveParamCount( GetByte(), 1 ) )
3367 double dVal
= ::rtl::math::approxFloor( GetDouble() );
3368 if ((dVal
< 0x000000) || (dVal
> 0x10FFFF))
3369 PushIllegalArgument();
3372 sal_uInt32 nCodePoint
= static_cast<sal_uInt32
>( dVal
);
3373 OUString
aStr( &nCodePoint
, 1 );
3380 void ScInterpreter::ScMin( bool bTextAsZero
)
3382 short nParamCount
= GetByte();
3383 if (!MustHaveParamCountMin( nParamCount
, 1))
3385 double nMin
= ::std::numeric_limits
<double>::max();
3389 size_t nRefInList
= 0;
3390 while (nParamCount
-- > 0)
3392 switch (GetStackType())
3397 if (nMin
> nVal
) nMin
= nVal
;
3398 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3403 PopSingleRef( aAdr
);
3404 ScRefCellValue aCell
;
3405 aCell
.assign(*pDok
, aAdr
);
3406 if (aCell
.hasNumeric())
3408 nVal
= GetCellValue(aAdr
, aCell
);
3410 if (nMin
> nVal
) nMin
= nVal
;
3412 else if (bTextAsZero
&& aCell
.hasString())
3422 sal_uInt16 nErr
= 0;
3423 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3424 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3425 if (aValIter
.GetFirst(nVal
, nErr
))
3429 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3430 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
3440 case svExternalSingleRef
:
3441 case svExternalDoubleRef
:
3443 ScMatrixRef pMat
= GetMatrix();
3446 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3447 nVal
= pMat
->GetMinValue(bTextAsZero
);
3462 SetError(errIllegalParameter
);
3467 SetError(errIllegalParameter
);
3476 void ScInterpreter::ScMax( bool bTextAsZero
)
3478 short nParamCount
= GetByte();
3479 if (!MustHaveParamCountMin( nParamCount
, 1))
3481 double nMax
= -(::std::numeric_limits
<double>::max());
3485 size_t nRefInList
= 0;
3486 while (nParamCount
-- > 0)
3488 switch (GetStackType())
3493 if (nMax
< nVal
) nMax
= nVal
;
3494 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3499 PopSingleRef( aAdr
);
3500 ScRefCellValue aCell
;
3501 aCell
.assign(*pDok
, aAdr
);
3502 if (aCell
.hasNumeric())
3504 nVal
= GetCellValue(aAdr
, aCell
);
3506 if (nMax
< nVal
) nMax
= nVal
;
3508 else if (bTextAsZero
&& aCell
.hasString())
3518 sal_uInt16 nErr
= 0;
3519 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3520 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3521 if (aValIter
.GetFirst(nVal
, nErr
))
3525 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3526 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
3536 case svExternalSingleRef
:
3537 case svExternalDoubleRef
:
3539 ScMatrixRef pMat
= GetMatrix();
3542 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3543 nVal
= pMat
->GetMaxValue(bTextAsZero
);
3558 SetError(errIllegalParameter
);
3563 SetError(errIllegalParameter
);
3572 void ScInterpreter::GetStVarParams( double& rVal
, double& rValCount
,
3575 short nParamCount
= GetByte();
3577 std::vector
<double> values
;
3585 size_t nRefInList
= 0;
3586 while (nParamCount
-- > 0)
3588 switch (GetStackType())
3593 values
.push_back(fVal
);
3600 PopSingleRef( aAdr
);
3601 ScRefCellValue aCell
;
3602 aCell
.assign(*pDok
, aAdr
);
3603 if (aCell
.hasNumeric())
3605 fVal
= GetCellValue(aAdr
, aCell
);
3606 values
.push_back(fVal
);
3610 else if (bTextAsZero
&& aCell
.hasString())
3612 values
.push_back(0.0);
3620 sal_uInt16 nErr
= 0;
3621 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3622 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3623 if (aValIter
.GetFirst(fVal
, nErr
))
3627 values
.push_back(fVal
);
3631 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
3637 ScMatrixRef pMat
= PopMatrix();
3641 pMat
->GetDimensions(nC
, nR
);
3642 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3644 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3646 if (!pMat
->IsString(nMatCol
,nMatRow
))
3648 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3649 values
.push_back(fVal
);
3653 else if ( bTextAsZero
)
3655 values
.push_back(0.0);
3668 values
.push_back(0.0);
3672 SetError(errIllegalParameter
);
3677 SetError(errIllegalParameter
);
3681 ::std::vector
<double>::size_type n
= values
.size();
3683 for (::std::vector
<double>::size_type i
= 0; i
< n
; i
++)
3684 vSum
+= ::rtl::math::approxSub( values
[i
], vMean
) * ::rtl::math::approxSub( values
[i
], vMean
);
3689 void ScInterpreter::ScVar( bool bTextAsZero
)
3693 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3695 if (nValCount
<= 1.0)
3696 PushError( errDivisionByZero
);
3698 PushDouble( nVal
/ (nValCount
- 1.0));
3702 void ScInterpreter::ScVarP( bool bTextAsZero
)
3706 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3708 PushDouble( div( nVal
, nValCount
));
3712 void ScInterpreter::ScStDev( bool bTextAsZero
)
3716 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3717 if (nValCount
<= 1.0)
3718 PushError( errDivisionByZero
);
3720 PushDouble( sqrt( nVal
/ (nValCount
- 1.0)));
3724 void ScInterpreter::ScStDevP( bool bTextAsZero
)
3728 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3729 if (nValCount
== 0.0)
3730 PushError( errDivisionByZero
);
3732 PushDouble( sqrt( nVal
/ nValCount
));
3734 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3736 * Besides that the special NAN gets lost in the call through sqrt(),
3737 * unxlngi6.pro then looped back and forth somewhere between div() and
3738 * ::rtl::math::setNan(). Tests showed that
3740 * sqrt( div( 1, 0));
3742 * produced a loop, but
3744 * double f1 = div( 1, 0);
3747 * was fine. There seems to be some compiler optimization problem. It does
3748 * not occur when compiled with debug=t.
3753 void ScInterpreter::ScColumns()
3755 sal_uInt8 nParamCount
= GetByte();
3763 while (nParamCount
-- > 0)
3765 switch ( GetStackType() )
3772 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3773 nVal
+= static_cast<sal_uLong
>(nTab2
- nTab1
+ 1) *
3774 static_cast<sal_uLong
>(nCol2
- nCol1
+ 1);
3778 ScMatrixRef pMat
= PopMatrix();
3782 pMat
->GetDimensions(nC
, nR
);
3787 case svExternalSingleRef
:
3791 case svExternalDoubleRef
:
3795 ScComplexRefData aRef
;
3796 PopExternalDoubleRef( nFileId
, aTabName
, aRef
);
3797 ScRange aAbs
= aRef
.toAbs(aPos
);
3798 nVal
+= static_cast<sal_uLong
>(aAbs
.aEnd
.Tab() - aAbs
.aStart
.Tab() + 1) *
3799 static_cast<sal_uLong
>(aAbs
.aEnd
.Col() - aAbs
.aStart
.Col() + 1);
3804 SetError(errIllegalParameter
);
3807 PushDouble((double)nVal
);
3811 void ScInterpreter::ScRows()
3813 sal_uInt8 nParamCount
= GetByte();
3821 while (nParamCount
-- > 0)
3823 switch ( GetStackType() )
3830 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3831 nVal
+= static_cast<sal_uLong
>(nTab2
- nTab1
+ 1) *
3832 static_cast<sal_uLong
>(nRow2
- nRow1
+ 1);
3836 ScMatrixRef pMat
= PopMatrix();
3840 pMat
->GetDimensions(nC
, nR
);
3845 case svExternalSingleRef
:
3849 case svExternalDoubleRef
:
3853 ScComplexRefData aRef
;
3854 PopExternalDoubleRef( nFileId
, aTabName
, aRef
);
3855 ScRange aAbs
= aRef
.toAbs(aPos
);
3856 nVal
+= static_cast<sal_uLong
>(aAbs
.aEnd
.Tab() - aAbs
.aStart
.Tab() + 1) *
3857 static_cast<sal_uLong
>(aAbs
.aEnd
.Row() - aAbs
.aStart
.Row() + 1);
3862 SetError(errIllegalParameter
);
3865 PushDouble((double)nVal
);
3868 void ScInterpreter::ScTables()
3870 sal_uInt8 nParamCount
= GetByte();
3872 if ( nParamCount
== 0 )
3873 nVal
= pDok
->GetTableCount();
3883 while (nParamCount
-- > 0)
3885 switch ( GetStackType() )
3892 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3893 nVal
+= static_cast<sal_uLong
>(nTab2
- nTab1
+ 1);
3899 case svExternalSingleRef
:
3903 case svExternalDoubleRef
:
3907 ScComplexRefData aRef
;
3908 PopExternalDoubleRef( nFileId
, aTabName
, aRef
);
3909 ScRange aAbs
= aRef
.toAbs(aPos
);
3910 nVal
+= static_cast<sal_uLong
>(aAbs
.aEnd
.Tab() - aAbs
.aStart
.Tab() + 1);
3915 SetError( errIllegalParameter
);
3919 PushDouble( (double) nVal
);
3923 void ScInterpreter::ScColumn()
3925 sal_uInt8 nParamCount
= GetByte();
3926 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3929 if (nParamCount
== 0)
3931 nVal
= aPos
.Col() + 1;
3936 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3939 // Happens if called via ScViewFunc::EnterMatrix()
3940 // ScFormulaCell::GetResultDimensions() as of course a
3941 // matrix result is not available yet.
3944 ScMatrixRef pResMat
= GetNewMat( static_cast<SCSIZE
>(nCols
), 1);
3947 for (SCCOL i
=0; i
< nCols
; ++i
)
3948 pResMat
->PutDouble( nVal
+ i
, static_cast<SCSIZE
>(i
), 0);
3949 PushMatrix( pResMat
);
3956 switch ( GetStackType() )
3963 PopSingleRef( nCol1
, nRow1
, nTab1
);
3964 nVal
= (double) (nCol1
+ 1);
3975 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3978 ScMatrixRef pResMat
= GetNewMat(
3979 static_cast<SCSIZE
>(nCol2
-nCol1
+1), 1);
3982 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
3983 pResMat
->PutDouble((double)(i
+1),
3984 static_cast<SCSIZE
>(i
-nCol1
), 0);
3985 PushMatrix(pResMat
);
3992 nVal
= (double) (nCol1
+ 1);
3996 SetError( errIllegalParameter
);
4005 void ScInterpreter::ScRow()
4007 sal_uInt8 nParamCount
= GetByte();
4008 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
4011 if (nParamCount
== 0)
4013 nVal
= aPos
.Row() + 1;
4018 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
4021 // Happens if called via ScViewFunc::EnterMatrix()
4022 // ScFormulaCell::GetResultDimensions() as of course a
4023 // matrix result is not available yet.
4026 ScMatrixRef pResMat
= GetNewMat( 1, static_cast<SCSIZE
>(nRows
));
4029 for (SCROW i
=0; i
< nRows
; i
++)
4030 pResMat
->PutDouble( nVal
+ i
, 0, static_cast<SCSIZE
>(i
));
4031 PushMatrix( pResMat
);
4038 switch ( GetStackType() )
4045 PopSingleRef( nCol1
, nRow1
, nTab1
);
4046 nVal
= (double) (nRow1
+ 1);
4057 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4060 ScMatrixRef pResMat
= GetNewMat( 1,
4061 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
4064 for (SCROW i
= nRow1
; i
<= nRow2
; i
++)
4065 pResMat
->PutDouble((double)(i
+1), 0,
4066 static_cast<SCSIZE
>(i
-nRow1
));
4067 PushMatrix(pResMat
);
4074 nVal
= (double) (nRow1
+ 1);
4078 SetError( errIllegalParameter
);
4086 void ScInterpreter::ScTable()
4088 sal_uInt8 nParamCount
= GetByte();
4089 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
4092 if ( nParamCount
== 0 )
4093 nVal
= aPos
.Tab() + 1;
4096 switch ( GetStackType() )
4100 svl::SharedString aStr
= PopString();
4101 if ( pDok
->GetTable(aStr
.getString(), nVal
))
4104 SetError( errIllegalArgument
);
4112 PopSingleRef( nCol1
, nRow1
, nTab1
);
4124 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4129 SetError( errIllegalParameter
);
4134 PushDouble( (double) nVal
);
4140 class VectorMatrixAccessor
4143 VectorMatrixAccessor(const ScMatrix
& rMat
, bool bColVec
) :
4144 mrMat(rMat
), mbColVec(bColVec
) {}
4146 bool IsEmpty(SCSIZE i
) const
4148 return mbColVec
? mrMat
.IsEmpty(0, i
) : mrMat
.IsEmpty(i
, 0);
4151 bool IsEmptyPath(SCSIZE i
) const
4153 return mbColVec
? mrMat
.IsEmptyPath(0, i
) : mrMat
.IsEmptyPath(i
, 0);
4156 bool IsValue(SCSIZE i
) const
4158 return mbColVec
? mrMat
.IsValue(0, i
) : mrMat
.IsValue(i
, 0);
4161 bool IsString(SCSIZE i
) const
4163 return mbColVec
? mrMat
.IsString(0, i
) : mrMat
.IsString(i
, 0);
4166 double GetDouble(SCSIZE i
) const
4168 return mbColVec
? mrMat
.GetDouble(0, i
) : mrMat
.GetDouble(i
, 0);
4171 OUString
GetString(SCSIZE i
) const
4173 return mbColVec
? mrMat
.GetString(0, i
).getString() : mrMat
.GetString(i
, 0).getString();
4176 SCSIZE
GetElementCount() const
4179 mrMat
.GetDimensions(nC
, nR
);
4180 return mbColVec
? nR
: nC
;
4184 const ScMatrix
& mrMat
;
4188 /** returns -1 when the matrix value is smaller than the query value, 0 when
4189 they are equal, and 1 when the matrix value is larger than the query
4191 static sal_Int32
lcl_CompareMatrix2Query(
4192 SCSIZE i
, const VectorMatrixAccessor
& rMat
, const ScQueryEntry
& rEntry
)
4194 if (rMat
.IsEmpty(i
))
4196 /* TODO: in case we introduced query for real empty this would have to
4198 return -1; // empty always less than anything else
4201 /* FIXME: what is an empty path (result of IF(false;true_path) in
4204 bool bByString
= rEntry
.GetQueryItem().meType
== ScQueryEntry::ByString
;
4205 if (rMat
.IsValue(i
))
4208 return -1; // numeric always less than string
4210 const double nVal1
= rMat
.GetDouble(i
);
4211 const double nVal2
= rEntry
.GetQueryItem().mfVal
;
4215 return nVal1
< nVal2
? -1 : 1;
4219 return 1; // string always greater than numeric
4221 OUString aStr1
= rMat
.GetString(i
);
4222 OUString aStr2
= rEntry
.GetQueryItem().maString
.getString();
4224 return ScGlobal::GetCollator()->compareString(aStr1
, aStr2
); // case-insensitive
4227 /** returns the last item with the identical value as the original item
4229 static void lcl_GetLastMatch( SCSIZE
& rIndex
, const VectorMatrixAccessor
& rMat
,
4230 SCSIZE nMatCount
, bool bReverse
)
4232 if (rMat
.IsValue(rIndex
))
4234 double nVal
= rMat
.GetDouble(rIndex
);
4236 while (rIndex
> 0 && rMat
.IsValue(rIndex
-1) &&
4237 nVal
== rMat
.GetDouble(rIndex
-1))
4240 while (rIndex
< nMatCount
-1 && rMat
.IsValue(rIndex
+1) &&
4241 nVal
== rMat
.GetDouble(rIndex
+1))
4244 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
4245 else if (rMat
.IsEmptyPath(rIndex
))
4248 while (rIndex
> 0 && rMat
.IsEmptyPath(rIndex
-1))
4251 while (rIndex
< nMatCount
-1 && rMat
.IsEmptyPath(rIndex
+1))
4254 else if (rMat
.IsEmpty(rIndex
))
4257 while (rIndex
> 0 && rMat
.IsEmpty(rIndex
-1))
4260 while (rIndex
< nMatCount
-1 && rMat
.IsEmpty(rIndex
+1))
4263 else if (rMat
.IsString(rIndex
))
4265 OUString
aStr( rMat
.GetString(rIndex
));
4267 while (rIndex
> 0 && rMat
.IsString(rIndex
-1) &&
4268 aStr
== rMat
.GetString(rIndex
-1))
4271 while (rIndex
< nMatCount
-1 && rMat
.IsString(rIndex
+1) &&
4272 aStr
== rMat
.GetString(rIndex
+1))
4277 OSL_FAIL("lcl_GetLastMatch: unhandled matrix type");
4283 void ScInterpreter::ScMatch()
4286 sal_uInt8 nParamCount
= GetByte();
4287 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4290 if (nParamCount
== 3)
4300 ScMatrixRef pMatSrc
= NULL
;
4302 switch (GetStackType())
4305 PopSingleRef( nCol1
, nRow1
, nTab1
);
4312 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4313 if (nTab1
!= nTab2
|| (nCol1
!= nCol2
&& nRow1
!= nRow2
))
4315 PushIllegalParameter();
4321 case svExternalDoubleRef
:
4323 if (GetStackType() == svMatrix
)
4324 pMatSrc
= PopMatrix();
4326 PopExternalDoubleRef(pMatSrc
);
4330 PushIllegalParameter();
4336 PushIllegalParameter();
4340 if (nGlobalError
== 0)
4343 ScQueryParam rParam
;
4344 rParam
.nCol1
= nCol1
;
4345 rParam
.nRow1
= nRow1
;
4346 rParam
.nCol2
= nCol2
;
4347 rParam
.nTab
= nTab1
;
4349 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4350 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
4351 rEntry
.bDoQuery
= true;
4353 rEntry
.eOp
= SC_GREATER_EQUAL
;
4354 else if (fTyp
> 0.0)
4355 rEntry
.eOp
= SC_LESS_EQUAL
;
4356 switch ( GetStackType() )
4362 rItem
.meType
= ScQueryEntry::ByValue
;
4367 rItem
.meType
= ScQueryEntry::ByString
;
4368 rItem
.maString
= GetString();
4375 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4380 ScRefCellValue aCell
;
4381 aCell
.assign(*pDok
, aAdr
);
4382 if (aCell
.hasNumeric())
4384 fVal
= GetCellValue(aAdr
, aCell
);
4385 rItem
.meType
= ScQueryEntry::ByValue
;
4390 GetCellString(rItem
.maString
, aCell
);
4391 rItem
.meType
= ScQueryEntry::ByString
;
4395 case svExternalSingleRef
:
4397 ScExternalRefCache::TokenRef pToken
;
4398 PopExternalSingleRef(pToken
);
4404 if (pToken
->GetType() == svDouble
)
4406 rItem
.meType
= ScQueryEntry::ByValue
;
4407 rItem
.mfVal
= pToken
->GetDouble();
4411 rItem
.meType
= ScQueryEntry::ByString
;
4412 rItem
.maString
= pToken
->GetString();
4416 case svExternalDoubleRef
:
4417 // TODO: Implement this.
4418 PushIllegalParameter();
4423 svl::SharedString aStr
;
4424 ScMatValType nType
= GetDoubleOrStringFromMatrix(
4426 rItem
.maString
= aStr
;
4427 rItem
.meType
= ScMatrix::IsNonValueType(nType
) ?
4428 ScQueryEntry::ByString
: ScQueryEntry::ByValue
;
4433 PushIllegalParameter();
4437 if (rItem
.meType
== ScQueryEntry::ByString
)
4439 bool bIsVBAMode
= false;
4441 bIsVBAMode
= pDok
->IsInVBAMode();
4443 // #TODO handle MSO wildcards
4445 rParam
.bRegExp
= false;
4447 rParam
.bRegExp
= MayBeRegExp(rEntry
.GetQueryItem().maString
.getString(), pDok
);
4450 if (pMatSrc
) // The source data is matrix array.
4453 pMatSrc
->GetDimensions( nC
, nR
);
4454 if (nC
> 1 && nR
> 1)
4456 // The source matrix must be a vector.
4457 PushIllegalParameter();
4460 SCSIZE nMatCount
= (nC
== 1) ? nR
: nC
;
4461 VectorMatrixAccessor
aMatAcc(*pMatSrc
, nC
== 1);
4463 // simple serial search for equality mode (source data doesn't
4464 // need to be sorted).
4466 if (rEntry
.eOp
== SC_EQUAL
)
4468 for (SCSIZE i
= 0; i
< nMatCount
; ++i
)
4470 if (lcl_CompareMatrix2Query( i
, aMatAcc
, rEntry
) == 0)
4472 PushDouble(i
+1); // found !
4476 PushNA(); // not found
4480 // binary search for non-equality mode (the source data is
4481 // assumed to be sorted).
4483 bool bAscOrder
= (rEntry
.eOp
== SC_LESS_EQUAL
);
4484 SCSIZE nFirst
= 0, nLast
= nMatCount
-1, nHitIndex
= 0;
4485 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
4487 SCSIZE nMid
= nFirst
+ nLen
/2;
4488 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, aMatAcc
, rEntry
);
4491 // exact match. find the last item with the same value.
4492 lcl_GetLastMatch( nMid
, aMatAcc
, nMatCount
, !bAscOrder
);
4493 PushDouble( nMid
+1);
4497 if (nLen
== 1) // first and last items are next to each other.
4500 nHitIndex
= bAscOrder
? nLast
: nFirst
;
4502 nHitIndex
= bAscOrder
? nFirst
: nLast
;
4522 if (nHitIndex
== nMatCount
-1) // last item
4524 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nHitIndex
, aMatAcc
, rEntry
);
4525 if ((bAscOrder
&& nCmp
<= 0) || (!bAscOrder
&& nCmp
>= 0))
4527 // either the last item is an exact match or the real
4528 // hit is beyond the last item.
4529 PushDouble( nHitIndex
+1);
4534 if (nHitIndex
> 0) // valid hit must be 2nd item or higher
4536 PushDouble( nHitIndex
); // non-exact match
4544 SCCOLROW nDelta
= 0;
4546 { // search row in column
4547 rParam
.nRow2
= nRow2
;
4548 rEntry
.nField
= nCol1
;
4549 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
4550 if (!LookupQueryWithCache( aResultPos
, rParam
))
4555 nDelta
= aResultPos
.Row() - nRow1
;
4558 { // search column in row
4560 rParam
.bByRow
= false;
4561 rParam
.nRow2
= nRow1
;
4562 rEntry
.nField
= nCol1
;
4563 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
4564 // Advance Entry.nField in Iterator if column changed
4565 aCellIter
.SetAdvanceQueryParamEntryField( true );
4568 if ( aCellIter
.GetFirst() )
4569 nC
= aCellIter
.GetCol();
4579 if ( !aCellIter
.FindEqualOrSortedLastInRange( nC
, nR
) )
4585 nDelta
= nC
- nCol1
;
4587 PushDouble((double) (nDelta
+ 1));
4590 PushIllegalParameter();
4595 void ScInterpreter::ScCountEmptyCells()
4597 if ( MustHaveParamCount( GetByte(), 1 ) )
4599 sal_uLong nMaxCount
= 0, nCount
= 0;
4601 switch (GetStackType())
4607 PopSingleRef( aAdr
);
4608 eCellType
= pDok
->GetCellType(aAdr
);
4609 if (eCellType
!= CELLTYPE_NONE
)
4618 size_t nRefInList
= 0;
4619 while (nParam
-- > 0)
4621 PopDoubleRef( aRange
, nParam
, nRefInList
);
4623 static_cast<sal_uLong
>(aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1) *
4624 static_cast<sal_uLong
>(aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1) *
4625 static_cast<sal_uLong
>(aRange
.aEnd
.Tab() - aRange
.aStart
.Tab() + 1);
4627 ScCellIterator
aIter( pDok
, aRange
, glSubTotal
);
4628 for (bool bHas
= aIter
.first(); bHas
; bHas
= aIter
.next())
4630 if (!aIter
.hasEmptyData())
4636 default : SetError(errIllegalParameter
); break;
4638 PushDouble(nMaxCount
- nCount
);
4643 double ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc
)
4645 sal_uInt8 nParamCount
= GetByte();
4646 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
4653 ScMatrixRef pSumExtraMatrix
;
4654 bool bSumExtraRange
= (nParamCount
== 3);
4657 // Save only the upperleft cell in case of cell range. The geometry
4658 // of the 3rd parameter is taken from the 1st parameter.
4660 switch ( GetStackType() )
4667 PopDoubleRef( nCol3
, nRow3
, nTab3
, nColJunk
, nRowJunk
, nTabJunk
);
4668 if ( nTabJunk
!= nTab3
)
4670 SetError( errIllegalParameter
);
4676 PopSingleRef( nCol3
, nRow3
, nTab3
);
4679 pSumExtraMatrix
= PopMatrix();
4680 //! nCol3, nRow3, nTab3 remain 0
4682 case svExternalSingleRef
:
4684 pSumExtraMatrix
= new ScMatrix(1, 1, 0.0);
4685 ScExternalRefCache::TokenRef pToken
;
4686 PopExternalSingleRef(pToken
);
4689 SetError( errIllegalParameter
);
4693 if (pToken
->GetType() == svDouble
)
4694 pSumExtraMatrix
->PutDouble(pToken
->GetDouble(), 0, 0);
4696 pSumExtraMatrix
->PutString(pToken
->GetString(), 0, 0);
4699 case svExternalDoubleRef
:
4700 PopExternalDoubleRef(pSumExtraMatrix
);
4703 SetError( errIllegalParameter
);
4708 svl::SharedString aString
;
4710 bool bIsString
= true;
4711 switch ( GetStackType() )
4717 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4720 ScRefCellValue aCell
;
4721 aCell
.assign(*pDok
, aAdr
);
4722 switch (aCell
.meType
)
4724 case CELLTYPE_VALUE
:
4725 fVal
= GetCellValue(aAdr
, aCell
);
4728 case CELLTYPE_FORMULA
:
4729 if (aCell
.mpFormula
->IsValue())
4731 fVal
= GetCellValue(aAdr
, aCell
);
4735 GetCellString(aString
, aCell
);
4737 case CELLTYPE_STRING
:
4738 case CELLTYPE_EDIT
:
4739 GetCellString(aString
, aCell
);
4748 aString
= GetString();
4751 case svExternalDoubleRef
:
4753 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
, aString
);
4754 bIsString
= ScMatrix::IsNonValueType( nType
);
4757 case svExternalSingleRef
:
4759 ScExternalRefCache::TokenRef pToken
;
4760 PopExternalSingleRef(pToken
);
4763 if (pToken
->GetType() == svDouble
)
4765 fVal
= pToken
->GetDouble();
4769 aString
= pToken
->GetString();
4783 double fCount
= 0.0;
4786 size_t nRefInList
= 0;
4787 while (nParam
-- > 0)
4795 ScMatrixRef pQueryMatrix
;
4796 switch ( GetStackType() )
4801 SetError( errIllegalParameter
);
4806 PopDoubleRef( aRange
, nParam
, nRefInList
);
4807 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4811 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4814 PopSingleRef( nCol1
, nRow1
, nTab1
);
4820 case svExternalSingleRef
:
4821 case svExternalDoubleRef
:
4823 pQueryMatrix
= GetMatrix();
4826 SetError( errIllegalParameter
);
4833 pQueryMatrix
->GetDimensions( nC
, nR
);
4834 nCol2
= static_cast<SCCOL
>(nC
- 1);
4835 nRow2
= static_cast<SCROW
>(nR
- 1);
4840 SetError( errIllegalParameter
);
4842 if ( nTab1
!= nTab2
)
4844 SetError( errIllegalParameter
);
4849 // Take the range geometry of the 1st parameter and apply it to
4850 // the 3rd. If parts of the resulting range would point outside
4851 // the sheet, don't complain but silently ignore and simply cut
4852 // them away, this is what Xcl does :-/
4854 // For the cut-away part we also don't need to determine the
4855 // criteria match, so shrink the source range accordingly,
4856 // instead of the result range.
4857 SCCOL nColDelta
= nCol2
- nCol1
;
4858 SCROW nRowDelta
= nRow2
- nRow1
;
4861 if (pSumExtraMatrix
)
4864 pSumExtraMatrix
->GetDimensions( nC
, nR
);
4865 nMaxCol
= static_cast<SCCOL
>(nC
- 1);
4866 nMaxRow
= static_cast<SCROW
>(nR
- 1);
4873 if (nCol3
+ nColDelta
> nMaxCol
)
4875 SCCOL nNewDelta
= nMaxCol
- nCol3
;
4876 nCol2
= nCol1
+ nNewDelta
;
4879 if (nRow3
+ nRowDelta
> nMaxRow
)
4881 SCROW nNewDelta
= nMaxRow
- nRow3
;
4882 nRow2
= nRow1
+ nNewDelta
;
4892 if (nGlobalError
== 0)
4894 ScQueryParam rParam
;
4895 rParam
.nRow1
= nRow1
;
4896 rParam
.nRow2
= nRow2
;
4898 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4899 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
4900 rEntry
.bDoQuery
= true;
4903 rItem
.meType
= ScQueryEntry::ByValue
;
4905 rEntry
.eOp
= SC_EQUAL
;
4909 rParam
.FillInExcelSyntax(pDok
->GetSharedStringPool(), aString
.getString(), 0);
4910 sal_uInt32 nIndex
= 0;
4911 bool bNumber
= pFormatter
->IsNumberFormat(
4912 rItem
.maString
.getString(), nIndex
, rItem
.mfVal
);
4913 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
4914 if (rItem
.meType
== ScQueryEntry::ByString
)
4915 rParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
4918 aAdr
.SetTab( nTab3
);
4919 rParam
.nCol1
= nCol1
;
4920 rParam
.nCol2
= nCol2
;
4921 rEntry
.nField
= nCol1
;
4922 SCsCOL nColDiff
= nCol3
- nCol1
;
4923 SCsROW nRowDiff
= nRow3
- nRow1
;
4926 // Never case-sensitive.
4927 sc::CompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
4928 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
4929 if (nGlobalError
|| !pResultMatrix
)
4931 SetError( errIllegalParameter
);
4934 if (pSumExtraMatrix
)
4936 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4938 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4940 if (pResultMatrix
->IsValue( nCol
, nRow
) &&
4941 pResultMatrix
->GetDouble( nCol
, nRow
))
4943 SCSIZE nC
= nCol
+ nColDiff
;
4944 SCSIZE nR
= nRow
+ nRowDiff
;
4945 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4947 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4949 if ( bNull
&& fVal
!= 0.0 )
4963 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4965 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4967 if (pResultMatrix
->GetDouble( nCol
, nRow
))
4969 aAdr
.SetCol( nCol
+ nColDiff
);
4970 aAdr
.SetRow( nRow
+ nRowDiff
);
4971 ScRefCellValue aCell
;
4972 aCell
.assign(*pDok
, aAdr
);
4973 if (aCell
.hasNumeric())
4975 fVal
= GetCellValue(aAdr
, aCell
);
4977 if ( bNull
&& fVal
!= 0.0 )
4992 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
4993 // Increment Entry.nField in iterator when switching to next column.
4994 aCellIter
.SetAdvanceQueryParamEntryField( true );
4995 if ( aCellIter
.GetFirst() )
4997 if (pSumExtraMatrix
)
5001 SCSIZE nC
= aCellIter
.GetCol() + nColDiff
;
5002 SCSIZE nR
= aCellIter
.GetRow() + nRowDiff
;
5003 if (pSumExtraMatrix
->IsValue( nC
, nR
))
5005 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
5007 if ( bNull
&& fVal
!= 0.0 )
5015 } while ( aCellIter
.GetNext() );
5021 aAdr
.SetCol( aCellIter
.GetCol() + nColDiff
);
5022 aAdr
.SetRow( aCellIter
.GetRow() + nRowDiff
);
5023 ScRefCellValue aCell
;
5024 aCell
.assign(*pDok
, aAdr
);
5025 if (aCell
.hasNumeric())
5027 fVal
= GetCellValue(aAdr
, aCell
);
5029 if ( bNull
&& fVal
!= 0.0 )
5037 } while ( aCellIter
.GetNext() );
5044 SetError( errIllegalParameter
);
5051 case ifSUMIF
: fRes
= ::rtl::math::approxAdd( fSum
, fMem
); break;
5052 case ifAVERAGEIF
: fRes
= div( ::rtl::math::approxAdd( fSum
, fMem
), fCount
); break;
5057 void ScInterpreter::ScSumIf()
5059 PushDouble( IterateParametersIf( ifSUMIF
));
5062 void ScInterpreter::ScAverageIf()
5064 PushDouble( IterateParametersIf( ifAVERAGEIF
));
5067 void ScInterpreter::ScCountIf()
5069 if ( MustHaveParamCount( GetByte(), 2 ) )
5071 svl::SharedString aString
;
5073 bool bIsString
= true;
5074 switch ( GetStackType() )
5080 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5085 ScRefCellValue aCell
;
5086 aCell
.assign(*pDok
, aAdr
);
5087 switch (aCell
.meType
)
5089 case CELLTYPE_VALUE
:
5090 fVal
= GetCellValue(aAdr
, aCell
);
5093 case CELLTYPE_FORMULA
:
5094 if (aCell
.mpFormula
->IsValue())
5096 fVal
= GetCellValue(aAdr
, aCell
);
5100 GetCellString(aString
, aCell
);
5102 case CELLTYPE_STRING
:
5103 case CELLTYPE_EDIT
:
5104 GetCellString(aString
, aCell
);
5113 case svExternalSingleRef
:
5114 case svExternalDoubleRef
:
5116 ScMatValType nType
= GetDoubleOrStringFromMatrix(fVal
, aString
);
5117 bIsString
= ScMatrix::IsNonValueType( nType
);
5121 aString
= GetString();
5129 double fCount
= 0.0;
5131 size_t nRefInList
= 0;
5132 while (nParam
-- > 0)
5140 ScMatrixRef pQueryMatrix
;
5141 switch ( GetStackType() )
5147 PopDoubleRef( aRange
, nParam
, nRefInList
);
5148 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5152 PopSingleRef( nCol1
, nRow1
, nTab1
);
5158 case svExternalSingleRef
:
5159 case svExternalDoubleRef
:
5161 pQueryMatrix
= GetMatrix();
5164 PushIllegalParameter();
5171 pQueryMatrix
->GetDimensions( nC
, nR
);
5172 nCol2
= static_cast<SCCOL
>(nC
- 1);
5173 nRow2
= static_cast<SCROW
>(nR
- 1);
5178 PushIllegalParameter();
5181 if ( nTab1
!= nTab2
)
5183 PushIllegalParameter();
5188 PushIllegalParameter();
5191 if (nGlobalError
== 0)
5193 ScQueryParam rParam
;
5194 rParam
.nRow1
= nRow1
;
5195 rParam
.nRow2
= nRow2
;
5197 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5198 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
5199 rEntry
.bDoQuery
= true;
5202 rItem
.meType
= ScQueryEntry::ByValue
;
5204 rEntry
.eOp
= SC_EQUAL
;
5208 rParam
.FillInExcelSyntax(pDok
->GetSharedStringPool(), aString
.getString(), 0);
5209 sal_uInt32 nIndex
= 0;
5210 bool bNumber
= pFormatter
->IsNumberFormat(
5211 rItem
.maString
.getString(), nIndex
, rItem
.mfVal
);
5212 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
5213 if (rItem
.meType
== ScQueryEntry::ByString
)
5214 rParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
5216 rParam
.nCol1
= nCol1
;
5217 rParam
.nCol2
= nCol2
;
5218 rEntry
.nField
= nCol1
;
5221 // Never case-sensitive.
5222 sc::CompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
5223 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
5224 if (nGlobalError
|| !pResultMatrix
)
5226 PushIllegalParameter();
5230 SCSIZE nSize
= pResultMatrix
->GetElementCount();
5231 for (SCSIZE nIndex
= 0; nIndex
< nSize
; ++nIndex
)
5233 if (pResultMatrix
->IsValue( nIndex
) &&
5234 pResultMatrix
->GetDouble( nIndex
))
5240 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
5241 // Keep Entry.nField in iterator on column change
5242 aCellIter
.SetAdvanceQueryParamEntryField( true );
5243 if ( aCellIter
.GetFirst() )
5248 } while ( aCellIter
.GetNext() );
5254 PushIllegalParameter();
5262 double ScInterpreter::IterateParametersIfs( ScIterFuncIfs eFunc
)
5264 sal_uInt8 nParamCount
= GetByte();
5265 sal_uInt8 nQueryCount
= nParamCount
/ 2;
5268 if ( eFunc
== ifCOUNTIFS
)
5269 bCheck
= (nParamCount
>= 2) && (nParamCount
% 2 == 0);
5271 bCheck
= (nParamCount
>= 3) && (nParamCount
% 2 == 1);
5275 SetError( errParameterExpected
);
5279 std::vector
<sal_uInt8
> aResArray
;
5280 size_t nRowSize
= 0;
5281 size_t nColSize
= 0;
5286 double fCount
= 0.0;
5288 size_t nRefInList
= 0;
5289 SCCOL nDimensionCols
= 0;
5290 SCROW nDimensionRows
= 0;
5292 while (nParamCount
> 1 && !nGlobalError
)
5295 svl::SharedString aString
;
5297 bool bIsString
= true;
5298 switch ( GetStackType() )
5304 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5307 ScRefCellValue aCell
;
5308 aCell
.assign(*pDok
, aAdr
);
5309 switch (aCell
.meType
)
5311 case CELLTYPE_VALUE
:
5312 fVal
= GetCellValue(aAdr
, aCell
);
5315 case CELLTYPE_FORMULA
:
5316 if (aCell
.mpFormula
->IsValue())
5318 fVal
= GetCellValue(aAdr
, aCell
);
5322 GetCellString(aString
, aCell
);
5324 case CELLTYPE_STRING
:
5325 case CELLTYPE_EDIT
:
5326 GetCellString(aString
, aCell
);
5335 aString
= GetString();
5338 case svExternalDoubleRef
:
5340 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
, aString
);
5341 bIsString
= ScMatrix::IsNonValueType( nType
);
5344 case svExternalSingleRef
:
5346 ScExternalRefCache::TokenRef pToken
;
5347 PopExternalSingleRef(pToken
);
5350 if (pToken
->GetType() == svDouble
)
5352 fVal
= pToken
->GetDouble();
5356 aString
= pToken
->GetString();
5368 return 0; // and bail out, no need to evaluate other arguments
5379 ScMatrixRef pQueryMatrix
;
5380 switch ( GetStackType() )
5385 PopDoubleRef( aRange
, nParam
, nRefInList
);
5386 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5390 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5393 PopSingleRef( nCol1
, nRow1
, nTab1
);
5399 case svExternalSingleRef
:
5400 case svExternalDoubleRef
:
5402 pQueryMatrix
= PopMatrix();
5405 SetError( errIllegalParameter
);
5412 pQueryMatrix
->GetDimensions( nC
, nR
);
5413 nCol2
= static_cast<SCCOL
>(nC
- 1);
5414 nRow2
= static_cast<SCROW
>(nR
- 1);
5419 SetError( errIllegalParameter
);
5422 if ( nTab1
!= nTab2
)
5424 SetError( errIllegalArgument
);
5428 // All reference ranges must be of same dimension and size.
5429 if (!nDimensionCols
)
5430 nDimensionCols
= nCol2
- nCol1
+ 1;
5431 if (!nDimensionRows
)
5432 nDimensionRows
= nRow2
- nRow1
+ 1;
5433 if ((nDimensionCols
!= (nCol2
- nCol1
+ 1)) || (nDimensionRows
!= (nRow2
- nRow1
+ 1)))
5435 SetError ( errIllegalArgument
);
5439 // recalculate matrix values
5443 // initialize temporary result matrix
5444 if (aResArray
.empty())
5446 nColSize
= nCol2
- nCol1
+ 1;
5447 nRowSize
= nRow2
- nRow1
+ 1;
5448 aResArray
.resize(nColSize
*nRowSize
, 0);
5451 ScQueryParam rParam
;
5452 rParam
.nRow1
= nRow1
;
5453 rParam
.nRow2
= nRow2
;
5455 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5456 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
5457 rEntry
.bDoQuery
= true;
5460 rItem
.meType
= ScQueryEntry::ByValue
;
5462 rEntry
.eOp
= SC_EQUAL
;
5466 rParam
.FillInExcelSyntax(pDok
->GetSharedStringPool(), aString
.getString(), 0);
5467 sal_uInt32 nIndex
= 0;
5468 bool bNumber
= pFormatter
->IsNumberFormat(
5469 rItem
.maString
.getString(), nIndex
, rItem
.mfVal
);
5470 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
5471 if (rItem
.meType
== ScQueryEntry::ByString
)
5472 rParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
5475 aAdr
.SetTab( nTab1
);
5476 rParam
.nCol1
= nCol1
;
5477 rParam
.nCol2
= nCol2
;
5478 rEntry
.nField
= nCol1
;
5479 SCsCOL nColDiff
= -nCol1
;
5480 SCsROW nRowDiff
= -nRow1
;
5483 // Never case-sensitive.
5484 sc::CompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
5485 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
5486 if (nGlobalError
|| !pResultMatrix
)
5488 SetError( errIllegalParameter
);
5492 // result matrix is filled with boolean values.
5493 std::vector
<double> aResValues
;
5494 pResultMatrix
->GetDoubleArray(aResValues
, true);
5495 if (aResArray
.size() != aResValues
.size())
5497 SetError( errIllegalParameter
);
5501 std::vector
<sal_uInt8
>::iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5502 std::vector
<double>::const_iterator itThisRes
= aResValues
.begin();
5503 for (; itRes
!= itResEnd
; ++itRes
, ++itThisRes
)
5504 *itRes
+= *itThisRes
;
5508 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, false);
5509 // Increment Entry.nField in iterator when switching to next column.
5510 aCellIter
.SetAdvanceQueryParamEntryField( true );
5511 if ( aCellIter
.GetFirst() )
5515 size_t nC
= aCellIter
.GetCol() + nColDiff
;
5516 size_t nR
= aCellIter
.GetRow() + nRowDiff
;
5517 ++aResArray
[nC
*nRowSize
+nR
];
5518 } while ( aCellIter
.GetNext() );
5525 return 0; // bail out
5527 // main range - only for AVERAGEIFS and SUMIFS
5528 if (nParamCount
== 1)
5533 SCCOL nMainCol1
= 0;
5534 SCROW nMainRow1
= 0;
5535 SCTAB nMainTab1
= 0;
5536 SCCOL nMainCol2
= 0;
5537 SCROW nMainRow2
= 0;
5538 SCTAB nMainTab2
= 0;
5539 ScMatrixRef pMainMatrix
;
5540 switch ( GetStackType() )
5545 PopDoubleRef( aRange
, nParam
, nRefInList
);
5546 aRange
.GetVars( nMainCol1
, nMainRow1
, nMainTab1
, nMainCol2
, nMainRow2
, nMainTab2
);
5550 PopDoubleRef( nMainCol1
, nMainRow1
, nMainTab1
, nMainCol2
, nMainRow2
, nMainTab2
);
5553 PopSingleRef( nMainCol1
, nMainRow1
, nMainTab1
);
5554 nMainCol2
= nMainCol1
;
5555 nMainRow2
= nMainRow1
;
5556 nMainTab2
= nMainTab1
;
5559 case svExternalSingleRef
:
5560 case svExternalDoubleRef
:
5562 pMainMatrix
= PopMatrix();
5565 SetError( errIllegalParameter
);
5571 pMainMatrix
->GetDimensions( nC
, nR
);
5572 nMainCol2
= static_cast<SCCOL
>(nC
- 1);
5573 nMainRow2
= static_cast<SCROW
>(nR
- 1);
5578 SetError( errIllegalParameter
);
5581 if ( nMainTab1
!= nMainTab2
)
5583 SetError( errIllegalArgument
);
5587 // All reference ranges must be of same dimension and size.
5588 if ((nDimensionCols
!= (nMainCol2
- nMainCol1
+ 1)) || (nDimensionRows
!= (nMainRow2
- nMainRow1
+ 1)))
5590 SetError ( errIllegalArgument
);
5595 return 0; // bail out
5597 // end-result calculation
5599 aAdr
.SetTab( nMainTab1
);
5602 std::vector
<double> aMainValues
;
5603 pMainMatrix
->GetDoubleArray(aMainValues
, false); // Map empty values to NaN's.
5604 if (aResArray
.size() != aMainValues
.size())
5606 SetError( errIllegalArgument
);
5610 std::vector
<sal_uInt8
>::const_iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5611 std::vector
<double>::const_iterator itMain
= aMainValues
.begin();
5612 for (; itRes
!= itResEnd
; ++itRes
, ++itMain
)
5614 if (*itRes
!= nQueryCount
)
5618 if (rtl::math::isNan(fVal
))
5622 if (bNull
&& fVal
!= 0.0)
5633 std::vector
<sal_uInt8
>::const_iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5634 for (size_t nCol
= 0; nCol
< nColSize
; ++nCol
)
5636 for (size_t nRow
= 0; nRow
< nRowSize
; ++nRow
, ++itRes
)
5638 if (*itRes
== nQueryCount
)
5640 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) + nMainCol1
);
5641 aAdr
.SetRow( static_cast<SCROW
>(nRow
) + nMainRow1
);
5642 ScRefCellValue aCell
;
5643 aCell
.assign(*pDok
, aAdr
);
5644 if (aCell
.hasNumeric())
5646 fVal
= GetCellValue(aAdr
, aCell
);
5648 if ( bNull
&& fVal
!= 0.0 )
5663 std::vector
<sal_uInt8
>::const_iterator itRes
= aResArray
.begin(), itResEnd
= aResArray
.end();
5664 for (; itRes
!= itResEnd
; ++itRes
)
5665 if (*itRes
== nQueryCount
)
5671 case ifSUMIFS
: fRes
= ::rtl::math::approxAdd( fSum
, fMem
); break;
5672 case ifAVERAGEIFS
: fRes
= div( ::rtl::math::approxAdd( fSum
, fMem
), fCount
); break;
5673 case ifCOUNTIFS
: fRes
= fCount
; break;
5674 default: ; // nothing
5681 void ScInterpreter::ScSumIfs()
5683 PushDouble( IterateParametersIfs( ifSUMIFS
));
5686 void ScInterpreter::ScAverageIfs()
5688 PushDouble( IterateParametersIfs( ifAVERAGEIFS
));
5691 void ScInterpreter::ScCountIfs()
5693 PushDouble( IterateParametersIfs( ifCOUNTIFS
));
5696 void ScInterpreter::ScLookup()
5698 sal_uInt8 nParamCount
= GetByte();
5699 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
5702 ScMatrixRef pDataMat
= NULL
, pResMat
= NULL
;
5703 SCCOL nCol1
= 0, nCol2
= 0, nResCol1
= 0, nResCol2
= 0;
5704 SCROW nRow1
= 0, nRow2
= 0, nResRow1
= 0, nResRow2
= 0;
5705 SCTAB nTab1
= 0, nResTab
= 0;
5706 SCSIZE nLenMajor
= 0; // length of major direction
5707 bool bVertical
= true; // whether to lookup vertically or horizontally
5709 // The third parameter, result array, for double, string and single reference.
5710 double fResVal
= 0.0;
5711 svl::SharedString aResStr
;
5713 StackVar eResArrayType
= svUnknown
;
5715 if (nParamCount
== 3)
5717 eResArrayType
= GetStackType();
5718 switch (eResArrayType
)
5723 PopDoubleRef(nResCol1
, nResRow1
, nResTab
,
5724 nResCol2
, nResRow2
, nTabJunk
);
5725 if (nResTab
!= nTabJunk
||
5726 ((nResRow2
- nResRow1
) > 0 && (nResCol2
- nResCol1
) > 0))
5728 // The result array must be a vector.
5729 PushIllegalParameter();
5735 case svExternalSingleRef
:
5736 case svExternalDoubleRef
:
5738 pResMat
= GetMatrix();
5741 PushIllegalParameter();
5745 pResMat
->GetDimensions(nC
, nR
);
5746 if (nC
!= 1 && nR
!= 1)
5748 // Result matrix must be a vector.
5749 PushIllegalParameter();
5755 fResVal
= GetDouble();
5758 aResStr
= GetString();
5761 PopSingleRef( aResAdr
);
5764 PushIllegalParameter();
5769 // For double, string and single reference.
5770 double fDataVal
= 0.0;
5771 svl::SharedString aDataStr
;
5773 bool bValueData
= false;
5775 // Get the data-result range and also determine whether this is vertical
5776 // lookup or horizontal lookup.
5778 StackVar eDataArrayType
= GetStackType();
5779 switch (eDataArrayType
)
5784 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTabJunk
);
5785 if (nTab1
!= nTabJunk
)
5787 PushIllegalParameter();
5790 bVertical
= (nRow2
- nRow1
) >= (nCol2
- nCol1
);
5791 nLenMajor
= bVertical
? nRow2
- nRow1
+ 1 : nCol2
- nCol1
+ 1;
5795 case svExternalSingleRef
:
5796 case svExternalDoubleRef
:
5798 pDataMat
= GetMatrix();
5801 PushIllegalParameter();
5806 pDataMat
->GetDimensions(nC
, nR
);
5807 bVertical
= (nR
>= nC
);
5808 nLenMajor
= bVertical
? nR
: nC
;
5813 fDataVal
= GetDouble();
5819 aDataStr
= GetString();
5824 PopSingleRef( aDataAdr
);
5825 ScRefCellValue aCell
;
5826 aCell
.assign(*pDok
, aDataAdr
);
5827 if (aCell
.hasEmptyValue())
5829 // Empty cells aren't found anywhere, bail out early.
5830 SetError( NOTAVAILABLE
);
5832 else if (aCell
.hasNumeric())
5834 fDataVal
= GetCellValue(aDataAdr
, aCell
);
5838 GetCellString(aDataStr
, aCell
);
5842 SetError( errIllegalParameter
);
5848 PushError( nGlobalError
);
5852 // Get the lookup value.
5854 ScQueryParam aParam
;
5855 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
5856 if ( !FillEntry(rEntry
) )
5859 if ( eDataArrayType
== svDouble
|| eDataArrayType
== svString
||
5860 eDataArrayType
== svSingleRef
)
5862 // Delta position for a single value is always 0.
5864 // Found if data <= query, but not if query is string and found data is
5865 // numeric or vice versa. This is how Excel does it but doesn't
5868 bool bFound
= false;
5869 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
5873 if (rItem
.meType
== ScQueryEntry::ByString
)
5876 bFound
= (fDataVal
<= rItem
.mfVal
);
5880 if (rItem
.meType
!= ScQueryEntry::ByString
)
5883 bFound
= (ScGlobal::GetCollator()->compareString(aDataStr
.getString(), rItem
.maString
.getString()) <= 0);
5894 if (pResMat
->IsValue( 0, 0 ))
5895 PushDouble(pResMat
->GetDouble( 0, 0 ));
5897 PushString(pResMat
->GetString(0, 0));
5899 else if (nParamCount
== 3)
5901 switch (eResArrayType
)
5904 PushDouble( fResVal
);
5907 PushString( aResStr
);
5910 aResAdr
.Set( nResCol1
, nResRow1
, nResTab
);
5913 PushCellResultToken( true, aResAdr
, NULL
, NULL
);
5916 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
5921 switch (eDataArrayType
)
5924 PushDouble( fDataVal
);
5927 PushString( aDataStr
);
5930 PushCellResultToken( true, aDataAdr
, NULL
, NULL
);
5933 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
5939 // Now, perform the search to compute the delta position (nDelta).
5943 // Data array is given as a matrix.
5944 rEntry
.bDoQuery
= true;
5945 rEntry
.eOp
= SC_LESS_EQUAL
;
5946 bool bFound
= false;
5949 pDataMat
->GetDimensions(nC
, nR
);
5951 // In case of non-vector matrix, only search the first row or column.
5952 ScMatrixRef pDataMat2
;
5955 ScMatrixRef
pTempMat(new ScMatrix(1, nR
, 0.0));
5956 for (SCSIZE i
= 0; i
< nR
; ++i
)
5957 if (pDataMat
->IsValue(0, i
))
5958 pTempMat
->PutDouble(pDataMat
->GetDouble(0, i
), 0, i
);
5960 pTempMat
->PutString(pDataMat
->GetString(0, i
), 0, i
);
5961 pDataMat2
= pTempMat
;
5965 ScMatrixRef
pTempMat(new ScMatrix(nC
, 1, 0.0));
5966 for (SCSIZE i
= 0; i
< nC
; ++i
)
5967 if (pDataMat
->IsValue(i
, 0))
5968 pTempMat
->PutDouble(pDataMat
->GetDouble(i
, 0), i
, 0);
5970 pTempMat
->PutString(pDataMat
->GetString(i
, 0), i
, 0);
5971 pDataMat2
= pTempMat
;
5974 VectorMatrixAccessor
aMatAcc2(*pDataMat2
, bVertical
);
5976 // binary search for non-equality mode (the source data is
5977 // assumed to be sorted in ascending order).
5979 SCCOLROW nDelta
= -1;
5981 SCSIZE nFirst
= 0, nLast
= nLenMajor
-1; //, nHitIndex = 0;
5982 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
5984 SCSIZE nMid
= nFirst
+ nLen
/2;
5985 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, aMatAcc2
, rEntry
);
5988 // exact match. find the last item with the same value.
5989 lcl_GetLastMatch( nMid
, aMatAcc2
, nLenMajor
, false);
5995 if (nLen
== 1) // first and last items are next to each other.
5997 nDelta
= nCmp
< 0 ? nLast
- 1 : nFirst
- 1;
5998 // If already the 1st item is greater there's nothing found.
5999 bFound
= (nDelta
>= 0);
6009 if (nDelta
== static_cast<SCCOLROW
>(nLenMajor
-2)) // last item
6011 sal_Int32 nCmp
= lcl_CompareMatrix2Query(nDelta
+1, aMatAcc2
, rEntry
);
6014 // either the last item is an exact match or the real
6015 // hit is beyond the last item.
6020 else if (nDelta
> 0) // valid hit must be 2nd item or higher
6026 // With 0-9 < A-Z, if query is numeric and data found is string, or
6027 // vice versa, the (yet another undocumented) Excel behavior is to
6028 // return #N/A instead.
6032 VectorMatrixAccessor
aMatAcc(*pDataMat
, bVertical
);
6033 SCCOLROW i
= nDelta
;
6034 SCSIZE n
= aMatAcc
.GetElementCount();
6035 if (static_cast<SCSIZE
>(i
) >= n
)
6036 i
= static_cast<SCCOLROW
>(n
);
6037 bool bByString
= rEntry
.GetQueryItem().meType
== ScQueryEntry::ByString
;
6038 if (bByString
== aMatAcc
.IsValue(i
))
6048 // Now that we've found the delta, push the result back to the cell.
6052 VectorMatrixAccessor
aResMatAcc(*pResMat
, bVertical
);
6053 // result array is matrix.
6054 if (static_cast<SCSIZE
>(nDelta
) >= aResMatAcc
.GetElementCount())
6059 if (aResMatAcc
.IsValue(nDelta
))
6060 PushDouble(aResMatAcc
.GetDouble(nDelta
));
6062 PushString(aResMatAcc
.GetString(nDelta
));
6064 else if (nParamCount
== 3)
6066 // result array is cell range.
6068 aAdr
.SetTab(nResTab
);
6069 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
6072 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
6073 if (nTempRow
> MAXROW
)
6078 aAdr
.SetCol(nResCol1
);
6079 aAdr
.SetRow(nTempRow
);
6083 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
6084 if (nTempCol
> MAXCOL
)
6089 aAdr
.SetCol(nTempCol
);
6090 aAdr
.SetRow(nResRow1
);
6092 PushCellResultToken(true, aAdr
, NULL
, NULL
);
6096 // no result array. Use the data array to get the final value from.
6099 if (pDataMat
->IsValue(nC
-1, nDelta
))
6100 PushDouble(pDataMat
->GetDouble(nC
-1, nDelta
));
6102 PushString(pDataMat
->GetString(nC
-1, nDelta
));
6106 if (pDataMat
->IsValue(nDelta
, nR
-1))
6107 PushDouble(pDataMat
->GetDouble(nDelta
, nR
-1));
6109 PushString(pDataMat
->GetString(nDelta
, nR
-1));
6116 // Perform cell range search.
6118 aParam
.nCol1
= nCol1
;
6119 aParam
.nRow1
= nRow1
;
6120 aParam
.nCol2
= bVertical
? nCol1
: nCol2
;
6121 aParam
.nRow2
= bVertical
? nRow2
: nRow1
;
6122 aParam
.bByRow
= bVertical
;
6124 rEntry
.bDoQuery
= true;
6125 rEntry
.eOp
= SC_LESS_EQUAL
;
6126 rEntry
.nField
= nCol1
;
6127 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6128 if (rItem
.meType
== ScQueryEntry::ByString
)
6129 aParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
6131 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, false);
6134 // Advance Entry.nField in iterator upon switching columns if
6136 aCellIter
.SetAdvanceQueryParamEntryField(!bVertical
);
6137 if ( !aCellIter
.FindEqualOrSortedLastInRange(nC
, nR
) )
6143 SCCOLROW nDelta
= bVertical
? static_cast<SCSIZE
>(nR
-nRow1
) : static_cast<SCSIZE
>(nC
-nCol1
);
6147 VectorMatrixAccessor
aResMatAcc(*pResMat
, bVertical
);
6148 // Use the matrix result array.
6149 if (aResMatAcc
.IsValue(nDelta
))
6150 PushDouble(aResMatAcc
.GetDouble(nDelta
));
6152 PushString(aResMatAcc
.GetString(nDelta
));
6154 else if (nParamCount
== 3)
6156 switch (eResArrayType
)
6160 // Use the result array vector. Note that the result array is assumed
6161 // to be a vector (i.e. 1-dimensinoal array).
6164 aAdr
.SetTab(nResTab
);
6165 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
6168 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
6169 if (nTempRow
> MAXROW
)
6174 aAdr
.SetCol(nResCol1
);
6175 aAdr
.SetRow(nTempRow
);
6179 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
6180 if (nTempCol
> MAXCOL
)
6185 aAdr
.SetCol(nTempCol
);
6186 aAdr
.SetRow(nResRow1
);
6188 PushCellResultToken( true, aAdr
, NULL
, NULL
);
6199 switch (eResArrayType
)
6202 PushDouble( fResVal
);
6205 PushString( aResStr
);
6208 PushCellResultToken( true, aResAdr
, NULL
, NULL
);
6217 OSL_FAIL( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
6222 // Regardless of whether or not the result array exists, the last
6223 // array is always used as the "result" array.
6229 SCROW nTempRow
= static_cast<SCROW
>(nRow1
+ nDelta
);
6230 if (nTempRow
> MAXROW
)
6236 aAdr
.SetRow(nTempRow
);
6240 SCCOL nTempCol
= static_cast<SCCOL
>(nCol1
+ nDelta
);
6241 if (nTempCol
> MAXCOL
)
6246 aAdr
.SetCol(nTempCol
);
6249 PushCellResultToken(true, aAdr
, NULL
, NULL
);
6254 void ScInterpreter::ScHLookup()
6256 CalculateLookup(true);
6259 void ScInterpreter::CalculateLookup(bool bHLookup
)
6261 sal_uInt8 nParamCount
= GetByte();
6262 if (!MustHaveParamCount(nParamCount
, 3, 4))
6265 // Optional 4th argument to declare whether or not the range is sorted.
6266 bool bSorted
= true;
6267 if (nParamCount
== 4)
6268 bSorted
= GetBool();
6270 // Index of column to search.
6271 double fIndex
= ::rtl::math::approxFloor( GetDouble() ) - 1.0;
6273 ScMatrixRef pMat
= NULL
;
6274 SCSIZE nC
= 0, nR
= 0;
6281 StackVar eType
= GetStackType();
6282 if (eType
== svDoubleRef
)
6284 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6287 PushIllegalParameter();
6291 else if (eType
== svSingleRef
)
6293 PopSingleRef(nCol1
, nRow1
, nTab1
);
6297 else if (eType
== svMatrix
|| eType
== svExternalDoubleRef
|| eType
== svExternalSingleRef
)
6302 pMat
->GetDimensions(nC
, nR
);
6305 PushIllegalParameter();
6311 PushIllegalParameter();
6315 if ( fIndex
< 0.0 || (bHLookup
? (pMat
? (fIndex
>= nR
) : (fIndex
+nRow1
> nRow2
)) : (pMat
? (fIndex
>= nC
) : (fIndex
+nCol1
> nCol2
)) ) )
6317 PushIllegalArgument();
6321 SCROW nZIndex
= static_cast<SCROW
>(fIndex
);
6322 SCCOL nSpIndex
= static_cast<SCCOL
>(fIndex
);
6326 nZIndex
+= nRow1
; // Wertzeile
6327 nSpIndex
= sal::static_int_cast
<SCCOL
>( nSpIndex
+ nCol1
); // value column
6332 PushIllegalParameter();
6336 ScQueryParam aParam
;
6337 aParam
.nCol1
= nCol1
;
6338 aParam
.nRow1
= nRow1
;
6341 aParam
.nCol2
= nCol2
;
6342 aParam
.nRow2
= nRow1
; // nur in der ersten Zeile suchen
6343 aParam
.bByRow
= false;
6347 aParam
.nCol2
= nCol1
; // nur in der ersten Spalte suchen
6348 aParam
.nRow2
= nRow2
;
6349 aParam
.nTab
= nTab1
;
6352 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
6353 rEntry
.bDoQuery
= true;
6355 rEntry
.eOp
= SC_LESS_EQUAL
;
6356 if ( !FillEntry(rEntry
) )
6359 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6360 if (rItem
.meType
== ScQueryEntry::ByString
)
6361 aParam
.bRegExp
= MayBeRegExp(rItem
.maString
.getString(), pDok
);
6364 SCSIZE nMatCount
= bHLookup
? nC
: nR
;
6365 SCSIZE nDelta
= SCSIZE_MAX
;
6366 if (rItem
.meType
== ScQueryEntry::ByString
)
6369 //! TODO: enable regex on matrix strings
6371 svl::SharedString aParamStr
= rItem
.maString
;
6374 static CollatorWrapper
* pCollator
= ScGlobal::GetCollator();
6375 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6377 if (bHLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
6380 pCollator
->compareString(
6381 bHLookup
? pMat
->GetString(i
,0).getString() : pMat
->GetString(0,i
).getString(), aParamStr
.getString());
6384 else if (i
>0) // #i2168# ignore first mismatch
6395 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6397 if (pMat
->IsString(i
, 0))
6399 if (pMat
->GetString(i
,0).getDataIgnoreCase() == aParamStr
.getDataIgnoreCase())
6409 nDelta
= pMat
->MatchStringInColumns(aParamStr
, 0, 0);
6417 // #i2168# ignore strings
6418 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6420 if (!(bHLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
6422 if ((bHLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) <= rItem
.mfVal
)
6433 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
6435 if (! pMat
->IsString(i
, 0) )
6437 if ( pMat
->GetDouble(i
,0) == rItem
.mfVal
)
6447 nDelta
= pMat
->MatchDoubleInColumns(rItem
.mfVal
, 0, 0);
6451 if ( nDelta
!= SCSIZE_MAX
)
6453 SCSIZE nX
= static_cast<SCSIZE
>(nSpIndex
);
6458 nY
= static_cast<SCSIZE
>(nZIndex
);
6460 if ( pMat
->IsString( nX
, nY
) )
6461 PushString(pMat
->GetString( nX
,nY
).getString());
6463 PushDouble(pMat
->GetDouble( nX
,nY
));
6470 rEntry
.nField
= nCol1
;
6471 bool bFound
= false;
6475 rEntry
.eOp
= SC_LESS_EQUAL
;
6478 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, false);
6479 // advance Entry.nField in Iterator upon switching columns
6480 aCellIter
.SetAdvanceQueryParamEntryField( true );
6484 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow1_temp
);
6486 else if ( aCellIter
.GetFirst() )
6489 nCol
= aCellIter
.GetCol();
6495 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
6496 bFound
= LookupQueryWithCache( aResultPos
, aParam
);
6497 nRow
= aResultPos
.Row();
6503 ScAddress
aAdr( nCol
, nRow
, nTab1
);
6504 PushCellResultToken( true, aAdr
, NULL
, NULL
);
6511 bool ScInterpreter::FillEntry(ScQueryEntry
& rEntry
)
6513 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6514 switch ( GetStackType() )
6518 rItem
.meType
= ScQueryEntry::ByValue
;
6519 rItem
.mfVal
= GetDouble();
6524 rItem
.meType
= ScQueryEntry::ByString
;
6525 rItem
.maString
= GetString();
6532 if ( !PopDoubleRefOrSingleRef( aAdr
) )
6537 ScRefCellValue aCell
;
6538 aCell
.assign(*pDok
, aAdr
);
6539 if (aCell
.hasNumeric())
6541 rItem
.meType
= ScQueryEntry::ByValue
;
6542 rItem
.mfVal
= GetCellValue(aAdr
, aCell
);
6546 GetCellString(rItem
.maString
, aCell
);
6547 rItem
.meType
= ScQueryEntry::ByString
;
6553 svl::SharedString aStr
;
6554 const ScMatValType nType
= GetDoubleOrStringFromMatrix(rItem
.mfVal
, aStr
);
6555 rItem
.maString
= aStr
;
6556 rItem
.meType
= ScMatrix::IsNonValueType(nType
) ?
6557 ScQueryEntry::ByString
: ScQueryEntry::ByValue
;
6562 PushIllegalParameter();
6565 } // switch ( GetStackType() )
6568 void ScInterpreter::ScVLookup()
6570 CalculateLookup(false);
6573 void ScInterpreter::ScSubTotal()
6575 sal_uInt8 nParamCount
= GetByte();
6576 if ( MustHaveParamCountMin( nParamCount
, 2 ) )
6578 // We must fish the 1st parameter deep from the stack! And push it on top.
6579 const FormulaToken
* p
= pStack
[ sp
- nParamCount
];
6580 PushTempToken( *p
);
6581 int nFunc
= (int) ::rtl::math::approxFloor( GetDouble() );
6582 bool bIncludeHidden
= true;
6585 // For opcodes 101 through 111, we need to skip hidden cells.
6586 // Other than that these opcodes are identical to 1 through 11.
6587 bIncludeHidden
= false;
6591 if (nFunc
< 1 || nFunc
> 11 || !bIncludeHidden
)
6592 PushIllegalArgument(); // simulate return on stack, not SetError(...)
6595 // TODO: Make use of bIncludeHidden flag. Then it's false, we do need to skip hidden cells.
6596 cPar
= nParamCount
- 1;
6600 case SUBTOTAL_FUNC_AVE
: ScAverage(); break;
6601 case SUBTOTAL_FUNC_CNT
: ScCount(); break;
6602 case SUBTOTAL_FUNC_CNT2
: ScCount2(); break;
6603 case SUBTOTAL_FUNC_MAX
: ScMax(); break;
6604 case SUBTOTAL_FUNC_MIN
: ScMin(); break;
6605 case SUBTOTAL_FUNC_PROD
: ScProduct(); break;
6606 case SUBTOTAL_FUNC_STD
: ScStDev(); break;
6607 case SUBTOTAL_FUNC_STDP
: ScStDevP(); break;
6608 case SUBTOTAL_FUNC_SUM
: ScSum(); break;
6609 case SUBTOTAL_FUNC_VAR
: ScVar(); break;
6610 case SUBTOTAL_FUNC_VARP
: ScVarP(); break;
6611 default : PushIllegalArgument(); break;
6615 // Get rid of the 1st (fished) parameter.
6616 double nVal
= GetDouble();
6622 ScDBQueryParamBase
* ScInterpreter::GetDBParams( bool& rMissingField
)
6624 bool bAllowMissingField
= false;
6625 if ( rMissingField
)
6627 bAllowMissingField
= true;
6628 rMissingField
= false;
6630 if ( GetByte() == 3 )
6632 // First, get the query criteria range.
6633 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6634 ::std::auto_ptr
<ScDBRangeBase
> pQueryRef( PopDBDoubleRef() );
6635 SAL_WNODEPRECATED_DECLARATIONS_POP
6636 if (!pQueryRef
.get())
6641 svl::SharedString aStr
;
6642 ScRange aMissingRange
;
6643 bool bRangeFake
= false;
6644 switch (GetStackType())
6647 nVal
= ::rtl::math::approxFloor( GetDouble() );
6648 if ( bAllowMissingField
&& nVal
== 0.0 )
6649 rMissingField
= true; // fake missing parameter
6658 PopSingleRef( aAdr
);
6659 ScRefCellValue aCell
;
6660 aCell
.assign(*pDok
, aAdr
);
6661 if (aCell
.hasNumeric())
6662 nVal
= GetCellValue(aAdr
, aCell
);
6666 GetCellString(aStr
, aCell
);
6671 if ( bAllowMissingField
)
6672 { // fake missing parameter for old SO compatibility
6674 PopDoubleRef( aMissingRange
);
6679 SetError( errIllegalParameter
);
6684 if ( bAllowMissingField
)
6685 rMissingField
= true;
6687 SetError( errIllegalParameter
);
6691 SetError( errIllegalParameter
);
6697 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6698 auto_ptr
<ScDBRangeBase
> pDBRef( PopDBDoubleRef() );
6699 SAL_WNODEPRECATED_DECLARATIONS_POP
6701 if (nGlobalError
|| !pDBRef
.get())
6706 // range parameter must match entire database range
6707 if (pDBRef
->isRangeEqual(aMissingRange
))
6708 rMissingField
= true;
6710 SetError( errIllegalParameter
);
6716 SCCOL nField
= pDBRef
->getFirstFieldColumn();
6720 nField
= pDBRef
->findFieldColumn(static_cast<SCCOL
>(nVal
));
6723 sal_uInt16 nErr
= 0;
6724 nField
= pDBRef
->findFieldColumn(aStr
.getString(), &nErr
);
6728 if (!ValidCol(nField
))
6731 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6732 auto_ptr
<ScDBQueryParamBase
> pParam( pDBRef
->createQueryParam(pQueryRef
.get()) );
6733 SAL_WNODEPRECATED_DECLARATIONS_POP
6737 // An allowed missing field parameter sets the result field
6738 // to any of the query fields, just to be able to return
6739 // some cell from the iterator.
6740 if ( rMissingField
)
6741 nField
= static_cast<SCCOL
>(pParam
->GetEntry(0).nField
);
6742 pParam
->mnField
= nField
;
6744 SCSIZE nCount
= pParam
->GetEntryCount();
6745 for ( SCSIZE i
=0; i
< nCount
; i
++ )
6747 ScQueryEntry
& rEntry
= pParam
->GetEntry(i
);
6748 if (!rEntry
.bDoQuery
)
6751 ScQueryEntry::Item
& rItem
= rEntry
.GetQueryItem();
6752 sal_uInt32 nIndex
= 0;
6753 OUString aQueryStr
= rItem
.maString
.getString();
6754 bool bNumber
= pFormatter
->IsNumberFormat(
6755 aQueryStr
, nIndex
, rItem
.mfVal
);
6756 rItem
.meType
= bNumber
? ScQueryEntry::ByValue
: ScQueryEntry::ByString
;
6758 if (!bNumber
&& !pParam
->bRegExp
)
6759 pParam
->bRegExp
= MayBeRegExp(aQueryStr
, pDok
);
6761 return pParam
.release();
6768 void ScInterpreter::DBIterator( ScIterFunc eFunc
)
6773 sal_uLong nCount
= 0;
6774 bool bMissingField
= false;
6775 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6776 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6777 SAL_WNODEPRECATED_DECLARATIONS_POP
6778 if (pQueryParam
.get())
6780 if (!pQueryParam
->IsValidFieldIndex())
6782 SetError(errNoValue
);
6785 ScDBQueryDataIterator
aValIter(pDok
, pQueryParam
.release());
6786 ScDBQueryDataIterator::Value aValue
;
6787 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6791 case ifPRODUCT
: nErg
= 1; break;
6792 case ifMAX
: nErg
= -MAXDOUBLE
; break;
6793 case ifMIN
: nErg
= MAXDOUBLE
; break;
6794 default: ; // nothing
6803 if ( bNull
&& aValue
.mfValue
!= 0.0 )
6806 fMem
= aValue
.mfValue
;
6809 nErg
+= aValue
.mfValue
;
6811 case ifSUMSQ
: nErg
+= aValue
.mfValue
* aValue
.mfValue
; break;
6812 case ifPRODUCT
: nErg
*= aValue
.mfValue
; break;
6813 case ifMAX
: if( aValue
.mfValue
> nErg
) nErg
= aValue
.mfValue
; break;
6814 case ifMIN
: if( aValue
.mfValue
< nErg
) nErg
= aValue
.mfValue
; break;
6815 default: ; // nothing
6818 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6820 SetError(aValue
.mnError
);
6823 SetError( errIllegalParameter
);
6826 case ifCOUNT
: nErg
= nCount
; break;
6827 case ifSUM
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
); break;
6828 case ifAVERAGE
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
) / nCount
; break;
6829 default: ; // nothing
6835 void ScInterpreter::ScDBSum()
6837 DBIterator( ifSUM
);
6841 void ScInterpreter::ScDBCount()
6843 bool bMissingField
= true;
6844 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6845 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6846 SAL_WNODEPRECATED_DECLARATIONS_POP
6847 if (pQueryParam
.get())
6849 sal_uLong nCount
= 0;
6850 if ( bMissingField
&& pQueryParam
->GetType() == ScDBQueryParamBase::INTERNAL
)
6851 { // count all matching records
6852 // TODO: currently the QueryIterators only return cell pointers of
6853 // existing cells, so if a query matches an empty cell there's
6854 // nothing returned, and therefor not counted!
6855 // Since this has ever been the case and this code here only came
6856 // into existance to fix #i6899 and it never worked before we'll
6857 // have to live with it until we reimplement the iterators to also
6858 // return empty cells, which would mean to adapt all callers of
6860 ScDBQueryParamInternal
* p
= static_cast<ScDBQueryParamInternal
*>(pQueryParam
.get());
6861 p
->nCol2
= p
->nCol1
; // Don't forget to select only one column.
6862 SCTAB nTab
= p
->nTab
;
6863 // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField,
6864 // so the source range has to be restricted, like before the introduction
6865 // of ScDBQueryParamBase.
6866 p
->nCol1
= p
->nCol2
= p
->mnField
;
6867 ScQueryCellIterator
aCellIter( pDok
, nTab
, *p
);
6868 if ( aCellIter
.GetFirst() )
6873 } while ( aCellIter
.GetNext() );
6877 { // count only matching records with a value in the "result" field
6878 if (!pQueryParam
->IsValidFieldIndex())
6880 SetError(errNoValue
);
6883 ScDBQueryDataIterator
aValIter( pDok
, pQueryParam
.release());
6884 ScDBQueryDataIterator::Value aValue
;
6885 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6891 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6893 SetError(aValue
.mnError
);
6895 PushDouble( nCount
);
6898 PushIllegalParameter();
6902 void ScInterpreter::ScDBCount2()
6904 bool bMissingField
= true;
6905 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6906 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6907 SAL_WNODEPRECATED_DECLARATIONS_POP
6908 if (pQueryParam
.get())
6910 if (!pQueryParam
->IsValidFieldIndex())
6912 SetError(errNoValue
);
6915 sal_uLong nCount
= 0;
6916 pQueryParam
->mbSkipString
= false;
6917 ScDBQueryDataIterator
aValIter( pDok
, pQueryParam
.release());
6918 ScDBQueryDataIterator::Value aValue
;
6919 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6925 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6927 SetError(aValue
.mnError
);
6928 PushDouble( nCount
);
6931 PushIllegalParameter();
6935 void ScInterpreter::ScDBAverage()
6937 DBIterator( ifAVERAGE
);
6941 void ScInterpreter::ScDBMax()
6943 DBIterator( ifMAX
);
6947 void ScInterpreter::ScDBMin()
6949 DBIterator( ifMIN
);
6953 void ScInterpreter::ScDBProduct()
6955 DBIterator( ifPRODUCT
);
6959 void ScInterpreter::GetDBStVarParams( double& rVal
, double& rValCount
)
6961 std::vector
<double> values
;
6967 bool bMissingField
= false;
6968 SAL_WNODEPRECATED_DECLARATIONS_PUSH
6969 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6970 SAL_WNODEPRECATED_DECLARATIONS_POP
6971 if (pQueryParam
.get())
6973 if (!pQueryParam
->IsValidFieldIndex())
6975 SetError(errNoValue
);
6978 ScDBQueryDataIterator
aValIter(pDok
, pQueryParam
.release());
6979 ScDBQueryDataIterator::Value aValue
;
6980 if (aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6985 values
.push_back(aValue
.mfValue
);
6986 fSum
+= aValue
.mfValue
;
6988 while ((aValue
.mnError
== 0) && aValIter
.GetNext(aValue
));
6990 SetError(aValue
.mnError
);
6993 SetError( errIllegalParameter
);
6995 vMean
= fSum
/ values
.size();
6997 for (size_t i
= 0; i
< values
.size(); i
++)
6998 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
7004 void ScInterpreter::ScDBStdDev()
7006 double fVal
, fCount
;
7007 GetDBStVarParams( fVal
, fCount
);
7008 PushDouble( sqrt(fVal
/(fCount
-1)));
7012 void ScInterpreter::ScDBStdDevP()
7014 double fVal
, fCount
;
7015 GetDBStVarParams( fVal
, fCount
);
7016 PushDouble( sqrt(fVal
/fCount
));
7020 void ScInterpreter::ScDBVar()
7022 double fVal
, fCount
;
7023 GetDBStVarParams( fVal
, fCount
);
7024 PushDouble(fVal
/(fCount
-1));
7028 void ScInterpreter::ScDBVarP()
7030 double fVal
, fCount
;
7031 GetDBStVarParams( fVal
, fCount
);
7032 PushDouble(fVal
/fCount
);
7035 void ScInterpreter::ScIndirect()
7037 sal_uInt8 nParamCount
= GetByte();
7038 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7040 // Reference address syntax for INDIRECT is configurable.
7041 FormulaGrammar::AddressConvention eConv
= GetGlobalConfig().meStringRefAddressSyntax
;
7042 if (eConv
== FormulaGrammar::CONV_UNSPECIFIED
)
7043 // Use the current address syntax if unspecified.
7044 eConv
= pDok
->GetAddressConvention();
7046 if (nParamCount
== 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
7048 // Overwrite the config and try Excel R1C1.
7049 eConv
= FormulaGrammar::CONV_XL_R1C1
;
7051 const ScAddress::Details
aDetails( eConv
, aPos
);
7052 SCTAB nTab
= aPos
.Tab();
7053 OUString sRefStr
= GetString().getString();
7054 ScRefAddress aRefAd
, aRefAd2
;
7055 ScAddress::ExternalInfo aExtInfo
;
7056 if (ConvertDoubleRef(pDok
, sRefStr
, nTab
, aRefAd
, aRefAd2
, aDetails
, &aExtInfo
))
7058 if (aExtInfo
.mbExternal
)
7060 PushExternalDoubleRef(
7061 aExtInfo
.mnFileId
, aExtInfo
.maTabName
,
7062 aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab(),
7063 aRefAd2
.Col(), aRefAd2
.Row(), aRefAd2
.Tab());
7066 PushDoubleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab(),
7067 aRefAd2
.Col(), aRefAd2
.Row(), aRefAd2
.Tab() );
7069 else if (ConvertSingleRef(pDok
, sRefStr
, nTab
, aRefAd
, aDetails
, &aExtInfo
))
7071 if (aExtInfo
.mbExternal
)
7073 PushExternalSingleRef(
7074 aExtInfo
.mnFileId
, aExtInfo
.maTabName
, aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab());
7077 PushSingleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab() );
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());
7110 PushError( errNoRef
);
7116 void ScInterpreter::ScAddressFunc()
7120 sal_uInt8 nParamCount
= GetByte();
7121 if( !MustHaveParamCount( nParamCount
, 2, 5 ) )
7124 if( nParamCount
>= 5 )
7125 sTabStr
= GetString().getString();
7127 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
; // default
7128 if( nParamCount
>= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
7129 eConv
= FormulaGrammar::CONV_XL_R1C1
;
7131 sal_uInt16 nFlags
= SCA_COL_ABSOLUTE
| SCA_ROW_ABSOLUTE
; // default
7132 if( nParamCount
>= 3 )
7134 sal_uInt16 n
= (sal_uInt16
) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
7142 case 1 : break; // default
7144 case 2 : nFlags
= SCA_ROW_ABSOLUTE
; break;
7146 case 3 : nFlags
= SCA_COL_ABSOLUTE
; break;
7148 case 4 : nFlags
= 0; break; // both relative
7151 nFlags
|= SCA_VALID
| SCA_VALID_ROW
| SCA_VALID_COL
;
7153 SCCOL nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
7154 SCROW nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
7155 if( eConv
== FormulaGrammar::CONV_XL_R1C1
)
7157 // YUCK! The XL interface actually treats rel R1C1 refs differently
7159 if( !(nFlags
& SCA_COL_ABSOLUTE
) )
7160 nCol
+= aPos
.Col() + 1;
7161 if( !(nFlags
& SCA_ROW_ABSOLUTE
) )
7162 nRow
+= aPos
.Row() + 1;
7167 if(!ValidCol( nCol
) || !ValidRow( nRow
))
7169 PushIllegalArgument();
7173 const ScAddress::Details
aDetails( eConv
, aPos
);
7174 const ScAddress
aAdr( nCol
, nRow
, 0);
7175 OUString
aRefStr(aAdr
.Format(nFlags
, pDok
, aDetails
));
7177 if( nParamCount
>= 5 && !sTabStr
.isEmpty() )
7180 if (eConv
== FormulaGrammar::CONV_OOO
)
7182 // Isolate Tab from 'Doc'#Tab
7183 sal_Int32 nPos
= ScCompiler::GetDocTabPos( sTabStr
);
7186 if (sTabStr
[nPos
+1] == '$')
7187 ++nPos
; // also split 'Doc'#$Tab
7188 aDoc
= sTabStr
.copy( 0, nPos
+1);
7189 sTabStr
= sTabStr
.copy( nPos
+1);
7192 /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may
7193 * need some extra handling to isolate Tab from Doc. */
7194 if (sTabStr
[0] != '\'' || !sTabStr
.endsWith("'"))
7195 ScCompiler::CheckTabQuotes( sTabStr
, eConv
);
7196 if (!aDoc
.isEmpty())
7197 sTabStr
= aDoc
+ sTabStr
;
7198 sTabStr
+= eConv
== FormulaGrammar::CONV_XL_R1C1
? OUString("!") : OUString(".");
7200 PushString( sTabStr
);
7203 PushString( aRefStr
);
7207 void ScInterpreter::ScOffset()
7209 sal_uInt8 nParamCount
= GetByte();
7210 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
7212 long nColNew
= -1, nRowNew
= -1, nColPlus
, nRowPlus
;
7213 if (nParamCount
== 5)
7214 nColNew
= (long) ::rtl::math::approxFloor(GetDouble());
7215 if (nParamCount
>= 4)
7216 nRowNew
= (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
7217 nColPlus
= (long) ::rtl::math::approxFloor(GetDouble());
7218 nRowPlus
= (long) ::rtl::math::approxFloor(GetDouble());
7225 if (nColNew
== 0 || nRowNew
== 0)
7227 PushIllegalArgument();
7230 switch (GetStackType())
7234 PopSingleRef(nCol1
, nRow1
, nTab1
);
7235 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
7237 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
7238 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
7239 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
7240 PushIllegalArgument();
7242 PushSingleRef(nCol1
, nRow1
, nTab1
);
7250 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7251 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7252 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7253 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7254 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7255 !ValidCol(nCol2
) || !ValidRow(nRow2
))
7256 PushIllegalArgument();
7258 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
7262 case svExternalSingleRef
:
7266 ScSingleRefData aRef
;
7267 PopExternalSingleRef(nFileId
, aTabName
, aRef
);
7268 ScAddress aAbsRef
= aRef
.toAbs(aPos
);
7269 nCol1
= aAbsRef
.Col();
7270 nRow1
= aAbsRef
.Row();
7271 nTab1
= aAbsRef
.Tab();
7273 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
7275 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
7276 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
7277 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
7278 PushIllegalArgument();
7280 PushExternalSingleRef(nFileId
, aTabName
, nCol1
, nRow1
, nTab1
);
7288 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7289 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7290 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7291 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7293 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7294 !ValidCol(nCol2
) || !ValidRow(nRow2
))
7295 PushIllegalArgument();
7297 PushExternalDoubleRef(nFileId
, aTabName
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7303 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7305 nColNew
= nCol2
- nCol1
+ 1;
7307 nRowNew
= nRow2
- nRow1
+ 1;
7308 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7309 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7310 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7311 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7312 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7313 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
7314 PushIllegalArgument();
7316 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
7319 case svExternalDoubleRef
:
7323 ScComplexRefData aRef
;
7324 PopExternalDoubleRef(nFileId
, aTabName
, aRef
);
7325 ScRange aAbs
= aRef
.toAbs(aPos
);
7326 nCol1
= aAbs
.aStart
.Col();
7327 nRow1
= aAbs
.aStart
.Row();
7328 nTab1
= aAbs
.aStart
.Tab();
7329 nCol2
= aAbs
.aEnd
.Col();
7330 nRow2
= aAbs
.aEnd
.Row();
7331 nTab2
= aAbs
.aEnd
.Tab();
7333 nColNew
= nCol2
- nCol1
+ 1;
7335 nRowNew
= nRow2
- nRow1
+ 1;
7336 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
7337 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
7338 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
7339 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
7340 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
7341 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
7342 PushIllegalArgument();
7344 PushExternalDoubleRef(nFileId
, aTabName
, nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7348 PushIllegalParameter();
7355 void ScInterpreter::ScIndex()
7357 sal_uInt8 nParamCount
= GetByte();
7358 if ( MustHaveParamCount( nParamCount
, 1, 4 ) )
7364 if (nParamCount
== 4)
7365 nArea
= (long) ::rtl::math::approxFloor(GetDouble());
7368 if (nParamCount
>= 3)
7369 nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
7372 if (nParamCount
>= 2)
7373 nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
7376 if (GetStackType() == svRefList
)
7377 nAreaCount
= (sp
? static_cast<ScToken
*>(pStack
[sp
-1])->GetRefList()->size() : 0);
7379 nAreaCount
= 1; // one reference or array or whatever
7380 if (nAreaCount
== 0 || (size_t)nArea
> nAreaCount
)
7382 PushError( errNoRef
);
7385 else if (nArea
< 1 || nCol
< 0 || nRow
< 0)
7387 PushIllegalArgument();
7390 switch (GetStackType())
7393 case svExternalSingleRef
:
7394 case svExternalDoubleRef
:
7397 SetError(errIllegalArgument
);
7398 sal_uInt16 nOldSp
= sp
;
7399 ScMatrixRef pMat
= GetMatrix();
7403 pMat
->GetDimensions(nC
, nR
);
7404 // Access one element of a vector independent of col/row
7406 bool bVector
= ((nCol
== 0 || nRow
== 0) && (nC
== 1 || nR
== 1));
7407 SCSIZE nElement
= ::std::max( static_cast<SCSIZE
>(nCol
),
7408 static_cast<SCSIZE
>(nRow
));
7409 if (nC
== 0 || nR
== 0 ||
7410 (!bVector
&& (static_cast<SCSIZE
>(nCol
) > nC
||
7411 static_cast<SCSIZE
>(nRow
) > nR
)) ||
7412 (bVector
&& nElement
> nC
* nR
))
7413 PushIllegalArgument();
7414 else if (nCol
== 0 && nRow
== 0)
7419 if (pMat
->IsString( nElement
))
7420 PushString( pMat
->GetString(nElement
).getString());
7422 PushDouble( pMat
->GetDouble( nElement
));
7426 ScMatrixRef pResMat
= GetNewMat(nC
, 1);
7429 SCSIZE nRowMinus1
= static_cast<SCSIZE
>(nRow
- 1);
7430 for (SCSIZE i
= 0; i
< nC
; i
++)
7431 if (!pMat
->IsString(i
, nRowMinus1
))
7432 pResMat
->PutDouble(pMat
->GetDouble(i
,
7435 pResMat
->PutString(pMat
->GetString(i
, nRowMinus1
), i
, 0);
7437 PushMatrix(pResMat
);
7440 PushIllegalArgument();
7444 ScMatrixRef pResMat
= GetNewMat(1, nR
);
7447 SCSIZE nColMinus1
= static_cast<SCSIZE
>(nCol
- 1);
7448 for (SCSIZE i
= 0; i
< nR
; i
++)
7449 if (!pMat
->IsString(nColMinus1
, i
))
7450 pResMat
->PutDouble(pMat
->GetDouble(nColMinus1
,
7453 pResMat
->PutString(pMat
->GetString(nColMinus1
, i
), i
);
7454 PushMatrix(pResMat
);
7457 PushIllegalArgument();
7461 if (!pMat
->IsString( static_cast<SCSIZE
>(nCol
-1),
7462 static_cast<SCSIZE
>(nRow
-1)))
7463 PushDouble( pMat
->GetDouble(
7464 static_cast<SCSIZE
>(nCol
-1),
7465 static_cast<SCSIZE
>(nRow
-1)));
7467 PushString( pMat
->GetString(
7468 static_cast<SCSIZE
>(nCol
-1),
7469 static_cast<SCSIZE
>(nRow
-1)).getString());
7479 PopSingleRef( nCol1
, nRow1
, nTab1
);
7480 if (nCol
> 1 || nRow
> 1)
7481 PushIllegalArgument();
7483 PushSingleRef( nCol1
, nRow1
, nTab1
);
7495 bool bRowArray
= false;
7496 if (GetStackType() == svRefList
)
7498 FormulaTokenRef xRef
= PopToken();
7499 if (nGlobalError
|| !xRef
)
7501 PushIllegalParameter();
7504 ScRange
aRange( ScAddress::UNINITIALIZED
);
7505 DoubleRefToRange( (*(static_cast<ScToken
*>(xRef
.get())->GetRefList()))[nArea
-1], aRange
);
7506 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7507 if ( nParamCount
== 2 && nRow1
== nRow2
)
7512 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
7513 if ( nParamCount
== 2 && nRow1
== nRow2
)
7516 if ( nTab1
!= nTab2
||
7517 (nCol
> 0 && nCol1
+nCol
-1 > nCol2
) ||
7518 (nRow
> 0 && nRow1
+nRow
-1 > nRow2
&& !bRowArray
) ||
7519 ( nRow
> nCol2
- nCol1
+ 1 && bRowArray
))
7520 PushIllegalArgument();
7521 else if (nCol
== 0 && nRow
== 0)
7523 if ( nCol1
== nCol2
&& nRow1
== nRow2
)
7524 PushSingleRef( nCol1
, nRow1
, nTab1
);
7526 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
7530 if ( nRow1
== nRow2
)
7531 PushSingleRef( nCol1
+nCol
-1, nRow1
, nTab1
);
7533 PushDoubleRef( nCol1
+nCol
-1, nRow1
, nTab1
,
7534 nCol1
+nCol
-1, nRow2
, nTab1
);
7538 if ( nCol1
== nCol2
)
7539 PushSingleRef( nCol1
, nRow1
+nRow
-1, nTab1
);
7540 else if ( bRowArray
)
7544 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
7547 PushDoubleRef( nCol1
, nRow1
+nRow
-1, nTab1
,
7548 nCol2
, nRow1
+nRow
-1, nTab1
);
7551 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
7555 PushIllegalParameter();
7561 void ScInterpreter::ScMultiArea()
7563 // Legacy support, convert to RefList
7564 sal_uInt8 nParamCount
= GetByte();
7565 if (MustHaveParamCountMin( nParamCount
, 1))
7567 while (!nGlobalError
&& nParamCount
-- > 1)
7575 void ScInterpreter::ScAreas()
7577 sal_uInt8 nParamCount
= GetByte();
7578 if (MustHaveParamCount( nParamCount
, 1))
7581 switch (GetStackType())
7585 FormulaTokenRef xT
= PopToken();
7586 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetSingleRef());
7592 FormulaTokenRef xT
= PopToken();
7593 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetDoubleRef());
7599 FormulaTokenRef xT
= PopToken();
7600 ValidateRef( *(static_cast<ScToken
*>(xT
.get())->GetRefList()));
7601 nCount
+= static_cast<ScToken
*>(xT
.get())->GetRefList()->size();
7605 SetError( errIllegalParameter
);
7607 PushDouble( double(nCount
));
7612 void ScInterpreter::ScCurrency()
7614 sal_uInt8 nParamCount
= GetByte();
7615 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7619 if (nParamCount
== 2)
7621 fDec
= ::rtl::math::approxFloor(GetDouble());
7622 if (fDec
< -15.0 || fDec
> 15.0)
7624 PushIllegalArgument();
7630 double fVal
= GetDouble();
7633 fFac
= pow( (double)10, fDec
);
7637 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
7639 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
7640 Color
* pColor
= NULL
;
7643 sal_uLong nIndex
= pFormatter
->GetStandardFormat(
7644 NUMBERFORMAT_CURRENCY
,
7646 if ( (sal_uInt16
) fDec
!= pFormatter
->GetFormatPrecision( nIndex
) )
7648 OUString sFormatString
= pFormatter
->GenerateFormat(
7651 true, // mit Tausenderpunkt
7653 (sal_uInt16
) fDec
,// Nachkommastellen
7654 1); // 1 Vorkommanull
7655 if (!pFormatter
->GetPreviewString(sFormatString
,
7660 SetError(errIllegalArgument
);
7664 pFormatter
->GetOutputString(fVal
, nIndex
, aStr
, &pColor
);
7671 void ScInterpreter::ScReplace()
7673 if ( MustHaveParamCount( GetByte(), 4 ) )
7675 OUString aNewStr
= GetString().getString();
7676 double fCount
= ::rtl::math::approxFloor( GetDouble());
7677 double fPos
= ::rtl::math::approxFloor( GetDouble());
7678 OUString aOldStr
= GetString().getString();
7679 if (fPos
< 1.0 || fPos
> static_cast<double>(STRING_MAXLEN
)
7680 || fCount
< 0.0 || fCount
> static_cast<double>(STRING_MAXLEN
))
7681 PushIllegalArgument();
7684 sal_Int32 nCount
= static_cast<sal_Int32
>(fCount
);
7685 sal_Int32 nPos
= static_cast<sal_Int32
>(fPos
);
7686 sal_Int32 nLen
= aOldStr
.getLength();
7687 if (nPos
> nLen
+ 1)
7689 if (nCount
> nLen
- nPos
+ 1)
7690 nCount
= nLen
- nPos
+ 1;
7691 aOldStr
= aOldStr
.replaceAt( nPos
-1, nCount
, "" );
7692 if ( CheckStringResultLen( aOldStr
, aNewStr
) )
7693 aOldStr
= aOldStr
.replaceAt( nPos
-1, 0, aNewStr
);
7694 PushString( aOldStr
);
7700 void ScInterpreter::ScFixed()
7702 sal_uInt8 nParamCount
= GetByte();
7703 if ( MustHaveParamCount( nParamCount
, 1, 3 ) )
7708 if (nParamCount
== 3)
7709 bThousand
= !GetBool(); // Param TRUE: keine Tausenderpunkte
7712 if (nParamCount
>= 2)
7714 fDec
= ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
7715 if (fDec
< -15.0 || fDec
> 15.0)
7717 PushIllegalArgument();
7723 double fVal
= GetDouble();
7726 fFac
= pow( (double)10, fDec
);
7730 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
7732 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
7733 Color
* pColor
= NULL
;
7736 sal_uLong nIndex
= pFormatter
->GetStandardFormat(
7737 NUMBERFORMAT_NUMBER
,
7739 OUString sFormatString
= pFormatter
->GenerateFormat(
7742 bThousand
, // mit Tausenderpunkt
7744 (sal_uInt16
) fDec
,// Nachkommastellen
7745 1); // 1 Vorkommanull
7746 if (!pFormatter
->GetPreviewString(sFormatString
,
7751 PushIllegalArgument();
7758 void ScInterpreter::ScFind()
7760 sal_uInt8 nParamCount
= GetByte();
7761 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
7764 if (nParamCount
== 3)
7768 OUString sStr
= GetString().getString();
7769 if( fAnz
< 1.0 || fAnz
> (double) sStr
.getLength() )
7773 sal_Int32 nPos
= sStr
.indexOf(GetString().getString(), static_cast<sal_Int32
>(fAnz
- 1));
7777 PushDouble((double)(nPos
+ 1));
7783 void ScInterpreter::ScExact()
7785 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
7786 if ( MustHaveParamCount( GetByte(), 2 ) )
7788 svl::SharedString s1
= GetString();
7789 svl::SharedString s2
= GetString();
7790 PushInt( s1
.getData() == s2
.getData() );
7795 void ScInterpreter::ScLeft()
7797 sal_uInt8 nParamCount
= GetByte();
7798 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7801 if (nParamCount
== 2)
7803 double nVal
= ::rtl::math::approxFloor(GetDouble());
7804 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
7806 PushIllegalArgument();
7810 n
= (sal_Int32
) nVal
;
7814 OUString aStr
= GetString().getString();
7815 n
= std::min(n
, aStr
.getLength());
7816 aStr
= aStr
.copy( 0, n
);
7826 static const UBlockScript scriptList
[] = {
7827 {UBLOCK_HANGUL_JAMO
, UBLOCK_HANGUL_JAMO
},
7828 {UBLOCK_CJK_RADICALS_SUPPLEMENT
, UBLOCK_HANGUL_SYLLABLES
},
7829 {UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
,UBLOCK_CJK_RADICALS_SUPPLEMENT
},
7830 {UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS
,UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS
},
7831 {UBLOCK_CJK_COMPATIBILITY_FORMS
, UBLOCK_CJK_COMPATIBILITY_FORMS
},
7832 {UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
, UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS
},
7833 {UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B
, UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT
},
7834 {UBLOCK_CJK_STROKES
, UBLOCK_CJK_STROKES
}
7836 #define scriptListCount sizeof (scriptList) / sizeof (UBlockScript)
7837 bool SAL_CALL
lcl_getScriptClass(sal_uInt32 currentChar
)
7839 // for the locale of ja-JP, character U+0x005c and U+0x20ac should be ScriptType::Asian
7840 if( (currentChar
== 0x005c || currentChar
== 0x20ac) &&
7841 (MsLangId::getSystemLanguage() == LANGUAGE_JAPANESE
) )
7844 static sal_Int16 nRet
= 0;
7845 UBlockCode block
= (UBlockCode
)ublock_getCode((sal_uInt32
)currentChar
);
7846 for ( i
= 0; i
< scriptListCount
; i
++) {
7847 if (block
<= scriptList
[i
].to
) break;
7849 nRet
= (i
< scriptListCount
&& block
>= scriptList
[i
].from
);
7852 bool IsDBCS(sal_Unicode ch
)
7854 return lcl_getScriptClass(ch
);
7856 sal_Int32
getLengthB(const OUString
&str
)
7860 sal_Int32 index
= 0;
7861 sal_Int32 length
= 0;
7862 while(index
< str
.getLength()){
7863 if(IsDBCS(str
[index
]))
7871 void ScInterpreter::ScLenB()
7873 PushDouble( getLengthB(GetString().getString()) );
7875 OUString
lcl_RightB(const OUString
&rStr
, sal_Int32 n
)
7877 if( n
< getLengthB(rStr
) )
7879 OUStringBuffer
aBuf(rStr
);
7880 sal_Int32 index
= aBuf
.getLength();
7885 aBuf
.remove( 0, index
+ 1);
7890 aBuf
.remove( 0, index
+ 2 );
7891 aBuf
.insert( 0, " ");
7894 if(IsDBCS(aBuf
[index
]))
7899 return aBuf
.makeStringAndClear();
7903 void ScInterpreter::ScRightB()
7905 sal_uInt8 nParamCount
= GetByte();
7906 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7909 if (nParamCount
== 2)
7911 double nVal
= ::rtl::math::approxFloor(GetDouble());
7912 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
7914 PushIllegalArgument();
7918 n
= (sal_Int32
) nVal
;
7922 OUString
aStr(lcl_RightB(GetString().getString(), n
));
7926 OUString
lcl_LeftB(const OUString
&rStr
, sal_Int32 n
)
7928 if( n
< getLengthB(rStr
) )
7930 OUStringBuffer
aBuf(rStr
);
7931 sal_Int32 index
= -1;
7932 while(index
++ < aBuf
.getLength())
7936 aBuf
.truncate(index
);
7941 aBuf
.truncate( index
- 1 );
7945 if(IsDBCS(aBuf
[index
]))
7950 return aBuf
.makeStringAndClear();
7954 void ScInterpreter::ScLeftB()
7956 sal_uInt8 nParamCount
= GetByte();
7957 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7960 if (nParamCount
== 2)
7962 double nVal
= ::rtl::math::approxFloor(GetDouble());
7963 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
7965 PushIllegalArgument();
7969 n
= (sal_Int32
) nVal
;
7973 OUString
aStr(lcl_LeftB(GetString().getString(), n
));
7977 void ScInterpreter::ScMidB()
7979 if ( MustHaveParamCount( GetByte(), 3 ) )
7981 double fAnz
= ::rtl::math::approxFloor(GetDouble());
7982 double fAnfang
= ::rtl::math::approxFloor(GetDouble());
7983 OUString aStr
= GetString().getString();
7984 if (fAnfang
< 1.0 || fAnz
< 0.0 || fAnfang
> double(STRING_MAXLEN
) || fAnz
> double(STRING_MAXLEN
))
7985 PushIllegalArgument();
7989 aStr
= lcl_LeftB(aStr
, (sal_Int32
)fAnfang
+ (sal_Int32
)fAnz
- 1);
7990 sal_Int32 nCnt
= getLengthB(aStr
) - (sal_Int32
)fAnfang
+ 1;
7991 aStr
= lcl_RightB(aStr
, nCnt
>0 ? nCnt
:0);
7997 void ScInterpreter::ScRight()
7999 sal_uInt8 nParamCount
= GetByte();
8000 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
8003 if (nParamCount
== 2)
8005 double nVal
= ::rtl::math::approxFloor(GetDouble());
8006 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
8008 PushIllegalArgument();
8012 n
= (sal_Int32
) nVal
;
8016 OUString aStr
= GetString().getString();
8017 if( n
< aStr
.getLength() )
8018 aStr
= aStr
.copy( aStr
.getLength() - n
);
8024 void ScInterpreter::ScSearch()
8026 sal_uInt8 nParamCount
= GetByte();
8027 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
8030 if (nParamCount
== 3)
8032 fAnz
= ::rtl::math::approxFloor(GetDouble());
8033 if (fAnz
> double(STRING_MAXLEN
))
8035 PushIllegalArgument();
8041 OUString sStr
= GetString().getString();
8042 OUString SearchStr
= GetString().getString();
8043 sal_Int32 nPos
= fAnz
- 1;
8044 sal_Int32 nEndPos
= sStr
.getLength();
8045 if( nPos
>= nEndPos
)
8049 utl::SearchParam::SearchType eSearchType
=
8050 (MayBeRegExp( SearchStr
, pDok
) ?
8051 utl::SearchParam::SRCH_REGEXP
: utl::SearchParam::SRCH_NORMAL
);
8052 utl::SearchParam
sPar(SearchStr
, eSearchType
, false, false, false);
8053 utl::TextSearch
sT( sPar
, *ScGlobal::pCharClass
);
8054 int nBool
= sT
.SearchForward(sStr
, &nPos
, &nEndPos
);
8058 PushDouble((double)(nPos
) + 1);
8063 void ScInterpreter::ScMid()
8065 if ( MustHaveParamCount( GetByte(), 3 ) )
8067 double fAnz
= ::rtl::math::approxFloor(GetDouble());
8068 double fAnfang
= ::rtl::math::approxFloor(GetDouble());
8069 OUString aStr
= GetString().getString();
8070 if (fAnfang
< 1.0 || fAnz
< 0.0 || fAnfang
> double(STRING_MAXLEN
) || fAnz
> double(STRING_MAXLEN
))
8071 PushIllegalArgument();
8074 sal_Int32 nCharacters
= std::min
<sal_Int32
>(static_cast<sal_Int32
>(fAnz
), aStr
.getLength() - fAnfang
+ 1);
8076 if (nCharacters
> 0)
8077 sRes
= aStr
.copy(static_cast<sal_Int32
>(fAnfang
-1), nCharacters
);
8083 void ScInterpreter::ScText()
8085 if ( MustHaveParamCount( GetByte(), 2 ) )
8087 OUString sFormatString
= GetString().getString();
8088 svl::SharedString aStr
;
8089 bool bString
= false;
8091 switch (GetStackType())
8101 FormulaTokenRef
xTok( PopToken());
8104 PushTempToken( xTok
.get());
8105 // Temporarily override the ConvertStringToValue()
8106 // error for GetCellValue() / GetCellValueOrZero()
8107 sal_uInt16 nSErr
= mnStringNoValueError
;
8108 mnStringNoValueError
= errNotNumericString
;
8110 mnStringNoValueError
= nSErr
;
8111 if (nGlobalError
== errNotNumericString
)
8115 PushTempToken( xTok
.get());
8123 PushError( nGlobalError
);
8127 Color
* pColor
= NULL
;
8128 LanguageType eCellLang
;
8129 const ScPatternAttr
* pPattern
= pDok
->GetPattern(
8130 aPos
.Col(), aPos
.Row(), aPos
.Tab() );
8132 eCellLang
= ((const SvxLanguageItem
&)
8133 pPattern
->GetItem( ATTR_LANGUAGE_FORMAT
)).GetValue();
8135 eCellLang
= ScGlobal::eLnge
;
8138 if (!pFormatter
->GetPreviewString( sFormatString
, aStr
.getString(),
8139 aResult
, &pColor
, eCellLang
))
8140 PushIllegalArgument();
8142 PushString( aResult
);
8146 if (!pFormatter
->GetPreviewStringGuess( sFormatString
, fVal
,
8147 aResult
, &pColor
, eCellLang
))
8148 PushIllegalArgument();
8150 PushString( aResult
);
8157 void ScInterpreter::ScSubstitute()
8159 sal_uInt8 nParamCount
= GetByte();
8160 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
8163 if (nParamCount
== 4)
8165 double fAnz
= ::rtl::math::approxFloor(GetDouble());
8166 if( fAnz
< 1 || fAnz
> STRING_MAXLEN
)
8168 PushIllegalArgument();
8172 nAnz
= (sal_Int32
) fAnz
;
8176 OUString sNewStr
= GetString().getString();
8177 OUString sOldStr
= GetString().getString();
8178 OUString sStr
= GetString().getString();
8180 sal_Int32 nCount
= 0;
8181 sal_Int32 nNewLen
= sNewStr
.getLength();
8182 sal_Int32 nOldLen
= sOldStr
.getLength();
8185 nPos
= sStr
.indexOf( sOldStr
, nPos
);
8189 if( !nAnz
|| nCount
== nAnz
)
8191 sStr
= sStr
.replaceAt(nPos
,nOldLen
, "");
8192 if ( CheckStringResultLen( sStr
, sNewStr
) )
8194 sStr
= sStr
.replaceAt(nPos
, 0, sNewStr
);
8195 nPos
= sal::static_int_cast
<sal_Int32
>( nPos
+ nNewLen
);
8211 void ScInterpreter::ScRept()
8213 if ( MustHaveParamCount( GetByte(), 2 ) )
8215 double fAnz
= ::rtl::math::approxFloor(GetDouble());
8216 OUString aStr
= GetString().getString();
8218 PushIllegalArgument();
8219 else if ( fAnz
* aStr
.getLength() > STRING_MAXLEN
)
8221 PushError( errStringOverflow
);
8223 else if ( fAnz
== 0.0 )
8224 PushString( EMPTY_OUSTRING
);
8227 const sal_Int32 nLen
= aStr
.getLength();
8228 sal_Int32 n
= (sal_Int32
) fAnz
;
8229 OUStringBuffer
aRes(n
*nLen
);
8232 PushString( aRes
.makeStringAndClear() );
8238 void ScInterpreter::ScConcat()
8240 sal_uInt8 nParamCount
= GetByte();
8242 while( nParamCount
-- > 0)
8244 OUString aStr
= GetString().getString();
8251 void ScInterpreter::ScErrorType()
8254 sal_uInt16 nOldError
= nGlobalError
;
8256 switch ( GetStackType() )
8260 FormulaTokenRef x
= PopToken();
8262 nErr
= nGlobalError
;
8265 const ScRefList
* pRefList
= static_cast<ScToken
*>(x
.get())->GetRefList();
8266 size_t n
= pRefList
->size();
8274 DoubleRefToRange( (*pRefList
)[0], aRange
);
8276 nErr
= nGlobalError
;
8280 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
8281 nErr
= pDok
->GetErrCode( aAdr
);
8283 nErr
= nGlobalError
;
8292 PopDoubleRef( aRange
);
8294 nErr
= nGlobalError
;
8298 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
8299 nErr
= pDok
->GetErrCode( aAdr
);
8301 nErr
= nGlobalError
;
8308 PopSingleRef( aAdr
);
8310 nErr
= nGlobalError
;
8312 nErr
= pDok
->GetErrCode( aAdr
);
8317 nErr
= nGlobalError
;
8326 nGlobalError
= nOldError
;
8332 bool ScInterpreter::MayBeRegExp( const OUString
& rStr
, const ScDocument
* pDoc
)
8334 if ( pDoc
&& !pDoc
->GetDocOptions().IsFormulaRegexEnabled() )
8336 if ( rStr
.isEmpty() || (rStr
.getLength() == 1 && !rStr
.startsWith(".")) )
8337 return false; // single meta characters can not be a regexp
8338 static const sal_Unicode cre
[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
8339 const sal_Unicode
* p1
= rStr
.getStr();
8341 while ( ( c1
= *p1
++ ) != 0 )
8343 const sal_Unicode
* p2
= cre
;
8353 static bool lcl_LookupQuery( ScAddress
& o_rResultPos
, ScDocument
* pDoc
,
8354 const ScQueryParam
& rParam
, const ScQueryEntry
& rEntry
)
8356 bool bFound
= false;
8357 ScQueryCellIterator
aCellIter( pDoc
, rParam
.nTab
, rParam
, false);
8358 if (rEntry
.eOp
!= SC_EQUAL
)
8360 // range lookup <= or >=
8363 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow
);
8366 o_rResultPos
.SetCol( nCol
);
8367 o_rResultPos
.SetRow( nRow
);
8370 else if (aCellIter
.GetFirst())
8374 o_rResultPos
.SetCol( aCellIter
.GetCol());
8375 o_rResultPos
.SetRow( aCellIter
.GetRow());
8380 bool ScInterpreter::LookupQueryWithCache( ScAddress
& o_rResultPos
,
8381 const ScQueryParam
& rParam
) const
8383 bool bFound
= false;
8384 const ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
8385 bool bColumnsMatch
= (rParam
.nCol1
== rEntry
.nField
);
8386 OSL_ENSURE( bColumnsMatch
, "ScInterpreter::LookupQueryWithCache: columns don't match");
8388 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
8391 ScRange
aLookupRange( rParam
.nCol1
, rParam
.nRow1
, rParam
.nTab
,
8392 rParam
.nCol2
, rParam
.nRow2
, rParam
.nTab
);
8393 ScLookupCache
& rCache
= pDok
->GetLookupCache( aLookupRange
);
8394 ScLookupCache::QueryCriteria
aCriteria( rEntry
);
8395 ScLookupCache::Result eCacheResult
= rCache
.lookup( o_rResultPos
,
8397 switch (eCacheResult
)
8399 case ScLookupCache::NOT_CACHED
:
8400 case ScLookupCache::CRITERIA_DIFFERENT
:
8401 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
8402 if (eCacheResult
== ScLookupCache::NOT_CACHED
)
8403 rCache
.insert( o_rResultPos
, aCriteria
, aPos
, bFound
);
8405 case ScLookupCache::FOUND
:
8408 case ScLookupCache::NOT_AVAILABLE
:
8409 ; // nothing, bFound remains FALSE
8416 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */