1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr1.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include "scitems.hxx"
37 #include <svx/langitem.hxx>
38 #include <svx/algitem.hxx>
39 #include <unotools/textsearch.hxx>
40 #include <svtools/zforlist.hxx>
41 #include <svtools/zformat.hxx>
42 #include <tools/urlobj.hxx>
43 #include <unotools/charclass.hxx>
44 #include <sfx2/docfile.hxx>
45 #include <sfx2/printer.hxx>
46 #include <unotools/collatorwrapper.hxx>
47 #include <unotools/transliterationwrapper.hxx>
48 #include <rtl/logfile.hxx>
50 #include "interpre.hxx"
51 #include "patattr.hxx"
53 #include "document.hxx"
54 #include "dociter.hxx"
56 #include "scmatrix.hxx"
57 #include "docoptio.hxx"
58 #include "globstr.hrc"
60 #include "jumpmatrix.hxx"
62 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
63 #include <comphelper/processfactory.hxx>
70 #include "cellkeytranslator.hxx"
71 #include "lookupcache.hxx"
72 #include "rangenam.hxx"
73 #include "compiler.hxx"
74 #include "externalrefmgr.hxx"
75 #include <basic/sbstar.hxx>
77 #define SC_DOUBLE_MAXVALUE 1.7e307
79 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack
, 8, 4 )
80 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter
, 32, 16 )
82 ScTokenStack
* ScInterpreter::pGlobalStack
= NULL
;
83 BOOL
ScInterpreter::bGlobalStackInUse
= FALSE
;
85 using namespace formula
;
86 //-----------------------------------------------------------------------------
88 //-----------------------------------------------------------------------------
91 void ScInterpreter::ScIfJump()
93 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIfJump" );
94 const short* pJump
= pCur
->GetJump();
95 short nJumpCount
= pJump
[ 0 ];
96 MatrixDoubleRefToMatrix();
97 switch ( GetStackType() )
101 ScMatrixRef pMat
= PopMatrix();
103 PushIllegalParameter();
106 FormulaTokenRef xNew
;
107 ScTokenMatrixMap::const_iterator aMapIter
;
108 // DoubleError handled by JumpMatrix
109 pMat
->SetErrorInterpreter( NULL
);
111 pMat
->GetDimensions( nCols
, nRows
);
112 if ( nCols
== 0 || nRows
== 0 )
113 PushIllegalArgument();
114 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
115 pCur
)) != pTokenMatrixMap
->end()))
116 xNew
= (*aMapIter
).second
;
119 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
120 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
122 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
126 ScMatValType nType
= 0;
127 const ScMatrixValue
* pMatVal
= pMat
->Get( nC
, nR
,
129 bool bIsValue
= ScMatrix::IsValueType( nType
);
132 fVal
= pMatVal
->fVal
;
133 bIsValue
= ::rtl::math::isFinite( fVal
);
134 bTrue
= bIsValue
&& (fVal
!= 0.0);
140 // Treat empty and empty path as 0, but string
142 bIsValue
= !ScMatrix::IsRealStringType( nType
);
144 fVal
= (bIsValue
? 0.0 : CreateDoubleError( errNoValue
));
148 if( nJumpCount
>= 2 )
150 pJumpMat
->SetJump( nC
, nR
, fVal
,
152 pJump
[ nJumpCount
]);
155 { // no parameter given for THEN
156 pJumpMat
->SetJump( nC
, nR
, fVal
,
158 pJump
[ nJumpCount
]);
163 if( nJumpCount
== 3 && bIsValue
)
165 pJumpMat
->SetJump( nC
, nR
, fVal
,
167 pJump
[ nJumpCount
]);
170 { // no parameter given for ELSE,
172 pJumpMat
->SetJump( nC
, nR
, fVal
,
174 pJump
[ nJumpCount
]);
179 xNew
= new ScJumpMatrixToken( pJumpMat
);
180 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur
, xNew
));
182 PushTempToken( xNew
);
183 // set endpoint of path for main code line
184 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
192 if( nJumpCount
>= 2 )
194 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
197 { // no parameter given for THEN
198 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
200 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
205 if( nJumpCount
== 3 )
207 aCode
.Jump( pJump
[ 2 ], pJump
[ nJumpCount
] );
210 { // no parameter given for ELSE
211 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
213 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
221 void ScInterpreter::ScChoseJump()
223 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChoseJump" );
224 // We have to set a jump, if there was none chosen because of an error set
226 bool bHaveJump
= false;
227 const short* pJump
= pCur
->GetJump();
228 short nJumpCount
= pJump
[ 0 ];
229 MatrixDoubleRefToMatrix();
230 switch ( GetStackType() )
234 ScMatrixRef pMat
= PopMatrix();
236 PushIllegalParameter();
239 FormulaTokenRef xNew
;
240 ScTokenMatrixMap::const_iterator aMapIter
;
241 // DoubleError handled by JumpMatrix
242 pMat
->SetErrorInterpreter( NULL
);
244 pMat
->GetDimensions( nCols
, nRows
);
245 if ( nCols
== 0 || nRows
== 0 )
246 PushIllegalParameter();
247 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
248 pCur
)) != pTokenMatrixMap
->end()))
249 xNew
= (*aMapIter
).second
;
252 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
253 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
255 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
259 const ScMatrixValue
* pMatVal
= pMat
->Get( nC
, nR
,
261 bool bIsValue
= ScMatrix::IsValueType( nType
);
264 fVal
= pMatVal
->fVal
;
265 bIsValue
= ::rtl::math::isFinite( fVal
);
268 fVal
= ::rtl::math::approxFloor( fVal
);
269 if ( (fVal
< 1) || (fVal
>= nJumpCount
))
272 fVal
= CreateDoubleError(
279 fVal
= CreateDoubleError( errNoValue
);
283 pJumpMat
->SetJump( nC
, nR
, fVal
,
284 pJump
[ (short)fVal
],
285 pJump
[ nJumpCount
]);
289 pJumpMat
->SetJump( nC
, nR
, fVal
,
291 pJump
[ nJumpCount
]);
295 xNew
= new ScJumpMatrixToken( pJumpMat
);
296 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
299 PushTempToken( xNew
);
300 // set endpoint of path for main code line
301 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
308 double nJumpIndex
= ::rtl::math::approxFloor( GetDouble() );
309 if (!nGlobalError
&& (nJumpIndex
>= 1) && (nJumpIndex
< nJumpCount
))
311 aCode
.Jump( pJump
[ (short) nJumpIndex
], pJump
[ nJumpCount
] );
315 PushIllegalArgument();
319 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
322 void lcl_AdjustJumpMatrix( ScJumpMatrix
* pJumpM
, ScMatrixRef
& pResMat
, SCSIZE nParmCols
, SCSIZE nParmRows
)
324 SCSIZE nJumpCols
, nJumpRows
;
325 SCSIZE nResCols
, nResRows
;
326 SCSIZE nAdjustCols
, nAdjustRows
;
327 pJumpM
->GetDimensions( nJumpCols
, nJumpRows
);
328 pJumpM
->GetResMatDimensions( nResCols
, nResRows
);
329 if (( nJumpCols
== 1 && nParmCols
> nResCols
) ||
330 ( nJumpRows
== 1 && nParmRows
> nResRows
))
332 if ( nJumpCols
== 1 && nJumpRows
== 1 )
334 nAdjustCols
= nParmCols
> nResCols
? nParmCols
: nResCols
;
335 nAdjustRows
= nParmRows
> nResRows
? nParmRows
: nResRows
;
337 else if ( nJumpCols
== 1 )
339 nAdjustCols
= nParmCols
;
340 nAdjustRows
= nResRows
;
344 nAdjustCols
= nResCols
;
345 nAdjustRows
= nParmRows
;
347 pJumpM
->SetNewResMat( nAdjustCols
, nAdjustRows
);
348 pResMat
= pJumpM
->GetResultMatrix();
352 bool ScInterpreter::JumpMatrix( short nStackLevel
)
354 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::JumpMatrix" );
355 pJumpMatrix
= static_cast<ScToken
*>(pStack
[sp
-nStackLevel
])->GetJumpMatrix();
356 ScMatrixRef pResMat
= pJumpMatrix
->GetResultMatrix();
358 if ( nStackLevel
== 2 )
360 if ( aCode
.HasStacked() )
361 aCode
.Pop(); // pop what Jump() pushed
364 DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
370 SetError( errUnknownStackVariable
);
374 pJumpMatrix
->GetPos( nC
, nR
);
375 switch ( GetStackType() )
379 double fVal
= GetDouble();
382 fVal
= CreateDoubleError( nGlobalError
);
385 pResMat
->PutDouble( fVal
, nC
, nR
);
390 const String
& rStr
= GetString();
393 pResMat
->PutDouble( CreateDoubleError( nGlobalError
),
398 pResMat
->PutString( rStr
, nC
, nR
);
404 PopSingleRef( aAdr
);
407 pResMat
->PutDouble( CreateDoubleError( nGlobalError
),
413 ScBaseCell
* pCell
= GetCell( aAdr
);
414 if (HasCellEmptyData( pCell
))
415 pResMat
->PutEmpty( nC
, nR
);
416 else if (HasCellValueData( pCell
))
418 double fVal
= GetCellValue( aAdr
, pCell
);
421 fVal
= CreateDoubleError(
425 pResMat
->PutDouble( fVal
, nC
, nR
);
430 GetCellString( aStr
, pCell
);
433 pResMat
->PutDouble( CreateDoubleError(
434 nGlobalError
), nC
, nR
);
438 pResMat
->PutString( aStr
, nC
, nR
);
444 { // upper left plus offset within matrix
447 PopDoubleRef( aRange
);
450 fVal
= CreateDoubleError( nGlobalError
);
452 pResMat
->PutDouble( fVal
, nC
, nR
);
456 // Do not modify the original range because we use it
457 // to adjust the size of the result matrix if necessary.
458 ScAddress
aAdr( aRange
.aStart
);
459 ULONG nCol
= (ULONG
)aAdr
.Col() + nC
;
460 ULONG nRow
= (ULONG
)aAdr
.Row() + nR
;
461 if ((nCol
> static_cast<ULONG
>(aRange
.aEnd
.Col()) &&
462 aRange
.aEnd
.Col() != aRange
.aStart
.Col())
463 || (nRow
> static_cast<ULONG
>(aRange
.aEnd
.Row()) &&
464 aRange
.aEnd
.Row() != aRange
.aStart
.Row()))
466 fVal
= CreateDoubleError( NOTAVAILABLE
);
467 pResMat
->PutDouble( fVal
, nC
, nR
);
471 // Replicate column and/or row of a vector if it is
472 // one. Note that this could be a range reference
473 // that in fact consists of only one cell, e.g. A1:A1
474 if (aRange
.aEnd
.Col() == aRange
.aStart
.Col())
475 nCol
= aRange
.aStart
.Col();
476 if (aRange
.aEnd
.Row() == aRange
.aStart
.Row())
477 nRow
= aRange
.aStart
.Row();
478 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) );
479 aAdr
.SetRow( static_cast<SCROW
>(nRow
) );
480 ScBaseCell
* pCell
= GetCell( aAdr
);
481 if (HasCellEmptyData( pCell
))
482 pResMat
->PutEmpty( nC
, nR
);
483 else if (HasCellValueData( pCell
))
485 double fCellVal
= GetCellValue( aAdr
, pCell
);
488 fCellVal
= CreateDoubleError(
492 pResMat
->PutDouble( fCellVal
, nC
, nR
);
497 GetCellString( aStr
, pCell
);
500 pResMat
->PutDouble( CreateDoubleError(
501 nGlobalError
), nC
, nR
);
505 pResMat
->PutString( aStr
, nC
, nR
);
508 SCSIZE nParmCols
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
509 SCSIZE nParmRows
= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
510 lcl_AdjustJumpMatrix( pJumpMatrix
, pResMat
, nParmCols
, nParmRows
);
515 { // match matrix offsets
517 ScMatrixRef pMat
= PopMatrix();
520 fVal
= CreateDoubleError( nGlobalError
);
522 pResMat
->PutDouble( fVal
, nC
, nR
);
526 fVal
= CreateDoubleError( errUnknownVariable
);
527 pResMat
->PutDouble( fVal
, nC
, nR
);
532 pMat
->GetDimensions( nCols
, nRows
);
533 if ((nCols
<= nC
&& nCols
!= 1) ||
534 (nRows
<= nR
&& nRows
!= 1))
536 fVal
= CreateDoubleError( NOTAVAILABLE
);
537 pResMat
->PutDouble( fVal
, nC
, nR
);
541 if ( pMat
->IsValue( nC
, nR
) )
543 fVal
= pMat
->GetDouble( nC
, nR
);
544 pResMat
->PutDouble( fVal
, nC
, nR
);
546 else if ( pMat
->IsEmpty( nC
, nR
) )
547 pResMat
->PutEmpty( nC
, nR
);
550 const String
& rStr
= pMat
->GetString( nC
, nR
);
551 pResMat
->PutString( rStr
, nC
, nR
);
554 lcl_AdjustJumpMatrix( pJumpMatrix
, pResMat
, nCols
, nRows
);
561 double fVal
= CreateDoubleError( nGlobalError
);
563 pResMat
->PutDouble( fVal
, nC
, nR
);
569 double fVal
= CreateDoubleError( errIllegalArgument
);
570 pResMat
->PutDouble( fVal
, nC
, nR
);
575 bool bCont
= pJumpMatrix
->Next( nC
, nR
);
579 short nStart
, nNext
, nStop
;
580 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
581 while ( bCont
&& nStart
== nNext
)
582 { // push all results that have no jump path
585 // a FALSE without path results in an empty path value
587 pResMat
->PutEmptyPath( nC
, nR
);
589 pResMat
->PutDouble( fBool
, nC
, nR
);
591 bCont
= pJumpMatrix
->Next( nC
, nR
);
593 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
595 if ( bCont
&& nStart
!= nNext
)
597 const ScTokenVec
* pParams
= pJumpMatrix
->GetJumpParameters();
600 for ( ScTokenVec::const_iterator i
= pParams
->begin();
601 i
!= pParams
->end(); ++i
)
603 // This is not the current state of the interpreter, so
604 // push without error, and elements' errors are coded into
606 PushWithoutError( *(*i
));
609 aCode
.Jump( nStart
, nNext
, nStop
);
613 { // we're done with it, throw away jump matrix, keep result
616 PushMatrix( pResMat
);
617 // Remove jump matrix from map and remember result matrix in case it
618 // could be reused in another path of the same condition.
621 pTokenMatrixMap
->erase( pCur
);
622 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type( pCur
,
631 ScCompareOptions::ScCompareOptions( ScDocument
* pDoc
, const ScQueryEntry
& rEntry
, bool bReg
) :
634 bMatchWholeCell(pDoc
->GetDocOptions().IsMatchWholeCell()),
637 bRegEx
= (bRegEx
&& (aQueryEntry
.eOp
== SC_EQUAL
|| aQueryEntry
.eOp
== SC_NOT_EQUAL
));
638 // Interpreter functions usually are case insensitive, except the simple
639 // comparison operators, for which these options aren't used. Override in
644 double ScInterpreter::CompareFunc( const ScCompare
& rComp
, ScCompareOptions
* pOptions
)
646 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareFunc" );
647 // Keep DoubleError if encountered
648 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
649 if ( !rComp
.bEmpty
[0] && rComp
.bVal
[0] && !::rtl::math::isFinite( rComp
.nVal
[0]))
650 return rComp
.nVal
[0];
651 if ( !rComp
.bEmpty
[1] && rComp
.bVal
[1] && !::rtl::math::isFinite( rComp
.nVal
[1]))
652 return rComp
.nVal
[1];
655 if ( rComp
.bEmpty
[ 0 ] )
657 if ( rComp
.bEmpty
[ 1 ] )
658 ; // empty cell == empty cell, fRes 0
659 else if( rComp
.bVal
[ 1 ] )
661 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 1 ], 0.0 ) )
663 if ( rComp
.nVal
[ 1 ] < 0.0 )
664 fRes
= 1; // empty cell > -x
666 fRes
= -1; // empty cell < x
668 // else: empty cell == 0.0
672 if ( rComp
.pVal
[ 1 ]->Len() )
673 fRes
= -1; // empty cell < "..."
674 // else: empty cell == ""
677 else if ( rComp
.bEmpty
[ 1 ] )
679 if( rComp
.bVal
[ 0 ] )
681 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 0 ], 0.0 ) )
683 if ( rComp
.nVal
[ 0 ] < 0.0 )
684 fRes
= -1; // -x < empty cell
686 fRes
= 1; // x > empty cell
688 // else: empty cell == 0.0
692 if ( rComp
.pVal
[ 0 ]->Len() )
693 fRes
= 1; // "..." > empty cell
694 // else: "" == empty cell
697 else if( rComp
.bVal
[ 0 ] )
699 if( rComp
.bVal
[ 1 ] )
701 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 0 ], rComp
.nVal
[ 1 ] ) )
703 if( rComp
.nVal
[ 0 ] - rComp
.nVal
[ 1 ] < 0 )
710 fRes
= -1; // number is less than string
712 else if( rComp
.bVal
[ 1 ] )
713 fRes
= 1; // number is less than string
719 // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually
720 // is/must be identical to *rEntry.pStr, which is essential for
721 // regex to work through GetSearchTextPtr().
722 ScQueryEntry
& rEntry
= pOptions
->aQueryEntry
;
723 DBG_ASSERT( *rComp
.pVal
[1] == *rEntry
.pStr
, "ScInterpreter::CompareFunc: broken options");
724 if (pOptions
->bRegEx
)
726 xub_StrLen nStart
= 0;
727 xub_StrLen nStop
= rComp
.pVal
[0]->Len();
728 bool bMatch
= rEntry
.GetSearchTextPtr(
729 !pOptions
->bIgnoreCase
)->SearchFrwrd( *rComp
.pVal
[0],
731 if (bMatch
&& pOptions
->bMatchWholeCell
&& (nStart
!= 0 || nStop
!= rComp
.pVal
[0]->Len()))
732 bMatch
= false; // RegEx must match entire string.
733 fRes
= (bMatch
? 0 : 1);
735 else if (rEntry
.eOp
== SC_EQUAL
|| rEntry
.eOp
== SC_NOT_EQUAL
)
737 ::utl::TransliterationWrapper
* pTransliteration
=
738 (pOptions
->bIgnoreCase
? ScGlobal::pTransliteration
:
739 ScGlobal::pCaseTransliteration
);
741 if (pOptions
->bMatchWholeCell
)
742 bMatch
= pTransliteration
->isEqual( *rComp
.pVal
[0], *rComp
.pVal
[1]);
745 String
aCell( pTransliteration
->transliterate(
746 *rComp
.pVal
[0], ScGlobal::eLnge
, 0,
747 rComp
.pVal
[0]->Len(), NULL
));
748 String
aQuer( pTransliteration
->transliterate(
749 *rComp
.pVal
[1], ScGlobal::eLnge
, 0,
750 rComp
.pVal
[1]->Len(), NULL
));
751 bMatch
= (aCell
.Search( aQuer
) != STRING_NOTFOUND
);
753 fRes
= (bMatch
? 0 : 1);
755 else if (pOptions
->bIgnoreCase
)
756 fRes
= (double) ScGlobal::pCollator
->compareString(
757 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
759 fRes
= (double) ScGlobal::pCaseCollator
->compareString(
760 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
762 else if (pDok
->GetDocOptions().IsIgnoreCase())
763 fRes
= (double) ScGlobal::pCollator
->compareString(
764 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
766 fRes
= (double) ScGlobal::pCaseCollator
->compareString(
767 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
773 double ScInterpreter::Compare()
775 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Compare" );
777 ScCompare
aComp( &aVal1
, &aVal2
);
778 for( short i
= 1; i
>= 0; i
-- )
780 switch ( GetRawStackType() )
783 aComp
.bEmpty
[ i
] = TRUE
;
787 aComp
.nVal
[ i
] = GetDouble();
788 aComp
.bVal
[ i
] = TRUE
;
791 *aComp
.pVal
[ i
] = GetString();
792 aComp
.bVal
[ i
] = FALSE
;
798 if ( !PopDoubleRefOrSingleRef( aAdr
) )
800 ScBaseCell
* pCell
= GetCell( aAdr
);
801 if (HasCellEmptyData( pCell
))
802 aComp
.bEmpty
[ i
] = TRUE
;
803 else if (HasCellStringData( pCell
))
805 GetCellString( *aComp
.pVal
[ i
], pCell
);
806 aComp
.bVal
[ i
] = FALSE
;
810 aComp
.nVal
[ i
] = GetCellValue( aAdr
, pCell
);
811 aComp
.bVal
[ i
] = TRUE
;
816 SetError( errIllegalParameter
);
822 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
823 return CompareFunc( aComp
);
827 ScMatrixRef
ScInterpreter::CompareMat( ScCompareOptions
* pOptions
)
829 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareMat" );
831 ScCompare
aComp( &aVal1
, &aVal2
);
834 for( short i
= 1; i
>= 0; i
-- )
836 switch (GetRawStackType())
839 aComp
.bEmpty
[ i
] = TRUE
;
843 aComp
.nVal
[ i
] = GetDouble();
844 aComp
.bVal
[ i
] = TRUE
;
847 *aComp
.pVal
[ i
] = GetString();
848 aComp
.bVal
[ i
] = FALSE
;
852 PopSingleRef( aAdr
);
853 ScBaseCell
* pCell
= GetCell( aAdr
);
854 if (HasCellEmptyData( pCell
))
855 aComp
.bEmpty
[ i
] = TRUE
;
856 else if (HasCellStringData( pCell
))
858 GetCellString( *aComp
.pVal
[ i
], pCell
);
859 aComp
.bVal
[ i
] = FALSE
;
863 aComp
.nVal
[ i
] = GetCellValue( aAdr
, pCell
);
864 aComp
.bVal
[ i
] = TRUE
;
870 pMat
[ i
] = GetMatrix();
872 SetError( errIllegalParameter
);
874 pMat
[i
]->SetErrorInterpreter( NULL
);
875 // errors are transported as DoubleError inside matrix
878 SetError( errIllegalParameter
);
882 ScMatrixRef pResMat
= NULL
;
885 if ( pMat
[0] && pMat
[1] )
889 pMat
[0]->GetDimensions( nC0
, nR0
);
890 pMat
[1]->GetDimensions( nC1
, nR1
);
891 SCSIZE nC
= Max( nC0
, nC1
);
892 SCSIZE nR
= Max( nR0
, nR1
);
893 pResMat
= GetNewMat( nC
, nR
);
896 for ( SCSIZE j
=0; j
<nC
; j
++ )
898 for ( SCSIZE k
=0; k
<nR
; k
++ )
900 SCSIZE nCol
= j
, nRow
= k
;
901 if ( pMat
[0]->ValidColRowOrReplicated( nCol
, nRow
) &&
902 pMat
[1]->ValidColRowOrReplicated( nCol
, nRow
))
904 for ( short i
=1; i
>=0; i
-- )
906 if ( pMat
[i
]->IsString(j
,k
) )
908 aComp
.bVal
[i
] = FALSE
;
909 *aComp
.pVal
[i
] = pMat
[i
]->GetString(j
,k
);
910 aComp
.bEmpty
[i
] = pMat
[i
]->IsEmpty(j
,k
);
914 aComp
.bVal
[i
] = TRUE
;
915 aComp
.nVal
[i
] = pMat
[i
]->GetDouble(j
,k
);
916 aComp
.bEmpty
[i
] = FALSE
;
919 pResMat
->PutDouble( CompareFunc( aComp
, pOptions
), j
,k
);
922 pResMat
->PutString( ScGlobal::GetRscString(STR_NO_VALUE
), j
,k
);
926 else if ( pMat
[0] || pMat
[1] )
928 short i
= ( pMat
[0] ? 0 : 1);
930 pMat
[i
]->GetDimensions( nC
, nR
);
931 pResMat
= GetNewMat( nC
, nR
);
935 for ( SCSIZE j
=0; j
<n
; j
++ )
937 if ( pMat
[i
]->IsValue(j
) )
939 aComp
.bVal
[i
] = TRUE
;
940 aComp
.nVal
[i
] = pMat
[i
]->GetDouble(j
);
941 aComp
.bEmpty
[i
] = FALSE
;
945 aComp
.bVal
[i
] = FALSE
;
946 *aComp
.pVal
[i
] = pMat
[i
]->GetString(j
);
947 aComp
.bEmpty
[i
] = pMat
[i
]->IsEmpty(j
);
949 pResMat
->PutDouble( CompareFunc( aComp
, pOptions
), j
);
953 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
958 ScMatrixRef
ScInterpreter::QueryMat( ScMatrix
* pMat
, ScCompareOptions
& rOptions
)
960 short nSaveCurFmtType
= nCurFmtType
;
961 short nSaveFuncFmtType
= nFuncFmtType
;
963 if (rOptions
.aQueryEntry
.bQueryByString
)
964 PushString( *rOptions
.aQueryEntry
.pStr
);
966 PushDouble( rOptions
.aQueryEntry
.nVal
);
967 ScMatrixRef pResultMatrix
= CompareMat( &rOptions
);
968 nCurFmtType
= nSaveCurFmtType
;
969 nFuncFmtType
= nSaveFuncFmtType
;
970 if (nGlobalError
|| !pResultMatrix
)
972 SetError( errIllegalParameter
);
973 return pResultMatrix
;
976 switch (rOptions
.aQueryEntry
.eOp
)
979 pResultMatrix
->CompareEqual();
982 pResultMatrix
->CompareLess();
985 pResultMatrix
->CompareGreater();
988 pResultMatrix
->CompareLessEqual();
990 case SC_GREATER_EQUAL
:
991 pResultMatrix
->CompareGreaterEqual();
994 pResultMatrix
->CompareNotEqual();
997 SetError( errIllegalArgument
);
998 DBG_ERROR1( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)rOptions
.aQueryEntry
.eOp
);
1000 return pResultMatrix
;
1004 void ScInterpreter::ScEqual()
1006 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEqual" );
1007 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1009 ScMatrixRef pMat
= CompareMat();
1011 PushIllegalParameter();
1014 pMat
->CompareEqual();
1019 PushInt( Compare() == 0 );
1023 void ScInterpreter::ScNotEqual()
1025 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNotEqual" );
1026 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1028 ScMatrixRef pMat
= CompareMat();
1030 PushIllegalParameter();
1033 pMat
->CompareNotEqual();
1038 PushInt( Compare() != 0 );
1042 void ScInterpreter::ScLess()
1044 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLess" );
1045 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1047 ScMatrixRef pMat
= CompareMat();
1049 PushIllegalParameter();
1052 pMat
->CompareLess();
1057 PushInt( Compare() < 0 );
1061 void ScInterpreter::ScGreater()
1063 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGreater" );
1064 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1066 ScMatrixRef pMat
= CompareMat();
1068 PushIllegalParameter();
1071 pMat
->CompareGreater();
1076 PushInt( Compare() > 0 );
1080 void ScInterpreter::ScLessEqual()
1082 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLessEqual" );
1083 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1085 ScMatrixRef pMat
= CompareMat();
1087 PushIllegalParameter();
1090 pMat
->CompareLessEqual();
1095 PushInt( Compare() <= 0 );
1099 void ScInterpreter::ScGreaterEqual()
1101 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGreaterEqual" );
1102 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1104 ScMatrixRef pMat
= CompareMat();
1106 PushIllegalParameter();
1109 pMat
->CompareGreaterEqual();
1114 PushInt( Compare() >= 0 );
1118 void ScInterpreter::ScAnd()
1120 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAnd" );
1121 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1122 short nParamCount
= GetByte();
1123 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1125 BOOL bHaveValue
= FALSE
;
1127 size_t nRefInList
= 0;
1128 while( nParamCount
-- > 0)
1130 if ( !nGlobalError
)
1132 switch ( GetStackType() )
1136 nRes
&= ( PopDouble() != 0.0 );
1140 SetError( errNoValue
);
1145 PopSingleRef( aAdr
);
1146 if ( !nGlobalError
)
1148 ScBaseCell
* pCell
= GetCell( aAdr
);
1149 if ( HasCellValueData( pCell
) )
1152 nRes
&= ( GetCellValue( aAdr
, pCell
) != 0.0 );
1154 // else: Xcl setzt hier keinen Fehler
1162 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1163 if ( !nGlobalError
)
1167 ScValueIterator
aValIter( pDok
, aRange
);
1168 if ( aValIter
.GetFirst( fVal
, nErr
) )
1173 nRes
&= ( fVal
!= 0.0 );
1174 } while ( (nErr
== 0) &&
1175 aValIter
.GetNext( fVal
, nErr
) );
1183 ScMatrixRef pMat
= GetMatrix();
1187 double fVal
= pMat
->And();
1188 USHORT nErr
= GetDoubleErrorValue( fVal
);
1195 nRes
&= (fVal
!= 0.0);
1197 // else: GetMatrix did set errIllegalParameter
1202 SetError( errIllegalParameter
);
1216 void ScInterpreter::ScOr()
1218 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOr" );
1219 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1220 short nParamCount
= GetByte();
1221 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1223 BOOL bHaveValue
= FALSE
;
1225 size_t nRefInList
= 0;
1226 while( nParamCount
-- > 0)
1228 if ( !nGlobalError
)
1230 switch ( GetStackType() )
1234 nRes
|= ( PopDouble() != 0.0 );
1238 SetError( errNoValue
);
1243 PopSingleRef( aAdr
);
1244 if ( !nGlobalError
)
1246 ScBaseCell
* pCell
= GetCell( aAdr
);
1247 if ( HasCellValueData( pCell
) )
1250 nRes
|= ( GetCellValue( aAdr
, pCell
) != 0.0 );
1252 // else: Xcl setzt hier keinen Fehler
1260 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1261 if ( !nGlobalError
)
1265 ScValueIterator
aValIter( pDok
, aRange
);
1266 if ( aValIter
.GetFirst( fVal
, nErr
) )
1271 nRes
|= ( fVal
!= 0.0 );
1272 } while ( (nErr
== 0) &&
1273 aValIter
.GetNext( fVal
, nErr
) );
1282 ScMatrixRef pMat
= GetMatrix();
1286 double fVal
= pMat
->Or();
1287 USHORT nErr
= GetDoubleErrorValue( fVal
);
1294 nRes
|= (fVal
!= 0.0);
1296 // else: GetMatrix did set errIllegalParameter
1301 SetError( errIllegalParameter
);
1315 void ScInterpreter::ScNeg()
1317 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNeg" );
1318 // Simple negation doesn't change current format type to number, keep
1320 nFuncFmtType
= nCurFmtType
;
1321 switch ( GetStackType() )
1325 ScMatrixRef pMat
= GetMatrix();
1327 PushIllegalParameter();
1331 pMat
->GetDimensions( nC
, nR
);
1332 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1334 PushIllegalArgument();
1337 SCSIZE nCount
= nC
* nR
;
1338 for ( SCSIZE j
=0; j
<nCount
; ++j
)
1340 if ( pMat
->IsValueOrEmpty(j
) )
1341 pResMat
->PutDouble( -pMat
->GetDouble(j
), j
);
1344 ScGlobal::GetRscString( STR_NO_VALUE
), j
);
1346 PushMatrix( pResMat
);
1352 PushDouble( -GetDouble() );
1357 void ScInterpreter::ScPercentSign()
1359 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentSign" );
1360 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1361 const FormulaToken
* pSaveCur
= pCur
;
1362 BYTE nSavePar
= cPar
;
1365 FormulaByteToken
aDivOp( ocDiv
, cPar
);
1373 void ScInterpreter::ScNot()
1375 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNot" );
1376 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1377 switch ( GetStackType() )
1381 ScMatrixRef pMat
= GetMatrix();
1383 PushIllegalParameter();
1387 pMat
->GetDimensions( nC
, nR
);
1388 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1390 PushIllegalArgument();
1393 SCSIZE nCount
= nC
* nR
;
1394 for ( SCSIZE j
=0; j
<nCount
; ++j
)
1396 if ( pMat
->IsValueOrEmpty(j
) )
1397 pResMat
->PutDouble( (pMat
->GetDouble(j
) == 0.0), j
);
1400 ScGlobal::GetRscString( STR_NO_VALUE
), j
);
1402 PushMatrix( pResMat
);
1408 PushInt( GetDouble() == 0.0 );
1413 void ScInterpreter::ScPi()
1415 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPi" );
1420 void ScInterpreter::ScRandom()
1422 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRandom" );
1423 PushDouble((double)rand() / ((double)RAND_MAX
+1.0));
1427 void ScInterpreter::ScTrue()
1429 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrue" );
1430 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1435 void ScInterpreter::ScFalse()
1437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFalse" );
1438 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1443 void ScInterpreter::ScDeg()
1445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDeg" );
1446 PushDouble((GetDouble() / F_PI
) * 180.0);
1450 void ScInterpreter::ScRad()
1452 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRad" );
1453 PushDouble(GetDouble() * (F_PI
/ 180));
1457 void ScInterpreter::ScSin()
1459 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSin" );
1460 PushDouble(::rtl::math::sin(GetDouble()));
1464 void ScInterpreter::ScCos()
1466 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCos" );
1467 PushDouble(::rtl::math::cos(GetDouble()));
1471 void ScInterpreter::ScTan()
1473 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTan" );
1474 PushDouble(::rtl::math::tan(GetDouble()));
1478 void ScInterpreter::ScCot()
1480 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCot" );
1481 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1485 void ScInterpreter::ScArcSin()
1487 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcSin" );
1488 PushDouble(asin(GetDouble()));
1492 void ScInterpreter::ScArcCos()
1494 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCos" );
1495 PushDouble(acos(GetDouble()));
1499 void ScInterpreter::ScArcTan()
1501 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTan" );
1502 PushDouble(atan(GetDouble()));
1506 void ScInterpreter::ScArcCot()
1508 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCot" );
1509 PushDouble((F_PI2
) - atan(GetDouble()));
1513 void ScInterpreter::ScSinHyp()
1515 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSinHyp" );
1516 PushDouble(sinh(GetDouble()));
1520 void ScInterpreter::ScCosHyp()
1522 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCosHyp" );
1523 PushDouble(cosh(GetDouble()));
1527 void ScInterpreter::ScTanHyp()
1529 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTanHyp" );
1530 PushDouble(tanh(GetDouble()));
1534 void ScInterpreter::ScCotHyp()
1536 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCotHyp" );
1537 PushDouble(1.0 / tanh(GetDouble()));
1541 void ScInterpreter::ScArcSinHyp()
1543 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcSinHyp" );
1544 double nVal
= GetDouble();
1545 PushDouble(log(nVal
+ sqrt((nVal
* nVal
) + 1.0)));
1549 void ScInterpreter::ScArcCosHyp()
1551 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCosHyp" );
1552 double nVal
= GetDouble();
1554 PushIllegalArgument();
1556 PushDouble(log(nVal
+ sqrt((nVal
* nVal
) - 1.0)));
1560 void ScInterpreter::ScArcTanHyp()
1562 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTanHyp" );
1563 double fVal
= GetDouble();
1564 if (fabs(fVal
) >= 1.0)
1565 PushIllegalArgument();
1567 PushDouble( ::rtl::math::atanh( fVal
));
1571 void ScInterpreter::ScArcCotHyp()
1573 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCotHyp" );
1574 double nVal
= GetDouble();
1575 if (fabs(nVal
) <= 1.0)
1576 PushIllegalArgument();
1578 PushDouble(0.5 * log((nVal
+ 1.0) / (nVal
- 1.0)));
1582 void ScInterpreter::ScExp()
1584 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExp" );
1585 PushDouble(exp(GetDouble()));
1589 void ScInterpreter::ScSqrt()
1591 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSqrt" );
1592 double fVal
= GetDouble();
1594 PushDouble(sqrt(fVal
));
1596 PushIllegalArgument();
1600 void ScInterpreter::ScIsEmpty()
1602 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsEmpty" );
1604 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1605 switch ( GetRawStackType() )
1609 FormulaTokenRef p
= PopToken();
1610 if (!static_cast<const ScEmptyCellToken
*>(p
.get())->IsInherited())
1618 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1620 // NOTE: this could test also on inherited emptiness, but then the
1621 // cell tested wouldn't be empty. Must correspond with
1622 // ScCountEmptyCells().
1623 // if (HasCellEmptyData( GetCell( aAdr)))
1624 CellType eCellType
= GetCellType( GetCell( aAdr
) );
1625 if((eCellType
== CELLTYPE_NONE
) || (eCellType
== CELLTYPE_NOTE
))
1631 ScMatrixRef pMat
= PopMatrix();
1634 else if ( !pJumpMatrix
)
1635 nRes
= pMat
->IsEmpty( 0 );
1638 SCSIZE nCols
, nRows
, nC
, nR
;
1639 pMat
->GetDimensions( nCols
, nRows
);
1640 pJumpMatrix
->GetPos( nC
, nR
);
1641 if ( nC
< nCols
&& nR
< nRows
)
1642 nRes
= pMat
->IsEmpty( nC
, nR
);
1643 // else: FALSE, not empty (which is what Xcl does)
1655 short ScInterpreter::IsString()
1657 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IsString" );
1658 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1660 switch ( GetRawStackType() )
1670 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1672 ScBaseCell
* pCell
= GetCell( aAdr
);
1673 if (GetCellErrCode( pCell
) == 0)
1675 switch ( GetCellType( pCell
) )
1677 case CELLTYPE_STRING
:
1678 case CELLTYPE_EDIT
:
1681 case CELLTYPE_FORMULA
:
1682 nRes
= !((ScFormulaCell
*)pCell
)->IsValue() &&
1683 !((ScFormulaCell
*)pCell
)->IsEmpty();
1693 ScMatrixRef pMat
= PopMatrix();
1696 else if ( !pJumpMatrix
)
1697 nRes
= pMat
->IsString(0) && !pMat
->IsEmpty(0);
1700 SCSIZE nCols
, nRows
, nC
, nR
;
1701 pMat
->GetDimensions( nCols
, nRows
);
1702 pJumpMatrix
->GetPos( nC
, nR
);
1703 if ( nC
< nCols
&& nR
< nRows
)
1704 nRes
= pMat
->IsString( nC
, nR
) && !pMat
->IsEmpty( nC
, nR
);
1716 void ScInterpreter::ScIsString()
1718 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsString" );
1719 PushInt( IsString() );
1723 void ScInterpreter::ScIsNonString()
1725 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsNonString" );
1726 PushInt( !IsString() );
1730 void ScInterpreter::ScIsLogical()
1732 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsLogical" );
1734 switch ( GetStackType() )
1740 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1742 ScBaseCell
* pCell
= GetCell( aAdr
);
1743 if (GetCellErrCode( pCell
) == 0)
1745 if (HasCellValueData(pCell
))
1747 ULONG nFormat
= GetCellNumberFormat( aAdr
, pCell
);
1748 nRes
= ( pFormatter
->GetType(nFormat
)
1749 == NUMBERFORMAT_LOGICAL
);
1755 // TODO: we don't have type information for arrays except
1756 // numerical/string.
1760 if ( !nGlobalError
)
1761 nRes
= ( nCurFmtType
== NUMBERFORMAT_LOGICAL
);
1763 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1769 void ScInterpreter::ScType()
1771 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScType" );
1773 switch ( GetStackType() )
1779 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1781 ScBaseCell
* pCell
= GetCell( aAdr
);
1782 if (GetCellErrCode( pCell
) == 0)
1784 switch ( GetCellType( pCell
) )
1786 // NOTE: this is Xcl nonsense!
1787 case CELLTYPE_NOTE
:
1788 nType
= 1; // empty cell is value (0)
1790 case CELLTYPE_STRING
:
1791 case CELLTYPE_EDIT
:
1794 case CELLTYPE_VALUE
:
1796 ULONG nFormat
= GetCellNumberFormat( aAdr
, pCell
);
1797 if (pFormatter
->GetType(nFormat
)
1798 == NUMBERFORMAT_LOGICAL
)
1804 case CELLTYPE_FORMULA
:
1808 PushIllegalArgument();
1834 // we could return the type of one element if in JumpMatrix or
1835 // ForceArray mode, but Xcl doesn't ...
1851 inline BOOL
lcl_FormatHasNegColor( const SvNumberformat
* pFormat
)
1853 return pFormat
&& pFormat
->GetColor( 1 );
1857 inline BOOL
lcl_FormatHasOpenPar( const SvNumberformat
* pFormat
)
1859 return pFormat
&& (pFormat
->GetFormatstring().Search( '(' ) != STRING_NOTFOUND
);
1863 void ScInterpreter::ScCell()
1864 { // ATTRIBUTE ; [REF]
1865 BYTE nParamCount
= GetByte();
1866 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
1868 ScAddress
aCellPos( aPos
);
1869 BOOL bError
= FALSE
;
1870 if( nParamCount
== 2 )
1871 bError
= !PopDoubleRefOrSingleRef( aCellPos
);
1872 String
aInfoType( GetString() );
1873 if( bError
|| nGlobalError
)
1874 PushIllegalParameter();
1878 ScBaseCell
* pCell
= GetCell( aCellPos
);
1880 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::pLocale
, ocCell
);
1882 // *** ADDRESS INFO ***
1883 if( aInfoType
.EqualsAscii( "COL" ) )
1884 { // column number (1-based)
1885 PushInt( aCellPos
.Col() + 1 );
1887 else if( aInfoType
.EqualsAscii( "ROW" ) )
1888 { // row number (1-based)
1889 PushInt( aCellPos
.Row() + 1 );
1891 else if( aInfoType
.EqualsAscii( "SHEET" ) )
1892 { // table number (1-based)
1893 PushInt( aCellPos
.Tab() + 1 );
1895 else if( aInfoType
.EqualsAscii( "ADDRESS" ) )
1896 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
1897 USHORT nFlags
= (aCellPos
.Tab() == aPos
.Tab()) ? (SCA_ABS
) : (SCA_ABS_3D
);
1898 aCellPos
.Format( aFuncResult
, nFlags
, pDok
, pDok
->GetAddressConvention() );
1899 PushString( aFuncResult
);
1901 else if( aInfoType
.EqualsAscii( "FILENAME" ) )
1902 { // file name and table name: 'FILENAME'#$TABLE
1903 SCTAB nTab
= aCellPos
.Tab();
1904 if( nTab
< pDok
->GetTableCount() )
1906 if( pDok
->GetLinkMode( nTab
) == SC_LINK_VALUE
)
1907 pDok
->GetName( nTab
, aFuncResult
);
1910 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
1911 if( pShell
&& pShell
->GetMedium() )
1913 aFuncResult
= (sal_Unicode
) '\'';
1914 const INetURLObject
& rURLObj
= pShell
->GetMedium()->GetURLObject();
1915 aFuncResult
+= String( rURLObj
.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS
) );
1916 aFuncResult
.AppendAscii( "'#$" );
1918 pDok
->GetName( nTab
, aTabName
);
1919 aFuncResult
+= aTabName
;
1923 PushString( aFuncResult
);
1925 else if( aInfoType
.EqualsAscii( "COORD" ) )
1926 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
1927 // Yes, passing tab as col is intentional!
1928 ScAddress( static_cast<SCCOL
>(aCellPos
.Tab()), 0, 0 ).Format(
1929 aFuncResult
, (SCA_COL_ABSOLUTE
|SCA_VALID_COL
), NULL
, pDok
->GetAddressConvention() );
1932 aCellPos
.Format( aCellStr
, (SCA_COL_ABSOLUTE
|SCA_VALID_COL
|SCA_ROW_ABSOLUTE
|SCA_VALID_ROW
),
1933 NULL
, pDok
->GetAddressConvention() );
1934 aFuncResult
+= aCellStr
;
1935 PushString( aFuncResult
);
1938 // *** CELL PROPERTIES ***
1939 else if( aInfoType
.EqualsAscii( "CONTENTS" ) )
1940 { // contents of the cell, no formatting
1941 if( pCell
&& pCell
->HasStringData() )
1943 GetCellString( aFuncResult
, pCell
);
1944 PushString( aFuncResult
);
1947 PushDouble( GetCellValue( aCellPos
, pCell
) );
1949 else if( aInfoType
.EqualsAscii( "TYPE" ) )
1950 { // b = blank; l = string (label); v = otherwise (value)
1951 if( HasCellStringData( pCell
) )
1954 aFuncResult
= HasCellValueData( pCell
) ? 'v' : 'b';
1955 PushString( aFuncResult
);
1957 else if( aInfoType
.EqualsAscii( "WIDTH" ) )
1958 { // column width (rounded off as count of zero characters in standard font and size)
1959 Printer
* pPrinter
= pDok
->GetPrinter();
1960 MapMode
aOldMode( pPrinter
->GetMapMode() );
1961 Font
aOldFont( pPrinter
->GetFont() );
1964 pPrinter
->SetMapMode( MAP_TWIP
);
1965 // font color doesn't matter here
1966 pDok
->GetDefPattern()->GetFont( aDefFont
, SC_AUTOCOL_BLACK
, pPrinter
);
1967 pPrinter
->SetFont( aDefFont
);
1968 long nZeroWidth
= pPrinter
->GetTextWidth( String( '0' ) );
1969 pPrinter
->SetFont( aOldFont
);
1970 pPrinter
->SetMapMode( aOldMode
);
1971 int nZeroCount
= (int)(pDok
->GetColWidth( aCellPos
.Col(), aCellPos
.Tab() ) / nZeroWidth
);
1972 PushInt( nZeroCount
);
1974 else if( aInfoType
.EqualsAscii( "PREFIX" ) )
1975 { // ' = left; " = right; ^ = centered
1976 if( HasCellStringData( pCell
) )
1978 const SvxHorJustifyItem
* pJustAttr
= (const SvxHorJustifyItem
*)
1979 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_HOR_JUSTIFY
);
1980 switch( pJustAttr
->GetValue() )
1982 case SVX_HOR_JUSTIFY_STANDARD
:
1983 case SVX_HOR_JUSTIFY_LEFT
:
1984 case SVX_HOR_JUSTIFY_BLOCK
: aFuncResult
= '\''; break;
1985 case SVX_HOR_JUSTIFY_CENTER
: aFuncResult
= '^'; break;
1986 case SVX_HOR_JUSTIFY_RIGHT
: aFuncResult
= '"'; break;
1987 case SVX_HOR_JUSTIFY_REPEAT
: aFuncResult
= '\\'; break;
1990 PushString( aFuncResult
);
1992 else if( aInfoType
.EqualsAscii( "PROTECT" ) )
1993 { // 1 = cell locked
1994 const ScProtectionAttr
* pProtAttr
= (const ScProtectionAttr
*)
1995 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_PROTECTION
);
1996 PushInt( pProtAttr
->GetProtection() ? 1 : 0 );
1999 // *** FORMATTING ***
2000 else if( aInfoType
.EqualsAscii( "FORMAT" ) )
2001 { // specific format code for standard formats
2002 ULONG nFormat
= pDok
->GetNumberFormat( aCellPos
);
2003 BOOL bAppendPrec
= TRUE
;
2004 USHORT nPrec
, nLeading
;
2005 BOOL bThousand
, bIsRed
;
2006 pFormatter
->GetFormatSpecialInfo( nFormat
, bThousand
, bIsRed
, nPrec
, nLeading
);
2008 switch( pFormatter
->GetType( nFormat
) )
2010 case NUMBERFORMAT_NUMBER
: aFuncResult
= (bThousand
? ',' : 'F'); break;
2011 case NUMBERFORMAT_CURRENCY
: aFuncResult
= 'C'; break;
2012 case NUMBERFORMAT_SCIENTIFIC
: aFuncResult
= 'S'; break;
2013 case NUMBERFORMAT_PERCENT
: aFuncResult
= 'P'; break;
2016 bAppendPrec
= FALSE
;
2017 switch( pFormatter
->GetIndexTableOffset( nFormat
) )
2019 case NF_DATE_SYSTEM_SHORT
:
2020 case NF_DATE_SYS_DMMMYY
:
2021 case NF_DATE_SYS_DDMMYY
:
2022 case NF_DATE_SYS_DDMMYYYY
:
2023 case NF_DATE_SYS_DMMMYYYY
:
2024 case NF_DATE_DIN_DMMMYYYY
:
2025 case NF_DATE_SYS_DMMMMYYYY
:
2026 case NF_DATE_DIN_DMMMMYYYY
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
2027 case NF_DATE_SYS_DDMMM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
2028 case NF_DATE_SYS_MMYY
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
2029 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
2030 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
2031 aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
2032 case NF_DATE_DIN_MMDD
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
2033 case NF_TIME_HHMMSSAMPM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
2034 case NF_TIME_HHMMAMPM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
2035 case NF_TIME_HHMMSS
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
2036 case NF_TIME_HHMM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
2037 default: aFuncResult
= 'G';
2042 aFuncResult
+= String::CreateFromInt32( nPrec
);
2043 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( nFormat
);
2044 if( lcl_FormatHasNegColor( pFormat
) )
2046 if( lcl_FormatHasOpenPar( pFormat
) )
2047 aFuncResult
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
2048 PushString( aFuncResult
);
2050 else if( aInfoType
.EqualsAscii( "COLOR" ) )
2051 { // 1 = negative values are colored, otherwise 0
2052 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2053 PushInt( lcl_FormatHasNegColor( pFormat
) ? 1 : 0 );
2055 else if( aInfoType
.EqualsAscii( "PARENTHESES" ) )
2056 { // 1 = format string contains a '(' character, otherwise 0
2057 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2058 PushInt( lcl_FormatHasOpenPar( pFormat
) ? 1 : 0 );
2061 PushIllegalArgument();
2067 void ScInterpreter::ScIsRef()
2069 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCell" );
2070 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2072 switch ( GetStackType() )
2077 PopSingleRef( aAdr
);
2078 if ( !nGlobalError
)
2085 PopDoubleRef( aRange
);
2086 if ( !nGlobalError
)
2092 FormulaTokenRef x
= PopToken();
2093 if ( !nGlobalError
)
2094 nRes
= !static_cast<ScToken
*>(x
.get())->GetRefList()->empty();
2105 void ScInterpreter::ScIsValue()
2107 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsValue" );
2108 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2110 switch ( GetRawStackType() )
2120 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2122 ScBaseCell
* pCell
= GetCell( aAdr
);
2123 if (GetCellErrCode( pCell
) == 0)
2125 switch ( GetCellType( pCell
) )
2127 case CELLTYPE_VALUE
:
2130 case CELLTYPE_FORMULA
:
2131 nRes
= ((ScFormulaCell
*)pCell
)->IsValue() &&
2132 !((ScFormulaCell
*)pCell
)->IsEmpty();
2142 ScMatrixRef pMat
= PopMatrix();
2145 else if ( !pJumpMatrix
)
2147 if (pMat
->GetErrorIfNotString( 0 ) == 0)
2148 nRes
= pMat
->IsValue( 0 );
2152 SCSIZE nCols
, nRows
, nC
, nR
;
2153 pMat
->GetDimensions( nCols
, nRows
);
2154 pJumpMatrix
->GetPos( nC
, nR
);
2155 if ( nC
< nCols
&& nR
< nRows
)
2156 if (pMat
->GetErrorIfNotString( nC
, nR
) == 0)
2157 nRes
= pMat
->IsValue( nC
, nR
);
2169 void ScInterpreter::ScIsFormula()
2171 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsFormula" );
2172 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2174 switch ( GetStackType() )
2180 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2182 nRes
= (GetCellType( GetCell( aAdr
) ) == CELLTYPE_FORMULA
);
2193 void ScInterpreter::ScFormula()
2195 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFormula" );
2197 switch ( GetStackType() )
2203 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2205 ScBaseCell
* pCell
= GetCell( aAdr
);
2206 switch ( GetCellType( pCell
) )
2208 case CELLTYPE_FORMULA
:
2209 ((ScFormulaCell
*)pCell
)->GetFormula( aFormula
);
2212 SetError( NOTAVAILABLE
);
2218 SetError( NOTAVAILABLE
);
2220 PushString( aFormula
);
2225 void ScInterpreter::ScIsNV()
2227 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsNV" );
2228 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2230 switch ( GetStackType() )
2236 PopDoubleRefOrSingleRef( aAdr
);
2237 if ( nGlobalError
== NOTAVAILABLE
)
2241 ScBaseCell
* pCell
= GetCell( aAdr
);
2242 USHORT nErr
= GetCellErrCode( pCell
);
2243 nRes
= (nErr
== NOTAVAILABLE
);
2249 ScMatrixRef pMat
= PopMatrix();
2252 else if ( !pJumpMatrix
)
2253 nRes
= (pMat
->GetErrorIfNotString( 0 ) == NOTAVAILABLE
);
2256 SCSIZE nCols
, nRows
, nC
, nR
;
2257 pMat
->GetDimensions( nCols
, nRows
);
2258 pJumpMatrix
->GetPos( nC
, nR
);
2259 if ( nC
< nCols
&& nR
< nRows
)
2260 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) == NOTAVAILABLE
);
2266 if ( nGlobalError
== NOTAVAILABLE
)
2274 void ScInterpreter::ScIsErr()
2276 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsErr" );
2277 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2279 switch ( GetStackType() )
2285 PopDoubleRefOrSingleRef( aAdr
);
2286 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2290 ScBaseCell
* pCell
= GetCell( aAdr
);
2291 USHORT nErr
= GetCellErrCode( pCell
);
2292 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2298 ScMatrixRef pMat
= PopMatrix();
2299 if ( nGlobalError
|| !pMat
)
2300 nRes
= ((nGlobalError
&& nGlobalError
!= NOTAVAILABLE
) || !pMat
);
2301 else if ( !pJumpMatrix
)
2303 USHORT nErr
= pMat
->GetErrorIfNotString( 0 );
2304 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2308 SCSIZE nCols
, nRows
, nC
, nR
;
2309 pMat
->GetDimensions( nCols
, nRows
);
2310 pJumpMatrix
->GetPos( nC
, nR
);
2311 if ( nC
< nCols
&& nR
< nRows
)
2313 USHORT nErr
= pMat
->GetErrorIfNotString( nC
, nR
);
2314 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2321 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2329 void ScInterpreter::ScIsError()
2331 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsError" );
2332 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2334 switch ( GetStackType() )
2340 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2349 ScBaseCell
* pCell
= GetCell( aAdr
);
2350 nRes
= (GetCellErrCode( pCell
) != 0);
2356 ScMatrixRef pMat
= PopMatrix();
2357 if ( nGlobalError
|| !pMat
)
2359 else if ( !pJumpMatrix
)
2360 nRes
= (pMat
->GetErrorIfNotString( 0 ) != 0);
2363 SCSIZE nCols
, nRows
, nC
, nR
;
2364 pMat
->GetDimensions( nCols
, nRows
);
2365 pJumpMatrix
->GetPos( nC
, nR
);
2366 if ( nC
< nCols
&& nR
< nRows
)
2367 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) != 0);
2381 short ScInterpreter::IsEven()
2383 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IsEven" );
2384 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2387 switch ( GetStackType() )
2393 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2395 ScBaseCell
* pCell
= GetCell( aAdr
);
2396 USHORT nErr
= GetCellErrCode( pCell
);
2401 switch ( GetCellType( pCell
) )
2403 case CELLTYPE_VALUE
:
2404 fVal
= GetCellValue( aAdr
, pCell
);
2407 case CELLTYPE_FORMULA
:
2408 if( ((ScFormulaCell
*)pCell
)->IsValue() )
2410 fVal
= GetCellValue( aAdr
, pCell
);
2428 ScMatrixRef pMat
= PopMatrix();
2431 else if ( !pJumpMatrix
)
2433 nRes
= pMat
->IsValue( 0 );
2435 fVal
= pMat
->GetDouble( 0 );
2439 SCSIZE nCols
, nRows
, nC
, nR
;
2440 pMat
->GetDimensions( nCols
, nRows
);
2441 pJumpMatrix
->GetPos( nC
, nR
);
2442 if ( nC
< nCols
&& nR
< nRows
)
2444 nRes
= pMat
->IsValue( nC
, nR
);
2446 fVal
= pMat
->GetDouble( nC
, nR
);
2449 SetError( errNoValue
);
2457 SetError( errIllegalParameter
);
2459 nRes
= ( fmod( ::rtl::math::approxFloor( fabs( fVal
) ), 2.0 ) < 0.5 );
2464 void ScInterpreter::ScIsEven()
2466 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsEven" );
2467 PushInt( IsEven() );
2471 void ScInterpreter::ScIsOdd()
2473 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsOdd" );
2474 PushInt( !IsEven() );
2478 void ScInterpreter::ScN()
2480 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScN" );
2481 USHORT nErr
= nGlobalError
;
2484 if ( GetRawStackType() == svString
)
2491 if ( nGlobalError
== NOTAVAILABLE
|| nGlobalError
== errIllegalArgument
)
2492 nGlobalError
= 0; // N(#NA) and N("text") are ok
2493 if ( !nGlobalError
&& nErr
!= NOTAVAILABLE
)
2494 nGlobalError
= nErr
;
2499 void ScInterpreter::ScTrim()
2500 { // trimmt nicht nur sondern schnibbelt auch doppelte raus!
2501 String
aVal( GetString() );
2502 aVal
.EraseLeadingChars();
2503 aVal
.EraseTrailingChars();
2505 register const sal_Unicode
* p
= aVal
.GetBuffer();
2506 register const sal_Unicode
* const pEnd
= p
+ aVal
.Len();
2509 if ( *p
!= ' ' || p
[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
2517 void ScInterpreter::ScUpper()
2519 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrim" );
2520 String aString
= GetString();
2521 ScGlobal::pCharClass
->toUpper(aString
);
2522 PushString(aString
);
2526 void ScInterpreter::ScPropper()
2528 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPropper" );
2529 //2do: what to do with I18N-CJK ?!?
2530 String
aStr( GetString() );
2531 const xub_StrLen nLen
= aStr
.Len();
2532 // #i82487# don't try to write to empty string's BufferAccess
2533 // (would crash now that the empty string is const)
2536 String
aUpr( ScGlobal::pCharClass
->upper( aStr
) );
2537 String
aLwr( ScGlobal::pCharClass
->lower( aStr
) );
2538 register sal_Unicode
* pStr
= aStr
.GetBufferAccess();
2539 const sal_Unicode
* pUpr
= aUpr
.GetBuffer();
2540 const sal_Unicode
* pLwr
= aLwr
.GetBuffer();
2542 String
aTmpStr( 'x' );
2543 xub_StrLen nPos
= 1;
2544 while( nPos
< nLen
)
2546 aTmpStr
.SetChar( 0, pStr
[nPos
-1] );
2547 if ( !ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 ) )
2548 pStr
[nPos
] = pUpr
[nPos
];
2550 pStr
[nPos
] = pLwr
[nPos
];
2553 aStr
.ReleaseBufferAccess( nLen
);
2559 void ScInterpreter::ScLower()
2561 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLower" );
2562 String
aString( GetString() );
2563 ScGlobal::pCharClass
->toLower(aString
);
2564 PushString(aString
);
2568 void ScInterpreter::ScLen()
2570 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLen" );
2571 String
aStr( GetString() );
2572 PushDouble( aStr
.Len() );
2576 void ScInterpreter::ScT()
2578 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScT" );
2579 switch ( GetStackType() )
2585 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2590 BOOL bValue
= FALSE
;
2591 ScBaseCell
* pCell
= GetCell( aAdr
);
2592 if ( GetCellErrCode( pCell
) == 0 )
2594 switch ( GetCellType( pCell
) )
2596 case CELLTYPE_VALUE
:
2599 case CELLTYPE_FORMULA
:
2600 bValue
= ((ScFormulaCell
*)pCell
)->IsValue();
2607 PushString( EMPTY_STRING
);
2611 GetCellString( aTempStr
, pCell
);
2612 PushString( aTempStr
);
2619 PushString( EMPTY_STRING
);
2626 PushError( errUnknownOpCode
);
2631 void ScInterpreter::ScValue()
2633 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScValue" );
2634 String aInputString
;
2637 switch ( GetRawStackType() )
2645 return; // leave on stack
2652 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2657 ScBaseCell
* pCell
= GetCell( aAdr
);
2658 if ( pCell
&& pCell
->HasStringData() )
2659 GetCellString( aInputString
, pCell
);
2660 else if ( pCell
&& pCell
->HasValueData() )
2662 PushDouble( GetCellValue(aAdr
, pCell
) );
2674 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
2678 case SC_MATVAL_EMPTY
:
2681 case SC_MATVAL_VALUE
:
2682 case SC_MATVAL_BOOLEAN
:
2686 case SC_MATVAL_STRING
:
2690 PushIllegalArgument();
2695 aInputString
= GetString();
2699 sal_uInt32 nFIndex
= 0; // 0 for default locale
2700 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
2703 PushIllegalArgument();
2707 //2do: this should be a proper unicode string method
2708 inline BOOL
lcl_ScInterpreter_IsPrintable( sal_Unicode c
)
2710 return 0x20 <= c
&& c
!= 0x7f;
2713 void ScInterpreter::ScClean()
2715 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScClean" );
2716 String
aStr( GetString() );
2717 for ( xub_StrLen i
= 0; i
< aStr
.Len(); i
++ )
2719 if ( !lcl_ScInterpreter_IsPrintable( aStr
.GetChar( i
) ) )
2726 void ScInterpreter::ScCode()
2728 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCode" );
2729 //2do: make it full range unicode?
2730 const String
& rStr
= GetString();
2731 PushInt( (sal_uChar
) ByteString::ConvertFromUnicode( rStr
.GetChar(0), gsl_getSystemTextEncoding() ) );
2735 void ScInterpreter::ScChar()
2737 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChar" );
2738 //2do: make it full range unicode?
2739 double fVal
= GetDouble();
2740 if (fVal
< 0.0 || fVal
>= 256.0)
2741 PushIllegalArgument();
2745 aStr
.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char
) fVal
, gsl_getSystemTextEncoding() ) );
2751 /* #i70213# fullwidth/halfwidth conversion provided by
2752 * Takashi Nakamoto <bluedwarf@ooo>
2753 * erAck: added Excel compatibility conversions as seen in issue's test case. */
2755 static ::rtl::OUString
lcl_convertIntoHalfWidth( const ::rtl::OUString
& rStr
)
2757 static bool bFirstASCCall
= true;
2758 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2762 aTrans
.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM
);
2763 bFirstASCCall
= false;
2766 return aTrans
.transliterate( rStr
, 0, USHORT( rStr
.getLength() ), NULL
);
2770 static ::rtl::OUString
lcl_convertIntoFullWidth( const ::rtl::OUString
& rStr
)
2772 static bool bFirstJISCall
= true;
2773 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2777 aTrans
.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM
);
2778 bFirstJISCall
= false;
2781 return aTrans
.transliterate( rStr
, 0, USHORT( rStr
.getLength() ), NULL
);
2786 * Summary: Converts half-width to full-width ASCII and katakana characters.
2787 * Semantics: Conversion is done for half-width ASCII and katakana characters,
2788 * other characters are simply copied from T to the result. This is the
2789 * complementary function to ASC.
2790 * For references regarding halfwidth and fullwidth characters see
2791 * http://www.unicode.org/reports/tr11/
2792 * http://www.unicode.org/charts/charindex2.html#H
2793 * http://www.unicode.org/charts/charindex2.html#F
2795 void ScInterpreter::ScJis()
2797 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScJis" );
2798 if (MustHaveParamCount( GetByte(), 1))
2799 PushString( lcl_convertIntoFullWidth( GetString()));
2804 * Summary: Converts full-width to half-width ASCII and katakana characters.
2805 * Semantics: Conversion is done for full-width ASCII and katakana characters,
2806 * other characters are simply copied from T to the result. This is the
2807 * complementary function to JIS.
2809 void ScInterpreter::ScAsc()
2811 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAsc" );
2812 if (MustHaveParamCount( GetByte(), 1))
2813 PushString( lcl_convertIntoHalfWidth( GetString()));
2817 void ScInterpreter::ScMin( BOOL bTextAsZero
)
2819 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMin" );
2820 short nParamCount
= GetByte();
2821 if (!MustHaveParamCountMin( nParamCount
, 1))
2823 double nMin
= ::std::numeric_limits
<double>::max();
2827 size_t nRefInList
= 0;
2828 while (nParamCount
-- > 0)
2830 switch (GetStackType())
2835 if (nMin
> nVal
) nMin
= nVal
;
2836 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2841 PopSingleRef( aAdr
);
2842 ScBaseCell
* pCell
= GetCell( aAdr
);
2843 if (HasCellValueData(pCell
))
2845 nVal
= GetCellValue( aAdr
, pCell
);
2847 if (nMin
> nVal
) nMin
= nVal
;
2849 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
2860 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2861 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
2862 if (aValIter
.GetFirst(nVal
, nErr
))
2866 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
2867 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
2878 ScMatrixRef pMat
= PopMatrix();
2882 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2883 pMat
->GetDimensions(nC
, nR
);
2884 if (pMat
->IsNumeric())
2886 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2887 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2889 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2890 if (nMin
> nVal
) nMin
= nVal
;
2895 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2897 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2899 if (!pMat
->IsString(nMatCol
,nMatRow
))
2901 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2902 if (nMin
> nVal
) nMin
= nVal
;
2904 else if ( bTextAsZero
)
2924 SetError(errIllegalParameter
);
2929 SetError(errIllegalParameter
);
2938 #if defined(WIN) && defined(MSC)
2939 #pragma optimize("",off)
2942 void ScInterpreter::ScMax( BOOL bTextAsZero
)
2944 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMax" );
2945 short nParamCount
= GetByte();
2946 if (!MustHaveParamCountMin( nParamCount
, 1))
2948 double nMax
= -(::std::numeric_limits
<double>::max());
2952 size_t nRefInList
= 0;
2953 while (nParamCount
-- > 0)
2955 switch (GetStackType())
2960 if (nMax
< nVal
) nMax
= nVal
;
2961 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2966 PopSingleRef( aAdr
);
2967 ScBaseCell
* pCell
= GetCell( aAdr
);
2968 if (HasCellValueData(pCell
))
2970 nVal
= GetCellValue( aAdr
, pCell
);
2972 if (nMax
< nVal
) nMax
= nVal
;
2974 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
2985 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2986 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
2987 if (aValIter
.GetFirst(nVal
, nErr
))
2991 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
2992 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
3003 ScMatrixRef pMat
= PopMatrix();
3006 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3008 pMat
->GetDimensions(nC
, nR
);
3009 if (pMat
->IsNumeric())
3011 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3012 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3014 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3015 if (nMax
< nVal
) nMax
= nVal
;
3020 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3022 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3024 if (!pMat
->IsString(nMatCol
,nMatRow
))
3026 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3027 if (nMax
< nVal
) nMax
= nVal
;
3029 else if ( bTextAsZero
)
3049 SetError(errIllegalParameter
);
3054 SetError(errIllegalParameter
);
3062 #if defined(WIN) && defined(MSC)
3063 #pragma optimize("",on)
3067 double ScInterpreter::IterateParameters( ScIterFunc eFunc
, BOOL bTextAsZero
)
3069 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IterateParameters" );
3070 short nParamCount
= GetByte();
3071 double fRes
= ( eFunc
== ifPRODUCT
) ? 1.0 : 0.0;
3078 size_t nRefInList
= 0;
3079 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3081 while (nParamCount
-- > 0)
3083 StackVar eStackType
= GetStackType();
3089 if( eFunc
== ifCOUNT
&& eStackType
== svString
)
3091 String
aStr( PopString() );
3092 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
3093 if ( bTextAsZero
|| pFormatter
->IsNumberFormat(aStr
, nFIndex
, fVal
))
3096 else if (eFunc
== ifCOUNT2
)
3097 // COUNTA - we should count both number and string.
3101 if ( bTextAsZero
&& eStackType
== svString
)
3105 if ( eFunc
== ifPRODUCT
)
3118 if ( bNull
&& fVal
!= 0.0 )
3126 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3127 case ifPRODUCT
: fRes
*= fVal
; break;
3132 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3137 PopSingleRef( aAdr
);
3138 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3141 if ( eFunc
== ifCOUNT2
)
3145 ScBaseCell
* pCell
= GetCell( aAdr
);
3148 if( eFunc
== ifCOUNT2
)
3150 CellType eCellType
= pCell
->GetCellType();
3151 if (eCellType
!= CELLTYPE_NONE
&& eCellType
!= CELLTYPE_NOTE
)
3156 else if ( pCell
->HasValueData() )
3159 fVal
= GetCellValue( aAdr
, pCell
);
3165 if ( bNull
&& fVal
!= 0.0 )
3173 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3174 case ifPRODUCT
: fRes
*= fVal
; break;
3182 default: ; // nothing
3185 else if ( bTextAsZero
&& pCell
->HasStringData() )
3188 if ( eFunc
== ifPRODUCT
)
3198 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3199 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3202 if ( eFunc
== ifCOUNT2
)
3206 if( eFunc
== ifCOUNT2
)
3209 ScCellIterator
aIter( pDok
, aRange
, glSubTotal
);
3210 if ( (pCell
= aIter
.GetFirst()) != NULL
)
3214 CellType eType
= pCell
->GetCellType();
3215 if( eType
!= CELLTYPE_NONE
&& eType
!= CELLTYPE_NOTE
)
3218 while ( (pCell
= aIter
.GetNext()) != NULL
);
3225 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3226 if (aValIter
.GetFirst(fVal
, nErr
))
3228 // Schleife aus Performance-Gruenden nach innen verlegt:
3229 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3237 if ( bNull
&& fVal
!= 0.0 )
3246 while (aValIter
.GetNext(fVal
, nErr
));
3252 fRes
+= fVal
* fVal
;
3255 while (aValIter
.GetNext(fVal
, nErr
));
3264 while (aValIter
.GetNext(fVal
, nErr
));
3272 while (aValIter
.GetNext(fVal
, nErr
));
3274 default: ; // nothing
3283 ScMatrixRef pMat
= PopMatrix();
3287 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3288 pMat
->GetDimensions(nC
, nR
);
3289 if( eFunc
== ifCOUNT2
)
3290 nCount
+= (ULONG
) nC
* nR
;
3293 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3295 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3297 if (!pMat
->IsString(nMatCol
,nMatRow
))
3300 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3305 if ( bNull
&& fVal
!= 0.0 )
3313 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3314 case ifPRODUCT
: fRes
*= fVal
; break;
3315 default: ; // nothing
3318 else if ( bTextAsZero
)
3321 if ( eFunc
== ifPRODUCT
)
3333 if ( eFunc
== ifCOUNT
)
3337 else if ( eFunc
== ifCOUNT2
)
3345 while (nParamCount
-- > 0)
3347 SetError(errIllegalParameter
);
3352 case ifSUM
: fRes
= ::rtl::math::approxAdd( fRes
, fMem
); break;
3353 case ifAVERAGE
: fRes
= div(::rtl::math::approxAdd( fRes
, fMem
), nCount
); break;
3355 case ifCOUNT
: fRes
= nCount
; break;
3356 case ifPRODUCT
: if ( !nCount
) fRes
= 0.0; break;
3357 default: ; // nothing
3359 // Bei Summen etc. macht ein BOOL-Ergebnis keinen Sinn
3360 // und Anzahl ist immer Number (#38345#)
3361 if( eFunc
== ifCOUNT
|| nFuncFmtType
== NUMBERFORMAT_LOGICAL
)
3362 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3367 void ScInterpreter::ScSumSQ()
3369 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumSQ" );
3370 PushDouble( IterateParameters( ifSUMSQ
) );
3374 void ScInterpreter::ScSum()
3376 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSum" );
3377 PushDouble( IterateParameters( ifSUM
) );
3381 void ScInterpreter::ScProduct()
3383 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScProduct" );
3384 PushDouble( IterateParameters( ifPRODUCT
) );
3388 void ScInterpreter::ScAverage( BOOL bTextAsZero
)
3390 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAverage" );
3391 PushDouble( IterateParameters( ifAVERAGE
, bTextAsZero
) );
3395 void ScInterpreter::ScCount()
3397 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCount" );
3398 PushDouble( IterateParameters( ifCOUNT
) );
3402 void ScInterpreter::ScCount2()
3404 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCount2" );
3405 PushDouble( IterateParameters( ifCOUNT2
) );
3409 void ScInterpreter::GetStVarParams( double& rVal
, double& rValCount
,
3412 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetStVarParams" );
3413 short nParamCount
= GetByte();
3415 std::vector
<double> values
;
3423 size_t nRefInList
= 0;
3424 while (nParamCount
-- > 0)
3426 switch (GetStackType())
3431 values
.push_back(fVal
);
3438 PopSingleRef( aAdr
);
3439 ScBaseCell
* pCell
= GetCell( aAdr
);
3440 if (HasCellValueData(pCell
))
3442 fVal
= GetCellValue( aAdr
, pCell
);
3443 values
.push_back(fVal
);
3447 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
3449 values
.push_back(0.0);
3458 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3459 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3460 if (aValIter
.GetFirst(fVal
, nErr
))
3464 values
.push_back(fVal
);
3468 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
3474 ScMatrixRef pMat
= PopMatrix();
3478 pMat
->GetDimensions(nC
, nR
);
3479 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3481 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3483 if (!pMat
->IsString(nMatCol
,nMatRow
))
3485 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3486 values
.push_back(fVal
);
3490 else if ( bTextAsZero
)
3492 values
.push_back(0.0);
3505 values
.push_back(0.0);
3509 SetError(errIllegalParameter
);
3514 SetError(errIllegalParameter
);
3518 ::std::vector
<double>::size_type n
= values
.size();
3520 for (::std::vector
<double>::size_type i
= 0; i
< n
; i
++)
3521 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
3527 void ScInterpreter::ScVar( BOOL bTextAsZero
)
3529 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVar" );
3532 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3534 if (nValCount
<= 1.0)
3535 PushError( errDivisionByZero
);
3537 PushDouble( nVal
/ (nValCount
- 1.0));
3541 void ScInterpreter::ScVarP( BOOL bTextAsZero
)
3543 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVarP" );
3546 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3548 PushDouble( div( nVal
, nValCount
));
3552 void ScInterpreter::ScStDev( BOOL bTextAsZero
)
3554 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStDev" );
3557 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3558 if (nValCount
<= 1.0)
3559 PushError( errDivisionByZero
);
3561 PushDouble( sqrt( nVal
/ (nValCount
- 1.0)));
3565 void ScInterpreter::ScStDevP( BOOL bTextAsZero
)
3567 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStDevP" );
3570 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3571 if (nValCount
== 0.0)
3572 PushError( errDivisionByZero
);
3574 PushDouble( sqrt( nVal
/ nValCount
));
3576 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3578 * Besides that the special NAN gets lost in the call through sqrt(),
3579 * unxlngi6.pro then looped back and forth somewhere between div() and
3580 * ::rtl::math::setNan(). Tests showed that
3582 * sqrt( div( 1, 0));
3584 * produced a loop, but
3586 * double f1 = div( 1, 0);
3589 * was fine. There seems to be some compiler optimization problem. It does
3590 * not occur when compiled with debug=t.
3595 void ScInterpreter::ScColumns()
3597 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScColumns" );
3598 BYTE nParamCount
= GetByte();
3606 while (nParamCount
-- > 0)
3608 switch ( GetStackType() )
3615 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3616 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1) *
3617 static_cast<ULONG
>(nCol2
- nCol1
+ 1);
3621 ScMatrixRef pMat
= PopMatrix();
3625 pMat
->GetDimensions(nC
, nR
);
3632 SetError(errIllegalParameter
);
3635 PushDouble((double)nVal
);
3639 void ScInterpreter::ScRows()
3641 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRows" );
3642 BYTE nParamCount
= GetByte();
3650 while (nParamCount
-- > 0)
3652 switch ( GetStackType() )
3659 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3660 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1) *
3661 static_cast<ULONG
>(nRow2
- nRow1
+ 1);
3665 ScMatrixRef pMat
= PopMatrix();
3669 pMat
->GetDimensions(nC
, nR
);
3676 SetError(errIllegalParameter
);
3679 PushDouble((double)nVal
);
3682 void ScInterpreter::ScTables()
3684 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTables" );
3685 BYTE nParamCount
= GetByte();
3687 if ( nParamCount
== 0 )
3688 nVal
= pDok
->GetTableCount();
3698 while (nParamCount
-- > 0)
3700 switch ( GetStackType() )
3707 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3708 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1);
3716 SetError( errIllegalParameter
);
3720 PushDouble( (double) nVal
);
3724 void ScInterpreter::ScColumn()
3726 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScColumn" );
3727 BYTE nParamCount
= GetByte();
3728 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3731 if (nParamCount
== 0)
3733 nVal
= aPos
.Col() + 1;
3738 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3739 ScMatrixRef pResMat
= GetNewMat( static_cast<SCSIZE
>(nCols
), 1);
3742 for (SCCOL i
=0; i
< nCols
; ++i
)
3743 pResMat
->PutDouble( nVal
+ i
, static_cast<SCSIZE
>(i
), 0);
3744 PushMatrix( pResMat
);
3751 switch ( GetStackType() )
3758 PopSingleRef( nCol1
, nRow1
, nTab1
);
3759 nVal
= (double) (nCol1
+ 1);
3770 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3773 ScMatrixRef pResMat
= GetNewMat(
3774 static_cast<SCSIZE
>(nCol2
-nCol1
+1), 1);
3777 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
3778 pResMat
->PutDouble((double)(i
+1),
3779 static_cast<SCSIZE
>(i
-nCol1
), 0);
3780 PushMatrix(pResMat
);
3787 nVal
= (double) (nCol1
+ 1);
3791 SetError( errIllegalParameter
);
3800 void ScInterpreter::ScRow()
3802 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRow" );
3803 BYTE nParamCount
= GetByte();
3804 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3807 if (nParamCount
== 0)
3809 nVal
= aPos
.Row() + 1;
3814 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3815 ScMatrixRef pResMat
= GetNewMat( 1, static_cast<SCSIZE
>(nRows
));
3818 for (SCROW i
=0; i
< nRows
; i
++)
3819 pResMat
->PutDouble( nVal
+ i
, 0, static_cast<SCSIZE
>(i
));
3820 PushMatrix( pResMat
);
3827 switch ( GetStackType() )
3834 PopSingleRef( nCol1
, nRow1
, nTab1
);
3835 nVal
= (double) (nRow1
+ 1);
3846 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3849 ScMatrixRef pResMat
= GetNewMat( 1,
3850 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
3853 for (SCROW i
= nRow1
; i
<= nRow2
; i
++)
3854 pResMat
->PutDouble((double)(i
+1), 0,
3855 static_cast<SCSIZE
>(i
-nRow1
));
3856 PushMatrix(pResMat
);
3863 nVal
= (double) (nRow1
+ 1);
3867 SetError( errIllegalParameter
);
3875 void ScInterpreter::ScTable()
3877 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTable" );
3878 BYTE nParamCount
= GetByte();
3879 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3882 if ( nParamCount
== 0 )
3883 nVal
= aPos
.Tab() + 1;
3886 switch ( GetStackType() )
3890 String
aStr( PopString() );
3891 if ( pDok
->GetTable( aStr
, nVal
) )
3894 SetError( errIllegalArgument
);
3902 PopSingleRef( nCol1
, nRow1
, nTab1
);
3914 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3919 SetError( errIllegalParameter
);
3924 PushDouble( (double) nVal
);
3928 /** returns -1 when the matrix value is smaller than the query value, 0 when
3929 they are equal, and 1 when the matrix value is larger than the query
3931 static sal_Int32
lcl_CompareMatrix2Query( SCSIZE i
, const ScMatrix
& rMat
,
3932 const ScQueryEntry
& rEntry
)
3934 if (rMat
.IsEmpty(i
))
3936 /* TODO: in case we introduced query for real empty this would have to
3938 return -1; // empty always less than anything else
3941 /* FIXME: what is an empty path (result of IF(false;true_path) in
3944 if (rMat
.IsValue(i
))
3946 if (rEntry
.bQueryByString
)
3947 return -1; // numeric always less than string
3949 const double nVal1
= rMat
.GetDouble(i
);
3950 const double nVal2
= rEntry
.nVal
;
3954 return nVal1
< nVal2
? -1 : 1;
3957 if (!rEntry
.bQueryByString
)
3958 return 1; // string always greater than numeric
3961 // this should not happen!
3964 const String
& rStr1
= rMat
.GetString(i
);
3965 const String
& rStr2
= *rEntry
.pStr
;
3967 return ScGlobal::pCollator
->compareString( rStr1
, rStr2
); // case-insensitive
3970 /** returns the last item with the identical value as the original item
3972 static void lcl_GetLastMatch( SCSIZE
& rIndex
, const ScMatrix
& rMat
,
3973 SCSIZE nMatCount
, bool bReverse
)
3975 if (rMat
.IsValue(rIndex
))
3977 double nVal
= rMat
.GetDouble(rIndex
);
3979 while (rIndex
> 0 && rMat
.IsValue(rIndex
-1) &&
3980 nVal
== rMat
.GetDouble(rIndex
-1))
3983 while (rIndex
< nMatCount
-1 && rMat
.IsValue(rIndex
+1) &&
3984 nVal
== rMat
.GetDouble(rIndex
+1))
3987 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
3988 else if (rMat
.IsEmptyPath(rIndex
))
3991 while (rIndex
> 0 && rMat
.IsEmptyPath(rIndex
-1))
3994 while (rIndex
< nMatCount
-1 && rMat
.IsEmptyPath(rIndex
+1))
3997 else if (rMat
.IsEmpty(rIndex
))
4000 while (rIndex
> 0 && rMat
.IsEmpty(rIndex
-1))
4003 while (rIndex
< nMatCount
-1 && rMat
.IsEmpty(rIndex
+1))
4006 else if (rMat
.IsString(rIndex
))
4008 String
aStr( rMat
.GetString(rIndex
));
4010 while (rIndex
> 0 && rMat
.IsString(rIndex
-1) &&
4011 aStr
== rMat
.GetString(rIndex
-1))
4014 while (rIndex
< nMatCount
-1 && rMat
.IsString(rIndex
+1) &&
4015 aStr
== rMat
.GetString(rIndex
+1))
4020 DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
4024 void ScInterpreter::ScMatch()
4026 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMatch" );
4027 ScMatrixRef pMatSrc
= NULL
;
4029 BYTE nParamCount
= GetByte();
4030 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4033 if (nParamCount
== 3)
4043 if (GetStackType() == svDoubleRef
)
4045 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4046 if (nTab1
!= nTab2
|| (nCol1
!= nCol2
&& nRow1
!= nRow2
))
4048 PushIllegalParameter();
4052 else if (GetStackType() == svMatrix
)
4054 pMatSrc
= PopMatrix();
4057 PushIllegalParameter();
4063 PushIllegalParameter();
4066 if (nGlobalError
== 0)
4070 ScQueryParam rParam
;
4071 rParam
.nCol1
= nCol1
;
4072 rParam
.nRow1
= nRow1
;
4073 rParam
.nCol2
= nCol2
;
4074 rParam
.nTab
= nTab1
;
4075 rParam
.bMixedComparison
= TRUE
;
4077 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4078 rEntry
.bDoQuery
= TRUE
;
4080 rEntry
.eOp
= SC_GREATER_EQUAL
;
4081 else if (fTyp
> 0.0)
4082 rEntry
.eOp
= SC_LESS_EQUAL
;
4083 switch ( GetStackType() )
4088 rEntry
.bQueryByString
= FALSE
;
4095 rEntry
.bQueryByString
= TRUE
;
4096 *rEntry
.pStr
= sStr
;
4103 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4108 ScBaseCell
* pCell
= GetCell( aAdr
);
4109 if (HasCellValueData(pCell
))
4111 fVal
= GetCellValue( aAdr
, pCell
);
4112 rEntry
.bQueryByString
= FALSE
;
4117 GetCellString(sStr
, pCell
);
4118 rEntry
.bQueryByString
= TRUE
;
4119 *rEntry
.pStr
= sStr
;
4125 ScMatValType nType
= GetDoubleOrStringFromMatrix(
4126 rEntry
.nVal
, *rEntry
.pStr
);
4127 rEntry
.bQueryByString
= ScMatrix::IsNonValueType( nType
);
4132 PushIllegalParameter();
4136 if ( rEntry
.bQueryByString
)
4138 BOOL bIsVBAMode
= FALSE
;
4141 SfxObjectShell
* pDocSh
= pDok
->GetDocumentShell();
4143 bIsVBAMode
= pDocSh
->GetBasic()->isVBAEnabled();
4145 // #TODO handle MSO wildcards
4147 rParam
.bRegExp
= FALSE
;
4149 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4152 if (pMatSrc
) // The source data is matrix array.
4155 pMatSrc
->GetDimensions( nC
, nR
);
4156 if (nC
> 1 && nR
> 1)
4158 // The source matrix must be a vector.
4159 PushIllegalParameter();
4162 SCSIZE nMatCount
= (nC
== 1) ? nR
: nC
;
4164 // simple serial search for equality mode (source data doesn't
4165 // need to be sorted).
4167 if (rEntry
.eOp
== SC_EQUAL
)
4169 for (SCSIZE i
= 0; i
< nMatCount
; ++i
)
4171 if (lcl_CompareMatrix2Query( i
, *pMatSrc
, rEntry
) == 0)
4173 PushDouble(i
+1); // found !
4177 PushNA(); // not found
4181 // binary search for non-equality mode (the source data is
4182 // assumed to be sorted).
4184 bool bAscOrder
= (rEntry
.eOp
== SC_LESS_EQUAL
);
4185 SCSIZE nFirst
= 0, nLast
= nMatCount
-1, nHitIndex
= 0;
4186 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
4188 SCSIZE nMid
= nFirst
+ nLen
/2;
4189 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, *pMatSrc
, rEntry
);
4192 // exact match. find the last item with the same value.
4193 lcl_GetLastMatch( nMid
, *pMatSrc
, nMatCount
, !bAscOrder
);
4194 PushDouble( nMid
+1);
4198 if (nLen
== 1) // first and last items are next to each other.
4201 nHitIndex
= bAscOrder
? nLast
: nFirst
;
4203 nHitIndex
= bAscOrder
? nFirst
: nLast
;
4223 if (nHitIndex
== nMatCount
-1) // last item
4225 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nHitIndex
, *pMatSrc
, rEntry
);
4226 if ((bAscOrder
&& nCmp
<= 0) || (!bAscOrder
&& nCmp
>= 0))
4228 // either the last item is an exact match or the real
4229 // hit is beyond the last item.
4230 PushDouble( nHitIndex
+1);
4235 if (nHitIndex
> 0) // valid hit must be 2nd item or higher
4237 PushDouble( nHitIndex
); // non-exact match
4245 SCCOLROW nDelta
= 0;
4247 { // search row in column
4248 rParam
.nRow2
= nRow2
;
4249 rEntry
.nField
= nCol1
;
4250 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
4251 if (!LookupQueryWithCache( aResultPos
, rParam
))
4256 nDelta
= aResultPos
.Row() - nRow1
;
4259 { // search column in row
4261 rParam
.bByRow
= FALSE
;
4262 rParam
.nRow2
= nRow1
;
4263 rEntry
.nField
= nCol1
;
4264 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4265 // Advance Entry.nField in Iterator if column changed
4266 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4269 if ( aCellIter
.GetFirst() )
4270 nC
= aCellIter
.GetCol();
4280 if ( !aCellIter
.FindEqualOrSortedLastInRange( nC
, nR
) )
4286 nDelta
= nC
- nCol1
;
4288 PushDouble((double) (nDelta
+ 1));
4291 PushIllegalParameter();
4296 void ScInterpreter::ScCountEmptyCells()
4298 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCountEmptyCells" );
4299 if ( MustHaveParamCount( GetByte(), 1 ) )
4301 ULONG nMaxCount
= 0, nCount
= 0;
4303 switch (GetStackType())
4309 PopSingleRef( aAdr
);
4310 eCellType
= GetCellType( GetCell( aAdr
) );
4311 if (eCellType
!= CELLTYPE_NONE
&& eCellType
!= CELLTYPE_NOTE
)
4320 size_t nRefInList
= 0;
4321 while (nParam
-- > 0)
4323 PopDoubleRef( aRange
, nParam
, nRefInList
);
4325 static_cast<ULONG
>(aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1) *
4326 static_cast<ULONG
>(aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1) *
4327 static_cast<ULONG
>(aRange
.aEnd
.Tab() - aRange
.aStart
.Tab() + 1);
4329 ScCellIterator
aDocIter( pDok
, aRange
, glSubTotal
);
4330 if ( (pCell
= aDocIter
.GetFirst()) != NULL
)
4334 if ((eCellType
= pCell
->GetCellType()) != CELLTYPE_NONE
4335 && eCellType
!= CELLTYPE_NOTE
)
4337 } while ( (pCell
= aDocIter
.GetNext()) != NULL
);
4342 default : SetError(errIllegalParameter
); break;
4344 PushDouble(nMaxCount
- nCount
);
4349 void ScInterpreter::ScCountIf()
4351 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCountIf" );
4352 if ( MustHaveParamCount( GetByte(), 2 ) )
4356 BOOL bIsString
= TRUE
;
4357 switch ( GetStackType() )
4363 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4368 ScBaseCell
* pCell
= GetCell( aAdr
);
4369 switch ( GetCellType( pCell
) )
4371 case CELLTYPE_VALUE
:
4372 fVal
= GetCellValue( aAdr
, pCell
);
4375 case CELLTYPE_FORMULA
:
4376 if( ((ScFormulaCell
*)pCell
)->IsValue() )
4378 fVal
= GetCellValue( aAdr
, pCell
);
4382 GetCellString(rString
, pCell
);
4384 case CELLTYPE_STRING
:
4385 case CELLTYPE_EDIT
:
4386 GetCellString(rString
, pCell
);
4396 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
4398 bIsString
= ScMatrix::IsNonValueType( nType
);
4402 rString
= GetString();
4412 size_t nRefInList
= 0;
4413 while (nParam
-- > 0)
4421 ScMatrixRef pQueryMatrix
;
4422 switch ( GetStackType() )
4428 PopDoubleRef( aRange
, nParam
, nRefInList
);
4429 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4433 PopSingleRef( nCol1
, nRow1
, nTab1
);
4440 pQueryMatrix
= PopMatrix();
4443 PushIllegalParameter();
4450 pQueryMatrix
->GetDimensions( nC
, nR
);
4451 nCol2
= static_cast<SCCOL
>(nC
- 1);
4452 nRow2
= static_cast<SCROW
>(nR
- 1);
4457 PushIllegalParameter();
4460 if ( nTab1
!= nTab2
)
4462 PushIllegalParameter();
4467 PushIllegalParameter();
4470 if (nGlobalError
== 0)
4472 ScQueryParam rParam
;
4473 rParam
.nRow1
= nRow1
;
4474 rParam
.nRow2
= nRow2
;
4476 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4477 rEntry
.bDoQuery
= TRUE
;
4480 rEntry
.bQueryByString
= FALSE
;
4482 rEntry
.eOp
= SC_EQUAL
;
4486 rParam
.FillInExcelSyntax(rString
, 0);
4487 sal_uInt32 nIndex
= 0;
4488 rEntry
.bQueryByString
=
4489 !(pFormatter
->IsNumberFormat(
4490 *rEntry
.pStr
, nIndex
, rEntry
.nVal
));
4491 if ( rEntry
.bQueryByString
)
4492 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4494 rParam
.nCol1
= nCol1
;
4495 rParam
.nCol2
= nCol2
;
4496 rEntry
.nField
= nCol1
;
4499 // Never case-sensitive.
4500 ScCompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
4501 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
4502 if (nGlobalError
|| !pResultMatrix
)
4504 PushIllegalParameter();
4508 SCSIZE nSize
= pResultMatrix
->GetElementCount();
4509 for (SCSIZE nIndex
= 0; nIndex
< nSize
; ++nIndex
)
4511 if (pResultMatrix
->IsValue( nIndex
) &&
4512 pResultMatrix
->GetDouble( nIndex
))
4518 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4519 // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
4520 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4521 if ( aCellIter
.GetFirst() )
4526 } while ( aCellIter
.GetNext() );
4532 PushIllegalParameter();
4541 void ScInterpreter::ScSumIf()
4543 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumIf" );
4544 BYTE nParamCount
= GetByte();
4545 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4551 ScMatrixRef pSumExtraMatrix
;
4552 bool bSumExtraRange
= (nParamCount
== 3);
4555 // Save only the upperleft cell in case of cell range. The geometry
4556 // of the 3rd parameter is taken from the 1st parameter.
4558 switch ( GetStackType() )
4565 PopDoubleRef( nCol3
, nRow3
, nTab3
, nColJunk
, nRowJunk
, nTabJunk
);
4566 if ( nTabJunk
!= nTab3
)
4568 PushIllegalParameter();
4574 PopSingleRef( nCol3
, nRow3
, nTab3
);
4577 pSumExtraMatrix
= PopMatrix();
4578 //! nCol3, nRow3, nTab3 remain 0
4581 PushIllegalParameter();
4587 BOOL bIsString
= TRUE
;
4588 switch ( GetStackType() )
4594 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4599 ScBaseCell
* pCell
= GetCell( aAdr
);
4600 switch ( GetCellType( pCell
) )
4602 case CELLTYPE_VALUE
:
4603 fVal
= GetCellValue( aAdr
, pCell
);
4606 case CELLTYPE_FORMULA
:
4607 if( ((ScFormulaCell
*)pCell
)->IsValue() )
4609 fVal
= GetCellValue( aAdr
, pCell
);
4613 GetCellString(rString
, pCell
);
4615 case CELLTYPE_STRING
:
4616 case CELLTYPE_EDIT
:
4617 GetCellString(rString
, pCell
);
4626 rString
= GetString();
4630 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
4632 bIsString
= ScMatrix::IsNonValueType( nType
);
4646 size_t nRefInList
= 0;
4647 while (nParam
-- > 0)
4655 ScMatrixRef pQueryMatrix
;
4656 switch ( GetStackType() )
4661 PushIllegalParameter();
4667 PopDoubleRef( aRange
, nParam
, nRefInList
);
4668 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4672 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4675 PopSingleRef( nCol1
, nRow1
, nTab1
);
4682 pQueryMatrix
= PopMatrix();
4685 PushIllegalParameter();
4692 pQueryMatrix
->GetDimensions( nC
, nR
);
4693 nCol2
= static_cast<SCCOL
>(nC
- 1);
4694 nRow2
= static_cast<SCROW
>(nR
- 1);
4699 PushIllegalParameter();
4702 if ( nTab1
!= nTab2
)
4704 PushIllegalArgument();
4710 // Take the range geometry of the 1st parameter and apply it to
4711 // the 3rd. If parts of the resulting range would point outside
4712 // the sheet, don't complain but silently ignore and simply cut
4713 // them away, this is what Xcl does :-/
4715 // For the cut-away part we also don't need to determine the
4716 // criteria match, so shrink the source range accordingly,
4717 // instead of the result range.
4718 SCCOL nColDelta
= nCol2
- nCol1
;
4719 SCROW nRowDelta
= nRow2
- nRow1
;
4722 if (pSumExtraMatrix
)
4725 pSumExtraMatrix
->GetDimensions( nC
, nR
);
4726 nMaxCol
= static_cast<SCCOL
>(nC
- 1);
4727 nMaxRow
= static_cast<SCROW
>(nR
- 1);
4734 if (nCol3
+ nColDelta
> nMaxCol
)
4736 SCCOL nNewDelta
= nMaxCol
- nCol3
;
4737 nCol2
= nCol1
+ nNewDelta
;
4740 if (nRow3
+ nRowDelta
> nMaxRow
)
4742 SCROW nNewDelta
= nMaxRow
- nRow3
;
4743 nRow2
= nRow1
+ nNewDelta
;
4753 if (nGlobalError
== 0)
4755 ScQueryParam rParam
;
4756 rParam
.nRow1
= nRow1
;
4757 rParam
.nRow2
= nRow2
;
4759 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4760 rEntry
.bDoQuery
= TRUE
;
4763 rEntry
.bQueryByString
= FALSE
;
4765 rEntry
.eOp
= SC_EQUAL
;
4769 rParam
.FillInExcelSyntax(rString
, 0);
4770 sal_uInt32 nIndex
= 0;
4771 rEntry
.bQueryByString
=
4772 !(pFormatter
->IsNumberFormat(
4773 *rEntry
.pStr
, nIndex
, rEntry
.nVal
));
4774 if ( rEntry
.bQueryByString
)
4775 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4778 aAdr
.SetTab( nTab3
);
4779 rParam
.nCol1
= nCol1
;
4780 rParam
.nCol2
= nCol2
;
4781 rEntry
.nField
= nCol1
;
4782 SCsCOL nColDiff
= nCol3
- nCol1
;
4783 SCsROW nRowDiff
= nRow3
- nRow1
;
4786 // Never case-sensitive.
4787 ScCompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
4788 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
4789 if (nGlobalError
|| !pResultMatrix
)
4791 PushIllegalParameter();
4795 if (pSumExtraMatrix
)
4797 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4799 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4801 if (pResultMatrix
->IsValue( nCol
, nRow
) &&
4802 pResultMatrix
->GetDouble( nCol
, nRow
))
4804 SCSIZE nC
= nCol
+ nColDiff
;
4805 SCSIZE nR
= nRow
+ nRowDiff
;
4806 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4808 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4809 if ( bNull
&& fVal
!= 0.0 )
4823 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4825 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4827 if (pResultMatrix
->GetDouble( nCol
, nRow
))
4829 aAdr
.SetCol( nCol
+ nColDiff
);
4830 aAdr
.SetRow( nRow
+ nRowDiff
);
4831 ScBaseCell
* pCell
= GetCell( aAdr
);
4832 if ( HasCellValueData(pCell
) )
4834 fVal
= GetCellValue( aAdr
, pCell
);
4835 if ( bNull
&& fVal
!= 0.0 )
4850 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4851 // Increment Entry.nField in iterator when switching to next column.
4852 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4853 if ( aCellIter
.GetFirst() )
4855 if (pSumExtraMatrix
)
4859 SCSIZE nC
= aCellIter
.GetCol() + nColDiff
;
4860 SCSIZE nR
= aCellIter
.GetRow() + nRowDiff
;
4861 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4863 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4864 if ( bNull
&& fVal
!= 0.0 )
4872 } while ( aCellIter
.GetNext() );
4878 aAdr
.SetCol( aCellIter
.GetCol() + nColDiff
);
4879 aAdr
.SetRow( aCellIter
.GetRow() + nRowDiff
);
4880 ScBaseCell
* pCell
= GetCell( aAdr
);
4881 if ( HasCellValueData(pCell
) )
4883 fVal
= GetCellValue( aAdr
, pCell
);
4884 if ( bNull
&& fVal
!= 0.0 )
4892 } while ( aCellIter
.GetNext() );
4899 PushIllegalParameter();
4903 PushDouble( ::rtl::math::approxAdd( fSum
, fMem
) );
4908 void ScInterpreter::ScLookup()
4910 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLookup" );
4911 BYTE nParamCount
= GetByte();
4912 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
4915 ScMatrixRef pDataMat
= NULL
, pResMat
= NULL
;
4916 SCCOL nCol1
= 0, nCol2
= 0, nResCol1
= 0, nResCol2
= 0;
4917 SCROW nRow1
= 0, nRow2
= 0, nResRow1
= 0, nResRow2
= 0;
4918 SCTAB nTab1
= 0, nResTab
= 0;
4919 SCSIZE nLenMajor
= 0; // length of major direction
4920 bool bVertical
= true; // whether to lookup vertically or horizontally
4922 if (nParamCount
== 3)
4924 switch (GetStackType())
4929 PopDoubleRef(nResCol1
, nResRow1
, nResTab
,
4930 nResCol2
, nResRow2
, nTabJunk
);
4931 if (nResTab
!= nTabJunk
||
4932 ((nResRow2
- nResRow1
) > 0 && (nResCol2
- nResCol1
) > 0))
4934 // The result array must be a vector.
4935 PushIllegalParameter();
4942 pResMat
= PopMatrix();
4945 PushIllegalParameter();
4949 pResMat
->GetDimensions(nC
, nR
);
4950 if (nC
!= 1 && nR
!= 1)
4952 // Result matrix must be a vector.
4953 PushIllegalParameter();
4959 PushIllegalParameter();
4964 // Get the data-result range and also determine whether this is vertical
4965 // lookup or horizontal lookup.
4967 switch (GetStackType())
4972 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTabJunk
);
4973 if (nTab1
!= nTabJunk
)
4975 PushIllegalParameter();
4978 bVertical
= (nRow2
- nRow1
) >= (nCol2
- nCol1
);
4979 nLenMajor
= bVertical
? nRow2
- nRow1
+ 1 : nCol2
- nCol1
+ 1;
4984 pDataMat
= PopMatrix();
4987 PushIllegalParameter();
4992 pDataMat
->GetDimensions(nC
, nR
);
4993 bVertical
= (nR
>= nC
);
4994 nLenMajor
= bVertical
? nR
: nC
;
4998 PushIllegalParameter();
5005 PushIllegalParameter();
5009 // Get the lookup value.
5011 ScQueryParam aParam
;
5012 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
5013 if ( !FillEntry(rEntry
) )
5016 // Now, perform the search to compute the delta position (nDelta).
5020 // Data array is given as a matrix.
5021 rEntry
.bDoQuery
= true;
5022 rEntry
.eOp
= SC_LESS_EQUAL
;
5023 bool bFound
= false;
5026 pDataMat
->GetDimensions(nC
, nR
);
5028 // In case of non-vector matrix, only search the first row or column.
5029 ScMatrixRef pDataMat2
;
5032 ScMatrixRef
pTempMat(new ScMatrix(1, nR
));
5033 for (SCSIZE i
= 0; i
< nR
; ++i
)
5034 if (pDataMat
->IsValue(0, i
))
5035 pTempMat
->PutDouble(pDataMat
->GetDouble(0, i
), 0, i
);
5037 pTempMat
->PutString(pDataMat
->GetString(0, i
), 0, i
);
5038 pDataMat2
= pTempMat
;
5042 ScMatrixRef
pTempMat(new ScMatrix(nC
, 1));
5043 for (SCSIZE i
= 0; i
< nC
; ++i
)
5044 if (pDataMat
->IsValue(i
, 0))
5045 pTempMat
->PutDouble(pDataMat
->GetDouble(i
, 0), i
, 0);
5047 pTempMat
->PutString(pDataMat
->GetString(i
, 0), i
, 0);
5048 pDataMat2
= pTempMat
;
5051 // binary search for non-equality mode (the source data is
5052 // assumed to be sorted in ascending order).
5054 SCCOLROW nDelta
= -1;
5056 SCSIZE nFirst
= 0, nLast
= nLenMajor
-1; //, nHitIndex = 0;
5057 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
5059 SCSIZE nMid
= nFirst
+ nLen
/2;
5060 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, *pDataMat2
, rEntry
);
5063 // exact match. find the last item with the same value.
5064 lcl_GetLastMatch( nMid
, *pDataMat2
, nLenMajor
, false);
5070 if (nLen
== 1) // first and last items are next to each other.
5072 nDelta
= nCmp
< 0 ? nLast
- 1 : nFirst
- 1;
5073 // If already the 1st item is greater there's nothing found.
5074 bFound
= (nDelta
>= 0);
5084 if (nDelta
== static_cast<SCCOLROW
>(nLenMajor
-2)) // last item
5086 sal_Int32 nCmp
= lcl_CompareMatrix2Query(nDelta
+1, *pDataMat2
, rEntry
);
5089 // either the last item is an exact match or the real
5090 // hit is beyond the last item.
5095 else if (nDelta
> 0) // valid hit must be 2nd item or higher
5107 // Now that we've found the delta, push the result back to the cell.
5111 // result array is matrix.
5112 if (static_cast<SCSIZE
>(nDelta
) >= pResMat
->GetElementCount())
5117 if (pResMat
->IsValue(nDelta
))
5118 PushDouble(pResMat
->GetDouble(nDelta
));
5120 PushString(pResMat
->GetString(nDelta
));
5122 else if (nParamCount
== 3)
5124 // result array is cell range.
5126 aAdr
.SetTab(nResTab
);
5127 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
5130 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
5131 if (nTempRow
> MAXROW
)
5136 aAdr
.SetCol(nResCol1
);
5137 aAdr
.SetRow(nTempRow
);
5141 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
5142 if (nTempCol
> MAXCOL
)
5147 aAdr
.SetCol(nTempCol
);
5148 aAdr
.SetRow(nResRow1
);
5150 PushCellResultToken(true, aAdr
, NULL
, NULL
);
5154 // no result array. Use the data array to get the final value from.
5157 if (pDataMat
->IsValue(nC
-1, nDelta
))
5158 PushDouble(pDataMat
->GetDouble(nC
-1, nDelta
));
5160 PushString(pDataMat
->GetString(nC
-1, nDelta
));
5164 if (pDataMat
->IsValue(nDelta
, nR
-1))
5165 PushDouble(pDataMat
->GetDouble(nDelta
, nR
-1));
5167 PushString(pDataMat
->GetString(nDelta
, nR
-1));
5174 // Perform cell range search.
5176 aParam
.nCol1
= nCol1
;
5177 aParam
.nRow1
= nRow1
;
5178 aParam
.nCol2
= bVertical
? nCol1
: nCol2
;
5179 aParam
.nRow2
= bVertical
? nRow2
: nRow1
;
5180 aParam
.bByRow
= bVertical
;
5181 aParam
.bMixedComparison
= true;
5183 rEntry
.bDoQuery
= TRUE
;
5184 rEntry
.eOp
= SC_LESS_EQUAL
;
5185 rEntry
.nField
= nCol1
;
5186 if ( rEntry
.bQueryByString
)
5187 aParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5189 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, FALSE
);
5192 // Advance Entry.nField in iterator upon switching columns if
5194 aCellIter
.SetAdvanceQueryParamEntryField(!bVertical
);
5195 if ( !aCellIter
.FindEqualOrSortedLastInRange(nC
, nR
) )
5201 SCCOLROW nDelta
= bVertical
? static_cast<SCSIZE
>(nR
-nRow1
) : static_cast<SCSIZE
>(nC
-nCol1
);
5205 // Use the matrix result array.
5206 if (pResMat
->IsValue(nDelta
))
5207 PushDouble(pResMat
->GetDouble(nDelta
));
5209 PushString(pResMat
->GetString(nDelta
));
5211 else if (nParamCount
== 3)
5213 // Use the result array vector. Note that the result array is assumed
5214 // to be a vector (i.e. 1-dimensinoal array).
5217 aAdr
.SetTab(nResTab
);
5218 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
5221 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
5222 if (nTempRow
> MAXROW
)
5227 aAdr
.SetCol(nResCol1
);
5228 aAdr
.SetRow(nTempRow
);
5232 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
5233 if (nTempCol
> MAXCOL
)
5238 aAdr
.SetCol(nTempCol
);
5239 aAdr
.SetRow(nResRow1
);
5241 PushCellResultToken(true, aAdr
, NULL
, NULL
);
5245 // Regardless of whether or not the result array exists, the last
5246 // array is always used as the "result" array.
5252 SCROW nTempRow
= static_cast<SCROW
>(nRow1
+ nDelta
);
5253 if (nTempRow
> MAXROW
)
5259 aAdr
.SetRow(nTempRow
);
5263 SCCOL nTempCol
= static_cast<SCCOL
>(nCol1
+ nDelta
);
5264 if (nTempCol
> MAXCOL
)
5269 aAdr
.SetCol(nTempCol
);
5272 PushCellResultToken(true, aAdr
, NULL
, NULL
);
5277 void ScInterpreter::ScHLookup()
5279 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHLookup" );
5280 CalculateLookup(TRUE
);
5282 void ScInterpreter::CalculateLookup(BOOL HLookup
)
5284 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateLookup" );
5285 BYTE nParamCount
= GetByte();
5286 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
5289 if (nParamCount
== 4)
5290 bSorted
= GetBool();
5293 double fIndex
= ::rtl::math::approxFloor( GetDouble() ) - 1.0;
5294 ScMatrixRef pMat
= NULL
;
5295 SCSIZE nC
= 0, nR
= 0;
5302 if (GetStackType() == svDoubleRef
)
5304 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5307 PushIllegalParameter();
5311 else if (GetStackType() == svMatrix
)
5315 pMat
->GetDimensions(nC
, nR
);
5318 PushIllegalParameter();
5324 PushIllegalParameter();
5327 if ( fIndex
< 0.0 || (HLookup
? (pMat
? (fIndex
>= nR
) : (fIndex
+nRow1
> nRow2
)) : (pMat
? (fIndex
>= nC
) : (fIndex
+nCol1
> nCol2
)) ) )
5329 PushIllegalArgument();
5332 SCROW nZIndex
= static_cast<SCROW
>(fIndex
);
5333 SCCOL nSpIndex
= static_cast<SCCOL
>(fIndex
);
5337 nZIndex
+= nRow1
; // Wertzeile
5338 nSpIndex
= sal::static_int_cast
<SCCOL
>( nSpIndex
+ nCol1
); // value column
5341 if (nGlobalError
== 0)
5343 ScQueryParam rParam
;
5344 rParam
.nCol1
= nCol1
;
5345 rParam
.nRow1
= nRow1
;
5348 rParam
.nCol2
= nCol2
;
5349 rParam
.nRow2
= nRow1
; // nur in der ersten Zeile suchen
5350 rParam
.bByRow
= FALSE
;
5354 rParam
.nCol2
= nCol1
; // nur in der ersten Spalte suchen
5355 rParam
.nRow2
= nRow2
;
5356 rParam
.nTab
= nTab1
;
5358 rParam
.bMixedComparison
= TRUE
;
5360 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5361 rEntry
.bDoQuery
= TRUE
;
5363 rEntry
.eOp
= SC_LESS_EQUAL
;
5364 if ( !FillEntry(rEntry
) )
5366 if ( rEntry
.bQueryByString
)
5367 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5370 SCSIZE nMatCount
= HLookup
? nC
: nR
;
5371 SCSIZE nDelta
= SCSIZE_MAX
;
5372 if (rEntry
.bQueryByString
)
5375 //! TODO: enable regex on matrix strings
5377 String aParamStr
= *rEntry
.pStr
;
5380 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5382 if (HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
5385 ScGlobal::pCollator
->compareString( HLookup
? pMat
->GetString(i
,0) : pMat
->GetString(0,i
), aParamStr
);
5388 else if (i
>0) // #i2168# ignore first mismatch
5397 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5399 if (HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
5401 if ( ScGlobal::pTransliteration
->isEqual(
5402 HLookup
? pMat
->GetString(i
,0) : pMat
->GetString(0,i
), aParamStr
) )
5415 // #i2168# ignore strings
5416 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5418 if (!(HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
5420 if ((HLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) <= rEntry
.nVal
)
5429 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5431 if (!(HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
5433 if ((HLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) == rEntry
.nVal
)
5442 if ( nDelta
!= SCSIZE_MAX
)
5444 SCSIZE nX
= static_cast<SCSIZE
>(nSpIndex
);
5449 nY
= static_cast<SCSIZE
>(nZIndex
);
5451 if ( pMat
->IsString( nX
, nY
) )
5452 PushString(pMat
->GetString( nX
,nY
));
5454 PushDouble(pMat
->GetDouble( nX
,nY
));
5461 rEntry
.nField
= nCol1
;
5462 BOOL bFound
= FALSE
;
5466 rEntry
.eOp
= SC_LESS_EQUAL
;
5469 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
5470 // advance Entry.nField in Iterator upon switching columns
5471 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
5475 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow1_temp
);
5477 else if ( aCellIter
.GetFirst() )
5480 nCol
= aCellIter
.GetCol();
5486 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
5487 bFound
= LookupQueryWithCache( aResultPos
, rParam
);
5488 nRow
= aResultPos
.Row();
5493 ScAddress
aAdr( nCol
, nRow
, nTab1
);
5494 PushCellResultToken( true, aAdr
, NULL
, NULL
);
5501 PushIllegalParameter();
5505 bool ScInterpreter::FillEntry(ScQueryEntry
& rEntry
)
5507 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::FillEntry" );
5508 switch ( GetStackType() )
5512 rEntry
.bQueryByString
= FALSE
;
5513 rEntry
.nVal
= GetDouble();
5518 const String sStr
= GetString();
5519 rEntry
.bQueryByString
= TRUE
;
5520 *rEntry
.pStr
= sStr
;
5527 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5532 ScBaseCell
* pCell
= GetCell( aAdr
);
5533 if (HasCellValueData(pCell
))
5535 rEntry
.bQueryByString
= FALSE
;
5536 rEntry
.nVal
= GetCellValue( aAdr
, pCell
);
5540 if ( GetCellType( pCell
) == CELLTYPE_NOTE
)
5542 rEntry
.bQueryByString
= FALSE
;
5548 GetCellString(sStr
, pCell
);
5549 rEntry
.bQueryByString
= TRUE
;
5550 *rEntry
.pStr
= sStr
;
5557 const ScMatValType nType
= GetDoubleOrStringFromMatrix(rEntry
.nVal
, *rEntry
.pStr
);
5558 rEntry
.bQueryByString
= ScMatrix::IsNonValueType( nType
);
5563 PushIllegalParameter();
5566 } // switch ( GetStackType() )
5569 void ScInterpreter::ScVLookup()
5571 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVLookup" );
5572 CalculateLookup(FALSE
);
5575 #if defined(WIN) && defined(MSC)
5576 #pragma optimize("",off)
5579 void ScInterpreter::ScSubTotal()
5581 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSubTotal" );
5582 BYTE nParamCount
= GetByte();
5583 if ( MustHaveParamCountMin( nParamCount
, 2 ) )
5585 // We must fish the 1st parameter deep from the stack! And push it on top.
5586 const FormulaToken
* p
= pStack
[ sp
- nParamCount
];
5587 PushTempToken( *p
);
5588 int nFunc
= (int) ::rtl::math::approxFloor( GetDouble() );
5589 if( nFunc
< 1 || nFunc
> 11 )
5590 PushIllegalArgument(); // simulate return on stack, not SetError(...)
5593 cPar
= nParamCount
- 1;
5597 case SUBTOTAL_FUNC_AVE
: ScAverage(); break;
5598 case SUBTOTAL_FUNC_CNT
: ScCount(); break;
5599 case SUBTOTAL_FUNC_CNT2
: ScCount2(); break;
5600 case SUBTOTAL_FUNC_MAX
: ScMax(); break;
5601 case SUBTOTAL_FUNC_MIN
: ScMin(); break;
5602 case SUBTOTAL_FUNC_PROD
: ScProduct(); break;
5603 case SUBTOTAL_FUNC_STD
: ScStDev(); break;
5604 case SUBTOTAL_FUNC_STDP
: ScStDevP(); break;
5605 case SUBTOTAL_FUNC_SUM
: ScSum(); break;
5606 case SUBTOTAL_FUNC_VAR
: ScVar(); break;
5607 case SUBTOTAL_FUNC_VARP
: ScVarP(); break;
5608 default : PushIllegalArgument(); break;
5612 // Get rid of the 1st (fished) parameter.
5613 double nVal
= GetDouble();
5618 #if defined(WIN) && defined(MSC)
5619 #pragma optimize("",on)
5623 BOOL
ScInterpreter::GetDBParams(SCTAB
& rTab
, ScQueryParam
& rParam
,
5624 BOOL
& rMissingField
)
5626 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDBParams" );
5628 BOOL bAllowMissingField
= FALSE
;
5629 if ( rMissingField
)
5631 bAllowMissingField
= TRUE
;
5632 rMissingField
= FALSE
;
5634 if ( GetByte() == 3 )
5643 PopDoubleRef(nQCol1
, nQRow1
, nQTab1
, nQCol2
, nQRow2
, nQTab2
);
5648 ScRange aMissingRange
;
5649 BOOL bRangeFake
= FALSE
;
5650 switch (GetStackType())
5653 nVal
= ::rtl::math::approxFloor( GetDouble() );
5654 if ( bAllowMissingField
&& nVal
== 0.0 )
5655 rMissingField
= TRUE
; // fake missing parameter
5664 PopSingleRef( aAdr
);
5665 ScBaseCell
* pCell
= GetCell( aAdr
);
5666 if (HasCellValueData(pCell
))
5667 nVal
= GetCellValue( aAdr
, pCell
);
5671 GetCellString(aStr
, pCell
);
5676 if ( bAllowMissingField
)
5677 { // fake missing parameter for old SO compatibility
5679 PopDoubleRef( aMissingRange
);
5684 SetError( errIllegalParameter
);
5689 if ( bAllowMissingField
)
5690 rMissingField
= TRUE
;
5692 SetError( errIllegalParameter
);
5696 SetError( errIllegalParameter
);
5705 PopDoubleRef(nDBCol1
, nDBRow1
, nDBTab1
, nDBCol2
, nDBRow2
, nDBTab2
);
5707 if ( nGlobalError
== 0 && bRangeFake
)
5709 // range parameter must match entire database range
5710 if ( aMissingRange
== ScRange( nDBCol1
, nDBRow1
, nDBTab1
, nDBCol2
,
5712 rMissingField
= TRUE
;
5714 SetError( errIllegalParameter
);
5717 if (nGlobalError
== 0)
5719 SCCOL nField
= nDBCol1
;
5721 if ( rMissingField
)
5725 if ( nVal
<= 0 || nVal
> (nDBCol2
- nDBCol1
+ 1) )
5728 nField
= Min(nDBCol2
, (SCCOL
)(nDBCol1
+ (SCCOL
)nVal
- 1));
5734 ScAddress
aLook( nDBCol1
, nDBRow1
, nDBTab1
);
5735 while (!bFound
&& (aLook
.Col() <= nDBCol2
))
5737 ScBaseCell
* pCell
= GetCell( aLook
);
5738 GetCellString( aCellStr
, pCell
);
5739 bFound
= ScGlobal::pTransliteration
->isEqual( aCellStr
, aStr
);
5743 nField
= aLook
.Col();
5747 rParam
.nCol1
= nDBCol1
;
5748 rParam
.nRow1
= nDBRow1
;
5749 rParam
.nCol2
= nDBCol2
;
5750 rParam
.nRow2
= nDBRow2
;
5751 rParam
.nTab
= nDBTab1
;
5752 rParam
.bHasHeader
= TRUE
;
5753 rParam
.bByRow
= TRUE
;
5754 rParam
.bInplace
= TRUE
;
5755 rParam
.bCaseSens
= FALSE
;
5756 rParam
.bRegExp
= FALSE
;
5757 rParam
.bDuplicate
= TRUE
;
5758 if (pDok
->CreateQueryParam(nQCol1
, nQRow1
, nQCol2
, nQRow2
, nQTab1
, rParam
))
5760 // An allowed missing field parameter sets the result field
5761 // to any of the query fields, just to be able to return
5762 // some cell from the iterator.
5763 if ( rMissingField
)
5764 nField
= static_cast<SCCOL
>(rParam
.GetEntry(0).nField
);
5766 rParam
.nCol1
= nField
;
5767 rParam
.nCol2
= nField
;
5770 SCSIZE nCount
= rParam
.GetEntryCount();
5771 for ( SCSIZE i
=0; i
< nCount
; i
++ )
5773 ScQueryEntry
& rEntry
= rParam
.GetEntry(i
);
5774 if ( rEntry
.bDoQuery
)
5776 sal_uInt32 nIndex
= 0;
5777 rEntry
.bQueryByString
= !pFormatter
->IsNumberFormat(
5778 *rEntry
.pStr
, nIndex
, rEntry
.nVal
);
5779 if ( rEntry
.bQueryByString
&& !rParam
.bRegExp
)
5780 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5793 void ScInterpreter::DBIterator( ScIterFunc eFunc
)
5795 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::DBIterator" );
5801 ScQueryParam aQueryParam
;
5802 BOOL bMissingField
= FALSE
;
5803 if ( GetDBParams( nTab1
, aQueryParam
, bMissingField
) )
5807 ScQueryValueIterator
aValIter(pDok
, nTab1
, aQueryParam
);
5808 if ( aValIter
.GetFirst(nVal
, nErr
) && !nErr
)
5812 case ifPRODUCT
: nErg
= 1; break;
5813 case ifMAX
: nErg
= -MAXDOUBLE
; break;
5814 case ifMIN
: nErg
= MAXDOUBLE
; break;
5815 default: ; // nothing
5824 if ( bNull
&& nVal
!= 0.0 )
5832 case ifSUMSQ
: nErg
+= nVal
* nVal
; break;
5833 case ifPRODUCT
: nErg
*= nVal
; break;
5834 case ifMAX
: if( nVal
> nErg
) nErg
= nVal
; break;
5835 case ifMIN
: if( nVal
< nErg
) nErg
= nVal
; break;
5836 default: ; // nothing
5839 while ( aValIter
.GetNext(nVal
, nErr
) && !nErr
);
5844 SetError( errIllegalParameter
);
5847 case ifCOUNT
: nErg
= nCount
; break;
5848 case ifSUM
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
); break;
5849 case ifAVERAGE
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
) / nCount
; break;
5850 default: ; // nothing
5856 void ScInterpreter::ScDBSum()
5858 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBSum" );
5859 DBIterator( ifSUM
);
5863 void ScInterpreter::ScDBCount()
5865 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBCount" );
5867 ScQueryParam aQueryParam
;
5868 BOOL bMissingField
= TRUE
;
5869 if ( GetDBParams( nTab
, aQueryParam
, bMissingField
) )
5872 if ( bMissingField
)
5873 { // count all matching records
5874 // TODO: currently the QueryIterators only return cell pointers of
5875 // existing cells, so if a query matches an empty cell there's
5876 // nothing returned, and therefor not counted!
5877 // Since this has ever been the case and this code here only came
5878 // into existance to fix #i6899 and it never worked before we'll
5879 // have to live with it until we reimplement the iterators to also
5880 // return empty cells, which would mean to adapt all callers of
5882 ScQueryCellIterator
aCellIter( pDok
, nTab
, aQueryParam
);
5883 if ( aCellIter
.GetFirst() )
5888 } while ( aCellIter
.GetNext() );
5892 { // count only matching records with a value in the "result" field
5895 ScQueryValueIterator
aValIter( pDok
, nTab
, aQueryParam
);
5896 if ( aValIter
.GetFirst( nVal
, nErr
) && !nErr
)
5901 } while ( aValIter
.GetNext( nVal
, nErr
) && !nErr
);
5905 PushDouble( nCount
);
5908 PushIllegalParameter();
5912 void ScInterpreter::ScDBCount2()
5914 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBCount2" );
5916 ScQueryParam aQueryParam
;
5917 BOOL bMissingField
= TRUE
;
5918 if (GetDBParams( nTab
, aQueryParam
, bMissingField
))
5921 ScQueryCellIterator
aCellIter(pDok
, nTab
, aQueryParam
);
5922 if ( aCellIter
.GetFirst() )
5927 } while ( aCellIter
.GetNext() );
5932 PushIllegalParameter();
5936 void ScInterpreter::ScDBAverage()
5938 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBAverage" );
5939 DBIterator( ifAVERAGE
);
5943 void ScInterpreter::ScDBMax()
5945 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBMax" );
5946 DBIterator( ifMAX
);
5950 void ScInterpreter::ScDBMin()
5952 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBMin" );
5953 DBIterator( ifMIN
);
5957 void ScInterpreter::ScDBProduct()
5959 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBProduct" );
5960 DBIterator( ifPRODUCT
);
5964 void ScInterpreter::GetDBStVarParams( double& rVal
, double& rValCount
)
5966 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDBStVarParams" );
5967 std::vector
<double> values
;
5974 ScQueryParam aQueryParam
;
5975 BOOL bMissingField
= FALSE
;
5976 if (GetDBParams( nTab
, aQueryParam
, bMissingField
))
5980 ScQueryValueIterator
aValIter(pDok
, nTab
, aQueryParam
);
5981 if (aValIter
.GetFirst(fVal
, nErr
) && !nErr
)
5986 values
.push_back(fVal
);
5989 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
5994 SetError( errIllegalParameter
);
5996 vMean
= fSum
/ values
.size();
5998 for (size_t i
= 0; i
< values
.size(); i
++)
5999 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
6005 void ScInterpreter::ScDBStdDev()
6007 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBStdDev" );
6008 double fVal
, fCount
;
6009 GetDBStVarParams( fVal
, fCount
);
6010 PushDouble( sqrt(fVal
/(fCount
-1)));
6014 void ScInterpreter::ScDBStdDevP()
6016 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBStdDevP" );
6017 double fVal
, fCount
;
6018 GetDBStVarParams( fVal
, fCount
);
6019 PushDouble( sqrt(fVal
/fCount
));
6023 void ScInterpreter::ScDBVar()
6025 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBVar" );
6026 double fVal
, fCount
;
6027 GetDBStVarParams( fVal
, fCount
);
6028 PushDouble(fVal
/(fCount
-1));
6032 void ScInterpreter::ScDBVarP()
6034 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBVarP" );
6035 double fVal
, fCount
;
6036 GetDBStVarParams( fVal
, fCount
);
6037 PushDouble(fVal
/fCount
);
6041 ScTokenArray
* lcl_CreateExternalRefTokenArray( const ScAddress
& rPos
, ScDocument
* pDoc
,
6042 const ScAddress::ExternalInfo
& rExtInfo
, const ScRefAddress
& rRefAd1
,
6043 const ScRefAddress
* pRefAd2
)
6045 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
6047 const String
* pRealTab
= pRefMgr
->getRealTableName( rExtInfo
.mnFileId
, rExtInfo
.maTabName
);
6048 ScTokenArray
* pTokenArray
= new ScTokenArray
;
6051 ScComplexRefData aRef
;
6052 aRef
.InitRangeRel( ScRange( rRefAd1
.GetAddress(), pRefAd2
->GetAddress()), rPos
);
6053 aRef
.Ref1
.SetColRel( rRefAd1
.IsRelCol());
6054 aRef
.Ref1
.SetRowRel( rRefAd1
.IsRelRow());
6055 aRef
.Ref1
.SetTabRel( rRefAd1
.IsRelTab());
6056 aRef
.Ref1
.SetFlag3D( true);
6057 aRef
.Ref2
.SetColRel( pRefAd2
->IsRelCol());
6058 aRef
.Ref2
.SetRowRel( pRefAd2
->IsRelRow());
6059 aRef
.Ref2
.SetTabRel( pRefAd2
->IsRelTab());
6060 nSheets
= aRef
.Ref2
.nTab
- aRef
.Ref1
.nTab
+ 1;
6061 aRef
.Ref2
.SetFlag3D( nSheets
> 1 );
6062 pTokenArray
->AddExternalDoubleReference( rExtInfo
.mnFileId
,
6063 (pRealTab
? *pRealTab
: rExtInfo
.maTabName
), aRef
);
6067 ScSingleRefData aRef
;
6068 aRef
.InitAddressRel( rRefAd1
.GetAddress(), rPos
);
6069 aRef
.SetColRel( rRefAd1
.IsRelCol());
6070 aRef
.SetRowRel( rRefAd1
.IsRelRow());
6071 aRef
.SetTabRel( rRefAd1
.IsRelTab());
6072 aRef
.SetFlag3D( true);
6073 pTokenArray
->AddExternalSingleReference( rExtInfo
.mnFileId
,
6074 (pRealTab
? *pRealTab
: rExtInfo
.maTabName
), aRef
);
6076 // The indirect usage of the external table can't be detected during the
6077 // store-to-file cycle, mark it as permanently referenced so it gets stored
6078 // even if not directly referenced anywhere.
6079 pRefMgr
->setCacheTableReferencedPermanently( rExtInfo
.mnFileId
,
6080 rExtInfo
.maTabName
, nSheets
);
6081 ScCompiler
aComp( pDoc
, rPos
, *pTokenArray
);
6082 aComp
.CompileTokenArray();
6087 void ScInterpreter::ScIndirect()
6089 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndirect" );
6090 BYTE nParamCount
= GetByte();
6091 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6093 bool bTryXlA1
= true; // whether to try XL_A1 style as well.
6094 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
;
6095 if (nParamCount
== 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
6097 eConv
= FormulaGrammar::CONV_XL_R1C1
;
6100 const ScAddress::Details
aDetails( eConv
, aPos
);
6101 const ScAddress::Details
aDetailsXlA1( FormulaGrammar::CONV_XL_A1
, aPos
);
6102 SCTAB nTab
= aPos
.Tab();
6103 String
sRefStr( GetString() );
6104 ScRefAddress aRefAd
, aRefAd2
;
6105 ScAddress::ExternalInfo aExtInfo
;
6106 if ( ConvertDoubleRef( pDok
, sRefStr
, nTab
, aRefAd
, aRefAd2
, aDetails
, &aExtInfo
) ||
6107 (bTryXlA1
&& ConvertDoubleRef( pDok
, sRefStr
, nTab
, aRefAd
,
6108 aRefAd2
, aDetailsXlA1
, &aExtInfo
)))
6110 if (aExtInfo
.mbExternal
)
6112 /* TODO: future versions should implement a proper subroutine
6113 * token. This procedure here is a minimally invasive fix for
6114 * #i101645# in OOo3.1.1 */
6115 // Push a subroutine on the instruction code stack that
6116 // resolves the external reference as the next instruction.
6117 aCode
.Push( lcl_CreateExternalRefTokenArray( aPos
, pDok
,
6118 aExtInfo
, aRefAd
, &aRefAd2
));
6119 // Signal subroutine call to interpreter.
6120 PushTempToken( new FormulaUnknownToken( ocCall
));
6123 PushDoubleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab(),
6124 aRefAd2
.Col(), aRefAd2
.Row(), aRefAd2
.Tab() );
6126 else if ( ConvertSingleRef ( pDok
, sRefStr
, nTab
, aRefAd
, aDetails
, &aExtInfo
) ||
6127 (bTryXlA1
&& ConvertSingleRef ( pDok
, sRefStr
, nTab
, aRefAd
,
6128 aDetailsXlA1
, &aExtInfo
)))
6130 if (aExtInfo
.mbExternal
)
6132 /* TODO: future versions should implement a proper subroutine
6133 * token. This procedure here is a minimally invasive fix for
6134 * #i101645# in OOo3.1.1 */
6135 // Push a subroutine on the instruction code stack that
6136 // resolves the external reference as the next instruction.
6137 aCode
.Push( lcl_CreateExternalRefTokenArray( aPos
, pDok
,
6138 aExtInfo
, aRefAd
, NULL
));
6139 // Signal subroutine call to interpreter.
6140 PushTempToken( new FormulaUnknownToken( ocCall
));
6143 PushSingleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab() );
6149 ScRangeName
* pNames
= pDok
->GetRangeName();
6154 if (!pNames
->SearchName( sRefStr
, nPos
))
6157 ScRangeData
* rData
= (*pNames
)[nPos
];
6161 // We need this in order to obtain a good range.
6162 rData
->ValidateTabRefs();
6166 // This is some really odd Excel behavior and renders named
6167 // ranges containing relative references totally useless.
6168 if (!rData
->IsReference(aRange
, ScAddress( aPos
.Tab(), 0, 0)))
6171 // This is the usual way to treat named ranges containing
6172 // relative references.
6173 if (!rData
->IsReference( aRange
, aPos
))
6177 if (aRange
.aStart
== aRange
.aEnd
)
6178 PushSingleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
6179 aRange
.aStart
.Tab());
6181 PushDoubleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
6182 aRange
.aStart
.Tab(), aRange
.aEnd
.Col(),
6183 aRange
.aEnd
.Row(), aRange
.aEnd
.Tab());
6190 PushIllegalArgument();
6196 void ScInterpreter::ScAddressFunc()
6198 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAddressFunc" );
6201 BYTE nParamCount
= GetByte();
6202 if( !MustHaveParamCount( nParamCount
, 2, 5 ) )
6205 if( nParamCount
>= 5 )
6206 sTabStr
= GetString();
6208 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
; // default
6209 if( nParamCount
>= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
6210 eConv
= FormulaGrammar::CONV_XL_R1C1
;
6212 USHORT nFlags
= SCA_COL_ABSOLUTE
| SCA_ROW_ABSOLUTE
; // default
6213 if( nParamCount
>= 3 )
6215 USHORT n
= (USHORT
) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
6223 case 1 : break; // default
6225 case 2 : nFlags
= SCA_ROW_ABSOLUTE
; break;
6227 case 3 : nFlags
= SCA_COL_ABSOLUTE
; break;
6229 case 4 : nFlags
= 0; break; // both relative
6232 nFlags
|= SCA_VALID
| SCA_VALID_ROW
| SCA_VALID_COL
;
6234 SCCOL nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
6235 SCROW nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
6236 if( eConv
== FormulaGrammar::CONV_XL_R1C1
)
6238 // YUCK! The XL interface actually treats rel R1C1 refs differently
6240 if( !(nFlags
& SCA_COL_ABSOLUTE
) )
6241 nCol
+= aPos
.Col() + 1;
6242 if( !(nFlags
& SCA_ROW_ABSOLUTE
) )
6243 nRow
+= aPos
.Row() + 1;
6248 if(!ValidCol( nCol
) || !ValidRow( nRow
))
6250 PushIllegalArgument();
6255 const ScAddress::Details
aDetails( eConv
, aPos
);
6256 const ScAddress
aAdr( nCol
, nRow
, 0);
6257 aAdr
.Format( aRefStr
, nFlags
, pDok
, aDetails
);
6259 if( nParamCount
>= 5 )
6261 ScCompiler::CheckTabQuotes( sTabStr
, eConv
);
6262 sTabStr
+= static_cast<sal_Unicode
>(eConv
== FormulaGrammar::CONV_XL_R1C1
? '!' : '.');
6264 PushString( sTabStr
);
6267 PushString( aRefStr
);
6271 void ScInterpreter::ScOffset()
6273 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOffset" );
6274 BYTE nParamCount
= GetByte();
6275 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
6277 long nColNew
= -1, nRowNew
= -1, nColPlus
, nRowPlus
;
6278 if (nParamCount
== 5)
6279 nColNew
= (long) ::rtl::math::approxFloor(GetDouble());
6280 if (nParamCount
>= 4)
6281 nRowNew
= (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
6282 nColPlus
= (long) ::rtl::math::approxFloor(GetDouble());
6283 nRowPlus
= (long) ::rtl::math::approxFloor(GetDouble());
6290 if (nColNew
== 0 || nRowNew
== 0)
6292 PushIllegalArgument();
6295 if (GetStackType() == svSingleRef
)
6297 PopSingleRef(nCol1
, nRow1
, nTab1
);
6298 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
6300 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
6301 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
6302 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
6303 PushIllegalArgument();
6305 PushSingleRef(nCol1
, nRow1
, nTab1
);
6313 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
); // ! nCol1 wird veraendert!
6314 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
6315 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
6316 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
6317 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
6318 !ValidCol(nCol2
) || !ValidRow(nRow2
))
6319 PushIllegalArgument();
6321 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6324 else if (GetStackType() == svDoubleRef
)
6326 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6328 nColNew
= nCol2
- nCol1
+ 1;
6330 nRowNew
= nRow2
- nRow1
+ 1;
6331 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
6332 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
6333 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
6334 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
6335 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
6336 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
6337 PushIllegalArgument();
6339 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6342 PushIllegalParameter();
6347 void ScInterpreter::ScIndex()
6349 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndex" );
6350 BYTE nParamCount
= GetByte();
6351 if ( MustHaveParamCount( nParamCount
, 1, 4 ) )
6357 if (nParamCount
== 4)
6358 nArea
= (long) ::rtl::math::approxFloor(GetDouble());
6361 if (nParamCount
>= 3)
6362 nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
6365 if (nParamCount
>= 2)
6366 nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
6369 if (GetStackType() == svRefList
)
6370 nAreaCount
= (sp
? static_cast<ScToken
*>(pStack
[sp
-1])->GetRefList()->size() : 0);
6372 nAreaCount
= 1; // one reference or array or whatever
6373 if (nAreaCount
== 0 || (size_t)nArea
> nAreaCount
)
6375 PushError( errNoRef
);
6378 else if (nArea
< 1 || nCol
< 0 || nRow
< 0)
6380 PushIllegalArgument();
6383 switch (GetStackType())
6388 SetError(errIllegalArgument
);
6390 ScMatrixRef pMat
= GetMatrix();
6394 pMat
->GetDimensions(nC
, nR
);
6395 // Access one element of a vector independent of col/row
6397 bool bVector
= ((nCol
== 0 || nRow
== 0) && (nC
== 1 || nR
== 1));
6398 SCSIZE nElement
= ::std::max( static_cast<SCSIZE
>(nCol
),
6399 static_cast<SCSIZE
>(nRow
));
6400 if (nC
== 0 || nR
== 0 ||
6401 (!bVector
&& (static_cast<SCSIZE
>(nCol
) > nC
||
6402 static_cast<SCSIZE
>(nRow
) > nR
)) ||
6403 (bVector
&& nElement
> nC
* nR
))
6404 PushIllegalArgument();
6405 else if (nCol
== 0 && nRow
== 0)
6410 if (pMat
->IsString( nElement
))
6411 PushString( pMat
->GetString( nElement
));
6413 PushDouble( pMat
->GetDouble( nElement
));
6417 ScMatrixRef pResMat
= GetNewMat(nC
, 1);
6420 SCSIZE nRowMinus1
= static_cast<SCSIZE
>(nRow
- 1);
6421 for (SCSIZE i
= 0; i
< nC
; i
++)
6422 if (!pMat
->IsString(i
, nRowMinus1
))
6423 pResMat
->PutDouble(pMat
->GetDouble(i
,
6426 pResMat
->PutString(pMat
->GetString(i
,
6428 PushMatrix(pResMat
);
6431 PushIllegalArgument();
6435 ScMatrixRef pResMat
= GetNewMat(1, nR
);
6438 SCSIZE nColMinus1
= static_cast<SCSIZE
>(nCol
- 1);
6439 for (SCSIZE i
= 0; i
< nR
; i
++)
6440 if (!pMat
->IsString(nColMinus1
, i
))
6441 pResMat
->PutDouble(pMat
->GetDouble(nColMinus1
,
6444 pResMat
->PutString(pMat
->GetString(nColMinus1
,
6446 PushMatrix(pResMat
);
6449 PushIllegalArgument();
6453 if (!pMat
->IsString( static_cast<SCSIZE
>(nCol
-1),
6454 static_cast<SCSIZE
>(nRow
-1)))
6455 PushDouble( pMat
->GetDouble(
6456 static_cast<SCSIZE
>(nCol
-1),
6457 static_cast<SCSIZE
>(nRow
-1)));
6459 PushString( pMat
->GetString(
6460 static_cast<SCSIZE
>(nCol
-1),
6461 static_cast<SCSIZE
>(nRow
-1)));
6471 PopSingleRef( nCol1
, nRow1
, nTab1
);
6472 if (nCol
> 1 || nRow
> 1)
6473 PushIllegalArgument();
6475 PushSingleRef( nCol1
, nRow1
, nTab1
);
6487 BOOL bRowArray
= FALSE
;
6488 if (GetStackType() == svRefList
)
6490 FormulaTokenRef xRef
= PopToken();
6491 if (nGlobalError
|| !xRef
)
6493 PushIllegalParameter();
6496 ScRange
aRange( ScAddress::UNINITIALIZED
);
6497 DoubleRefToRange( (*(static_cast<ScToken
*>(xRef
.get())->GetRefList()))[nArea
-1], aRange
);
6498 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6499 if ( nParamCount
== 2 && nRow1
== nRow2
)
6504 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6505 if ( nParamCount
== 2 && nRow1
== nRow2
)
6508 if ( nTab1
!= nTab2
||
6509 (nCol
> 0 && nCol1
+nCol
-1 > nCol2
) ||
6510 (nRow
> 0 && nRow1
+nRow
-1 > nRow2
&& !bRowArray
) ||
6511 ( nRow
> nCol2
- nCol1
+ 1 && bRowArray
))
6512 PushIllegalArgument();
6513 else if (nCol
== 0 && nRow
== 0)
6515 if ( nCol1
== nCol2
&& nRow1
== nRow2
)
6516 PushSingleRef( nCol1
, nRow1
, nTab1
);
6518 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6522 if ( nRow1
== nRow2
)
6523 PushSingleRef( nCol1
+nCol
-1, nRow1
, nTab1
);
6525 PushDoubleRef( nCol1
+nCol
-1, nRow1
, nTab1
,
6526 nCol1
+nCol
-1, nRow2
, nTab1
);
6530 if ( nCol1
== nCol2
)
6531 PushSingleRef( nCol1
, nRow1
+nRow
-1, nTab1
);
6532 else if ( bRowArray
)
6536 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
6539 PushDoubleRef( nCol1
, nRow1
+nRow
-1, nTab1
,
6540 nCol2
, nRow1
+nRow
-1, nTab1
);
6543 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
6547 PushIllegalParameter();
6553 void ScInterpreter::ScMultiArea()
6555 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMultiArea" );
6556 // Legacy support, convert to RefList
6557 BYTE nParamCount
= GetByte();
6558 if (MustHaveParamCountMin( nParamCount
, 1))
6560 while (!nGlobalError
&& nParamCount
-- > 1)
6568 void ScInterpreter::ScAreas()
6570 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAreas" );
6571 BYTE nParamCount
= GetByte();
6572 if (MustHaveParamCount( nParamCount
, 1))
6575 switch (GetStackType())
6579 FormulaTokenRef xT
= PopToken();
6580 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetSingleRef());
6586 FormulaTokenRef xT
= PopToken();
6587 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetDoubleRef());
6593 FormulaTokenRef xT
= PopToken();
6594 ValidateRef( *(static_cast<ScToken
*>(xT
.get())->GetRefList()));
6595 nCount
+= static_cast<ScToken
*>(xT
.get())->GetRefList()->size();
6599 SetError( errIllegalParameter
);
6601 PushDouble( double(nCount
));
6606 void ScInterpreter::ScCurrency()
6608 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCurrency" );
6609 BYTE nParamCount
= GetByte();
6610 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6614 if (nParamCount
== 2)
6616 fDec
= ::rtl::math::approxFloor(GetDouble());
6617 if (fDec
< -15.0 || fDec
> 15.0)
6619 PushIllegalArgument();
6625 double fVal
= GetDouble();
6628 fFac
= pow( (double)10, fDec
);
6632 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
6634 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
6635 Color
* pColor
= NULL
;
6638 ULONG nIndex
= pFormatter
->GetStandardFormat(
6639 NUMBERFORMAT_CURRENCY
,
6641 if ( (USHORT
) fDec
!= pFormatter
->GetFormatPrecision( nIndex
) )
6643 String sFormatString
;
6644 pFormatter
->GenerateFormat(sFormatString
,
6647 TRUE
, // mit Tausenderpunkt
6649 (USHORT
) fDec
,// Nachkommastellen
6650 1); // 1 Vorkommanull
6651 if (!pFormatter
->GetPreviewString(sFormatString
,
6656 SetError(errIllegalArgument
);
6660 pFormatter
->GetOutputString(fVal
, nIndex
, aStr
, &pColor
);
6667 void ScInterpreter::ScReplace()
6669 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScReplace" );
6670 if ( MustHaveParamCount( GetByte(), 4 ) )
6672 String
aNewStr( GetString() );
6673 short nCount
= (short) GetDouble();
6674 short nPos
= (short) GetDouble();
6675 String
aOldStr( GetString() );
6676 if( nPos
< 1 || nCount
< 1 )
6677 PushIllegalArgument();
6680 aOldStr
.Erase( nPos
-1, nCount
);
6681 if ( CheckStringResultLen( aOldStr
, aNewStr
) )
6682 aOldStr
.Insert( aNewStr
, nPos
-1 );
6683 PushString( aOldStr
);
6689 void ScInterpreter::ScFixed()
6691 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFixed" );
6692 BYTE nParamCount
= GetByte();
6693 if ( MustHaveParamCount( nParamCount
, 1, 3 ) )
6698 if (nParamCount
== 3)
6699 bThousand
= !GetBool(); // Param TRUE: keine Tausenderpunkte
6702 if (nParamCount
>= 2)
6704 fDec
= ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
6705 if (fDec
< -15.0 || fDec
> 15.0)
6707 PushIllegalArgument();
6713 double fVal
= GetDouble();
6716 fFac
= pow( (double)10, fDec
);
6720 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
6722 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
6723 Color
* pColor
= NULL
;
6724 String sFormatString
;
6727 ULONG nIndex
= pFormatter
->GetStandardFormat(
6728 NUMBERFORMAT_NUMBER
,
6730 pFormatter
->GenerateFormat(sFormatString
,
6733 bThousand
, // mit Tausenderpunkt
6735 (USHORT
) fDec
,// Nachkommastellen
6736 1); // 1 Vorkommanull
6737 if (!pFormatter
->GetPreviewString(sFormatString
,
6742 PushIllegalArgument();
6749 void ScInterpreter::ScFind()
6751 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFind" );
6752 BYTE nParamCount
= GetByte();
6753 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
6756 if (nParamCount
== 3)
6760 String sStr
= GetString();
6761 if( fAnz
< 1.0 || fAnz
> (double) sStr
.Len() )
6765 xub_StrLen nPos
= sStr
.Search( GetString(), (xub_StrLen
) fAnz
- 1 );
6766 if (nPos
== STRING_NOTFOUND
)
6769 PushDouble((double)(nPos
+ 1));
6775 void ScInterpreter::ScExact()
6777 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExact" );
6778 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
6779 if ( MustHaveParamCount( GetByte(), 2 ) )
6781 String
s1( GetString() );
6782 String
s2( GetString() );
6783 PushInt( s1
== s2
);
6788 void ScInterpreter::ScLeft()
6790 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLeft" );
6791 BYTE nParamCount
= GetByte();
6792 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6795 if (nParamCount
== 2)
6797 double nVal
= ::rtl::math::approxFloor(GetDouble());
6798 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
6800 PushIllegalArgument();
6804 n
= (xub_StrLen
) nVal
;
6808 String
aStr( GetString() );
6815 void ScInterpreter::ScRight()
6817 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRight" );
6818 BYTE nParamCount
= GetByte();
6819 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6822 if (nParamCount
== 2)
6824 double nVal
= ::rtl::math::approxFloor(GetDouble());
6825 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
6827 PushIllegalArgument();
6831 n
= (xub_StrLen
) nVal
;
6835 String
aStr( GetString() );
6836 if( n
< aStr
.Len() )
6837 aStr
.Erase( 0, aStr
.Len() - n
);
6843 void ScInterpreter::ScSearch()
6845 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSearch" );
6847 BYTE nParamCount
= GetByte();
6848 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
6850 if (nParamCount
== 3)
6852 fAnz
= ::rtl::math::approxFloor(GetDouble());
6853 if (fAnz
> double(STRING_MAXLEN
))
6855 PushIllegalArgument();
6861 String sStr
= GetString();
6862 String SearchStr
= GetString();
6863 xub_StrLen nPos
= (xub_StrLen
) fAnz
- 1;
6864 xub_StrLen nEndPos
= sStr
.Len();
6865 if( nPos
>= nEndPos
)
6869 utl::SearchParam::SearchType eSearchType
=
6870 (MayBeRegExp( SearchStr
, pDok
) ?
6871 utl::SearchParam::SRCH_REGEXP
: utl::SearchParam::SRCH_NORMAL
);
6872 utl::SearchParam
sPar(SearchStr
, eSearchType
, FALSE
, FALSE
, FALSE
);
6873 utl::TextSearch
sT( sPar
, *ScGlobal::pCharClass
);
6874 int nBool
= sT
.SearchFrwrd(sStr
, &nPos
, &nEndPos
);
6878 PushDouble((double)(nPos
) + 1);
6884 void ScInterpreter::ScMid()
6886 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMid" );
6887 if ( MustHaveParamCount( GetByte(), 3 ) )
6889 double fAnz
= ::rtl::math::approxFloor(GetDouble());
6890 double fAnfang
= ::rtl::math::approxFloor(GetDouble());
6891 const String
& rStr
= GetString();
6892 if (fAnfang
< 1.0 || fAnz
< 0.0 || fAnfang
> double(STRING_MAXLEN
) || fAnz
> double(STRING_MAXLEN
))
6893 PushIllegalArgument();
6895 PushString(rStr
.Copy( (xub_StrLen
) fAnfang
- 1, (xub_StrLen
) fAnz
));
6900 void ScInterpreter::ScText()
6902 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScText" );
6903 if ( MustHaveParamCount( GetByte(), 2 ) )
6905 String sFormatString
= GetString();
6906 double fVal
= GetDouble();
6908 Color
* pColor
= NULL
;
6909 LanguageType eCellLang
;
6910 const ScPatternAttr
* pPattern
= pDok
->GetPattern(
6911 aPos
.Col(), aPos
.Row(), aPos
.Tab() );
6913 eCellLang
= ((const SvxLanguageItem
&)
6914 pPattern
->GetItem( ATTR_LANGUAGE_FORMAT
)).GetValue();
6916 eCellLang
= ScGlobal::eLnge
;
6917 if ( !pFormatter
->GetPreviewStringGuess( sFormatString
, fVal
, aStr
,
6918 &pColor
, eCellLang
) )
6919 PushIllegalArgument();
6926 void ScInterpreter::ScSubstitute()
6928 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSubstitute" );
6929 BYTE nParamCount
= GetByte();
6930 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
6933 if (nParamCount
== 4)
6935 double fAnz
= ::rtl::math::approxFloor(GetDouble());
6936 if( fAnz
< 1 || fAnz
> STRING_MAXLEN
)
6938 PushIllegalArgument();
6942 nAnz
= (xub_StrLen
) fAnz
;
6946 String sNewStr
= GetString();
6947 String sOldStr
= GetString();
6948 String sStr
= GetString();
6949 xub_StrLen nPos
= 0;
6950 xub_StrLen nCount
= 0;
6951 xub_StrLen nNewLen
= sNewStr
.Len();
6952 xub_StrLen nOldLen
= sOldStr
.Len();
6955 nPos
= sStr
.Search( sOldStr
, nPos
);
6956 if (nPos
!= STRING_NOTFOUND
)
6959 if( !nAnz
|| nCount
== nAnz
)
6961 sStr
.Erase(nPos
,nOldLen
);
6962 if ( CheckStringResultLen( sStr
, sNewStr
) )
6964 sStr
.Insert(sNewStr
,nPos
);
6965 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ nNewLen
);
6981 void ScInterpreter::ScRept()
6983 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRept" );
6984 if ( MustHaveParamCount( GetByte(), 2 ) )
6986 double fAnz
= ::rtl::math::approxFloor(GetDouble());
6987 String
aStr( GetString() );
6989 PushIllegalArgument();
6990 else if ( fAnz
* aStr
.Len() > STRING_MAXLEN
)
6992 PushError( errStringOverflow
);
6994 else if ( fAnz
== 0.0 )
6995 PushString( EMPTY_STRING
);
6998 xub_StrLen n
= (xub_StrLen
) fAnz
;
6999 const xub_StrLen nLen
= aStr
.Len();
7001 const sal_Unicode
* const pSrc
= aStr
.GetBuffer();
7002 sal_Unicode
* pDst
= aRes
.AllocBuffer( n
* nLen
);
7005 memcpy( pDst
, pSrc
, nLen
* sizeof(sal_Unicode
) );
7014 void ScInterpreter::ScConcat()
7016 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScConcat" );
7017 BYTE nParamCount
= GetByte();
7019 while( nParamCount
-- > 0)
7021 const String
& rStr
= GetString();
7022 aRes
.Insert( rStr
, 0 );
7028 void ScInterpreter::ScErrorType()
7030 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScErrorType" );
7032 USHORT nOldError
= nGlobalError
;
7034 switch ( GetStackType() )
7038 FormulaTokenRef x
= PopToken();
7040 nErr
= nGlobalError
;
7043 const ScRefList
* pRefList
= static_cast<ScToken
*>(x
.get())->GetRefList();
7044 size_t n
= pRefList
->size();
7052 DoubleRefToRange( (*pRefList
)[0], aRange
);
7054 nErr
= nGlobalError
;
7058 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
7059 nErr
= pDok
->GetErrCode( aAdr
);
7061 nErr
= nGlobalError
;
7070 PopDoubleRef( aRange
);
7072 nErr
= nGlobalError
;
7076 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
7077 nErr
= pDok
->GetErrCode( aAdr
);
7079 nErr
= nGlobalError
;
7086 PopSingleRef( aAdr
);
7088 nErr
= nGlobalError
;
7090 nErr
= pDok
->GetErrCode( aAdr
);
7095 nErr
= nGlobalError
;
7104 nGlobalError
= nOldError
;
7110 BOOL
ScInterpreter::MayBeRegExp( const String
& rStr
, const ScDocument
* pDoc
)
7112 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::MayBeRegExp" );
7113 if ( pDoc
&& !pDoc
->GetDocOptions().IsFormulaRegexEnabled() )
7115 if ( !rStr
.Len() || (rStr
.Len() == 1 && rStr
.GetChar(0) != '.') )
7116 return FALSE
; // einzelnes Metazeichen kann keine RegExp sein
7117 static const sal_Unicode cre
[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
7118 const sal_Unicode
* p1
= rStr
.GetBuffer();
7120 while ( ( c1
= *p1
++ ) != 0 )
7122 const sal_Unicode
* p2
= cre
;
7132 static bool lcl_LookupQuery( ScAddress
& o_rResultPos
, ScDocument
* pDoc
,
7133 const ScQueryParam
& rParam
, const ScQueryEntry
& rEntry
)
7135 bool bFound
= false;
7136 ScQueryCellIterator
aCellIter( pDoc
, rParam
.nTab
, rParam
, FALSE
);
7137 if (rEntry
.eOp
!= SC_EQUAL
)
7139 // range lookup <= or >=
7142 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow
);
7145 o_rResultPos
.SetCol( nCol
);
7146 o_rResultPos
.SetRow( nRow
);
7149 else if (aCellIter
.GetFirst())
7153 o_rResultPos
.SetCol( aCellIter
.GetCol());
7154 o_rResultPos
.SetRow( aCellIter
.GetRow());
7159 #define erDEBUG_LOOKUPCACHE 0
7160 #if erDEBUG_LOOKUPCACHE
7162 using ::std::fprintf
;
7163 using ::std::fflush
;
7164 static struct LookupCacheDebugCounter
7166 unsigned long nMiss
;
7168 LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
7169 ~LookupCacheDebugCounter()
7171 fprintf( stderr
, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
7172 nMiss
, nHit
, nHit
+nMiss
, (nMiss
>0 ? nHit
/nMiss
: 0),
7173 ((nHit
+nMiss
)>0 ? (100*nHit
)/(nHit
+nMiss
) : 0));
7176 } aLookupCacheDebugCounter
;
7179 bool ScInterpreter::LookupQueryWithCache( ScAddress
& o_rResultPos
,
7180 const ScQueryParam
& rParam
) const
7182 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::LookupQueryWithCache" );
7183 bool bFound
= false;
7184 const ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
7185 bool bColumnsMatch
= (rParam
.nCol1
== rEntry
.nField
);
7186 DBG_ASSERT( bColumnsMatch
, "ScInterpreter::LookupQueryWithCache: columns don't match");
7188 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
7191 ScRange
aLookupRange( rParam
.nCol1
, rParam
.nRow1
, rParam
.nTab
,
7192 rParam
.nCol2
, rParam
.nRow2
, rParam
.nTab
);
7193 ScLookupCache
& rCache
= pDok
->GetLookupCache( aLookupRange
);
7194 ScLookupCache::QueryCriteria
aCriteria( rEntry
);
7195 ScLookupCache::Result eCacheResult
= rCache
.lookup( o_rResultPos
,
7197 switch (eCacheResult
)
7199 case ScLookupCache::NOT_CACHED
:
7200 case ScLookupCache::CRITERIA_DIFFERENT
:
7201 #if erDEBUG_LOOKUPCACHE
7202 ++aLookupCacheDebugCounter
.nMiss
;
7203 #if erDEBUG_LOOKUPCACHE > 1
7204 fprintf( stderr
, "miss %d,%d,%d\n", (int)aPos
.Col(), (int)aPos
.Row(), (int)aPos
.Tab());
7207 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
7208 if (eCacheResult
== ScLookupCache::NOT_CACHED
)
7209 rCache
.insert( o_rResultPos
, aCriteria
, aPos
, bFound
);
7211 case ScLookupCache::FOUND
:
7212 #if erDEBUG_LOOKUPCACHE
7213 ++aLookupCacheDebugCounter
.nHit
;
7214 #if erDEBUG_LOOKUPCACHE > 1
7215 fprintf( stderr
, "hit %d,%d,%d\n", (int)aPos
.Col(), (int)aPos
.Row(), (int)aPos
.Tab());
7220 case ScLookupCache::NOT_AVAILABLE
:
7221 ; // nothing, bFound remains FALSE