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/ustring.hxx>
49 #include <rtl/logfile.hxx>
51 #include "interpre.hxx"
52 #include "patattr.hxx"
54 #include "document.hxx"
55 #include "dociter.hxx"
57 #include "scmatrix.hxx"
58 #include "docoptio.hxx"
59 #include "globstr.hrc"
61 #include "jumpmatrix.hxx"
63 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
64 #include <comphelper/processfactory.hxx>
72 #include "cellkeytranslator.hxx"
73 #include "lookupcache.hxx"
74 #include "rangenam.hxx"
75 #include "compiler.hxx"
76 #include "externalrefmgr.hxx"
77 #include <basic/sbstar.hxx>
78 #include "doubleref.hxx"
79 #include "queryparam.hxx"
81 #define SC_DOUBLE_MAXVALUE 1.7e307
83 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack
, 8, 4 )
84 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter
, 32, 16 )
86 ScTokenStack
* ScInterpreter::pGlobalStack
= NULL
;
87 BOOL
ScInterpreter::bGlobalStackInUse
= FALSE
;
89 using namespace formula
;
90 using ::std::auto_ptr
;
92 //-----------------------------------------------------------------------------
94 //-----------------------------------------------------------------------------
97 void ScInterpreter::ScIfJump()
99 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIfJump" );
100 const short* pJump
= pCur
->GetJump();
101 short nJumpCount
= pJump
[ 0 ];
102 MatrixDoubleRefToMatrix();
103 switch ( GetStackType() )
107 ScMatrixRef pMat
= PopMatrix();
109 PushIllegalParameter();
112 FormulaTokenRef xNew
;
113 ScTokenMatrixMap::const_iterator aMapIter
;
114 // DoubleError handled by JumpMatrix
115 pMat
->SetErrorInterpreter( NULL
);
117 pMat
->GetDimensions( nCols
, nRows
);
118 if ( nCols
== 0 || nRows
== 0 )
119 PushIllegalArgument();
120 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
121 pCur
)) != pTokenMatrixMap
->end()))
122 xNew
= (*aMapIter
).second
;
125 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
126 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
128 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
132 ScMatValType nType
= 0;
133 const ScMatrixValue
* pMatVal
= pMat
->Get( nC
, nR
,
135 bool bIsValue
= ScMatrix::IsValueType( nType
);
138 fVal
= pMatVal
->fVal
;
139 bIsValue
= ::rtl::math::isFinite( fVal
);
140 bTrue
= bIsValue
&& (fVal
!= 0.0);
146 // Treat empty and empty path as 0, but string
148 bIsValue
= !ScMatrix::IsRealStringType( nType
);
150 fVal
= (bIsValue
? 0.0 : CreateDoubleError( errNoValue
));
154 if( nJumpCount
>= 2 )
156 pJumpMat
->SetJump( nC
, nR
, fVal
,
158 pJump
[ nJumpCount
]);
161 { // no parameter given for THEN
162 pJumpMat
->SetJump( nC
, nR
, fVal
,
164 pJump
[ nJumpCount
]);
169 if( nJumpCount
== 3 && bIsValue
)
171 pJumpMat
->SetJump( nC
, nR
, fVal
,
173 pJump
[ nJumpCount
]);
176 { // no parameter given for ELSE,
178 pJumpMat
->SetJump( nC
, nR
, fVal
,
180 pJump
[ nJumpCount
]);
185 xNew
= new ScJumpMatrixToken( pJumpMat
);
186 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur
, xNew
));
188 PushTempToken( xNew
);
189 // set endpoint of path for main code line
190 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
198 if( nJumpCount
>= 2 )
200 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
203 { // no parameter given for THEN
204 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
206 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
211 if( nJumpCount
== 3 )
213 aCode
.Jump( pJump
[ 2 ], pJump
[ nJumpCount
] );
216 { // no parameter given for ELSE
217 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
219 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
227 void ScInterpreter::ScChoseJump()
229 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScChoseJump" );
230 // We have to set a jump, if there was none chosen because of an error set
232 bool bHaveJump
= false;
233 const short* pJump
= pCur
->GetJump();
234 short nJumpCount
= pJump
[ 0 ];
235 MatrixDoubleRefToMatrix();
236 switch ( GetStackType() )
240 ScMatrixRef pMat
= PopMatrix();
242 PushIllegalParameter();
245 FormulaTokenRef xNew
;
246 ScTokenMatrixMap::const_iterator aMapIter
;
247 // DoubleError handled by JumpMatrix
248 pMat
->SetErrorInterpreter( NULL
);
250 pMat
->GetDimensions( nCols
, nRows
);
251 if ( nCols
== 0 || nRows
== 0 )
252 PushIllegalParameter();
253 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
254 pCur
)) != pTokenMatrixMap
->end()))
255 xNew
= (*aMapIter
).second
;
258 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
259 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
261 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
265 const ScMatrixValue
* pMatVal
= pMat
->Get( nC
, nR
,
267 bool bIsValue
= ScMatrix::IsValueType( nType
);
270 fVal
= pMatVal
->fVal
;
271 bIsValue
= ::rtl::math::isFinite( fVal
);
274 fVal
= ::rtl::math::approxFloor( fVal
);
275 if ( (fVal
< 1) || (fVal
>= nJumpCount
))
278 fVal
= CreateDoubleError(
285 fVal
= CreateDoubleError( errNoValue
);
289 pJumpMat
->SetJump( nC
, nR
, fVal
,
290 pJump
[ (short)fVal
],
291 pJump
[ nJumpCount
]);
295 pJumpMat
->SetJump( nC
, nR
, fVal
,
297 pJump
[ nJumpCount
]);
301 xNew
= new ScJumpMatrixToken( pJumpMat
);
302 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
305 PushTempToken( xNew
);
306 // set endpoint of path for main code line
307 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
314 double nJumpIndex
= ::rtl::math::approxFloor( GetDouble() );
315 if (!nGlobalError
&& (nJumpIndex
>= 1) && (nJumpIndex
< nJumpCount
))
317 aCode
.Jump( pJump
[ (short) nJumpIndex
], pJump
[ nJumpCount
] );
321 PushIllegalArgument();
325 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
328 void lcl_AdjustJumpMatrix( ScJumpMatrix
* pJumpM
, ScMatrixRef
& pResMat
, SCSIZE nParmCols
, SCSIZE nParmRows
)
330 SCSIZE nJumpCols
, nJumpRows
;
331 SCSIZE nResCols
, nResRows
;
332 SCSIZE nAdjustCols
, nAdjustRows
;
333 pJumpM
->GetDimensions( nJumpCols
, nJumpRows
);
334 pJumpM
->GetResMatDimensions( nResCols
, nResRows
);
335 if (( nJumpCols
== 1 && nParmCols
> nResCols
) ||
336 ( nJumpRows
== 1 && nParmRows
> nResRows
))
338 if ( nJumpCols
== 1 && nJumpRows
== 1 )
340 nAdjustCols
= nParmCols
> nResCols
? nParmCols
: nResCols
;
341 nAdjustRows
= nParmRows
> nResRows
? nParmRows
: nResRows
;
343 else if ( nJumpCols
== 1 )
345 nAdjustCols
= nParmCols
;
346 nAdjustRows
= nResRows
;
350 nAdjustCols
= nResCols
;
351 nAdjustRows
= nParmRows
;
353 pJumpM
->SetNewResMat( nAdjustCols
, nAdjustRows
);
354 pResMat
= pJumpM
->GetResultMatrix();
358 bool ScInterpreter::JumpMatrix( short nStackLevel
)
360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::JumpMatrix" );
361 pJumpMatrix
= static_cast<ScToken
*>(pStack
[sp
-nStackLevel
])->GetJumpMatrix();
362 ScMatrixRef pResMat
= pJumpMatrix
->GetResultMatrix();
364 if ( nStackLevel
== 2 )
366 if ( aCode
.HasStacked() )
367 aCode
.Pop(); // pop what Jump() pushed
370 DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
376 SetError( errUnknownStackVariable
);
380 pJumpMatrix
->GetPos( nC
, nR
);
381 switch ( GetStackType() )
385 double fVal
= GetDouble();
388 fVal
= CreateDoubleError( nGlobalError
);
391 pResMat
->PutDouble( fVal
, nC
, nR
);
396 const String
& rStr
= GetString();
399 pResMat
->PutDouble( CreateDoubleError( nGlobalError
),
404 pResMat
->PutString( rStr
, nC
, nR
);
410 PopSingleRef( aAdr
);
413 pResMat
->PutDouble( CreateDoubleError( nGlobalError
),
419 ScBaseCell
* pCell
= GetCell( aAdr
);
420 if (HasCellEmptyData( pCell
))
421 pResMat
->PutEmpty( nC
, nR
);
422 else if (HasCellValueData( pCell
))
424 double fVal
= GetCellValue( aAdr
, pCell
);
427 fVal
= CreateDoubleError(
431 pResMat
->PutDouble( fVal
, nC
, nR
);
436 GetCellString( aStr
, pCell
);
439 pResMat
->PutDouble( CreateDoubleError(
440 nGlobalError
), nC
, nR
);
444 pResMat
->PutString( aStr
, nC
, nR
);
450 { // upper left plus offset within matrix
453 PopDoubleRef( aRange
);
456 fVal
= CreateDoubleError( nGlobalError
);
458 pResMat
->PutDouble( fVal
, nC
, nR
);
462 // Do not modify the original range because we use it
463 // to adjust the size of the result matrix if necessary.
464 ScAddress
aAdr( aRange
.aStart
);
465 ULONG nCol
= (ULONG
)aAdr
.Col() + nC
;
466 ULONG nRow
= (ULONG
)aAdr
.Row() + nR
;
467 if ((nCol
> static_cast<ULONG
>(aRange
.aEnd
.Col()) &&
468 aRange
.aEnd
.Col() != aRange
.aStart
.Col())
469 || (nRow
> static_cast<ULONG
>(aRange
.aEnd
.Row()) &&
470 aRange
.aEnd
.Row() != aRange
.aStart
.Row()))
472 fVal
= CreateDoubleError( NOTAVAILABLE
);
473 pResMat
->PutDouble( fVal
, nC
, nR
);
477 // Replicate column and/or row of a vector if it is
478 // one. Note that this could be a range reference
479 // that in fact consists of only one cell, e.g. A1:A1
480 if (aRange
.aEnd
.Col() == aRange
.aStart
.Col())
481 nCol
= aRange
.aStart
.Col();
482 if (aRange
.aEnd
.Row() == aRange
.aStart
.Row())
483 nRow
= aRange
.aStart
.Row();
484 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) );
485 aAdr
.SetRow( static_cast<SCROW
>(nRow
) );
486 ScBaseCell
* pCell
= GetCell( aAdr
);
487 if (HasCellEmptyData( pCell
))
488 pResMat
->PutEmpty( nC
, nR
);
489 else if (HasCellValueData( pCell
))
491 double fCellVal
= GetCellValue( aAdr
, pCell
);
494 fCellVal
= CreateDoubleError(
498 pResMat
->PutDouble( fCellVal
, nC
, nR
);
503 GetCellString( aStr
, pCell
);
506 pResMat
->PutDouble( CreateDoubleError(
507 nGlobalError
), nC
, nR
);
511 pResMat
->PutString( aStr
, nC
, nR
);
514 SCSIZE nParmCols
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
515 SCSIZE nParmRows
= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
516 lcl_AdjustJumpMatrix( pJumpMatrix
, pResMat
, nParmCols
, nParmRows
);
521 { // match matrix offsets
523 ScMatrixRef pMat
= PopMatrix();
526 fVal
= CreateDoubleError( nGlobalError
);
528 pResMat
->PutDouble( fVal
, nC
, nR
);
532 fVal
= CreateDoubleError( errUnknownVariable
);
533 pResMat
->PutDouble( fVal
, nC
, nR
);
538 pMat
->GetDimensions( nCols
, nRows
);
539 if ((nCols
<= nC
&& nCols
!= 1) ||
540 (nRows
<= nR
&& nRows
!= 1))
542 fVal
= CreateDoubleError( NOTAVAILABLE
);
543 pResMat
->PutDouble( fVal
, nC
, nR
);
547 if ( pMat
->IsValue( nC
, nR
) )
549 fVal
= pMat
->GetDouble( nC
, nR
);
550 pResMat
->PutDouble( fVal
, nC
, nR
);
552 else if ( pMat
->IsEmpty( nC
, nR
) )
553 pResMat
->PutEmpty( nC
, nR
);
556 const String
& rStr
= pMat
->GetString( nC
, nR
);
557 pResMat
->PutString( rStr
, nC
, nR
);
560 lcl_AdjustJumpMatrix( pJumpMatrix
, pResMat
, nCols
, nRows
);
567 double fVal
= CreateDoubleError( nGlobalError
);
569 pResMat
->PutDouble( fVal
, nC
, nR
);
575 double fVal
= CreateDoubleError( errIllegalArgument
);
576 pResMat
->PutDouble( fVal
, nC
, nR
);
581 bool bCont
= pJumpMatrix
->Next( nC
, nR
);
585 short nStart
, nNext
, nStop
;
586 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
587 while ( bCont
&& nStart
== nNext
)
588 { // push all results that have no jump path
591 // a FALSE without path results in an empty path value
593 pResMat
->PutEmptyPath( nC
, nR
);
595 pResMat
->PutDouble( fBool
, nC
, nR
);
597 bCont
= pJumpMatrix
->Next( nC
, nR
);
599 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
601 if ( bCont
&& nStart
!= nNext
)
603 const ScTokenVec
* pParams
= pJumpMatrix
->GetJumpParameters();
606 for ( ScTokenVec::const_iterator i
= pParams
->begin();
607 i
!= pParams
->end(); ++i
)
609 // This is not the current state of the interpreter, so
610 // push without error, and elements' errors are coded into
612 PushWithoutError( *(*i
));
615 aCode
.Jump( nStart
, nNext
, nStop
);
619 { // we're done with it, throw away jump matrix, keep result
622 PushMatrix( pResMat
);
623 // Remove jump matrix from map and remember result matrix in case it
624 // could be reused in another path of the same condition.
627 pTokenMatrixMap
->erase( pCur
);
628 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type( pCur
,
637 ScCompareOptions::ScCompareOptions( ScDocument
* pDoc
, const ScQueryEntry
& rEntry
, bool bReg
) :
640 bMatchWholeCell(pDoc
->GetDocOptions().IsMatchWholeCell()),
643 bRegEx
= (bRegEx
&& (aQueryEntry
.eOp
== SC_EQUAL
|| aQueryEntry
.eOp
== SC_NOT_EQUAL
));
644 // Interpreter functions usually are case insensitive, except the simple
645 // comparison operators, for which these options aren't used. Override in
650 double ScInterpreter::CompareFunc( const ScCompare
& rComp
, ScCompareOptions
* pOptions
)
652 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CompareFunc" );
653 // Keep DoubleError if encountered
654 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
655 if ( !rComp
.bEmpty
[0] && rComp
.bVal
[0] && !::rtl::math::isFinite( rComp
.nVal
[0]))
656 return rComp
.nVal
[0];
657 if ( !rComp
.bEmpty
[1] && rComp
.bVal
[1] && !::rtl::math::isFinite( rComp
.nVal
[1]))
658 return rComp
.nVal
[1];
661 if ( rComp
.bEmpty
[ 0 ] )
663 if ( rComp
.bEmpty
[ 1 ] )
664 ; // empty cell == empty cell, fRes 0
665 else if( rComp
.bVal
[ 1 ] )
667 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 1 ], 0.0 ) )
669 if ( rComp
.nVal
[ 1 ] < 0.0 )
670 fRes
= 1; // empty cell > -x
672 fRes
= -1; // empty cell < x
674 // else: empty cell == 0.0
678 if ( rComp
.pVal
[ 1 ]->Len() )
679 fRes
= -1; // empty cell < "..."
680 // else: empty cell == ""
683 else if ( rComp
.bEmpty
[ 1 ] )
685 if( rComp
.bVal
[ 0 ] )
687 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 0 ], 0.0 ) )
689 if ( rComp
.nVal
[ 0 ] < 0.0 )
690 fRes
= -1; // -x < empty cell
692 fRes
= 1; // x > empty cell
694 // else: empty cell == 0.0
698 if ( rComp
.pVal
[ 0 ]->Len() )
699 fRes
= 1; // "..." > empty cell
700 // else: "" == empty cell
703 else if( rComp
.bVal
[ 0 ] )
705 if( rComp
.bVal
[ 1 ] )
707 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 0 ], rComp
.nVal
[ 1 ] ) )
709 if( rComp
.nVal
[ 0 ] - rComp
.nVal
[ 1 ] < 0 )
716 fRes
= -1; // number is less than string
718 else if( rComp
.bVal
[ 1 ] )
719 fRes
= 1; // number is less than string
725 // All similar to Sctable::ValidQuery(), *rComp.pVal[1] actually
726 // is/must be identical to *rEntry.pStr, which is essential for
727 // regex to work through GetSearchTextPtr().
728 ScQueryEntry
& rEntry
= pOptions
->aQueryEntry
;
729 DBG_ASSERT( *rComp
.pVal
[1] == *rEntry
.pStr
, "ScInterpreter::CompareFunc: broken options");
730 if (pOptions
->bRegEx
)
732 xub_StrLen nStart
= 0;
733 xub_StrLen nStop
= rComp
.pVal
[0]->Len();
734 bool bMatch
= rEntry
.GetSearchTextPtr(
735 !pOptions
->bIgnoreCase
)->SearchFrwrd( *rComp
.pVal
[0],
737 if (bMatch
&& pOptions
->bMatchWholeCell
&& (nStart
!= 0 || nStop
!= rComp
.pVal
[0]->Len()))
738 bMatch
= false; // RegEx must match entire string.
739 fRes
= (bMatch
? 0 : 1);
741 else if (rEntry
.eOp
== SC_EQUAL
|| rEntry
.eOp
== SC_NOT_EQUAL
)
743 ::utl::TransliterationWrapper
* pTransliteration
=
744 (pOptions
->bIgnoreCase
? ScGlobal::GetpTransliteration() :
745 ScGlobal::GetCaseTransliteration());
747 if (pOptions
->bMatchWholeCell
)
748 bMatch
= pTransliteration
->isEqual( *rComp
.pVal
[0], *rComp
.pVal
[1]);
751 String
aCell( pTransliteration
->transliterate(
752 *rComp
.pVal
[0], ScGlobal::eLnge
, 0,
753 rComp
.pVal
[0]->Len(), NULL
));
754 String
aQuer( pTransliteration
->transliterate(
755 *rComp
.pVal
[1], ScGlobal::eLnge
, 0,
756 rComp
.pVal
[1]->Len(), NULL
));
757 bMatch
= (aCell
.Search( aQuer
) != STRING_NOTFOUND
);
759 fRes
= (bMatch
? 0 : 1);
761 else if (pOptions
->bIgnoreCase
)
762 fRes
= (double) ScGlobal::GetCollator()->compareString(
763 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
765 fRes
= (double) ScGlobal::GetCaseCollator()->compareString(
766 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
768 else if (pDok
->GetDocOptions().IsIgnoreCase())
769 fRes
= (double) ScGlobal::GetCollator()->compareString(
770 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
772 fRes
= (double) ScGlobal::GetCaseCollator()->compareString(
773 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
779 double ScInterpreter::Compare()
781 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::Compare" );
783 ScCompare
aComp( &aVal1
, &aVal2
);
784 for( short i
= 1; i
>= 0; i
-- )
786 switch ( GetRawStackType() )
789 aComp
.bEmpty
[ i
] = TRUE
;
793 aComp
.nVal
[ i
] = GetDouble();
794 aComp
.bVal
[ i
] = TRUE
;
797 *aComp
.pVal
[ i
] = GetString();
798 aComp
.bVal
[ i
] = FALSE
;
804 if ( !PopDoubleRefOrSingleRef( aAdr
) )
806 ScBaseCell
* pCell
= GetCell( aAdr
);
807 if (HasCellEmptyData( pCell
))
808 aComp
.bEmpty
[ i
] = TRUE
;
809 else if (HasCellStringData( pCell
))
811 GetCellString( *aComp
.pVal
[ i
], pCell
);
812 aComp
.bVal
[ i
] = FALSE
;
816 aComp
.nVal
[ i
] = GetCellValue( aAdr
, pCell
);
817 aComp
.bVal
[ i
] = TRUE
;
822 SetError( errIllegalParameter
);
828 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
829 return CompareFunc( aComp
);
833 ScMatrixRef
ScInterpreter::CompareMat( ScCompareOptions
* pOptions
)
835 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CompareMat" );
837 ScCompare
aComp( &aVal1
, &aVal2
);
840 for( short i
= 1; i
>= 0; i
-- )
842 switch (GetRawStackType())
845 aComp
.bEmpty
[ i
] = TRUE
;
849 aComp
.nVal
[ i
] = GetDouble();
850 aComp
.bVal
[ i
] = TRUE
;
853 *aComp
.pVal
[ i
] = GetString();
854 aComp
.bVal
[ i
] = FALSE
;
858 PopSingleRef( aAdr
);
859 ScBaseCell
* pCell
= GetCell( aAdr
);
860 if (HasCellEmptyData( pCell
))
861 aComp
.bEmpty
[ i
] = TRUE
;
862 else if (HasCellStringData( pCell
))
864 GetCellString( *aComp
.pVal
[ i
], pCell
);
865 aComp
.bVal
[ i
] = FALSE
;
869 aComp
.nVal
[ i
] = GetCellValue( aAdr
, pCell
);
870 aComp
.bVal
[ i
] = TRUE
;
876 pMat
[ i
] = GetMatrix();
878 SetError( errIllegalParameter
);
880 pMat
[i
]->SetErrorInterpreter( NULL
);
881 // errors are transported as DoubleError inside matrix
884 SetError( errIllegalParameter
);
888 ScMatrixRef pResMat
= NULL
;
891 if ( pMat
[0] && pMat
[1] )
895 pMat
[0]->GetDimensions( nC0
, nR0
);
896 pMat
[1]->GetDimensions( nC1
, nR1
);
897 SCSIZE nC
= Max( nC0
, nC1
);
898 SCSIZE nR
= Max( nR0
, nR1
);
899 pResMat
= GetNewMat( nC
, nR
);
902 for ( SCSIZE j
=0; j
<nC
; j
++ )
904 for ( SCSIZE k
=0; k
<nR
; k
++ )
906 SCSIZE nCol
= j
, nRow
= k
;
907 if ( pMat
[0]->ValidColRowOrReplicated( nCol
, nRow
) &&
908 pMat
[1]->ValidColRowOrReplicated( nCol
, nRow
))
910 for ( short i
=1; i
>=0; i
-- )
912 if ( pMat
[i
]->IsString(j
,k
) )
914 aComp
.bVal
[i
] = FALSE
;
915 *aComp
.pVal
[i
] = pMat
[i
]->GetString(j
,k
);
916 aComp
.bEmpty
[i
] = pMat
[i
]->IsEmpty(j
,k
);
920 aComp
.bVal
[i
] = TRUE
;
921 aComp
.nVal
[i
] = pMat
[i
]->GetDouble(j
,k
);
922 aComp
.bEmpty
[i
] = FALSE
;
925 pResMat
->PutDouble( CompareFunc( aComp
, pOptions
), j
,k
);
928 pResMat
->PutString( ScGlobal::GetRscString(STR_NO_VALUE
), j
,k
);
932 else if ( pMat
[0] || pMat
[1] )
934 short i
= ( pMat
[0] ? 0 : 1);
936 pMat
[i
]->GetDimensions( nC
, nR
);
937 pResMat
= GetNewMat( nC
, nR
);
941 for ( SCSIZE j
=0; j
<n
; j
++ )
943 if ( pMat
[i
]->IsValue(j
) )
945 aComp
.bVal
[i
] = TRUE
;
946 aComp
.nVal
[i
] = pMat
[i
]->GetDouble(j
);
947 aComp
.bEmpty
[i
] = FALSE
;
951 aComp
.bVal
[i
] = FALSE
;
952 *aComp
.pVal
[i
] = pMat
[i
]->GetString(j
);
953 aComp
.bEmpty
[i
] = pMat
[i
]->IsEmpty(j
);
955 pResMat
->PutDouble( CompareFunc( aComp
, pOptions
), j
);
959 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
964 ScMatrixRef
ScInterpreter::QueryMat( ScMatrix
* pMat
, ScCompareOptions
& rOptions
)
966 short nSaveCurFmtType
= nCurFmtType
;
967 short nSaveFuncFmtType
= nFuncFmtType
;
969 if (rOptions
.aQueryEntry
.bQueryByString
)
970 PushString( *rOptions
.aQueryEntry
.pStr
);
972 PushDouble( rOptions
.aQueryEntry
.nVal
);
973 ScMatrixRef pResultMatrix
= CompareMat( &rOptions
);
974 nCurFmtType
= nSaveCurFmtType
;
975 nFuncFmtType
= nSaveFuncFmtType
;
976 if (nGlobalError
|| !pResultMatrix
)
978 SetError( errIllegalParameter
);
979 return pResultMatrix
;
982 switch (rOptions
.aQueryEntry
.eOp
)
985 pResultMatrix
->CompareEqual();
988 pResultMatrix
->CompareLess();
991 pResultMatrix
->CompareGreater();
994 pResultMatrix
->CompareLessEqual();
996 case SC_GREATER_EQUAL
:
997 pResultMatrix
->CompareGreaterEqual();
1000 pResultMatrix
->CompareNotEqual();
1003 SetError( errIllegalArgument
);
1004 DBG_ERROR1( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)rOptions
.aQueryEntry
.eOp
);
1006 return pResultMatrix
;
1010 void ScInterpreter::ScEqual()
1012 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScEqual" );
1013 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1015 ScMatrixRef pMat
= CompareMat();
1017 PushIllegalParameter();
1020 pMat
->CompareEqual();
1025 PushInt( Compare() == 0 );
1029 void ScInterpreter::ScNotEqual()
1031 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNotEqual" );
1032 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1034 ScMatrixRef pMat
= CompareMat();
1036 PushIllegalParameter();
1039 pMat
->CompareNotEqual();
1044 PushInt( Compare() != 0 );
1048 void ScInterpreter::ScLess()
1050 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLess" );
1051 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1053 ScMatrixRef pMat
= CompareMat();
1055 PushIllegalParameter();
1058 pMat
->CompareLess();
1063 PushInt( Compare() < 0 );
1067 void ScInterpreter::ScGreater()
1069 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGreater" );
1070 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1072 ScMatrixRef pMat
= CompareMat();
1074 PushIllegalParameter();
1077 pMat
->CompareGreater();
1082 PushInt( Compare() > 0 );
1086 void ScInterpreter::ScLessEqual()
1088 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLessEqual" );
1089 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1091 ScMatrixRef pMat
= CompareMat();
1093 PushIllegalParameter();
1096 pMat
->CompareLessEqual();
1101 PushInt( Compare() <= 0 );
1105 void ScInterpreter::ScGreaterEqual()
1107 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScGreaterEqual" );
1108 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
1110 ScMatrixRef pMat
= CompareMat();
1112 PushIllegalParameter();
1115 pMat
->CompareGreaterEqual();
1120 PushInt( Compare() >= 0 );
1124 void ScInterpreter::ScAnd()
1126 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScAnd" );
1127 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1128 short nParamCount
= GetByte();
1129 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1131 BOOL bHaveValue
= FALSE
;
1133 size_t nRefInList
= 0;
1134 while( nParamCount
-- > 0)
1136 if ( !nGlobalError
)
1138 switch ( GetStackType() )
1142 nRes
&= ( PopDouble() != 0.0 );
1146 SetError( errNoValue
);
1151 PopSingleRef( aAdr
);
1152 if ( !nGlobalError
)
1154 ScBaseCell
* pCell
= GetCell( aAdr
);
1155 if ( HasCellValueData( pCell
) )
1158 nRes
&= ( GetCellValue( aAdr
, pCell
) != 0.0 );
1160 // else: Xcl setzt hier keinen Fehler
1168 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1169 if ( !nGlobalError
)
1173 ScValueIterator
aValIter( pDok
, aRange
);
1174 if ( aValIter
.GetFirst( fVal
, nErr
) )
1179 nRes
&= ( fVal
!= 0.0 );
1180 } while ( (nErr
== 0) &&
1181 aValIter
.GetNext( fVal
, nErr
) );
1189 ScMatrixRef pMat
= GetMatrix();
1193 double fVal
= pMat
->And();
1194 USHORT nErr
= GetDoubleErrorValue( fVal
);
1201 nRes
&= (fVal
!= 0.0);
1203 // else: GetMatrix did set errIllegalParameter
1208 SetError( errIllegalParameter
);
1222 void ScInterpreter::ScOr()
1224 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScOr" );
1225 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1226 short nParamCount
= GetByte();
1227 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1229 BOOL bHaveValue
= FALSE
;
1231 size_t nRefInList
= 0;
1232 while( nParamCount
-- > 0)
1234 if ( !nGlobalError
)
1236 switch ( GetStackType() )
1240 nRes
|= ( PopDouble() != 0.0 );
1244 SetError( errNoValue
);
1249 PopSingleRef( aAdr
);
1250 if ( !nGlobalError
)
1252 ScBaseCell
* pCell
= GetCell( aAdr
);
1253 if ( HasCellValueData( pCell
) )
1256 nRes
|= ( GetCellValue( aAdr
, pCell
) != 0.0 );
1258 // else: Xcl setzt hier keinen Fehler
1266 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1267 if ( !nGlobalError
)
1271 ScValueIterator
aValIter( pDok
, aRange
);
1272 if ( aValIter
.GetFirst( fVal
, nErr
) )
1277 nRes
|= ( fVal
!= 0.0 );
1278 } while ( (nErr
== 0) &&
1279 aValIter
.GetNext( fVal
, nErr
) );
1288 ScMatrixRef pMat
= GetMatrix();
1292 double fVal
= pMat
->Or();
1293 USHORT nErr
= GetDoubleErrorValue( fVal
);
1300 nRes
|= (fVal
!= 0.0);
1302 // else: GetMatrix did set errIllegalParameter
1307 SetError( errIllegalParameter
);
1321 void ScInterpreter::ScNeg()
1323 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNeg" );
1324 // Simple negation doesn't change current format type to number, keep
1326 nFuncFmtType
= nCurFmtType
;
1327 switch ( GetStackType() )
1331 ScMatrixRef pMat
= GetMatrix();
1333 PushIllegalParameter();
1337 pMat
->GetDimensions( nC
, nR
);
1338 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1340 PushIllegalArgument();
1343 SCSIZE nCount
= nC
* nR
;
1344 for ( SCSIZE j
=0; j
<nCount
; ++j
)
1346 if ( pMat
->IsValueOrEmpty(j
) )
1347 pResMat
->PutDouble( -pMat
->GetDouble(j
), j
);
1350 ScGlobal::GetRscString( STR_NO_VALUE
), j
);
1352 PushMatrix( pResMat
);
1358 PushDouble( -GetDouble() );
1363 void ScInterpreter::ScPercentSign()
1365 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPercentSign" );
1366 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1367 const FormulaToken
* pSaveCur
= pCur
;
1368 BYTE nSavePar
= cPar
;
1371 FormulaByteToken
aDivOp( ocDiv
, cPar
);
1379 void ScInterpreter::ScNot()
1381 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScNot" );
1382 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1383 switch ( GetStackType() )
1387 ScMatrixRef pMat
= GetMatrix();
1389 PushIllegalParameter();
1393 pMat
->GetDimensions( nC
, nR
);
1394 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1396 PushIllegalArgument();
1399 SCSIZE nCount
= nC
* nR
;
1400 for ( SCSIZE j
=0; j
<nCount
; ++j
)
1402 if ( pMat
->IsValueOrEmpty(j
) )
1403 pResMat
->PutDouble( (pMat
->GetDouble(j
) == 0.0), j
);
1406 ScGlobal::GetRscString( STR_NO_VALUE
), j
);
1408 PushMatrix( pResMat
);
1414 PushInt( GetDouble() == 0.0 );
1419 void ScInterpreter::ScPi()
1421 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPi" );
1426 void ScInterpreter::ScRandom()
1428 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRandom" );
1429 PushDouble((double)rand() / ((double)RAND_MAX
+1.0));
1433 void ScInterpreter::ScTrue()
1435 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTrue" );
1436 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1441 void ScInterpreter::ScFalse()
1443 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFalse" );
1444 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1449 void ScInterpreter::ScDeg()
1451 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDeg" );
1452 PushDouble((GetDouble() / F_PI
) * 180.0);
1456 void ScInterpreter::ScRad()
1458 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRad" );
1459 PushDouble(GetDouble() * (F_PI
/ 180));
1463 void ScInterpreter::ScSin()
1465 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSin" );
1466 PushDouble(::rtl::math::sin(GetDouble()));
1470 void ScInterpreter::ScCos()
1472 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCos" );
1473 PushDouble(::rtl::math::cos(GetDouble()));
1477 void ScInterpreter::ScTan()
1479 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTan" );
1480 PushDouble(::rtl::math::tan(GetDouble()));
1484 void ScInterpreter::ScCot()
1486 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCot" );
1487 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1491 void ScInterpreter::ScArcSin()
1493 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcSin" );
1494 PushDouble(asin(GetDouble()));
1498 void ScInterpreter::ScArcCos()
1500 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcCos" );
1501 PushDouble(acos(GetDouble()));
1505 void ScInterpreter::ScArcTan()
1507 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcTan" );
1508 PushDouble(atan(GetDouble()));
1512 void ScInterpreter::ScArcCot()
1514 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcCot" );
1515 PushDouble((F_PI2
) - atan(GetDouble()));
1519 void ScInterpreter::ScSinHyp()
1521 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSinHyp" );
1522 PushDouble(sinh(GetDouble()));
1526 void ScInterpreter::ScCosHyp()
1528 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCosHyp" );
1529 PushDouble(cosh(GetDouble()));
1533 void ScInterpreter::ScTanHyp()
1535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTanHyp" );
1536 PushDouble(tanh(GetDouble()));
1540 void ScInterpreter::ScCotHyp()
1542 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCotHyp" );
1543 PushDouble(1.0 / tanh(GetDouble()));
1547 void ScInterpreter::ScArcSinHyp()
1549 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcSinHyp" );
1550 PushDouble( ::rtl::math::asinh( GetDouble()));
1553 void ScInterpreter::ScArcCosHyp()
1555 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcCosHyp" );
1556 double fVal
= GetDouble();
1558 PushIllegalArgument();
1560 PushDouble( ::rtl::math::acosh( fVal
));
1563 void ScInterpreter::ScArcTanHyp()
1565 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcTanHyp" );
1566 double fVal
= GetDouble();
1567 if (fabs(fVal
) >= 1.0)
1568 PushIllegalArgument();
1570 PushDouble( ::rtl::math::atanh( fVal
));
1574 void ScInterpreter::ScArcCotHyp()
1576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScArcCotHyp" );
1577 double nVal
= GetDouble();
1578 if (fabs(nVal
) <= 1.0)
1579 PushIllegalArgument();
1581 PushDouble(0.5 * log((nVal
+ 1.0) / (nVal
- 1.0)));
1585 void ScInterpreter::ScExp()
1587 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScExp" );
1588 PushDouble(exp(GetDouble()));
1592 void ScInterpreter::ScSqrt()
1594 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSqrt" );
1595 double fVal
= GetDouble();
1597 PushDouble(sqrt(fVal
));
1599 PushIllegalArgument();
1603 void ScInterpreter::ScIsEmpty()
1605 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsEmpty" );
1607 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1608 switch ( GetRawStackType() )
1612 FormulaTokenRef p
= PopToken();
1613 if (!static_cast<const ScEmptyCellToken
*>(p
.get())->IsInherited())
1621 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1623 // NOTE: this could test also on inherited emptiness, but then the
1624 // cell tested wouldn't be empty. Must correspond with
1625 // ScCountEmptyCells().
1626 // if (HasCellEmptyData( GetCell( aAdr)))
1627 CellType eCellType
= GetCellType( GetCell( aAdr
) );
1628 if((eCellType
== CELLTYPE_NONE
) || (eCellType
== CELLTYPE_NOTE
))
1634 ScMatrixRef pMat
= PopMatrix();
1637 else if ( !pJumpMatrix
)
1638 nRes
= pMat
->IsEmpty( 0 );
1641 SCSIZE nCols
, nRows
, nC
, nR
;
1642 pMat
->GetDimensions( nCols
, nRows
);
1643 pJumpMatrix
->GetPos( nC
, nR
);
1644 if ( nC
< nCols
&& nR
< nRows
)
1645 nRes
= pMat
->IsEmpty( nC
, nR
);
1646 // else: FALSE, not empty (which is what Xcl does)
1658 short ScInterpreter::IsString()
1660 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::IsString" );
1661 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1663 switch ( GetRawStackType() )
1673 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1675 ScBaseCell
* pCell
= GetCell( aAdr
);
1676 if (GetCellErrCode( pCell
) == 0)
1678 switch ( GetCellType( pCell
) )
1680 case CELLTYPE_STRING
:
1681 case CELLTYPE_EDIT
:
1684 case CELLTYPE_FORMULA
:
1685 nRes
= !((ScFormulaCell
*)pCell
)->IsValue() &&
1686 !((ScFormulaCell
*)pCell
)->IsEmpty();
1696 ScMatrixRef pMat
= PopMatrix();
1699 else if ( !pJumpMatrix
)
1700 nRes
= pMat
->IsString(0) && !pMat
->IsEmpty(0);
1703 SCSIZE nCols
, nRows
, nC
, nR
;
1704 pMat
->GetDimensions( nCols
, nRows
);
1705 pJumpMatrix
->GetPos( nC
, nR
);
1706 if ( nC
< nCols
&& nR
< nRows
)
1707 nRes
= pMat
->IsString( nC
, nR
) && !pMat
->IsEmpty( nC
, nR
);
1719 void ScInterpreter::ScIsString()
1721 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsString" );
1722 PushInt( IsString() );
1726 void ScInterpreter::ScIsNonString()
1728 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsNonString" );
1729 PushInt( !IsString() );
1733 void ScInterpreter::ScIsLogical()
1735 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsLogical" );
1737 switch ( GetStackType() )
1743 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1745 ScBaseCell
* pCell
= GetCell( aAdr
);
1746 if (GetCellErrCode( pCell
) == 0)
1748 if (HasCellValueData(pCell
))
1750 ULONG nFormat
= GetCellNumberFormat( aAdr
, pCell
);
1751 nRes
= ( pFormatter
->GetType(nFormat
)
1752 == NUMBERFORMAT_LOGICAL
);
1758 // TODO: we don't have type information for arrays except
1759 // numerical/string.
1763 if ( !nGlobalError
)
1764 nRes
= ( nCurFmtType
== NUMBERFORMAT_LOGICAL
);
1766 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1772 void ScInterpreter::ScType()
1774 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScType" );
1776 switch ( GetStackType() )
1782 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1784 ScBaseCell
* pCell
= GetCell( aAdr
);
1785 if (GetCellErrCode( pCell
) == 0)
1787 switch ( GetCellType( pCell
) )
1789 // NOTE: this is Xcl nonsense!
1790 case CELLTYPE_NOTE
:
1791 nType
= 1; // empty cell is value (0)
1793 case CELLTYPE_STRING
:
1794 case CELLTYPE_EDIT
:
1797 case CELLTYPE_VALUE
:
1799 ULONG nFormat
= GetCellNumberFormat( aAdr
, pCell
);
1800 if (pFormatter
->GetType(nFormat
)
1801 == NUMBERFORMAT_LOGICAL
)
1807 case CELLTYPE_FORMULA
:
1811 PushIllegalArgument();
1837 // we could return the type of one element if in JumpMatrix or
1838 // ForceArray mode, but Xcl doesn't ...
1854 inline BOOL
lcl_FormatHasNegColor( const SvNumberformat
* pFormat
)
1856 return pFormat
&& pFormat
->GetColor( 1 );
1860 inline BOOL
lcl_FormatHasOpenPar( const SvNumberformat
* pFormat
)
1862 return pFormat
&& (pFormat
->GetFormatstring().Search( '(' ) != STRING_NOTFOUND
);
1866 void ScInterpreter::ScCell()
1867 { // ATTRIBUTE ; [REF]
1868 BYTE nParamCount
= GetByte();
1869 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
1871 ScAddress
aCellPos( aPos
);
1872 BOOL bError
= FALSE
;
1873 if( nParamCount
== 2 )
1874 bError
= !PopDoubleRefOrSingleRef( aCellPos
);
1875 String
aInfoType( GetString() );
1876 if( bError
|| nGlobalError
)
1877 PushIllegalParameter();
1881 ScBaseCell
* pCell
= GetCell( aCellPos
);
1883 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::GetLocale(), ocCell
);
1885 // *** ADDRESS INFO ***
1886 if( aInfoType
.EqualsAscii( "COL" ) )
1887 { // column number (1-based)
1888 PushInt( aCellPos
.Col() + 1 );
1890 else if( aInfoType
.EqualsAscii( "ROW" ) )
1891 { // row number (1-based)
1892 PushInt( aCellPos
.Row() + 1 );
1894 else if( aInfoType
.EqualsAscii( "SHEET" ) )
1895 { // table number (1-based)
1896 PushInt( aCellPos
.Tab() + 1 );
1898 else if( aInfoType
.EqualsAscii( "ADDRESS" ) )
1899 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
1900 USHORT nFlags
= (aCellPos
.Tab() == aPos
.Tab()) ? (SCA_ABS
) : (SCA_ABS_3D
);
1901 aCellPos
.Format( aFuncResult
, nFlags
, pDok
, pDok
->GetAddressConvention() );
1902 PushString( aFuncResult
);
1904 else if( aInfoType
.EqualsAscii( "FILENAME" ) )
1905 { // file name and table name: 'FILENAME'#$TABLE
1906 SCTAB nTab
= aCellPos
.Tab();
1907 if( nTab
< pDok
->GetTableCount() )
1909 if( pDok
->GetLinkMode( nTab
) == SC_LINK_VALUE
)
1910 pDok
->GetName( nTab
, aFuncResult
);
1913 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
1914 if( pShell
&& pShell
->GetMedium() )
1916 aFuncResult
= (sal_Unicode
) '\'';
1917 const INetURLObject
& rURLObj
= pShell
->GetMedium()->GetURLObject();
1918 aFuncResult
+= String( rURLObj
.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS
) );
1919 aFuncResult
.AppendAscii( "'#$" );
1921 pDok
->GetName( nTab
, aTabName
);
1922 aFuncResult
+= aTabName
;
1926 PushString( aFuncResult
);
1928 else if( aInfoType
.EqualsAscii( "COORD" ) )
1929 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
1930 // Yes, passing tab as col is intentional!
1931 ScAddress( static_cast<SCCOL
>(aCellPos
.Tab()), 0, 0 ).Format(
1932 aFuncResult
, (SCA_COL_ABSOLUTE
|SCA_VALID_COL
), NULL
, pDok
->GetAddressConvention() );
1935 aCellPos
.Format( aCellStr
, (SCA_COL_ABSOLUTE
|SCA_VALID_COL
|SCA_ROW_ABSOLUTE
|SCA_VALID_ROW
),
1936 NULL
, pDok
->GetAddressConvention() );
1937 aFuncResult
+= aCellStr
;
1938 PushString( aFuncResult
);
1941 // *** CELL PROPERTIES ***
1942 else if( aInfoType
.EqualsAscii( "CONTENTS" ) )
1943 { // contents of the cell, no formatting
1944 if( pCell
&& pCell
->HasStringData() )
1946 GetCellString( aFuncResult
, pCell
);
1947 PushString( aFuncResult
);
1950 PushDouble( GetCellValue( aCellPos
, pCell
) );
1952 else if( aInfoType
.EqualsAscii( "TYPE" ) )
1953 { // b = blank; l = string (label); v = otherwise (value)
1954 if( HasCellStringData( pCell
) )
1957 aFuncResult
= HasCellValueData( pCell
) ? 'v' : 'b';
1958 PushString( aFuncResult
);
1960 else if( aInfoType
.EqualsAscii( "WIDTH" ) )
1961 { // column width (rounded off as count of zero characters in standard font and size)
1962 Printer
* pPrinter
= pDok
->GetPrinter();
1963 MapMode
aOldMode( pPrinter
->GetMapMode() );
1964 Font
aOldFont( pPrinter
->GetFont() );
1967 pPrinter
->SetMapMode( MAP_TWIP
);
1968 // font color doesn't matter here
1969 pDok
->GetDefPattern()->GetFont( aDefFont
, SC_AUTOCOL_BLACK
, pPrinter
);
1970 pPrinter
->SetFont( aDefFont
);
1971 long nZeroWidth
= pPrinter
->GetTextWidth( String( '0' ) );
1972 pPrinter
->SetFont( aOldFont
);
1973 pPrinter
->SetMapMode( aOldMode
);
1974 int nZeroCount
= (int)(pDok
->GetColWidth( aCellPos
.Col(), aCellPos
.Tab() ) / nZeroWidth
);
1975 PushInt( nZeroCount
);
1977 else if( aInfoType
.EqualsAscii( "PREFIX" ) )
1978 { // ' = left; " = right; ^ = centered
1979 if( HasCellStringData( pCell
) )
1981 const SvxHorJustifyItem
* pJustAttr
= (const SvxHorJustifyItem
*)
1982 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_HOR_JUSTIFY
);
1983 switch( pJustAttr
->GetValue() )
1985 case SVX_HOR_JUSTIFY_STANDARD
:
1986 case SVX_HOR_JUSTIFY_LEFT
:
1987 case SVX_HOR_JUSTIFY_BLOCK
: aFuncResult
= '\''; break;
1988 case SVX_HOR_JUSTIFY_CENTER
: aFuncResult
= '^'; break;
1989 case SVX_HOR_JUSTIFY_RIGHT
: aFuncResult
= '"'; break;
1990 case SVX_HOR_JUSTIFY_REPEAT
: aFuncResult
= '\\'; break;
1993 PushString( aFuncResult
);
1995 else if( aInfoType
.EqualsAscii( "PROTECT" ) )
1996 { // 1 = cell locked
1997 const ScProtectionAttr
* pProtAttr
= (const ScProtectionAttr
*)
1998 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_PROTECTION
);
1999 PushInt( pProtAttr
->GetProtection() ? 1 : 0 );
2002 // *** FORMATTING ***
2003 else if( aInfoType
.EqualsAscii( "FORMAT" ) )
2004 { // specific format code for standard formats
2005 ULONG nFormat
= pDok
->GetNumberFormat( aCellPos
);
2006 BOOL bAppendPrec
= TRUE
;
2007 USHORT nPrec
, nLeading
;
2008 BOOL bThousand
, bIsRed
;
2009 pFormatter
->GetFormatSpecialInfo( nFormat
, bThousand
, bIsRed
, nPrec
, nLeading
);
2011 switch( pFormatter
->GetType( nFormat
) )
2013 case NUMBERFORMAT_NUMBER
: aFuncResult
= (bThousand
? ',' : 'F'); break;
2014 case NUMBERFORMAT_CURRENCY
: aFuncResult
= 'C'; break;
2015 case NUMBERFORMAT_SCIENTIFIC
: aFuncResult
= 'S'; break;
2016 case NUMBERFORMAT_PERCENT
: aFuncResult
= 'P'; break;
2019 bAppendPrec
= FALSE
;
2020 switch( pFormatter
->GetIndexTableOffset( nFormat
) )
2022 case NF_DATE_SYSTEM_SHORT
:
2023 case NF_DATE_SYS_DMMMYY
:
2024 case NF_DATE_SYS_DDMMYY
:
2025 case NF_DATE_SYS_DDMMYYYY
:
2026 case NF_DATE_SYS_DMMMYYYY
:
2027 case NF_DATE_DIN_DMMMYYYY
:
2028 case NF_DATE_SYS_DMMMMYYYY
:
2029 case NF_DATE_DIN_DMMMMYYYY
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
2030 case NF_DATE_SYS_DDMMM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
2031 case NF_DATE_SYS_MMYY
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
2032 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
2033 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
2034 aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
2035 case NF_DATE_DIN_MMDD
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
2036 case NF_TIME_HHMMSSAMPM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
2037 case NF_TIME_HHMMAMPM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
2038 case NF_TIME_HHMMSS
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
2039 case NF_TIME_HHMM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
2040 default: aFuncResult
= 'G';
2045 aFuncResult
+= String::CreateFromInt32( nPrec
);
2046 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( nFormat
);
2047 if( lcl_FormatHasNegColor( pFormat
) )
2049 if( lcl_FormatHasOpenPar( pFormat
) )
2050 aFuncResult
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
2051 PushString( aFuncResult
);
2053 else if( aInfoType
.EqualsAscii( "COLOR" ) )
2054 { // 1 = negative values are colored, otherwise 0
2055 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2056 PushInt( lcl_FormatHasNegColor( pFormat
) ? 1 : 0 );
2058 else if( aInfoType
.EqualsAscii( "PARENTHESES" ) )
2059 { // 1 = format string contains a '(' character, otherwise 0
2060 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
2061 PushInt( lcl_FormatHasOpenPar( pFormat
) ? 1 : 0 );
2064 PushIllegalArgument();
2070 void ScInterpreter::ScIsRef()
2072 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCell" );
2073 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2075 switch ( GetStackType() )
2080 PopSingleRef( aAdr
);
2081 if ( !nGlobalError
)
2088 PopDoubleRef( aRange
);
2089 if ( !nGlobalError
)
2095 FormulaTokenRef x
= PopToken();
2096 if ( !nGlobalError
)
2097 nRes
= !static_cast<ScToken
*>(x
.get())->GetRefList()->empty();
2108 void ScInterpreter::ScIsValue()
2110 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsValue" );
2111 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2113 switch ( GetRawStackType() )
2123 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2125 ScBaseCell
* pCell
= GetCell( aAdr
);
2126 if (GetCellErrCode( pCell
) == 0)
2128 switch ( GetCellType( pCell
) )
2130 case CELLTYPE_VALUE
:
2133 case CELLTYPE_FORMULA
:
2134 nRes
= ((ScFormulaCell
*)pCell
)->IsValue() &&
2135 !((ScFormulaCell
*)pCell
)->IsEmpty();
2145 ScMatrixRef pMat
= PopMatrix();
2148 else if ( !pJumpMatrix
)
2150 if (pMat
->GetErrorIfNotString( 0 ) == 0)
2151 nRes
= pMat
->IsValue( 0 );
2155 SCSIZE nCols
, nRows
, nC
, nR
;
2156 pMat
->GetDimensions( nCols
, nRows
);
2157 pJumpMatrix
->GetPos( nC
, nR
);
2158 if ( nC
< nCols
&& nR
< nRows
)
2159 if (pMat
->GetErrorIfNotString( nC
, nR
) == 0)
2160 nRes
= pMat
->IsValue( nC
, nR
);
2172 void ScInterpreter::ScIsFormula()
2174 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsFormula" );
2175 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2177 switch ( GetStackType() )
2183 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2185 nRes
= (GetCellType( GetCell( aAdr
) ) == CELLTYPE_FORMULA
);
2196 void ScInterpreter::ScFormula()
2198 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFormula" );
2200 switch ( GetStackType() )
2206 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2208 ScBaseCell
* pCell
= GetCell( aAdr
);
2209 switch ( GetCellType( pCell
) )
2211 case CELLTYPE_FORMULA
:
2212 ((ScFormulaCell
*)pCell
)->GetFormula( aFormula
);
2215 SetError( NOTAVAILABLE
);
2221 SetError( NOTAVAILABLE
);
2223 PushString( aFormula
);
2228 void ScInterpreter::ScIsNV()
2230 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsNV" );
2231 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2233 switch ( GetStackType() )
2239 PopDoubleRefOrSingleRef( aAdr
);
2240 if ( nGlobalError
== NOTAVAILABLE
)
2244 ScBaseCell
* pCell
= GetCell( aAdr
);
2245 USHORT nErr
= GetCellErrCode( pCell
);
2246 nRes
= (nErr
== NOTAVAILABLE
);
2252 ScMatrixRef pMat
= PopMatrix();
2255 else if ( !pJumpMatrix
)
2256 nRes
= (pMat
->GetErrorIfNotString( 0 ) == NOTAVAILABLE
);
2259 SCSIZE nCols
, nRows
, nC
, nR
;
2260 pMat
->GetDimensions( nCols
, nRows
);
2261 pJumpMatrix
->GetPos( nC
, nR
);
2262 if ( nC
< nCols
&& nR
< nRows
)
2263 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) == NOTAVAILABLE
);
2269 if ( nGlobalError
== NOTAVAILABLE
)
2277 void ScInterpreter::ScIsErr()
2279 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsErr" );
2280 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2282 switch ( GetStackType() )
2288 PopDoubleRefOrSingleRef( aAdr
);
2289 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2293 ScBaseCell
* pCell
= GetCell( aAdr
);
2294 USHORT nErr
= GetCellErrCode( pCell
);
2295 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2301 ScMatrixRef pMat
= PopMatrix();
2302 if ( nGlobalError
|| !pMat
)
2303 nRes
= ((nGlobalError
&& nGlobalError
!= NOTAVAILABLE
) || !pMat
);
2304 else if ( !pJumpMatrix
)
2306 USHORT nErr
= pMat
->GetErrorIfNotString( 0 );
2307 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2311 SCSIZE nCols
, nRows
, nC
, nR
;
2312 pMat
->GetDimensions( nCols
, nRows
);
2313 pJumpMatrix
->GetPos( nC
, nR
);
2314 if ( nC
< nCols
&& nR
< nRows
)
2316 USHORT nErr
= pMat
->GetErrorIfNotString( nC
, nR
);
2317 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2324 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2332 void ScInterpreter::ScIsError()
2334 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsError" );
2335 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2337 switch ( GetStackType() )
2343 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2352 ScBaseCell
* pCell
= GetCell( aAdr
);
2353 nRes
= (GetCellErrCode( pCell
) != 0);
2359 ScMatrixRef pMat
= PopMatrix();
2360 if ( nGlobalError
|| !pMat
)
2362 else if ( !pJumpMatrix
)
2363 nRes
= (pMat
->GetErrorIfNotString( 0 ) != 0);
2366 SCSIZE nCols
, nRows
, nC
, nR
;
2367 pMat
->GetDimensions( nCols
, nRows
);
2368 pJumpMatrix
->GetPos( nC
, nR
);
2369 if ( nC
< nCols
&& nR
< nRows
)
2370 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) != 0);
2384 short ScInterpreter::IsEven()
2386 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::IsEven" );
2387 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2390 switch ( GetStackType() )
2396 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2398 ScBaseCell
* pCell
= GetCell( aAdr
);
2399 USHORT nErr
= GetCellErrCode( pCell
);
2404 switch ( GetCellType( pCell
) )
2406 case CELLTYPE_VALUE
:
2407 fVal
= GetCellValue( aAdr
, pCell
);
2410 case CELLTYPE_FORMULA
:
2411 if( ((ScFormulaCell
*)pCell
)->IsValue() )
2413 fVal
= GetCellValue( aAdr
, pCell
);
2431 ScMatrixRef pMat
= PopMatrix();
2434 else if ( !pJumpMatrix
)
2436 nRes
= pMat
->IsValue( 0 );
2438 fVal
= pMat
->GetDouble( 0 );
2442 SCSIZE nCols
, nRows
, nC
, nR
;
2443 pMat
->GetDimensions( nCols
, nRows
);
2444 pJumpMatrix
->GetPos( nC
, nR
);
2445 if ( nC
< nCols
&& nR
< nRows
)
2447 nRes
= pMat
->IsValue( nC
, nR
);
2449 fVal
= pMat
->GetDouble( nC
, nR
);
2452 SetError( errNoValue
);
2460 SetError( errIllegalParameter
);
2462 nRes
= ( fmod( ::rtl::math::approxFloor( fabs( fVal
) ), 2.0 ) < 0.5 );
2467 void ScInterpreter::ScIsEven()
2469 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsEven" );
2470 PushInt( IsEven() );
2474 void ScInterpreter::ScIsOdd()
2476 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIsOdd" );
2477 PushInt( !IsEven() );
2481 void ScInterpreter::ScN()
2483 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScN" );
2484 USHORT nErr
= nGlobalError
;
2487 if ( GetRawStackType() == svString
)
2494 if ( nGlobalError
== NOTAVAILABLE
|| nGlobalError
== errIllegalArgument
)
2495 nGlobalError
= 0; // N(#NA) and N("text") are ok
2496 if ( !nGlobalError
&& nErr
!= NOTAVAILABLE
)
2497 nGlobalError
= nErr
;
2502 void ScInterpreter::ScTrim()
2503 { // trimmt nicht nur sondern schnibbelt auch doppelte raus!
2504 String
aVal( GetString() );
2505 aVal
.EraseLeadingChars();
2506 aVal
.EraseTrailingChars();
2508 register const sal_Unicode
* p
= aVal
.GetBuffer();
2509 register const sal_Unicode
* const pEnd
= p
+ aVal
.Len();
2512 if ( *p
!= ' ' || p
[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
2520 void ScInterpreter::ScUpper()
2522 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTrim" );
2523 String aString
= GetString();
2524 ScGlobal::pCharClass
->toUpper(aString
);
2525 PushString(aString
);
2529 void ScInterpreter::ScPropper()
2531 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScPropper" );
2532 //2do: what to do with I18N-CJK ?!?
2533 String
aStr( GetString() );
2534 const xub_StrLen nLen
= aStr
.Len();
2535 // #i82487# don't try to write to empty string's BufferAccess
2536 // (would crash now that the empty string is const)
2539 String
aUpr( ScGlobal::pCharClass
->upper( aStr
) );
2540 String
aLwr( ScGlobal::pCharClass
->lower( aStr
) );
2541 register sal_Unicode
* pStr
= aStr
.GetBufferAccess();
2542 const sal_Unicode
* pUpr
= aUpr
.GetBuffer();
2543 const sal_Unicode
* pLwr
= aLwr
.GetBuffer();
2545 String
aTmpStr( 'x' );
2546 xub_StrLen nPos
= 1;
2547 while( nPos
< nLen
)
2549 aTmpStr
.SetChar( 0, pStr
[nPos
-1] );
2550 if ( !ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 ) )
2551 pStr
[nPos
] = pUpr
[nPos
];
2553 pStr
[nPos
] = pLwr
[nPos
];
2556 aStr
.ReleaseBufferAccess( nLen
);
2562 void ScInterpreter::ScLower()
2564 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLower" );
2565 String
aString( GetString() );
2566 ScGlobal::pCharClass
->toLower(aString
);
2567 PushString(aString
);
2571 void ScInterpreter::ScLen()
2573 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLen" );
2574 String
aStr( GetString() );
2575 PushDouble( aStr
.Len() );
2579 void ScInterpreter::ScT()
2581 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScT" );
2582 switch ( GetStackType() )
2588 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2593 BOOL bValue
= FALSE
;
2594 ScBaseCell
* pCell
= GetCell( aAdr
);
2595 if ( GetCellErrCode( pCell
) == 0 )
2597 switch ( GetCellType( pCell
) )
2599 case CELLTYPE_VALUE
:
2602 case CELLTYPE_FORMULA
:
2603 bValue
= ((ScFormulaCell
*)pCell
)->IsValue();
2610 PushString( EMPTY_STRING
);
2614 GetCellString( aTempStr
, pCell
);
2615 PushString( aTempStr
);
2622 PushString( EMPTY_STRING
);
2629 PushError( errUnknownOpCode
);
2634 void ScInterpreter::ScValue()
2636 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScValue" );
2637 String aInputString
;
2640 switch ( GetRawStackType() )
2648 return; // leave on stack
2655 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2660 ScBaseCell
* pCell
= GetCell( aAdr
);
2661 if ( pCell
&& pCell
->HasStringData() )
2662 GetCellString( aInputString
, pCell
);
2663 else if ( pCell
&& pCell
->HasValueData() )
2665 PushDouble( GetCellValue(aAdr
, pCell
) );
2677 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
2681 case SC_MATVAL_EMPTY
:
2684 case SC_MATVAL_VALUE
:
2685 case SC_MATVAL_BOOLEAN
:
2689 case SC_MATVAL_STRING
:
2693 PushIllegalArgument();
2698 aInputString
= GetString();
2702 sal_uInt32 nFIndex
= 0; // 0 for default locale
2703 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
2706 PushIllegalArgument();
2710 //2do: this should be a proper unicode string method
2711 inline BOOL
lcl_ScInterpreter_IsPrintable( sal_Unicode c
)
2713 return 0x20 <= c
&& c
!= 0x7f;
2716 void ScInterpreter::ScClean()
2718 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScClean" );
2719 String
aStr( GetString() );
2720 for ( xub_StrLen i
= 0; i
< aStr
.Len(); i
++ )
2722 if ( !lcl_ScInterpreter_IsPrintable( aStr
.GetChar( i
) ) )
2729 void ScInterpreter::ScCode()
2731 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCode" );
2732 //2do: make it full range unicode?
2733 const String
& rStr
= GetString();
2734 PushInt( (sal_uChar
) ByteString::ConvertFromUnicode( rStr
.GetChar(0), gsl_getSystemTextEncoding() ) );
2738 void ScInterpreter::ScChar()
2740 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScChar" );
2741 //2do: make it full range unicode?
2742 double fVal
= GetDouble();
2743 if (fVal
< 0.0 || fVal
>= 256.0)
2744 PushIllegalArgument();
2748 aStr
.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char
) fVal
, gsl_getSystemTextEncoding() ) );
2754 /* #i70213# fullwidth/halfwidth conversion provided by
2755 * Takashi Nakamoto <bluedwarf@ooo>
2756 * erAck: added Excel compatibility conversions as seen in issue's test case. */
2758 static ::rtl::OUString
lcl_convertIntoHalfWidth( const ::rtl::OUString
& rStr
)
2760 static bool bFirstASCCall
= true;
2761 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2765 aTrans
.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM
);
2766 bFirstASCCall
= false;
2769 return aTrans
.transliterate( rStr
, 0, USHORT( rStr
.getLength() ), NULL
);
2773 static ::rtl::OUString
lcl_convertIntoFullWidth( const ::rtl::OUString
& rStr
)
2775 static bool bFirstJISCall
= true;
2776 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2780 aTrans
.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM
);
2781 bFirstJISCall
= false;
2784 return aTrans
.transliterate( rStr
, 0, USHORT( rStr
.getLength() ), NULL
);
2789 * Summary: Converts half-width to full-width ASCII and katakana characters.
2790 * Semantics: Conversion is done for half-width ASCII and katakana characters,
2791 * other characters are simply copied from T to the result. This is the
2792 * complementary function to ASC.
2793 * For references regarding halfwidth and fullwidth characters see
2794 * http://www.unicode.org/reports/tr11/
2795 * http://www.unicode.org/charts/charindex2.html#H
2796 * http://www.unicode.org/charts/charindex2.html#F
2798 void ScInterpreter::ScJis()
2800 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScJis" );
2801 if (MustHaveParamCount( GetByte(), 1))
2802 PushString( lcl_convertIntoFullWidth( GetString()));
2807 * Summary: Converts full-width to half-width ASCII and katakana characters.
2808 * Semantics: Conversion is done for full-width ASCII and katakana characters,
2809 * other characters are simply copied from T to the result. This is the
2810 * complementary function to JIS.
2812 void ScInterpreter::ScAsc()
2814 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScAsc" );
2815 if (MustHaveParamCount( GetByte(), 1))
2816 PushString( lcl_convertIntoHalfWidth( GetString()));
2819 void ScInterpreter::ScUnicode()
2821 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScUnicode" );
2822 if ( MustHaveParamCount( GetByte(), 1 ) )
2824 const rtl::OUString
& rStr
= GetString();
2825 if (rStr
.getLength() <= 0)
2826 PushIllegalParameter();
2830 PushDouble( rStr
.iterateCodePoints(&i
) );
2835 void ScInterpreter::ScUnichar()
2837 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScUnichar" );
2838 if ( MustHaveParamCount( GetByte(), 1 ) )
2840 double dVal
= ::rtl::math::approxFloor( GetDouble() );
2841 if ((dVal
< 0x000000) || (dVal
> 0x10FFFF))
2842 PushIllegalArgument();
2845 sal_uInt32 nCodePoint
= static_cast<sal_uInt32
>( dVal
);
2846 rtl::OUString
aStr( &nCodePoint
, 1 );
2853 void ScInterpreter::ScMin( BOOL bTextAsZero
)
2855 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScMin" );
2856 short nParamCount
= GetByte();
2857 if (!MustHaveParamCountMin( nParamCount
, 1))
2859 double nMin
= ::std::numeric_limits
<double>::max();
2863 size_t nRefInList
= 0;
2864 while (nParamCount
-- > 0)
2866 switch (GetStackType())
2871 if (nMin
> nVal
) nMin
= nVal
;
2872 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2877 PopSingleRef( aAdr
);
2878 ScBaseCell
* pCell
= GetCell( aAdr
);
2879 if (HasCellValueData(pCell
))
2881 nVal
= GetCellValue( aAdr
, pCell
);
2883 if (nMin
> nVal
) nMin
= nVal
;
2885 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
2896 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2897 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
2898 if (aValIter
.GetFirst(nVal
, nErr
))
2902 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
2903 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
2914 ScMatrixRef pMat
= PopMatrix();
2918 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2919 pMat
->GetDimensions(nC
, nR
);
2920 if (pMat
->IsNumeric())
2922 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2923 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2925 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2926 if (nMin
> nVal
) nMin
= nVal
;
2931 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2933 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2935 if (!pMat
->IsString(nMatCol
,nMatRow
))
2937 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2938 if (nMin
> nVal
) nMin
= nVal
;
2940 else if ( bTextAsZero
)
2960 SetError(errIllegalParameter
);
2965 SetError(errIllegalParameter
);
2974 #if defined(WIN) && defined(MSC)
2975 #pragma optimize("",off)
2978 void ScInterpreter::ScMax( BOOL bTextAsZero
)
2980 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScMax" );
2981 short nParamCount
= GetByte();
2982 if (!MustHaveParamCountMin( nParamCount
, 1))
2984 double nMax
= -(::std::numeric_limits
<double>::max());
2988 size_t nRefInList
= 0;
2989 while (nParamCount
-- > 0)
2991 switch (GetStackType())
2996 if (nMax
< nVal
) nMax
= nVal
;
2997 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3002 PopSingleRef( aAdr
);
3003 ScBaseCell
* pCell
= GetCell( aAdr
);
3004 if (HasCellValueData(pCell
))
3006 nVal
= GetCellValue( aAdr
, pCell
);
3008 if (nMax
< nVal
) nMax
= nVal
;
3010 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
3021 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3022 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3023 if (aValIter
.GetFirst(nVal
, nErr
))
3027 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3028 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
3039 ScMatrixRef pMat
= PopMatrix();
3042 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3044 pMat
->GetDimensions(nC
, nR
);
3045 if (pMat
->IsNumeric())
3047 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3048 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3050 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3051 if (nMax
< nVal
) nMax
= nVal
;
3056 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3058 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3060 if (!pMat
->IsString(nMatCol
,nMatRow
))
3062 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3063 if (nMax
< nVal
) nMax
= nVal
;
3065 else if ( bTextAsZero
)
3085 SetError(errIllegalParameter
);
3090 SetError(errIllegalParameter
);
3098 #if defined(WIN) && defined(MSC)
3099 #pragma optimize("",on)
3103 double ScInterpreter::IterateParameters( ScIterFunc eFunc
, BOOL bTextAsZero
)
3105 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::IterateParameters" );
3106 short nParamCount
= GetByte();
3107 double fRes
= ( eFunc
== ifPRODUCT
) ? 1.0 : 0.0;
3114 size_t nRefInList
= 0;
3115 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3117 while (nParamCount
-- > 0)
3119 switch (GetStackType())
3124 if( eFunc
== ifCOUNT
)
3126 String
aStr( PopString() );
3127 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
3128 if ( bTextAsZero
|| pFormatter
->IsNumberFormat(aStr
, nFIndex
, fVal
))
3144 if ( eFunc
== ifPRODUCT
)
3149 while (nParamCount
-- > 0)
3151 SetError( errNoValue
);
3169 if ( bNull
&& fVal
!= 0.0 )
3177 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3178 case ifPRODUCT
: fRes
*= fVal
; break;
3179 default: ; // nothing
3181 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3185 PopSingleRef( aAdr
);
3186 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3189 if ( eFunc
== ifCOUNT2
)
3193 ScBaseCell
* pCell
= GetCell( aAdr
);
3196 if( eFunc
== ifCOUNT2
)
3198 CellType eCellType
= pCell
->GetCellType();
3199 if (eCellType
!= CELLTYPE_NONE
&& eCellType
!= CELLTYPE_NOTE
)
3204 else if ( pCell
->HasValueData() )
3207 fVal
= GetCellValue( aAdr
, pCell
);
3213 if ( bNull
&& fVal
!= 0.0 )
3221 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3222 case ifPRODUCT
: fRes
*= fVal
; break;
3230 default: ; // nothing
3233 else if ( bTextAsZero
&& pCell
->HasStringData() )
3236 if ( eFunc
== ifPRODUCT
)
3246 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3247 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3250 if ( eFunc
== ifCOUNT2
)
3254 if( eFunc
== ifCOUNT2
)
3257 ScCellIterator
aIter( pDok
, aRange
, glSubTotal
);
3258 if ( (pCell
= aIter
.GetFirst()) != NULL
)
3262 CellType eType
= pCell
->GetCellType();
3263 if( eType
!= CELLTYPE_NONE
&& eType
!= CELLTYPE_NOTE
)
3266 while ( (pCell
= aIter
.GetNext()) != NULL
);
3273 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3274 if (aValIter
.GetFirst(fVal
, nErr
))
3276 // Schleife aus Performance-Gruenden nach innen verlegt:
3277 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3285 if ( bNull
&& fVal
!= 0.0 )
3294 while (aValIter
.GetNext(fVal
, nErr
));
3300 fRes
+= fVal
* fVal
;
3303 while (aValIter
.GetNext(fVal
, nErr
));
3312 while (aValIter
.GetNext(fVal
, nErr
));
3320 while (aValIter
.GetNext(fVal
, nErr
));
3322 default: ; // nothing
3331 ScMatrixRef pMat
= PopMatrix();
3335 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3336 pMat
->GetDimensions(nC
, nR
);
3337 if( eFunc
== ifCOUNT2
)
3338 nCount
+= (ULONG
) nC
* nR
;
3341 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3343 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3345 if (!pMat
->IsString(nMatCol
,nMatRow
))
3348 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3353 if ( bNull
&& fVal
!= 0.0 )
3361 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3362 case ifPRODUCT
: fRes
*= fVal
; break;
3363 default: ; // nothing
3366 else if ( bTextAsZero
)
3369 if ( eFunc
== ifPRODUCT
)
3381 if ( eFunc
== ifCOUNT
)
3385 else if ( eFunc
== ifCOUNT2
)
3393 while (nParamCount
-- > 0)
3395 SetError(errIllegalParameter
);
3400 case ifSUM
: fRes
= ::rtl::math::approxAdd( fRes
, fMem
); break;
3401 case ifAVERAGE
: fRes
= div(::rtl::math::approxAdd( fRes
, fMem
), nCount
); break;
3403 case ifCOUNT
: fRes
= nCount
; break;
3404 case ifPRODUCT
: if ( !nCount
) fRes
= 0.0; break;
3405 default: ; // nothing
3407 // Bei Summen etc. macht ein BOOL-Ergebnis keinen Sinn
3408 // und Anzahl ist immer Number (#38345#)
3409 if( eFunc
== ifCOUNT
|| nFuncFmtType
== NUMBERFORMAT_LOGICAL
)
3410 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3415 void ScInterpreter::ScSumSQ()
3417 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSumSQ" );
3418 PushDouble( IterateParameters( ifSUMSQ
) );
3422 void ScInterpreter::ScSum()
3424 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSum" );
3425 PushDouble( IterateParameters( ifSUM
) );
3429 void ScInterpreter::ScProduct()
3431 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScProduct" );
3432 PushDouble( IterateParameters( ifPRODUCT
) );
3436 void ScInterpreter::ScAverage( BOOL bTextAsZero
)
3438 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScAverage" );
3439 PushDouble( IterateParameters( ifAVERAGE
, bTextAsZero
) );
3443 void ScInterpreter::ScCount()
3445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCount" );
3446 PushDouble( IterateParameters( ifCOUNT
) );
3450 void ScInterpreter::ScCount2()
3452 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCount2" );
3453 PushDouble( IterateParameters( ifCOUNT2
) );
3457 void ScInterpreter::GetStVarParams( double& rVal
, double& rValCount
,
3460 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetStVarParams" );
3461 short nParamCount
= GetByte();
3463 std::vector
<double> values
;
3471 size_t nRefInList
= 0;
3472 while (nParamCount
-- > 0)
3474 switch (GetStackType())
3479 values
.push_back(fVal
);
3486 PopSingleRef( aAdr
);
3487 ScBaseCell
* pCell
= GetCell( aAdr
);
3488 if (HasCellValueData(pCell
))
3490 fVal
= GetCellValue( aAdr
, pCell
);
3491 values
.push_back(fVal
);
3495 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
3497 values
.push_back(0.0);
3506 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3507 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3508 if (aValIter
.GetFirst(fVal
, nErr
))
3512 values
.push_back(fVal
);
3516 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
3522 ScMatrixRef pMat
= PopMatrix();
3526 pMat
->GetDimensions(nC
, nR
);
3527 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3529 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3531 if (!pMat
->IsString(nMatCol
,nMatRow
))
3533 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3534 values
.push_back(fVal
);
3538 else if ( bTextAsZero
)
3540 values
.push_back(0.0);
3553 values
.push_back(0.0);
3557 SetError(errIllegalParameter
);
3562 SetError(errIllegalParameter
);
3566 ::std::vector
<double>::size_type n
= values
.size();
3568 for (::std::vector
<double>::size_type i
= 0; i
< n
; i
++)
3569 vSum
+= ::rtl::math::approxSub( values
[i
], vMean
) * ::rtl::math::approxSub( values
[i
], vMean
);
3574 void ScInterpreter::ScVar( BOOL bTextAsZero
)
3576 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScVar" );
3579 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3581 if (nValCount
<= 1.0)
3582 PushError( errDivisionByZero
);
3584 PushDouble( nVal
/ (nValCount
- 1.0));
3588 void ScInterpreter::ScVarP( BOOL bTextAsZero
)
3590 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScVarP" );
3593 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3595 PushDouble( div( nVal
, nValCount
));
3599 void ScInterpreter::ScStDev( BOOL bTextAsZero
)
3601 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScStDev" );
3604 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3605 if (nValCount
<= 1.0)
3606 PushError( errDivisionByZero
);
3608 PushDouble( sqrt( nVal
/ (nValCount
- 1.0)));
3612 void ScInterpreter::ScStDevP( BOOL bTextAsZero
)
3614 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScStDevP" );
3617 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3618 if (nValCount
== 0.0)
3619 PushError( errDivisionByZero
);
3621 PushDouble( sqrt( nVal
/ nValCount
));
3623 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3625 * Besides that the special NAN gets lost in the call through sqrt(),
3626 * unxlngi6.pro then looped back and forth somewhere between div() and
3627 * ::rtl::math::setNan(). Tests showed that
3629 * sqrt( div( 1, 0));
3631 * produced a loop, but
3633 * double f1 = div( 1, 0);
3636 * was fine. There seems to be some compiler optimization problem. It does
3637 * not occur when compiled with debug=t.
3642 void ScInterpreter::ScColumns()
3644 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScColumns" );
3645 BYTE nParamCount
= GetByte();
3653 while (nParamCount
-- > 0)
3655 switch ( GetStackType() )
3662 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3663 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1) *
3664 static_cast<ULONG
>(nCol2
- nCol1
+ 1);
3668 ScMatrixRef pMat
= PopMatrix();
3672 pMat
->GetDimensions(nC
, nR
);
3679 SetError(errIllegalParameter
);
3682 PushDouble((double)nVal
);
3686 void ScInterpreter::ScRows()
3688 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRows" );
3689 BYTE nParamCount
= GetByte();
3697 while (nParamCount
-- > 0)
3699 switch ( GetStackType() )
3706 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3707 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1) *
3708 static_cast<ULONG
>(nRow2
- nRow1
+ 1);
3712 ScMatrixRef pMat
= PopMatrix();
3716 pMat
->GetDimensions(nC
, nR
);
3723 SetError(errIllegalParameter
);
3726 PushDouble((double)nVal
);
3729 void ScInterpreter::ScTables()
3731 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTables" );
3732 BYTE nParamCount
= GetByte();
3734 if ( nParamCount
== 0 )
3735 nVal
= pDok
->GetTableCount();
3745 while (nParamCount
-- > 0)
3747 switch ( GetStackType() )
3754 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3755 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1);
3763 SetError( errIllegalParameter
);
3767 PushDouble( (double) nVal
);
3771 void ScInterpreter::ScColumn()
3773 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScColumn" );
3774 BYTE nParamCount
= GetByte();
3775 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3778 if (nParamCount
== 0)
3780 nVal
= aPos
.Col() + 1;
3785 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3786 ScMatrixRef pResMat
= GetNewMat( static_cast<SCSIZE
>(nCols
), 1);
3789 for (SCCOL i
=0; i
< nCols
; ++i
)
3790 pResMat
->PutDouble( nVal
+ i
, static_cast<SCSIZE
>(i
), 0);
3791 PushMatrix( pResMat
);
3798 switch ( GetStackType() )
3805 PopSingleRef( nCol1
, nRow1
, nTab1
);
3806 nVal
= (double) (nCol1
+ 1);
3817 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3820 ScMatrixRef pResMat
= GetNewMat(
3821 static_cast<SCSIZE
>(nCol2
-nCol1
+1), 1);
3824 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
3825 pResMat
->PutDouble((double)(i
+1),
3826 static_cast<SCSIZE
>(i
-nCol1
), 0);
3827 PushMatrix(pResMat
);
3834 nVal
= (double) (nCol1
+ 1);
3838 SetError( errIllegalParameter
);
3847 void ScInterpreter::ScRow()
3849 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRow" );
3850 BYTE nParamCount
= GetByte();
3851 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3854 if (nParamCount
== 0)
3856 nVal
= aPos
.Row() + 1;
3861 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3862 ScMatrixRef pResMat
= GetNewMat( 1, static_cast<SCSIZE
>(nRows
));
3865 for (SCROW i
=0; i
< nRows
; i
++)
3866 pResMat
->PutDouble( nVal
+ i
, 0, static_cast<SCSIZE
>(i
));
3867 PushMatrix( pResMat
);
3874 switch ( GetStackType() )
3881 PopSingleRef( nCol1
, nRow1
, nTab1
);
3882 nVal
= (double) (nRow1
+ 1);
3893 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3896 ScMatrixRef pResMat
= GetNewMat( 1,
3897 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
3900 for (SCROW i
= nRow1
; i
<= nRow2
; i
++)
3901 pResMat
->PutDouble((double)(i
+1), 0,
3902 static_cast<SCSIZE
>(i
-nRow1
));
3903 PushMatrix(pResMat
);
3910 nVal
= (double) (nRow1
+ 1);
3914 SetError( errIllegalParameter
);
3922 void ScInterpreter::ScTable()
3924 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScTable" );
3925 BYTE nParamCount
= GetByte();
3926 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3929 if ( nParamCount
== 0 )
3930 nVal
= aPos
.Tab() + 1;
3933 switch ( GetStackType() )
3937 String
aStr( PopString() );
3938 if ( pDok
->GetTable( aStr
, nVal
) )
3941 SetError( errIllegalArgument
);
3949 PopSingleRef( nCol1
, nRow1
, nTab1
);
3961 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3966 SetError( errIllegalParameter
);
3971 PushDouble( (double) nVal
);
3975 /** returns -1 when the matrix value is smaller than the query value, 0 when
3976 they are equal, and 1 when the matrix value is larger than the query
3978 static sal_Int32
lcl_CompareMatrix2Query( SCSIZE i
, const ScMatrix
& rMat
,
3979 const ScQueryEntry
& rEntry
)
3981 if (rMat
.IsEmpty(i
))
3983 /* TODO: in case we introduced query for real empty this would have to
3985 return -1; // empty always less than anything else
3988 /* FIXME: what is an empty path (result of IF(false;true_path) in
3991 if (rMat
.IsValue(i
))
3993 if (rEntry
.bQueryByString
)
3994 return -1; // numeric always less than string
3996 const double nVal1
= rMat
.GetDouble(i
);
3997 const double nVal2
= rEntry
.nVal
;
4001 return nVal1
< nVal2
? -1 : 1;
4004 if (!rEntry
.bQueryByString
)
4005 return 1; // string always greater than numeric
4008 // this should not happen!
4011 const String
& rStr1
= rMat
.GetString(i
);
4012 const String
& rStr2
= *rEntry
.pStr
;
4014 return ScGlobal::GetCollator()->compareString( rStr1
, rStr2
); // case-insensitive
4017 /** returns the last item with the identical value as the original item
4019 static void lcl_GetLastMatch( SCSIZE
& rIndex
, const ScMatrix
& rMat
,
4020 SCSIZE nMatCount
, bool bReverse
)
4022 if (rMat
.IsValue(rIndex
))
4024 double nVal
= rMat
.GetDouble(rIndex
);
4026 while (rIndex
> 0 && rMat
.IsValue(rIndex
-1) &&
4027 nVal
== rMat
.GetDouble(rIndex
-1))
4030 while (rIndex
< nMatCount
-1 && rMat
.IsValue(rIndex
+1) &&
4031 nVal
== rMat
.GetDouble(rIndex
+1))
4034 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
4035 else if (rMat
.IsEmptyPath(rIndex
))
4038 while (rIndex
> 0 && rMat
.IsEmptyPath(rIndex
-1))
4041 while (rIndex
< nMatCount
-1 && rMat
.IsEmptyPath(rIndex
+1))
4044 else if (rMat
.IsEmpty(rIndex
))
4047 while (rIndex
> 0 && rMat
.IsEmpty(rIndex
-1))
4050 while (rIndex
< nMatCount
-1 && rMat
.IsEmpty(rIndex
+1))
4053 else if (rMat
.IsString(rIndex
))
4055 String
aStr( rMat
.GetString(rIndex
));
4057 while (rIndex
> 0 && rMat
.IsString(rIndex
-1) &&
4058 aStr
== rMat
.GetString(rIndex
-1))
4061 while (rIndex
< nMatCount
-1 && rMat
.IsString(rIndex
+1) &&
4062 aStr
== rMat
.GetString(rIndex
+1))
4067 DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
4071 void ScInterpreter::ScMatch()
4073 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScMatch" );
4074 ScMatrixRef pMatSrc
= NULL
;
4076 BYTE nParamCount
= GetByte();
4077 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4080 if (nParamCount
== 3)
4090 if (GetStackType() == svDoubleRef
)
4092 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4093 if (nTab1
!= nTab2
|| (nCol1
!= nCol2
&& nRow1
!= nRow2
))
4095 PushIllegalParameter();
4099 else if (GetStackType() == svMatrix
)
4101 pMatSrc
= PopMatrix();
4104 PushIllegalParameter();
4110 PushIllegalParameter();
4113 if (nGlobalError
== 0)
4117 ScQueryParam rParam
;
4118 rParam
.nCol1
= nCol1
;
4119 rParam
.nRow1
= nRow1
;
4120 rParam
.nCol2
= nCol2
;
4121 rParam
.nTab
= nTab1
;
4122 rParam
.bMixedComparison
= TRUE
;
4124 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4125 rEntry
.bDoQuery
= TRUE
;
4127 rEntry
.eOp
= SC_GREATER_EQUAL
;
4128 else if (fTyp
> 0.0)
4129 rEntry
.eOp
= SC_LESS_EQUAL
;
4130 switch ( GetStackType() )
4135 rEntry
.bQueryByString
= FALSE
;
4142 rEntry
.bQueryByString
= TRUE
;
4143 *rEntry
.pStr
= sStr
;
4150 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4155 ScBaseCell
* pCell
= GetCell( aAdr
);
4156 if (HasCellValueData(pCell
))
4158 fVal
= GetCellValue( aAdr
, pCell
);
4159 rEntry
.bQueryByString
= FALSE
;
4164 GetCellString(sStr
, pCell
);
4165 rEntry
.bQueryByString
= TRUE
;
4166 *rEntry
.pStr
= sStr
;
4172 ScMatValType nType
= GetDoubleOrStringFromMatrix(
4173 rEntry
.nVal
, *rEntry
.pStr
);
4174 rEntry
.bQueryByString
= ScMatrix::IsNonValueType( nType
);
4179 PushIllegalParameter();
4183 if ( rEntry
.bQueryByString
)
4185 BOOL bIsVBAMode
= FALSE
;
4188 SfxObjectShell
* pDocSh
= pDok
->GetDocumentShell();
4190 bIsVBAMode
= pDocSh
->GetBasic()->isVBAEnabled();
4192 // #TODO handle MSO wildcards
4194 rParam
.bRegExp
= FALSE
;
4196 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4199 if (pMatSrc
) // The source data is matrix array.
4202 pMatSrc
->GetDimensions( nC
, nR
);
4203 if (nC
> 1 && nR
> 1)
4205 // The source matrix must be a vector.
4206 PushIllegalParameter();
4209 SCSIZE nMatCount
= (nC
== 1) ? nR
: nC
;
4211 // simple serial search for equality mode (source data doesn't
4212 // need to be sorted).
4214 if (rEntry
.eOp
== SC_EQUAL
)
4216 for (SCSIZE i
= 0; i
< nMatCount
; ++i
)
4218 if (lcl_CompareMatrix2Query( i
, *pMatSrc
, rEntry
) == 0)
4220 PushDouble(i
+1); // found !
4224 PushNA(); // not found
4228 // binary search for non-equality mode (the source data is
4229 // assumed to be sorted).
4231 bool bAscOrder
= (rEntry
.eOp
== SC_LESS_EQUAL
);
4232 SCSIZE nFirst
= 0, nLast
= nMatCount
-1, nHitIndex
= 0;
4233 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
4235 SCSIZE nMid
= nFirst
+ nLen
/2;
4236 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, *pMatSrc
, rEntry
);
4239 // exact match. find the last item with the same value.
4240 lcl_GetLastMatch( nMid
, *pMatSrc
, nMatCount
, !bAscOrder
);
4241 PushDouble( nMid
+1);
4245 if (nLen
== 1) // first and last items are next to each other.
4248 nHitIndex
= bAscOrder
? nLast
: nFirst
;
4250 nHitIndex
= bAscOrder
? nFirst
: nLast
;
4270 if (nHitIndex
== nMatCount
-1) // last item
4272 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nHitIndex
, *pMatSrc
, rEntry
);
4273 if ((bAscOrder
&& nCmp
<= 0) || (!bAscOrder
&& nCmp
>= 0))
4275 // either the last item is an exact match or the real
4276 // hit is beyond the last item.
4277 PushDouble( nHitIndex
+1);
4282 if (nHitIndex
> 0) // valid hit must be 2nd item or higher
4284 PushDouble( nHitIndex
); // non-exact match
4292 SCCOLROW nDelta
= 0;
4294 { // search row in column
4295 rParam
.nRow2
= nRow2
;
4296 rEntry
.nField
= nCol1
;
4297 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
4298 if (!LookupQueryWithCache( aResultPos
, rParam
))
4303 nDelta
= aResultPos
.Row() - nRow1
;
4306 { // search column in row
4308 rParam
.bByRow
= FALSE
;
4309 rParam
.nRow2
= nRow1
;
4310 rEntry
.nField
= nCol1
;
4311 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4312 // Advance Entry.nField in Iterator if column changed
4313 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4316 if ( aCellIter
.GetFirst() )
4317 nC
= aCellIter
.GetCol();
4327 if ( !aCellIter
.FindEqualOrSortedLastInRange( nC
, nR
) )
4333 nDelta
= nC
- nCol1
;
4335 PushDouble((double) (nDelta
+ 1));
4338 PushIllegalParameter();
4343 void ScInterpreter::ScCountEmptyCells()
4345 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCountEmptyCells" );
4346 if ( MustHaveParamCount( GetByte(), 1 ) )
4348 ULONG nMaxCount
= 0, nCount
= 0;
4350 switch (GetStackType())
4356 PopSingleRef( aAdr
);
4357 eCellType
= GetCellType( GetCell( aAdr
) );
4358 if (eCellType
!= CELLTYPE_NONE
&& eCellType
!= CELLTYPE_NOTE
)
4367 size_t nRefInList
= 0;
4368 while (nParam
-- > 0)
4370 PopDoubleRef( aRange
, nParam
, nRefInList
);
4372 static_cast<ULONG
>(aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1) *
4373 static_cast<ULONG
>(aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1) *
4374 static_cast<ULONG
>(aRange
.aEnd
.Tab() - aRange
.aStart
.Tab() + 1);
4376 ScCellIterator
aDocIter( pDok
, aRange
, glSubTotal
);
4377 if ( (pCell
= aDocIter
.GetFirst()) != NULL
)
4381 if ((eCellType
= pCell
->GetCellType()) != CELLTYPE_NONE
4382 && eCellType
!= CELLTYPE_NOTE
)
4384 } while ( (pCell
= aDocIter
.GetNext()) != NULL
);
4389 default : SetError(errIllegalParameter
); break;
4391 PushDouble(nMaxCount
- nCount
);
4396 void ScInterpreter::ScCountIf()
4398 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCountIf" );
4399 if ( MustHaveParamCount( GetByte(), 2 ) )
4403 BOOL bIsString
= TRUE
;
4404 switch ( GetStackType() )
4410 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4415 ScBaseCell
* pCell
= GetCell( aAdr
);
4416 switch ( GetCellType( pCell
) )
4418 case CELLTYPE_VALUE
:
4419 fVal
= GetCellValue( aAdr
, pCell
);
4422 case CELLTYPE_FORMULA
:
4423 if( ((ScFormulaCell
*)pCell
)->IsValue() )
4425 fVal
= GetCellValue( aAdr
, pCell
);
4429 GetCellString(rString
, pCell
);
4431 case CELLTYPE_STRING
:
4432 case CELLTYPE_EDIT
:
4433 GetCellString(rString
, pCell
);
4443 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
4445 bIsString
= ScMatrix::IsNonValueType( nType
);
4449 rString
= GetString();
4459 size_t nRefInList
= 0;
4460 while (nParam
-- > 0)
4468 ScMatrixRef pQueryMatrix
;
4469 switch ( GetStackType() )
4475 PopDoubleRef( aRange
, nParam
, nRefInList
);
4476 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4480 PopSingleRef( nCol1
, nRow1
, nTab1
);
4487 pQueryMatrix
= PopMatrix();
4490 PushIllegalParameter();
4497 pQueryMatrix
->GetDimensions( nC
, nR
);
4498 nCol2
= static_cast<SCCOL
>(nC
- 1);
4499 nRow2
= static_cast<SCROW
>(nR
- 1);
4504 PushIllegalParameter();
4507 if ( nTab1
!= nTab2
)
4509 PushIllegalParameter();
4514 PushIllegalParameter();
4517 if (nGlobalError
== 0)
4519 ScQueryParam rParam
;
4520 rParam
.nRow1
= nRow1
;
4521 rParam
.nRow2
= nRow2
;
4523 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4524 rEntry
.bDoQuery
= TRUE
;
4527 rEntry
.bQueryByString
= FALSE
;
4529 rEntry
.eOp
= SC_EQUAL
;
4533 rParam
.FillInExcelSyntax(rString
, 0);
4534 sal_uInt32 nIndex
= 0;
4535 rEntry
.bQueryByString
=
4536 !(pFormatter
->IsNumberFormat(
4537 *rEntry
.pStr
, nIndex
, rEntry
.nVal
));
4538 if ( rEntry
.bQueryByString
)
4539 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4541 rParam
.nCol1
= nCol1
;
4542 rParam
.nCol2
= nCol2
;
4543 rEntry
.nField
= nCol1
;
4546 // Never case-sensitive.
4547 ScCompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
4548 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
4549 if (nGlobalError
|| !pResultMatrix
)
4551 PushIllegalParameter();
4555 SCSIZE nSize
= pResultMatrix
->GetElementCount();
4556 for (SCSIZE nIndex
= 0; nIndex
< nSize
; ++nIndex
)
4558 if (pResultMatrix
->IsValue( nIndex
) &&
4559 pResultMatrix
->GetDouble( nIndex
))
4565 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4566 // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
4567 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4568 if ( aCellIter
.GetFirst() )
4573 } while ( aCellIter
.GetNext() );
4579 PushIllegalParameter();
4588 void ScInterpreter::ScSumIf()
4590 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSumIf" );
4591 BYTE nParamCount
= GetByte();
4592 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4598 ScMatrixRef pSumExtraMatrix
;
4599 bool bSumExtraRange
= (nParamCount
== 3);
4602 // Save only the upperleft cell in case of cell range. The geometry
4603 // of the 3rd parameter is taken from the 1st parameter.
4605 switch ( GetStackType() )
4612 PopDoubleRef( nCol3
, nRow3
, nTab3
, nColJunk
, nRowJunk
, nTabJunk
);
4613 if ( nTabJunk
!= nTab3
)
4615 PushIllegalParameter();
4621 PopSingleRef( nCol3
, nRow3
, nTab3
);
4624 pSumExtraMatrix
= PopMatrix();
4625 //! nCol3, nRow3, nTab3 remain 0
4628 PushIllegalParameter();
4634 BOOL bIsString
= TRUE
;
4635 switch ( GetStackType() )
4641 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4646 ScBaseCell
* pCell
= GetCell( aAdr
);
4647 switch ( GetCellType( pCell
) )
4649 case CELLTYPE_VALUE
:
4650 fVal
= GetCellValue( aAdr
, pCell
);
4653 case CELLTYPE_FORMULA
:
4654 if( ((ScFormulaCell
*)pCell
)->IsValue() )
4656 fVal
= GetCellValue( aAdr
, pCell
);
4660 GetCellString(rString
, pCell
);
4662 case CELLTYPE_STRING
:
4663 case CELLTYPE_EDIT
:
4664 GetCellString(rString
, pCell
);
4673 rString
= GetString();
4677 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
4679 bIsString
= ScMatrix::IsNonValueType( nType
);
4693 size_t nRefInList
= 0;
4694 while (nParam
-- > 0)
4702 ScMatrixRef pQueryMatrix
;
4703 switch ( GetStackType() )
4708 PushIllegalParameter();
4714 PopDoubleRef( aRange
, nParam
, nRefInList
);
4715 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4719 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4722 PopSingleRef( nCol1
, nRow1
, nTab1
);
4729 pQueryMatrix
= PopMatrix();
4732 PushIllegalParameter();
4739 pQueryMatrix
->GetDimensions( nC
, nR
);
4740 nCol2
= static_cast<SCCOL
>(nC
- 1);
4741 nRow2
= static_cast<SCROW
>(nR
- 1);
4746 PushIllegalParameter();
4749 if ( nTab1
!= nTab2
)
4751 PushIllegalArgument();
4757 // Take the range geometry of the 1st parameter and apply it to
4758 // the 3rd. If parts of the resulting range would point outside
4759 // the sheet, don't complain but silently ignore and simply cut
4760 // them away, this is what Xcl does :-/
4762 // For the cut-away part we also don't need to determine the
4763 // criteria match, so shrink the source range accordingly,
4764 // instead of the result range.
4765 SCCOL nColDelta
= nCol2
- nCol1
;
4766 SCROW nRowDelta
= nRow2
- nRow1
;
4769 if (pSumExtraMatrix
)
4772 pSumExtraMatrix
->GetDimensions( nC
, nR
);
4773 nMaxCol
= static_cast<SCCOL
>(nC
- 1);
4774 nMaxRow
= static_cast<SCROW
>(nR
- 1);
4781 if (nCol3
+ nColDelta
> nMaxCol
)
4783 SCCOL nNewDelta
= nMaxCol
- nCol3
;
4784 nCol2
= nCol1
+ nNewDelta
;
4787 if (nRow3
+ nRowDelta
> nMaxRow
)
4789 SCROW nNewDelta
= nMaxRow
- nRow3
;
4790 nRow2
= nRow1
+ nNewDelta
;
4800 if (nGlobalError
== 0)
4802 ScQueryParam rParam
;
4803 rParam
.nRow1
= nRow1
;
4804 rParam
.nRow2
= nRow2
;
4806 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4807 rEntry
.bDoQuery
= TRUE
;
4810 rEntry
.bQueryByString
= FALSE
;
4812 rEntry
.eOp
= SC_EQUAL
;
4816 rParam
.FillInExcelSyntax(rString
, 0);
4817 sal_uInt32 nIndex
= 0;
4818 rEntry
.bQueryByString
=
4819 !(pFormatter
->IsNumberFormat(
4820 *rEntry
.pStr
, nIndex
, rEntry
.nVal
));
4821 if ( rEntry
.bQueryByString
)
4822 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4825 aAdr
.SetTab( nTab3
);
4826 rParam
.nCol1
= nCol1
;
4827 rParam
.nCol2
= nCol2
;
4828 rEntry
.nField
= nCol1
;
4829 SCsCOL nColDiff
= nCol3
- nCol1
;
4830 SCsROW nRowDiff
= nRow3
- nRow1
;
4833 // Never case-sensitive.
4834 ScCompareOptions
aOptions( pDok
, rEntry
, rParam
.bRegExp
);
4835 ScMatrixRef pResultMatrix
= QueryMat( pQueryMatrix
, aOptions
);
4836 if (nGlobalError
|| !pResultMatrix
)
4838 PushIllegalParameter();
4842 if (pSumExtraMatrix
)
4844 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4846 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4848 if (pResultMatrix
->IsValue( nCol
, nRow
) &&
4849 pResultMatrix
->GetDouble( nCol
, nRow
))
4851 SCSIZE nC
= nCol
+ nColDiff
;
4852 SCSIZE nR
= nRow
+ nRowDiff
;
4853 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4855 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4856 if ( bNull
&& fVal
!= 0.0 )
4870 for (SCCOL nCol
= nCol1
; nCol
<= nCol2
; ++nCol
)
4872 for (SCROW nRow
= nRow1
; nRow
<= nRow2
; ++nRow
)
4874 if (pResultMatrix
->GetDouble( nCol
, nRow
))
4876 aAdr
.SetCol( nCol
+ nColDiff
);
4877 aAdr
.SetRow( nRow
+ nRowDiff
);
4878 ScBaseCell
* pCell
= GetCell( aAdr
);
4879 if ( HasCellValueData(pCell
) )
4881 fVal
= GetCellValue( aAdr
, pCell
);
4882 if ( bNull
&& fVal
!= 0.0 )
4897 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4898 // Increment Entry.nField in iterator when switching to next column.
4899 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4900 if ( aCellIter
.GetFirst() )
4902 if (pSumExtraMatrix
)
4906 SCSIZE nC
= aCellIter
.GetCol() + nColDiff
;
4907 SCSIZE nR
= aCellIter
.GetRow() + nRowDiff
;
4908 if (pSumExtraMatrix
->IsValue( nC
, nR
))
4910 fVal
= pSumExtraMatrix
->GetDouble( nC
, nR
);
4911 if ( bNull
&& fVal
!= 0.0 )
4919 } while ( aCellIter
.GetNext() );
4925 aAdr
.SetCol( aCellIter
.GetCol() + nColDiff
);
4926 aAdr
.SetRow( aCellIter
.GetRow() + nRowDiff
);
4927 ScBaseCell
* pCell
= GetCell( aAdr
);
4928 if ( HasCellValueData(pCell
) )
4930 fVal
= GetCellValue( aAdr
, pCell
);
4931 if ( bNull
&& fVal
!= 0.0 )
4939 } while ( aCellIter
.GetNext() );
4946 PushIllegalParameter();
4950 PushDouble( ::rtl::math::approxAdd( fSum
, fMem
) );
4955 void ScInterpreter::ScLookup()
4957 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLookup" );
4958 BYTE nParamCount
= GetByte();
4959 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
4962 ScMatrixRef pDataMat
= NULL
, pResMat
= NULL
;
4963 SCCOL nCol1
= 0, nCol2
= 0, nResCol1
= 0, nResCol2
= 0;
4964 SCROW nRow1
= 0, nRow2
= 0, nResRow1
= 0, nResRow2
= 0;
4965 SCTAB nTab1
= 0, nResTab
= 0;
4966 SCSIZE nLenMajor
= 0; // length of major direction
4967 bool bVertical
= true; // whether to lookup vertically or horizontally
4969 // The third parameter, result array, for double, string and single reference.
4970 double fResVal
= 0.0;
4973 StackVar eResArrayType
= svUnknown
;
4975 if (nParamCount
== 3)
4977 eResArrayType
= GetStackType();
4978 switch (eResArrayType
)
4983 PopDoubleRef(nResCol1
, nResRow1
, nResTab
,
4984 nResCol2
, nResRow2
, nTabJunk
);
4985 if (nResTab
!= nTabJunk
||
4986 ((nResRow2
- nResRow1
) > 0 && (nResCol2
- nResCol1
) > 0))
4988 // The result array must be a vector.
4989 PushIllegalParameter();
4996 pResMat
= PopMatrix();
4999 PushIllegalParameter();
5003 pResMat
->GetDimensions(nC
, nR
);
5004 if (nC
!= 1 && nR
!= 1)
5006 // Result matrix must be a vector.
5007 PushIllegalParameter();
5013 fResVal
= GetDouble();
5016 aResStr
= GetString();
5019 PopSingleRef( aResAdr
);
5022 PushIllegalParameter();
5027 // For double, string and single reference.
5028 double fDataVal
= 0.0;
5031 bool bValueData
= false;
5033 // Get the data-result range and also determine whether this is vertical
5034 // lookup or horizontal lookup.
5036 StackVar eDataArrayType
= GetStackType();
5037 switch (eDataArrayType
)
5042 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTabJunk
);
5043 if (nTab1
!= nTabJunk
)
5045 PushIllegalParameter();
5048 bVertical
= (nRow2
- nRow1
) >= (nCol2
- nCol1
);
5049 nLenMajor
= bVertical
? nRow2
- nRow1
+ 1 : nCol2
- nCol1
+ 1;
5054 pDataMat
= PopMatrix();
5057 PushIllegalParameter();
5062 pDataMat
->GetDimensions(nC
, nR
);
5063 bVertical
= (nR
>= nC
);
5064 nLenMajor
= bVertical
? nR
: nC
;
5069 fDataVal
= GetDouble();
5075 aDataStr
= GetString();
5080 PopSingleRef( aDataAdr
);
5081 const ScBaseCell
* pDataCell
= GetCell( aDataAdr
);
5082 if (HasCellEmptyData( pDataCell
))
5084 // Empty cells aren't found anywhere, bail out early.
5085 SetError( NOTAVAILABLE
);
5087 else if (HasCellValueData( pDataCell
))
5089 fDataVal
= GetCellValue( aDataAdr
, pDataCell
);
5093 GetCellString( aDataStr
, pDataCell
);
5097 SetError( errIllegalParameter
);
5103 PushError( nGlobalError
);
5107 // Get the lookup value.
5109 ScQueryParam aParam
;
5110 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
5111 if ( !FillEntry(rEntry
) )
5114 if ( eDataArrayType
== svDouble
|| eDataArrayType
== svString
||
5115 eDataArrayType
== svSingleRef
)
5117 // Delta position for a single value is always 0.
5119 // Found if data <= query, but not if query is string and found data is
5120 // numeric or vice versa. This is how Excel does it but doesn't
5123 bool bFound
= false;
5126 if ( rEntry
.bQueryByString
)
5129 bFound
= (fDataVal
<= rEntry
.nVal
);
5133 if ( !rEntry
.bQueryByString
)
5136 bFound
= (ScGlobal::GetCollator()->compareString( aDataStr
, *rEntry
.pStr
) <= 0);
5147 if (pResMat
->IsValue( 0 ))
5148 PushDouble(pResMat
->GetDouble( 0 ));
5150 PushString(pResMat
->GetString( 0 ));
5152 else if (nParamCount
== 3)
5154 switch (eResArrayType
)
5157 PushDouble( fResVal
);
5160 PushString( aResStr
);
5163 aResAdr
.Set( nResCol1
, nResRow1
, nResTab
);
5166 PushCellResultToken( true, aResAdr
, NULL
, NULL
);
5169 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
5174 switch (eDataArrayType
)
5177 PushDouble( fDataVal
);
5180 PushString( aDataStr
);
5183 PushCellResultToken( true, aDataAdr
, NULL
, NULL
);
5186 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
5192 // Now, perform the search to compute the delta position (nDelta).
5196 // Data array is given as a matrix.
5197 rEntry
.bDoQuery
= true;
5198 rEntry
.eOp
= SC_LESS_EQUAL
;
5199 bool bFound
= false;
5202 pDataMat
->GetDimensions(nC
, nR
);
5204 // In case of non-vector matrix, only search the first row or column.
5205 ScMatrixRef pDataMat2
;
5208 ScMatrixRef
pTempMat(new ScMatrix(1, nR
));
5209 for (SCSIZE i
= 0; i
< nR
; ++i
)
5210 if (pDataMat
->IsValue(0, i
))
5211 pTempMat
->PutDouble(pDataMat
->GetDouble(0, i
), 0, i
);
5213 pTempMat
->PutString(pDataMat
->GetString(0, i
), 0, i
);
5214 pDataMat2
= pTempMat
;
5218 ScMatrixRef
pTempMat(new ScMatrix(nC
, 1));
5219 for (SCSIZE i
= 0; i
< nC
; ++i
)
5220 if (pDataMat
->IsValue(i
, 0))
5221 pTempMat
->PutDouble(pDataMat
->GetDouble(i
, 0), i
, 0);
5223 pTempMat
->PutString(pDataMat
->GetString(i
, 0), i
, 0);
5224 pDataMat2
= pTempMat
;
5227 // binary search for non-equality mode (the source data is
5228 // assumed to be sorted in ascending order).
5230 SCCOLROW nDelta
= -1;
5232 SCSIZE nFirst
= 0, nLast
= nLenMajor
-1; //, nHitIndex = 0;
5233 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
5235 SCSIZE nMid
= nFirst
+ nLen
/2;
5236 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, *pDataMat2
, rEntry
);
5239 // exact match. find the last item with the same value.
5240 lcl_GetLastMatch( nMid
, *pDataMat2
, nLenMajor
, false);
5246 if (nLen
== 1) // first and last items are next to each other.
5248 nDelta
= nCmp
< 0 ? nLast
- 1 : nFirst
- 1;
5249 // If already the 1st item is greater there's nothing found.
5250 bFound
= (nDelta
>= 0);
5260 if (nDelta
== static_cast<SCCOLROW
>(nLenMajor
-2)) // last item
5262 sal_Int32 nCmp
= lcl_CompareMatrix2Query(nDelta
+1, *pDataMat2
, rEntry
);
5265 // either the last item is an exact match or the real
5266 // hit is beyond the last item.
5271 else if (nDelta
> 0) // valid hit must be 2nd item or higher
5277 // With 0-9 < A-Z, if query is numeric and data found is string, or
5278 // vice versa, the (yet another undocumented) Excel behavior is to
5279 // return #N/A instead.
5283 SCCOLROW i
= nDelta
;
5284 SCSIZE n
= pDataMat
->GetElementCount();
5285 if (static_cast<SCSIZE
>(i
) >= n
)
5286 i
= static_cast<SCCOLROW
>(n
);
5287 if (bool(rEntry
.bQueryByString
) == bool(pDataMat
->IsValue(i
)))
5297 // Now that we've found the delta, push the result back to the cell.
5301 // result array is matrix.
5302 if (static_cast<SCSIZE
>(nDelta
) >= pResMat
->GetElementCount())
5307 if (pResMat
->IsValue(nDelta
))
5308 PushDouble(pResMat
->GetDouble(nDelta
));
5310 PushString(pResMat
->GetString(nDelta
));
5312 else if (nParamCount
== 3)
5314 // result array is cell range.
5316 aAdr
.SetTab(nResTab
);
5317 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
5320 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
5321 if (nTempRow
> MAXROW
)
5326 aAdr
.SetCol(nResCol1
);
5327 aAdr
.SetRow(nTempRow
);
5331 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
5332 if (nTempCol
> MAXCOL
)
5337 aAdr
.SetCol(nTempCol
);
5338 aAdr
.SetRow(nResRow1
);
5340 PushCellResultToken(true, aAdr
, NULL
, NULL
);
5344 // no result array. Use the data array to get the final value from.
5347 if (pDataMat
->IsValue(nC
-1, nDelta
))
5348 PushDouble(pDataMat
->GetDouble(nC
-1, nDelta
));
5350 PushString(pDataMat
->GetString(nC
-1, nDelta
));
5354 if (pDataMat
->IsValue(nDelta
, nR
-1))
5355 PushDouble(pDataMat
->GetDouble(nDelta
, nR
-1));
5357 PushString(pDataMat
->GetString(nDelta
, nR
-1));
5364 // Perform cell range search.
5366 aParam
.nCol1
= nCol1
;
5367 aParam
.nRow1
= nRow1
;
5368 aParam
.nCol2
= bVertical
? nCol1
: nCol2
;
5369 aParam
.nRow2
= bVertical
? nRow2
: nRow1
;
5370 aParam
.bByRow
= bVertical
;
5371 aParam
.bMixedComparison
= true;
5373 rEntry
.bDoQuery
= TRUE
;
5374 rEntry
.eOp
= SC_LESS_EQUAL
;
5375 rEntry
.nField
= nCol1
;
5376 if ( rEntry
.bQueryByString
)
5377 aParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5379 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, FALSE
);
5382 // Advance Entry.nField in iterator upon switching columns if
5384 aCellIter
.SetAdvanceQueryParamEntryField(!bVertical
);
5385 if ( !aCellIter
.FindEqualOrSortedLastInRange(nC
, nR
) )
5391 SCCOLROW nDelta
= bVertical
? static_cast<SCSIZE
>(nR
-nRow1
) : static_cast<SCSIZE
>(nC
-nCol1
);
5395 // Use the matrix result array.
5396 if (pResMat
->IsValue(nDelta
))
5397 PushDouble(pResMat
->GetDouble(nDelta
));
5399 PushString(pResMat
->GetString(nDelta
));
5401 else if (nParamCount
== 3)
5403 switch (eResArrayType
)
5407 // Use the result array vector. Note that the result array is assumed
5408 // to be a vector (i.e. 1-dimensinoal array).
5411 aAdr
.SetTab(nResTab
);
5412 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
5415 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
5416 if (nTempRow
> MAXROW
)
5421 aAdr
.SetCol(nResCol1
);
5422 aAdr
.SetRow(nTempRow
);
5426 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
5427 if (nTempCol
> MAXCOL
)
5432 aAdr
.SetCol(nTempCol
);
5433 aAdr
.SetRow(nResRow1
);
5435 PushCellResultToken( true, aAdr
, NULL
, NULL
);
5446 switch (eResArrayType
)
5449 PushDouble( fResVal
);
5452 PushString( aResStr
);
5455 PushCellResultToken( true, aResAdr
, NULL
, NULL
);
5464 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
5469 // Regardless of whether or not the result array exists, the last
5470 // array is always used as the "result" array.
5476 SCROW nTempRow
= static_cast<SCROW
>(nRow1
+ nDelta
);
5477 if (nTempRow
> MAXROW
)
5483 aAdr
.SetRow(nTempRow
);
5487 SCCOL nTempCol
= static_cast<SCCOL
>(nCol1
+ nDelta
);
5488 if (nTempCol
> MAXCOL
)
5493 aAdr
.SetCol(nTempCol
);
5496 PushCellResultToken(true, aAdr
, NULL
, NULL
);
5501 void ScInterpreter::ScHLookup()
5503 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScHLookup" );
5504 CalculateLookup(TRUE
);
5506 void ScInterpreter::CalculateLookup(BOOL HLookup
)
5508 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::CalculateLookup" );
5509 BYTE nParamCount
= GetByte();
5510 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
5513 if (nParamCount
== 4)
5514 bSorted
= GetBool();
5517 double fIndex
= ::rtl::math::approxFloor( GetDouble() ) - 1.0;
5518 ScMatrixRef pMat
= NULL
;
5519 SCSIZE nC
= 0, nR
= 0;
5526 if (GetStackType() == svDoubleRef
)
5528 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5531 PushIllegalParameter();
5535 else if (GetStackType() == svMatrix
)
5539 pMat
->GetDimensions(nC
, nR
);
5542 PushIllegalParameter();
5548 PushIllegalParameter();
5551 if ( fIndex
< 0.0 || (HLookup
? (pMat
? (fIndex
>= nR
) : (fIndex
+nRow1
> nRow2
)) : (pMat
? (fIndex
>= nC
) : (fIndex
+nCol1
> nCol2
)) ) )
5553 PushIllegalArgument();
5556 SCROW nZIndex
= static_cast<SCROW
>(fIndex
);
5557 SCCOL nSpIndex
= static_cast<SCCOL
>(fIndex
);
5561 nZIndex
+= nRow1
; // Wertzeile
5562 nSpIndex
= sal::static_int_cast
<SCCOL
>( nSpIndex
+ nCol1
); // value column
5565 if (nGlobalError
== 0)
5567 ScQueryParam rParam
;
5568 rParam
.nCol1
= nCol1
;
5569 rParam
.nRow1
= nRow1
;
5572 rParam
.nCol2
= nCol2
;
5573 rParam
.nRow2
= nRow1
; // nur in der ersten Zeile suchen
5574 rParam
.bByRow
= FALSE
;
5578 rParam
.nCol2
= nCol1
; // nur in der ersten Spalte suchen
5579 rParam
.nRow2
= nRow2
;
5580 rParam
.nTab
= nTab1
;
5582 rParam
.bMixedComparison
= TRUE
;
5584 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5585 rEntry
.bDoQuery
= TRUE
;
5587 rEntry
.eOp
= SC_LESS_EQUAL
;
5588 if ( !FillEntry(rEntry
) )
5590 if ( rEntry
.bQueryByString
)
5591 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5594 SCSIZE nMatCount
= HLookup
? nC
: nR
;
5595 SCSIZE nDelta
= SCSIZE_MAX
;
5596 if (rEntry
.bQueryByString
)
5599 //! TODO: enable regex on matrix strings
5601 String aParamStr
= *rEntry
.pStr
;
5604 static CollatorWrapper
* pCollator
= ScGlobal::GetCollator();
5605 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5607 if (HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
5610 pCollator
->compareString( HLookup
? pMat
->GetString(i
,0) : pMat
->GetString(0,i
), aParamStr
);
5613 else if (i
>0) // #i2168# ignore first mismatch
5622 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5624 if (HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
5626 if ( ScGlobal::GetpTransliteration()->isEqual(
5627 HLookup
? pMat
->GetString(i
,0) : pMat
->GetString(0,i
), aParamStr
) )
5640 // #i2168# ignore strings
5641 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5643 if (!(HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
5645 if ((HLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) <= rEntry
.nVal
)
5654 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5656 if (!(HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
5658 if ((HLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) == rEntry
.nVal
)
5667 if ( nDelta
!= SCSIZE_MAX
)
5669 SCSIZE nX
= static_cast<SCSIZE
>(nSpIndex
);
5674 nY
= static_cast<SCSIZE
>(nZIndex
);
5676 if ( pMat
->IsString( nX
, nY
) )
5677 PushString(pMat
->GetString( nX
,nY
));
5679 PushDouble(pMat
->GetDouble( nX
,nY
));
5686 rEntry
.nField
= nCol1
;
5687 BOOL bFound
= FALSE
;
5691 rEntry
.eOp
= SC_LESS_EQUAL
;
5694 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
5695 // advance Entry.nField in Iterator upon switching columns
5696 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
5700 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow1_temp
);
5702 else if ( aCellIter
.GetFirst() )
5705 nCol
= aCellIter
.GetCol();
5711 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
5712 bFound
= LookupQueryWithCache( aResultPos
, rParam
);
5713 nRow
= aResultPos
.Row();
5718 ScAddress
aAdr( nCol
, nRow
, nTab1
);
5719 PushCellResultToken( true, aAdr
, NULL
, NULL
);
5726 PushIllegalParameter();
5730 bool ScInterpreter::FillEntry(ScQueryEntry
& rEntry
)
5732 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::FillEntry" );
5733 switch ( GetStackType() )
5737 rEntry
.bQueryByString
= FALSE
;
5738 rEntry
.nVal
= GetDouble();
5743 const String sStr
= GetString();
5744 rEntry
.bQueryByString
= TRUE
;
5745 *rEntry
.pStr
= sStr
;
5752 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5757 ScBaseCell
* pCell
= GetCell( aAdr
);
5758 if (HasCellValueData(pCell
))
5760 rEntry
.bQueryByString
= FALSE
;
5761 rEntry
.nVal
= GetCellValue( aAdr
, pCell
);
5765 if ( GetCellType( pCell
) == CELLTYPE_NOTE
)
5767 rEntry
.bQueryByString
= FALSE
;
5773 GetCellString(sStr
, pCell
);
5774 rEntry
.bQueryByString
= TRUE
;
5775 *rEntry
.pStr
= sStr
;
5782 const ScMatValType nType
= GetDoubleOrStringFromMatrix(rEntry
.nVal
, *rEntry
.pStr
);
5783 rEntry
.bQueryByString
= ScMatrix::IsNonValueType( nType
);
5788 PushIllegalParameter();
5791 } // switch ( GetStackType() )
5794 void ScInterpreter::ScVLookup()
5796 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScVLookup" );
5797 CalculateLookup(FALSE
);
5800 #if defined(WIN) && defined(MSC)
5801 #pragma optimize("",off)
5804 void ScInterpreter::ScSubTotal()
5806 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSubTotal" );
5807 BYTE nParamCount
= GetByte();
5808 if ( MustHaveParamCountMin( nParamCount
, 2 ) )
5810 // We must fish the 1st parameter deep from the stack! And push it on top.
5811 const FormulaToken
* p
= pStack
[ sp
- nParamCount
];
5812 PushTempToken( *p
);
5813 int nFunc
= (int) ::rtl::math::approxFloor( GetDouble() );
5814 if( nFunc
< 1 || nFunc
> 11 )
5815 PushIllegalArgument(); // simulate return on stack, not SetError(...)
5818 cPar
= nParamCount
- 1;
5822 case SUBTOTAL_FUNC_AVE
: ScAverage(); break;
5823 case SUBTOTAL_FUNC_CNT
: ScCount(); break;
5824 case SUBTOTAL_FUNC_CNT2
: ScCount2(); break;
5825 case SUBTOTAL_FUNC_MAX
: ScMax(); break;
5826 case SUBTOTAL_FUNC_MIN
: ScMin(); break;
5827 case SUBTOTAL_FUNC_PROD
: ScProduct(); break;
5828 case SUBTOTAL_FUNC_STD
: ScStDev(); break;
5829 case SUBTOTAL_FUNC_STDP
: ScStDevP(); break;
5830 case SUBTOTAL_FUNC_SUM
: ScSum(); break;
5831 case SUBTOTAL_FUNC_VAR
: ScVar(); break;
5832 case SUBTOTAL_FUNC_VARP
: ScVarP(); break;
5833 default : PushIllegalArgument(); break;
5837 // Get rid of the 1st (fished) parameter.
5838 double nVal
= GetDouble();
5843 #if defined(WIN) && defined(MSC)
5844 #pragma optimize("",on)
5848 ScDBQueryParamBase
* ScInterpreter::GetDBParams( BOOL
& rMissingField
)
5850 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetDBParams" );
5851 BOOL bAllowMissingField
= FALSE
;
5852 if ( rMissingField
)
5854 bAllowMissingField
= TRUE
;
5855 rMissingField
= FALSE
;
5857 if ( GetByte() == 3 )
5859 // First, get the query criteria range.
5860 ::std::auto_ptr
<ScDBRangeBase
> pQueryRef( PopDoubleRef() );
5861 if (!pQueryRef
.get())
5867 ScRange aMissingRange
;
5868 BOOL bRangeFake
= FALSE
;
5869 switch (GetStackType())
5872 nVal
= ::rtl::math::approxFloor( GetDouble() );
5873 if ( bAllowMissingField
&& nVal
== 0.0 )
5874 rMissingField
= TRUE
; // fake missing parameter
5883 PopSingleRef( aAdr
);
5884 ScBaseCell
* pCell
= GetCell( aAdr
);
5885 if (HasCellValueData(pCell
))
5886 nVal
= GetCellValue( aAdr
, pCell
);
5890 GetCellString(aStr
, pCell
);
5895 if ( bAllowMissingField
)
5896 { // fake missing parameter for old SO compatibility
5898 PopDoubleRef( aMissingRange
);
5903 SetError( errIllegalParameter
);
5908 if ( bAllowMissingField
)
5909 rMissingField
= TRUE
;
5911 SetError( errIllegalParameter
);
5915 SetError( errIllegalParameter
);
5918 auto_ptr
<ScDBRangeBase
> pDBRef( PopDoubleRef() );
5920 if (nGlobalError
|| !pDBRef
.get())
5925 // range parameter must match entire database range
5926 if (pDBRef
->isRangeEqual(aMissingRange
))
5927 rMissingField
= TRUE
;
5929 SetError( errIllegalParameter
);
5935 SCCOL nField
= pDBRef
->getFirstFieldColumn();
5939 nField
= pDBRef
->findFieldColumn(static_cast<SCCOL
>(nVal
));
5942 sal_uInt16 nErr
= 0;
5943 nField
= pDBRef
->findFieldColumn(aStr
, &nErr
);
5947 if (!ValidCol(nField
))
5950 auto_ptr
<ScDBQueryParamBase
> pParam( pDBRef
->createQueryParam(pQueryRef
.get()) );
5954 // An allowed missing field parameter sets the result field
5955 // to any of the query fields, just to be able to return
5956 // some cell from the iterator.
5957 if ( rMissingField
)
5958 nField
= static_cast<SCCOL
>(pParam
->GetEntry(0).nField
);
5959 pParam
->mnField
= nField
;
5961 SCSIZE nCount
= pParam
->GetEntryCount();
5962 for ( SCSIZE i
=0; i
< nCount
; i
++ )
5964 ScQueryEntry
& rEntry
= pParam
->GetEntry(i
);
5965 if ( rEntry
.bDoQuery
)
5967 sal_uInt32 nIndex
= 0;
5968 rEntry
.bQueryByString
= !pFormatter
->IsNumberFormat(
5969 *rEntry
.pStr
, nIndex
, rEntry
.nVal
);
5970 if ( rEntry
.bQueryByString
&& !pParam
->bRegExp
)
5971 pParam
->bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5976 return pParam
.release();
5983 void ScInterpreter::DBIterator( ScIterFunc eFunc
)
5985 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::DBIterator" );
5990 BOOL bMissingField
= FALSE
;
5991 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
5992 if (pQueryParam
.get())
5994 ScDBQueryDataIterator
aValIter(pDok
, pQueryParam
.release());
5995 ScDBQueryDataIterator::Value aValue
;
5996 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6000 case ifPRODUCT
: nErg
= 1; break;
6001 case ifMAX
: nErg
= -MAXDOUBLE
; break;
6002 case ifMIN
: nErg
= MAXDOUBLE
; break;
6003 default: ; // nothing
6012 if ( bNull
&& aValue
.mfValue
!= 0.0 )
6015 fMem
= aValue
.mfValue
;
6018 nErg
+= aValue
.mfValue
;
6020 case ifSUMSQ
: nErg
+= aValue
.mfValue
* aValue
.mfValue
; break;
6021 case ifPRODUCT
: nErg
*= aValue
.mfValue
; break;
6022 case ifMAX
: if( aValue
.mfValue
> nErg
) nErg
= aValue
.mfValue
; break;
6023 case ifMIN
: if( aValue
.mfValue
< nErg
) nErg
= aValue
.mfValue
; break;
6024 default: ; // nothing
6027 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6029 SetError(aValue
.mnError
);
6032 SetError( errIllegalParameter
);
6035 case ifCOUNT
: nErg
= nCount
; break;
6036 case ifSUM
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
); break;
6037 case ifAVERAGE
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
) / nCount
; break;
6038 default: ; // nothing
6044 void ScInterpreter::ScDBSum()
6046 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBSum" );
6047 DBIterator( ifSUM
);
6051 void ScInterpreter::ScDBCount()
6053 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBCount" );
6054 BOOL bMissingField
= TRUE
;
6055 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6056 if (pQueryParam
.get())
6059 if ( bMissingField
&& pQueryParam
->GetType() == ScDBQueryParamBase::INTERNAL
)
6060 { // count all matching records
6061 // TODO: currently the QueryIterators only return cell pointers of
6062 // existing cells, so if a query matches an empty cell there's
6063 // nothing returned, and therefor not counted!
6064 // Since this has ever been the case and this code here only came
6065 // into existance to fix #i6899 and it never worked before we'll
6066 // have to live with it until we reimplement the iterators to also
6067 // return empty cells, which would mean to adapt all callers of
6069 ScDBQueryParamInternal
* p
= static_cast<ScDBQueryParamInternal
*>(pQueryParam
.get());
6070 SCTAB nTab
= p
->nTab
;
6071 ScQueryCellIterator
aCellIter( pDok
, nTab
, *p
);
6072 if ( aCellIter
.GetFirst() )
6077 } while ( aCellIter
.GetNext() );
6081 { // count only matching records with a value in the "result" field
6082 ScDBQueryDataIterator
aValIter( pDok
, pQueryParam
.release());
6083 ScDBQueryDataIterator::Value aValue
;
6084 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6090 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6092 SetError(aValue
.mnError
);
6094 PushDouble( nCount
);
6097 PushIllegalParameter();
6101 void ScInterpreter::ScDBCount2()
6103 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBCount2" );
6104 BOOL bMissingField
= TRUE
;
6105 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6106 if (pQueryParam
.get())
6109 pQueryParam
->mbSkipString
= false;
6110 ScDBQueryDataIterator
aValIter( pDok
, pQueryParam
.release());
6111 ScDBQueryDataIterator::Value aValue
;
6112 if ( aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6118 while ( aValIter
.GetNext(aValue
) && !aValue
.mnError
);
6120 SetError(aValue
.mnError
);
6121 PushDouble( nCount
);
6124 PushIllegalParameter();
6128 void ScInterpreter::ScDBAverage()
6130 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBAverage" );
6131 DBIterator( ifAVERAGE
);
6135 void ScInterpreter::ScDBMax()
6137 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBMax" );
6138 DBIterator( ifMAX
);
6142 void ScInterpreter::ScDBMin()
6144 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBMin" );
6145 DBIterator( ifMIN
);
6149 void ScInterpreter::ScDBProduct()
6151 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBProduct" );
6152 DBIterator( ifPRODUCT
);
6156 void ScInterpreter::GetDBStVarParams( double& rVal
, double& rValCount
)
6158 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::GetDBStVarParams" );
6159 std::vector
<double> values
;
6165 BOOL bMissingField
= FALSE
;
6166 auto_ptr
<ScDBQueryParamBase
> pQueryParam( GetDBParams(bMissingField
) );
6167 if (pQueryParam
.get())
6169 ScDBQueryDataIterator
aValIter(pDok
, pQueryParam
.release());
6170 ScDBQueryDataIterator::Value aValue
;
6171 if (aValIter
.GetFirst(aValue
) && !aValue
.mnError
)
6176 values
.push_back(aValue
.mfValue
);
6177 fSum
+= aValue
.mfValue
;
6179 while ((aValue
.mnError
== 0) && aValIter
.GetNext(aValue
));
6181 SetError(aValue
.mnError
);
6184 SetError( errIllegalParameter
);
6186 vMean
= fSum
/ values
.size();
6188 for (size_t i
= 0; i
< values
.size(); i
++)
6189 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
6195 void ScInterpreter::ScDBStdDev()
6197 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBStdDev" );
6198 double fVal
, fCount
;
6199 GetDBStVarParams( fVal
, fCount
);
6200 PushDouble( sqrt(fVal
/(fCount
-1)));
6204 void ScInterpreter::ScDBStdDevP()
6206 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBStdDevP" );
6207 double fVal
, fCount
;
6208 GetDBStVarParams( fVal
, fCount
);
6209 PushDouble( sqrt(fVal
/fCount
));
6213 void ScInterpreter::ScDBVar()
6215 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBVar" );
6216 double fVal
, fCount
;
6217 GetDBStVarParams( fVal
, fCount
);
6218 PushDouble(fVal
/(fCount
-1));
6222 void ScInterpreter::ScDBVarP()
6224 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScDBVarP" );
6225 double fVal
, fCount
;
6226 GetDBStVarParams( fVal
, fCount
);
6227 PushDouble(fVal
/fCount
);
6231 ScTokenArray
* lcl_CreateExternalRefTokenArray( const ScAddress
& rPos
, ScDocument
* pDoc
,
6232 const ScAddress::ExternalInfo
& rExtInfo
, const ScRefAddress
& rRefAd1
,
6233 const ScRefAddress
* pRefAd2
)
6235 ScExternalRefManager
* pRefMgr
= pDoc
->GetExternalRefManager();
6237 const String
* pRealTab
= pRefMgr
->getRealTableName( rExtInfo
.mnFileId
, rExtInfo
.maTabName
);
6238 ScTokenArray
* pTokenArray
= new ScTokenArray
;
6241 ScComplexRefData aRef
;
6242 aRef
.InitRangeRel( ScRange( rRefAd1
.GetAddress(), pRefAd2
->GetAddress()), rPos
);
6243 aRef
.Ref1
.SetColRel( rRefAd1
.IsRelCol());
6244 aRef
.Ref1
.SetRowRel( rRefAd1
.IsRelRow());
6245 aRef
.Ref1
.SetTabRel( rRefAd1
.IsRelTab());
6246 aRef
.Ref1
.SetFlag3D( true);
6247 aRef
.Ref2
.SetColRel( pRefAd2
->IsRelCol());
6248 aRef
.Ref2
.SetRowRel( pRefAd2
->IsRelRow());
6249 aRef
.Ref2
.SetTabRel( pRefAd2
->IsRelTab());
6250 nSheets
= aRef
.Ref2
.nTab
- aRef
.Ref1
.nTab
+ 1;
6251 aRef
.Ref2
.SetFlag3D( nSheets
> 1 );
6252 pTokenArray
->AddExternalDoubleReference( rExtInfo
.mnFileId
,
6253 (pRealTab
? *pRealTab
: rExtInfo
.maTabName
), aRef
);
6257 ScSingleRefData aRef
;
6258 aRef
.InitAddressRel( rRefAd1
.GetAddress(), rPos
);
6259 aRef
.SetColRel( rRefAd1
.IsRelCol());
6260 aRef
.SetRowRel( rRefAd1
.IsRelRow());
6261 aRef
.SetTabRel( rRefAd1
.IsRelTab());
6262 aRef
.SetFlag3D( true);
6263 pTokenArray
->AddExternalSingleReference( rExtInfo
.mnFileId
,
6264 (pRealTab
? *pRealTab
: rExtInfo
.maTabName
), aRef
);
6266 // The indirect usage of the external table can't be detected during the
6267 // store-to-file cycle, mark it as permanently referenced so it gets stored
6268 // even if not directly referenced anywhere.
6269 pRefMgr
->setCacheTableReferencedPermanently( rExtInfo
.mnFileId
,
6270 rExtInfo
.maTabName
, nSheets
);
6271 ScCompiler
aComp( pDoc
, rPos
, *pTokenArray
);
6272 aComp
.CompileTokenArray();
6277 void ScInterpreter::ScIndirect()
6279 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIndirect" );
6280 BYTE nParamCount
= GetByte();
6281 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6283 bool bTryXlA1
= true; // whether to try XL_A1 style as well.
6284 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
;
6285 if (nParamCount
== 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
6287 eConv
= FormulaGrammar::CONV_XL_R1C1
;
6290 const ScAddress::Details
aDetails( eConv
, aPos
);
6291 const ScAddress::Details
aDetailsXlA1( FormulaGrammar::CONV_XL_A1
, aPos
);
6292 SCTAB nTab
= aPos
.Tab();
6293 String
sRefStr( GetString() );
6294 ScRefAddress aRefAd
, aRefAd2
;
6295 ScAddress::ExternalInfo aExtInfo
;
6296 if ( ConvertDoubleRef( pDok
, sRefStr
, nTab
, aRefAd
, aRefAd2
, aDetails
, &aExtInfo
) ||
6297 (bTryXlA1
&& ConvertDoubleRef( pDok
, sRefStr
, nTab
, aRefAd
,
6298 aRefAd2
, aDetailsXlA1
, &aExtInfo
)))
6300 if (aExtInfo
.mbExternal
)
6302 /* TODO: future versions should implement a proper subroutine
6303 * token. This procedure here is a minimally invasive fix for
6304 * #i101645# in OOo3.1.1 */
6305 // Push a subroutine on the instruction code stack that
6306 // resolves the external reference as the next instruction.
6307 aCode
.Push( lcl_CreateExternalRefTokenArray( aPos
, pDok
,
6308 aExtInfo
, aRefAd
, &aRefAd2
));
6309 // Signal subroutine call to interpreter.
6310 PushTempToken( new FormulaUnknownToken( ocCall
));
6313 PushDoubleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab(),
6314 aRefAd2
.Col(), aRefAd2
.Row(), aRefAd2
.Tab() );
6316 else if ( ConvertSingleRef ( pDok
, sRefStr
, nTab
, aRefAd
, aDetails
, &aExtInfo
) ||
6317 (bTryXlA1
&& ConvertSingleRef ( pDok
, sRefStr
, nTab
, aRefAd
,
6318 aDetailsXlA1
, &aExtInfo
)))
6320 if (aExtInfo
.mbExternal
)
6322 /* TODO: future versions should implement a proper subroutine
6323 * token. This procedure here is a minimally invasive fix for
6324 * #i101645# in OOo3.1.1 */
6325 // Push a subroutine on the instruction code stack that
6326 // resolves the external reference as the next instruction.
6327 aCode
.Push( lcl_CreateExternalRefTokenArray( aPos
, pDok
,
6328 aExtInfo
, aRefAd
, NULL
));
6329 // Signal subroutine call to interpreter.
6330 PushTempToken( new FormulaUnknownToken( ocCall
));
6333 PushSingleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab() );
6339 ScRangeName
* pNames
= pDok
->GetRangeName();
6344 if (!pNames
->SearchName( sRefStr
, nPos
))
6347 ScRangeData
* rData
= (*pNames
)[nPos
];
6351 // We need this in order to obtain a good range.
6352 rData
->ValidateTabRefs();
6356 // This is some really odd Excel behavior and renders named
6357 // ranges containing relative references totally useless.
6358 if (!rData
->IsReference(aRange
, ScAddress( aPos
.Tab(), 0, 0)))
6361 // This is the usual way to treat named ranges containing
6362 // relative references.
6363 if (!rData
->IsReference( aRange
, aPos
))
6367 if (aRange
.aStart
== aRange
.aEnd
)
6368 PushSingleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
6369 aRange
.aStart
.Tab());
6371 PushDoubleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
6372 aRange
.aStart
.Tab(), aRange
.aEnd
.Col(),
6373 aRange
.aEnd
.Row(), aRange
.aEnd
.Tab());
6380 PushIllegalArgument();
6386 void ScInterpreter::ScAddressFunc()
6388 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScAddressFunc" );
6391 BYTE nParamCount
= GetByte();
6392 if( !MustHaveParamCount( nParamCount
, 2, 5 ) )
6395 if( nParamCount
>= 5 )
6396 sTabStr
= GetString();
6398 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
; // default
6399 if( nParamCount
>= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
6400 eConv
= FormulaGrammar::CONV_XL_R1C1
;
6402 USHORT nFlags
= SCA_COL_ABSOLUTE
| SCA_ROW_ABSOLUTE
; // default
6403 if( nParamCount
>= 3 )
6405 USHORT n
= (USHORT
) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
6413 case 1 : break; // default
6415 case 2 : nFlags
= SCA_ROW_ABSOLUTE
; break;
6417 case 3 : nFlags
= SCA_COL_ABSOLUTE
; break;
6419 case 4 : nFlags
= 0; break; // both relative
6422 nFlags
|= SCA_VALID
| SCA_VALID_ROW
| SCA_VALID_COL
;
6424 SCCOL nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
6425 SCROW nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
6426 if( eConv
== FormulaGrammar::CONV_XL_R1C1
)
6428 // YUCK! The XL interface actually treats rel R1C1 refs differently
6430 if( !(nFlags
& SCA_COL_ABSOLUTE
) )
6431 nCol
+= aPos
.Col() + 1;
6432 if( !(nFlags
& SCA_ROW_ABSOLUTE
) )
6433 nRow
+= aPos
.Row() + 1;
6438 if(!ValidCol( nCol
) || !ValidRow( nRow
))
6440 PushIllegalArgument();
6445 const ScAddress::Details
aDetails( eConv
, aPos
);
6446 const ScAddress
aAdr( nCol
, nRow
, 0);
6447 aAdr
.Format( aRefStr
, nFlags
, pDok
, aDetails
);
6449 if( nParamCount
>= 5 )
6451 ScCompiler::CheckTabQuotes( sTabStr
, eConv
);
6452 sTabStr
+= static_cast<sal_Unicode
>(eConv
== FormulaGrammar::CONV_XL_R1C1
? '!' : '.');
6454 PushString( sTabStr
);
6457 PushString( aRefStr
);
6461 void ScInterpreter::ScOffset()
6463 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScOffset" );
6464 BYTE nParamCount
= GetByte();
6465 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
6467 long nColNew
= -1, nRowNew
= -1, nColPlus
, nRowPlus
;
6468 if (nParamCount
== 5)
6469 nColNew
= (long) ::rtl::math::approxFloor(GetDouble());
6470 if (nParamCount
>= 4)
6471 nRowNew
= (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
6472 nColPlus
= (long) ::rtl::math::approxFloor(GetDouble());
6473 nRowPlus
= (long) ::rtl::math::approxFloor(GetDouble());
6480 if (nColNew
== 0 || nRowNew
== 0)
6482 PushIllegalArgument();
6485 if (GetStackType() == svSingleRef
)
6487 PopSingleRef(nCol1
, nRow1
, nTab1
);
6488 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
6490 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
6491 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
6492 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
6493 PushIllegalArgument();
6495 PushSingleRef(nCol1
, nRow1
, nTab1
);
6503 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
); // ! nCol1 wird veraendert!
6504 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
6505 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
6506 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
6507 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
6508 !ValidCol(nCol2
) || !ValidRow(nRow2
))
6509 PushIllegalArgument();
6511 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6514 else if (GetStackType() == svDoubleRef
)
6516 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6518 nColNew
= nCol2
- nCol1
+ 1;
6520 nRowNew
= nRow2
- nRow1
+ 1;
6521 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
6522 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
6523 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
6524 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
6525 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
6526 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
6527 PushIllegalArgument();
6529 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6532 PushIllegalParameter();
6537 void ScInterpreter::ScIndex()
6539 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScIndex" );
6540 BYTE nParamCount
= GetByte();
6541 if ( MustHaveParamCount( nParamCount
, 1, 4 ) )
6547 if (nParamCount
== 4)
6548 nArea
= (long) ::rtl::math::approxFloor(GetDouble());
6551 if (nParamCount
>= 3)
6552 nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
6555 if (nParamCount
>= 2)
6556 nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
6559 if (GetStackType() == svRefList
)
6560 nAreaCount
= (sp
? static_cast<ScToken
*>(pStack
[sp
-1])->GetRefList()->size() : 0);
6562 nAreaCount
= 1; // one reference or array or whatever
6563 if (nAreaCount
== 0 || (size_t)nArea
> nAreaCount
)
6565 PushError( errNoRef
);
6568 else if (nArea
< 1 || nCol
< 0 || nRow
< 0)
6570 PushIllegalArgument();
6573 switch (GetStackType())
6578 SetError(errIllegalArgument
);
6580 ScMatrixRef pMat
= GetMatrix();
6584 pMat
->GetDimensions(nC
, nR
);
6585 // Access one element of a vector independent of col/row
6587 bool bVector
= ((nCol
== 0 || nRow
== 0) && (nC
== 1 || nR
== 1));
6588 SCSIZE nElement
= ::std::max( static_cast<SCSIZE
>(nCol
),
6589 static_cast<SCSIZE
>(nRow
));
6590 if (nC
== 0 || nR
== 0 ||
6591 (!bVector
&& (static_cast<SCSIZE
>(nCol
) > nC
||
6592 static_cast<SCSIZE
>(nRow
) > nR
)) ||
6593 (bVector
&& nElement
> nC
* nR
))
6594 PushIllegalArgument();
6595 else if (nCol
== 0 && nRow
== 0)
6600 if (pMat
->IsString( nElement
))
6601 PushString( pMat
->GetString( nElement
));
6603 PushDouble( pMat
->GetDouble( nElement
));
6607 ScMatrixRef pResMat
= GetNewMat(nC
, 1);
6610 SCSIZE nRowMinus1
= static_cast<SCSIZE
>(nRow
- 1);
6611 for (SCSIZE i
= 0; i
< nC
; i
++)
6612 if (!pMat
->IsString(i
, nRowMinus1
))
6613 pResMat
->PutDouble(pMat
->GetDouble(i
,
6616 pResMat
->PutString(pMat
->GetString(i
,
6618 PushMatrix(pResMat
);
6621 PushIllegalArgument();
6625 ScMatrixRef pResMat
= GetNewMat(1, nR
);
6628 SCSIZE nColMinus1
= static_cast<SCSIZE
>(nCol
- 1);
6629 for (SCSIZE i
= 0; i
< nR
; i
++)
6630 if (!pMat
->IsString(nColMinus1
, i
))
6631 pResMat
->PutDouble(pMat
->GetDouble(nColMinus1
,
6634 pResMat
->PutString(pMat
->GetString(nColMinus1
,
6636 PushMatrix(pResMat
);
6639 PushIllegalArgument();
6643 if (!pMat
->IsString( static_cast<SCSIZE
>(nCol
-1),
6644 static_cast<SCSIZE
>(nRow
-1)))
6645 PushDouble( pMat
->GetDouble(
6646 static_cast<SCSIZE
>(nCol
-1),
6647 static_cast<SCSIZE
>(nRow
-1)));
6649 PushString( pMat
->GetString(
6650 static_cast<SCSIZE
>(nCol
-1),
6651 static_cast<SCSIZE
>(nRow
-1)));
6661 PopSingleRef( nCol1
, nRow1
, nTab1
);
6662 if (nCol
> 1 || nRow
> 1)
6663 PushIllegalArgument();
6665 PushSingleRef( nCol1
, nRow1
, nTab1
);
6677 BOOL bRowArray
= FALSE
;
6678 if (GetStackType() == svRefList
)
6680 FormulaTokenRef xRef
= PopToken();
6681 if (nGlobalError
|| !xRef
)
6683 PushIllegalParameter();
6686 ScRange
aRange( ScAddress::UNINITIALIZED
);
6687 DoubleRefToRange( (*(static_cast<ScToken
*>(xRef
.get())->GetRefList()))[nArea
-1], aRange
);
6688 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6689 if ( nParamCount
== 2 && nRow1
== nRow2
)
6694 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6695 if ( nParamCount
== 2 && nRow1
== nRow2
)
6698 if ( nTab1
!= nTab2
||
6699 (nCol
> 0 && nCol1
+nCol
-1 > nCol2
) ||
6700 (nRow
> 0 && nRow1
+nRow
-1 > nRow2
&& !bRowArray
) ||
6701 ( nRow
> nCol2
- nCol1
+ 1 && bRowArray
))
6702 PushIllegalArgument();
6703 else if (nCol
== 0 && nRow
== 0)
6705 if ( nCol1
== nCol2
&& nRow1
== nRow2
)
6706 PushSingleRef( nCol1
, nRow1
, nTab1
);
6708 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6712 if ( nRow1
== nRow2
)
6713 PushSingleRef( nCol1
+nCol
-1, nRow1
, nTab1
);
6715 PushDoubleRef( nCol1
+nCol
-1, nRow1
, nTab1
,
6716 nCol1
+nCol
-1, nRow2
, nTab1
);
6720 if ( nCol1
== nCol2
)
6721 PushSingleRef( nCol1
, nRow1
+nRow
-1, nTab1
);
6722 else if ( bRowArray
)
6726 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
6729 PushDoubleRef( nCol1
, nRow1
+nRow
-1, nTab1
,
6730 nCol2
, nRow1
+nRow
-1, nTab1
);
6733 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
6737 PushIllegalParameter();
6743 void ScInterpreter::ScMultiArea()
6745 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScMultiArea" );
6746 // Legacy support, convert to RefList
6747 BYTE nParamCount
= GetByte();
6748 if (MustHaveParamCountMin( nParamCount
, 1))
6750 while (!nGlobalError
&& nParamCount
-- > 1)
6758 void ScInterpreter::ScAreas()
6760 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScAreas" );
6761 BYTE nParamCount
= GetByte();
6762 if (MustHaveParamCount( nParamCount
, 1))
6765 switch (GetStackType())
6769 FormulaTokenRef xT
= PopToken();
6770 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetSingleRef());
6776 FormulaTokenRef xT
= PopToken();
6777 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetDoubleRef());
6783 FormulaTokenRef xT
= PopToken();
6784 ValidateRef( *(static_cast<ScToken
*>(xT
.get())->GetRefList()));
6785 nCount
+= static_cast<ScToken
*>(xT
.get())->GetRefList()->size();
6789 SetError( errIllegalParameter
);
6791 PushDouble( double(nCount
));
6796 void ScInterpreter::ScCurrency()
6798 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScCurrency" );
6799 BYTE nParamCount
= GetByte();
6800 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6804 if (nParamCount
== 2)
6806 fDec
= ::rtl::math::approxFloor(GetDouble());
6807 if (fDec
< -15.0 || fDec
> 15.0)
6809 PushIllegalArgument();
6815 double fVal
= GetDouble();
6818 fFac
= pow( (double)10, fDec
);
6822 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
6824 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
6825 Color
* pColor
= NULL
;
6828 ULONG nIndex
= pFormatter
->GetStandardFormat(
6829 NUMBERFORMAT_CURRENCY
,
6831 if ( (USHORT
) fDec
!= pFormatter
->GetFormatPrecision( nIndex
) )
6833 String sFormatString
;
6834 pFormatter
->GenerateFormat(sFormatString
,
6837 TRUE
, // mit Tausenderpunkt
6839 (USHORT
) fDec
,// Nachkommastellen
6840 1); // 1 Vorkommanull
6841 if (!pFormatter
->GetPreviewString(sFormatString
,
6846 SetError(errIllegalArgument
);
6850 pFormatter
->GetOutputString(fVal
, nIndex
, aStr
, &pColor
);
6857 void ScInterpreter::ScReplace()
6859 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScReplace" );
6860 if ( MustHaveParamCount( GetByte(), 4 ) )
6862 String
aNewStr( GetString() );
6863 double fCount
= ::rtl::math::approxFloor( GetDouble());
6864 double fPos
= ::rtl::math::approxFloor( GetDouble());
6865 String
aOldStr( GetString() );
6866 if (fPos
< 1.0 || fPos
> static_cast<double>(STRING_MAXLEN
)
6867 || fCount
< 0.0 || fCount
> static_cast<double>(STRING_MAXLEN
))
6868 PushIllegalArgument();
6871 xub_StrLen nCount
= static_cast<xub_StrLen
>(fCount
);
6872 xub_StrLen nPos
= static_cast<xub_StrLen
>(fPos
);
6873 xub_StrLen nLen
= aOldStr
.Len();
6874 if (nPos
> nLen
+ 1)
6876 if (nCount
> nLen
- nPos
+ 1)
6877 nCount
= nLen
- nPos
+ 1;
6878 aOldStr
.Erase( nPos
-1, nCount
);
6879 if ( CheckStringResultLen( aOldStr
, aNewStr
) )
6880 aOldStr
.Insert( aNewStr
, nPos
-1 );
6881 PushString( aOldStr
);
6887 void ScInterpreter::ScFixed()
6889 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFixed" );
6890 BYTE nParamCount
= GetByte();
6891 if ( MustHaveParamCount( nParamCount
, 1, 3 ) )
6896 if (nParamCount
== 3)
6897 bThousand
= !GetBool(); // Param TRUE: keine Tausenderpunkte
6900 if (nParamCount
>= 2)
6902 fDec
= ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
6903 if (fDec
< -15.0 || fDec
> 15.0)
6905 PushIllegalArgument();
6911 double fVal
= GetDouble();
6914 fFac
= pow( (double)10, fDec
);
6918 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
6920 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
6921 Color
* pColor
= NULL
;
6922 String sFormatString
;
6925 ULONG nIndex
= pFormatter
->GetStandardFormat(
6926 NUMBERFORMAT_NUMBER
,
6928 pFormatter
->GenerateFormat(sFormatString
,
6931 bThousand
, // mit Tausenderpunkt
6933 (USHORT
) fDec
,// Nachkommastellen
6934 1); // 1 Vorkommanull
6935 if (!pFormatter
->GetPreviewString(sFormatString
,
6940 PushIllegalArgument();
6947 void ScInterpreter::ScFind()
6949 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScFind" );
6950 BYTE nParamCount
= GetByte();
6951 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
6954 if (nParamCount
== 3)
6958 String sStr
= GetString();
6959 if( fAnz
< 1.0 || fAnz
> (double) sStr
.Len() )
6963 xub_StrLen nPos
= sStr
.Search( GetString(), (xub_StrLen
) fAnz
- 1 );
6964 if (nPos
== STRING_NOTFOUND
)
6967 PushDouble((double)(nPos
+ 1));
6973 void ScInterpreter::ScExact()
6975 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScExact" );
6976 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
6977 if ( MustHaveParamCount( GetByte(), 2 ) )
6979 String
s1( GetString() );
6980 String
s2( GetString() );
6981 PushInt( s1
== s2
);
6986 void ScInterpreter::ScLeft()
6988 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScLeft" );
6989 BYTE nParamCount
= GetByte();
6990 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6993 if (nParamCount
== 2)
6995 double nVal
= ::rtl::math::approxFloor(GetDouble());
6996 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
6998 PushIllegalArgument();
7002 n
= (xub_StrLen
) nVal
;
7006 String
aStr( GetString() );
7013 void ScInterpreter::ScRight()
7015 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRight" );
7016 BYTE nParamCount
= GetByte();
7017 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
7020 if (nParamCount
== 2)
7022 double nVal
= ::rtl::math::approxFloor(GetDouble());
7023 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
7025 PushIllegalArgument();
7029 n
= (xub_StrLen
) nVal
;
7033 String
aStr( GetString() );
7034 if( n
< aStr
.Len() )
7035 aStr
.Erase( 0, aStr
.Len() - n
);
7041 void ScInterpreter::ScSearch()
7043 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSearch" );
7045 BYTE nParamCount
= GetByte();
7046 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
7048 if (nParamCount
== 3)
7050 fAnz
= ::rtl::math::approxFloor(GetDouble());
7051 if (fAnz
> double(STRING_MAXLEN
))
7053 PushIllegalArgument();
7059 String sStr
= GetString();
7060 String SearchStr
= GetString();
7061 xub_StrLen nPos
= (xub_StrLen
) fAnz
- 1;
7062 xub_StrLen nEndPos
= sStr
.Len();
7063 if( nPos
>= nEndPos
)
7067 utl::SearchParam::SearchType eSearchType
=
7068 (MayBeRegExp( SearchStr
, pDok
) ?
7069 utl::SearchParam::SRCH_REGEXP
: utl::SearchParam::SRCH_NORMAL
);
7070 utl::SearchParam
sPar(SearchStr
, eSearchType
, FALSE
, FALSE
, FALSE
);
7071 utl::TextSearch
sT( sPar
, *ScGlobal::pCharClass
);
7072 int nBool
= sT
.SearchFrwrd(sStr
, &nPos
, &nEndPos
);
7076 PushDouble((double)(nPos
) + 1);
7082 void ScInterpreter::ScMid()
7084 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScMid" );
7085 if ( MustHaveParamCount( GetByte(), 3 ) )
7087 double fAnz
= ::rtl::math::approxFloor(GetDouble());
7088 double fAnfang
= ::rtl::math::approxFloor(GetDouble());
7089 const String
& rStr
= GetString();
7090 if (fAnfang
< 1.0 || fAnz
< 0.0 || fAnfang
> double(STRING_MAXLEN
) || fAnz
> double(STRING_MAXLEN
))
7091 PushIllegalArgument();
7093 PushString(rStr
.Copy( (xub_StrLen
) fAnfang
- 1, (xub_StrLen
) fAnz
));
7098 void ScInterpreter::ScText()
7100 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScText" );
7101 if ( MustHaveParamCount( GetByte(), 2 ) )
7103 String sFormatString
= GetString();
7104 double fVal
= GetDouble();
7106 Color
* pColor
= NULL
;
7107 LanguageType eCellLang
;
7108 const ScPatternAttr
* pPattern
= pDok
->GetPattern(
7109 aPos
.Col(), aPos
.Row(), aPos
.Tab() );
7111 eCellLang
= ((const SvxLanguageItem
&)
7112 pPattern
->GetItem( ATTR_LANGUAGE_FORMAT
)).GetValue();
7114 eCellLang
= ScGlobal::eLnge
;
7115 if ( !pFormatter
->GetPreviewStringGuess( sFormatString
, fVal
, aStr
,
7116 &pColor
, eCellLang
) )
7117 PushIllegalArgument();
7124 void ScInterpreter::ScSubstitute()
7126 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScSubstitute" );
7127 BYTE nParamCount
= GetByte();
7128 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
7131 if (nParamCount
== 4)
7133 double fAnz
= ::rtl::math::approxFloor(GetDouble());
7134 if( fAnz
< 1 || fAnz
> STRING_MAXLEN
)
7136 PushIllegalArgument();
7140 nAnz
= (xub_StrLen
) fAnz
;
7144 String sNewStr
= GetString();
7145 String sOldStr
= GetString();
7146 String sStr
= GetString();
7147 xub_StrLen nPos
= 0;
7148 xub_StrLen nCount
= 0;
7149 xub_StrLen nNewLen
= sNewStr
.Len();
7150 xub_StrLen nOldLen
= sOldStr
.Len();
7153 nPos
= sStr
.Search( sOldStr
, nPos
);
7154 if (nPos
!= STRING_NOTFOUND
)
7157 if( !nAnz
|| nCount
== nAnz
)
7159 sStr
.Erase(nPos
,nOldLen
);
7160 if ( CheckStringResultLen( sStr
, sNewStr
) )
7162 sStr
.Insert(sNewStr
,nPos
);
7163 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ nNewLen
);
7179 void ScInterpreter::ScRept()
7181 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScRept" );
7182 if ( MustHaveParamCount( GetByte(), 2 ) )
7184 double fAnz
= ::rtl::math::approxFloor(GetDouble());
7185 String
aStr( GetString() );
7187 PushIllegalArgument();
7188 else if ( fAnz
* aStr
.Len() > STRING_MAXLEN
)
7190 PushError( errStringOverflow
);
7192 else if ( fAnz
== 0.0 )
7193 PushString( EMPTY_STRING
);
7196 xub_StrLen n
= (xub_StrLen
) fAnz
;
7197 const xub_StrLen nLen
= aStr
.Len();
7199 const sal_Unicode
* const pSrc
= aStr
.GetBuffer();
7200 sal_Unicode
* pDst
= aRes
.AllocBuffer( n
* nLen
);
7203 memcpy( pDst
, pSrc
, nLen
* sizeof(sal_Unicode
) );
7212 void ScInterpreter::ScConcat()
7214 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScConcat" );
7215 BYTE nParamCount
= GetByte();
7217 while( nParamCount
-- > 0)
7219 const String
& rStr
= GetString();
7220 aRes
.Insert( rStr
, 0 );
7226 void ScInterpreter::ScErrorType()
7228 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::ScErrorType" );
7230 USHORT nOldError
= nGlobalError
;
7232 switch ( GetStackType() )
7236 FormulaTokenRef x
= PopToken();
7238 nErr
= nGlobalError
;
7241 const ScRefList
* pRefList
= static_cast<ScToken
*>(x
.get())->GetRefList();
7242 size_t n
= pRefList
->size();
7250 DoubleRefToRange( (*pRefList
)[0], aRange
);
7252 nErr
= nGlobalError
;
7256 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
7257 nErr
= pDok
->GetErrCode( aAdr
);
7259 nErr
= nGlobalError
;
7268 PopDoubleRef( aRange
);
7270 nErr
= nGlobalError
;
7274 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
7275 nErr
= pDok
->GetErrCode( aAdr
);
7277 nErr
= nGlobalError
;
7284 PopSingleRef( aAdr
);
7286 nErr
= nGlobalError
;
7288 nErr
= pDok
->GetErrCode( aAdr
);
7293 nErr
= nGlobalError
;
7302 nGlobalError
= nOldError
;
7308 BOOL
ScInterpreter::MayBeRegExp( const String
& rStr
, const ScDocument
* pDoc
)
7310 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::MayBeRegExp" );
7311 if ( pDoc
&& !pDoc
->GetDocOptions().IsFormulaRegexEnabled() )
7313 if ( !rStr
.Len() || (rStr
.Len() == 1 && rStr
.GetChar(0) != '.') )
7314 return FALSE
; // einzelnes Metazeichen kann keine RegExp sein
7315 static const sal_Unicode cre
[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
7316 const sal_Unicode
* p1
= rStr
.GetBuffer();
7318 while ( ( c1
= *p1
++ ) != 0 )
7320 const sal_Unicode
* p2
= cre
;
7330 static bool lcl_LookupQuery( ScAddress
& o_rResultPos
, ScDocument
* pDoc
,
7331 const ScQueryParam
& rParam
, const ScQueryEntry
& rEntry
)
7333 bool bFound
= false;
7334 ScQueryCellIterator
aCellIter( pDoc
, rParam
.nTab
, rParam
, FALSE
);
7335 if (rEntry
.eOp
!= SC_EQUAL
)
7337 // range lookup <= or >=
7340 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow
);
7343 o_rResultPos
.SetCol( nCol
);
7344 o_rResultPos
.SetRow( nRow
);
7347 else if (aCellIter
.GetFirst())
7351 o_rResultPos
.SetCol( aCellIter
.GetCol());
7352 o_rResultPos
.SetRow( aCellIter
.GetRow());
7357 #define erDEBUG_LOOKUPCACHE 0
7358 #if erDEBUG_LOOKUPCACHE
7360 using ::std::fprintf
;
7361 using ::std::fflush
;
7362 static struct LookupCacheDebugCounter
7364 unsigned long nMiss
;
7366 LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
7367 ~LookupCacheDebugCounter()
7369 fprintf( stderr
, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
7370 nMiss
, nHit
, nHit
+nMiss
, (nMiss
>0 ? nHit
/nMiss
: 0),
7371 ((nHit
+nMiss
)>0 ? (100*nHit
)/(nHit
+nMiss
) : 0));
7374 } aLookupCacheDebugCounter
;
7377 bool ScInterpreter::LookupQueryWithCache( ScAddress
& o_rResultPos
,
7378 const ScQueryParam
& rParam
) const
7380 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "er", "ScInterpreter::LookupQueryWithCache" );
7381 bool bFound
= false;
7382 const ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
7383 bool bColumnsMatch
= (rParam
.nCol1
== rEntry
.nField
);
7384 DBG_ASSERT( bColumnsMatch
, "ScInterpreter::LookupQueryWithCache: columns don't match");
7386 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
7389 ScRange
aLookupRange( rParam
.nCol1
, rParam
.nRow1
, rParam
.nTab
,
7390 rParam
.nCol2
, rParam
.nRow2
, rParam
.nTab
);
7391 ScLookupCache
& rCache
= pDok
->GetLookupCache( aLookupRange
);
7392 ScLookupCache::QueryCriteria
aCriteria( rEntry
);
7393 ScLookupCache::Result eCacheResult
= rCache
.lookup( o_rResultPos
,
7395 switch (eCacheResult
)
7397 case ScLookupCache::NOT_CACHED
:
7398 case ScLookupCache::CRITERIA_DIFFERENT
:
7399 #if erDEBUG_LOOKUPCACHE
7400 ++aLookupCacheDebugCounter
.nMiss
;
7401 #if erDEBUG_LOOKUPCACHE > 1
7402 fprintf( stderr
, "miss %d,%d,%d\n", (int)aPos
.Col(), (int)aPos
.Row(), (int)aPos
.Tab());
7405 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
7406 if (eCacheResult
== ScLookupCache::NOT_CACHED
)
7407 rCache
.insert( o_rResultPos
, aCriteria
, aPos
, bFound
);
7409 case ScLookupCache::FOUND
:
7410 #if erDEBUG_LOOKUPCACHE
7411 ++aLookupCacheDebugCounter
.nHit
;
7412 #if erDEBUG_LOOKUPCACHE > 1
7413 fprintf( stderr
, "hit %d,%d,%d\n", (int)aPos
.Col(), (int)aPos
.Row(), (int)aPos
.Tab());
7418 case ScLookupCache::NOT_AVAILABLE
:
7419 ; // nothing, bFound remains FALSE