1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: interpr1.cxx,v $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_sc.hxx"
34 // INCLUDE ---------------------------------------------------------------
36 #include "scitems.hxx"
37 #include <svx/langitem.hxx>
38 #include <svx/algitem.hxx>
39 #include <unotools/textsearch.hxx>
40 #include <svtools/zforlist.hxx>
41 #include <svtools/zformat.hxx>
42 #include <tools/urlobj.hxx>
43 #include <unotools/charclass.hxx>
44 #include <sfx2/docfile.hxx>
45 #include <sfx2/printer.hxx>
46 #include <unotools/collatorwrapper.hxx>
47 #include <unotools/transliterationwrapper.hxx>
48 #include <rtl/logfile.hxx>
50 #include "interpre.hxx"
51 #include "patattr.hxx"
53 #include "document.hxx"
54 #include "dociter.hxx"
56 #include "scmatrix.hxx"
57 #include "docoptio.hxx"
58 #include "globstr.hrc"
60 #include "jumpmatrix.hxx"
62 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
63 #include <comphelper/processfactory.hxx>
70 #include "cellkeytranslator.hxx"
71 #include "lookupcache.hxx"
72 #include "rangenam.hxx"
73 #include "compiler.hxx"
74 #include <basic/sbstar.hxx>
76 #define SC_DOUBLE_MAXVALUE 1.7e307
78 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack
, 8, 4 )
79 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter
, 32, 16 )
81 ScTokenStack
* ScInterpreter::pGlobalStack
= NULL
;
82 BOOL
ScInterpreter::bGlobalStackInUse
= FALSE
;
84 using namespace formula
;
85 //-----------------------------------------------------------------------------
87 //-----------------------------------------------------------------------------
90 void ScInterpreter::ScIfJump()
92 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIfJump" );
93 const short* pJump
= pCur
->GetJump();
94 short nJumpCount
= pJump
[ 0 ];
95 MatrixDoubleRefToMatrix();
96 switch ( GetStackType() )
100 ScMatrixRef pMat
= PopMatrix();
102 PushIllegalParameter();
105 FormulaTokenRef xNew
;
106 ScTokenMatrixMap::const_iterator aMapIter
;
107 // DoubleError handled by JumpMatrix
108 pMat
->SetErrorInterpreter( NULL
);
110 pMat
->GetDimensions( nCols
, nRows
);
111 if ( nCols
== 0 || nRows
== 0 )
112 PushIllegalArgument();
113 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
114 pCur
)) != pTokenMatrixMap
->end()))
115 xNew
= (*aMapIter
).second
;
118 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
119 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
121 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
125 ScMatValType nType
= 0;
126 const ScMatrixValue
* pMatVal
= pMat
->Get( nC
, nR
,
128 bool bIsValue
= ScMatrix::IsValueType( nType
);
131 fVal
= pMatVal
->fVal
;
132 bIsValue
= ::rtl::math::isFinite( fVal
);
133 bTrue
= bIsValue
&& (fVal
!= 0.0);
139 // Treat empty and empty path as 0, but string
141 bIsValue
= !ScMatrix::IsRealStringType( nType
);
143 fVal
= (bIsValue
? 0.0 : CreateDoubleError( errNoValue
));
147 if( nJumpCount
>= 2 )
149 pJumpMat
->SetJump( nC
, nR
, fVal
,
151 pJump
[ nJumpCount
]);
154 { // no parameter given for THEN
155 pJumpMat
->SetJump( nC
, nR
, fVal
,
157 pJump
[ nJumpCount
]);
162 if( nJumpCount
== 3 && bIsValue
)
164 pJumpMat
->SetJump( nC
, nR
, fVal
,
166 pJump
[ nJumpCount
]);
169 { // no parameter given for ELSE,
171 pJumpMat
->SetJump( nC
, nR
, fVal
,
173 pJump
[ nJumpCount
]);
178 xNew
= new ScJumpMatrixToken( pJumpMat
);
179 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur
, xNew
));
181 PushTempToken( xNew
);
182 // set endpoint of path for main code line
183 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
191 if( nJumpCount
>= 2 )
193 aCode
.Jump( pJump
[ 1 ], pJump
[ nJumpCount
] );
196 { // no parameter given for THEN
197 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
199 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
204 if( nJumpCount
== 3 )
206 aCode
.Jump( pJump
[ 2 ], pJump
[ nJumpCount
] );
209 { // no parameter given for ELSE
210 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
212 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
220 void ScInterpreter::ScChoseJump()
222 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChoseJump" );
223 // We have to set a jump, if there was none chosen because of an error set
225 bool bHaveJump
= false;
226 const short* pJump
= pCur
->GetJump();
227 short nJumpCount
= pJump
[ 0 ];
228 MatrixDoubleRefToMatrix();
229 switch ( GetStackType() )
233 ScMatrixRef pMat
= PopMatrix();
235 PushIllegalParameter();
238 FormulaTokenRef xNew
;
239 ScTokenMatrixMap::const_iterator aMapIter
;
240 // DoubleError handled by JumpMatrix
241 pMat
->SetErrorInterpreter( NULL
);
243 pMat
->GetDimensions( nCols
, nRows
);
244 if ( nCols
== 0 || nRows
== 0 )
245 PushIllegalParameter();
246 else if (pTokenMatrixMap
&& ((aMapIter
= pTokenMatrixMap
->find(
247 pCur
)) != pTokenMatrixMap
->end()))
248 xNew
= (*aMapIter
).second
;
251 ScJumpMatrix
* pJumpMat
= new ScJumpMatrix( nCols
, nRows
);
252 for ( SCSIZE nC
=0; nC
< nCols
; ++nC
)
254 for ( SCSIZE nR
=0; nR
< nRows
; ++nR
)
258 const ScMatrixValue
* pMatVal
= pMat
->Get( nC
, nR
,
260 bool bIsValue
= ScMatrix::IsValueType( nType
);
263 fVal
= pMatVal
->fVal
;
264 bIsValue
= ::rtl::math::isFinite( fVal
);
267 fVal
= ::rtl::math::approxFloor( fVal
);
268 if ( (fVal
< 1) || (fVal
>= nJumpCount
))
271 fVal
= CreateDoubleError(
278 fVal
= CreateDoubleError( errNoValue
);
282 pJumpMat
->SetJump( nC
, nR
, fVal
,
283 pJump
[ (short)fVal
],
284 pJump
[ nJumpCount
]);
288 pJumpMat
->SetJump( nC
, nR
, fVal
,
290 pJump
[ nJumpCount
]);
294 xNew
= new ScJumpMatrixToken( pJumpMat
);
295 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
298 PushTempToken( xNew
);
299 // set endpoint of path for main code line
300 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
307 double nJumpIndex
= ::rtl::math::approxFloor( GetDouble() );
308 if (!nGlobalError
&& (nJumpIndex
>= 1) && (nJumpIndex
< nJumpCount
))
310 aCode
.Jump( pJump
[ (short) nJumpIndex
], pJump
[ nJumpCount
] );
314 PushIllegalArgument();
318 aCode
.Jump( pJump
[ nJumpCount
], pJump
[ nJumpCount
] );
321 void lcl_AdjustJumpMatrix( ScJumpMatrix
* pJumpM
, ScMatrixRef
& pResMat
, SCSIZE nParmCols
, SCSIZE nParmRows
)
323 SCSIZE nJumpCols
, nJumpRows
;
324 SCSIZE nResCols
, nResRows
;
325 SCSIZE nAdjustCols
, nAdjustRows
;
326 pJumpM
->GetDimensions( nJumpCols
, nJumpRows
);
327 pJumpM
->GetResMatDimensions( nResCols
, nResRows
);
328 if (( nJumpCols
== 1 && nParmCols
> nResCols
) ||
329 ( nJumpRows
== 1 && nParmRows
> nResRows
))
331 if ( nJumpCols
== 1 && nJumpRows
== 1 )
333 nAdjustCols
= nParmCols
> nResCols
? nParmCols
: nResCols
;
334 nAdjustRows
= nParmRows
> nResRows
? nParmRows
: nResRows
;
336 else if ( nJumpCols
== 1 )
338 nAdjustCols
= nParmCols
;
339 nAdjustRows
= nResRows
;
343 nAdjustCols
= nResCols
;
344 nAdjustRows
= nParmRows
;
346 pJumpM
->SetNewResMat( nAdjustCols
, nAdjustRows
);
347 pResMat
= pJumpM
->GetResultMatrix();
351 bool ScInterpreter::JumpMatrix( short nStackLevel
)
353 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::JumpMatrix" );
354 pJumpMatrix
= static_cast<ScToken
*>(pStack
[sp
-nStackLevel
])->GetJumpMatrix();
355 ScMatrixRef pResMat
= pJumpMatrix
->GetResultMatrix();
357 if ( nStackLevel
== 2 )
359 if ( aCode
.HasStacked() )
360 aCode
.Pop(); // pop what Jump() pushed
363 DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
369 SetError( errUnknownStackVariable
);
373 pJumpMatrix
->GetPos( nC
, nR
);
374 switch ( GetStackType() )
378 double fVal
= GetDouble();
381 fVal
= CreateDoubleError( nGlobalError
);
384 pResMat
->PutDouble( fVal
, nC
, nR
);
389 const String
& rStr
= GetString();
392 pResMat
->PutDouble( CreateDoubleError( nGlobalError
),
397 pResMat
->PutString( rStr
, nC
, nR
);
403 PopSingleRef( aAdr
);
406 pResMat
->PutDouble( CreateDoubleError( nGlobalError
),
412 ScBaseCell
* pCell
= GetCell( aAdr
);
413 if (HasCellEmptyData( pCell
))
414 pResMat
->PutEmpty( nC
, nR
);
415 else if (HasCellValueData( pCell
))
417 double fVal
= GetCellValue( aAdr
, pCell
);
420 fVal
= CreateDoubleError(
424 pResMat
->PutDouble( fVal
, nC
, nR
);
429 GetCellString( aStr
, pCell
);
432 pResMat
->PutDouble( CreateDoubleError(
433 nGlobalError
), nC
, nR
);
437 pResMat
->PutString( aStr
, nC
, nR
);
443 { // upper left plus offset within matrix
446 PopDoubleRef( aRange
);
449 fVal
= CreateDoubleError( nGlobalError
);
451 pResMat
->PutDouble( fVal
, nC
, nR
);
455 // Do not modify the original range because we use it
456 // to adjust the size of the result matrix if necessary.
457 ScAddress
aAdr( aRange
.aStart
);
458 ULONG nCol
= (ULONG
)aAdr
.Col() + nC
;
459 ULONG nRow
= (ULONG
)aAdr
.Row() + nR
;
460 if ((nCol
> static_cast<ULONG
>(aRange
.aEnd
.Col()) &&
461 aRange
.aEnd
.Col() != aRange
.aStart
.Col())
462 || (nRow
> static_cast<ULONG
>(aRange
.aEnd
.Row()) &&
463 aRange
.aEnd
.Row() != aRange
.aStart
.Row()))
465 fVal
= CreateDoubleError( NOTAVAILABLE
);
466 pResMat
->PutDouble( fVal
, nC
, nR
);
470 // Replicate column and/or row of a vector if it is
471 // one. Note that this could be a range reference
472 // that in fact consists of only one cell, e.g. A1:A1
473 if (aRange
.aEnd
.Col() == aRange
.aStart
.Col())
474 nCol
= aRange
.aStart
.Col();
475 if (aRange
.aEnd
.Row() == aRange
.aStart
.Row())
476 nRow
= aRange
.aStart
.Row();
477 aAdr
.SetCol( static_cast<SCCOL
>(nCol
) );
478 aAdr
.SetRow( static_cast<SCROW
>(nRow
) );
479 ScBaseCell
* pCell
= GetCell( aAdr
);
480 if (HasCellEmptyData( pCell
))
481 pResMat
->PutEmpty( nC
, nR
);
482 else if (HasCellValueData( pCell
))
484 double fCellVal
= GetCellValue( aAdr
, pCell
);
487 fCellVal
= CreateDoubleError(
491 pResMat
->PutDouble( fCellVal
, nC
, nR
);
496 GetCellString( aStr
, pCell
);
499 pResMat
->PutDouble( CreateDoubleError(
500 nGlobalError
), nC
, nR
);
504 pResMat
->PutString( aStr
, nC
, nR
);
507 SCSIZE nParmCols
= aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1;
508 SCSIZE nParmRows
= aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1;
509 lcl_AdjustJumpMatrix( pJumpMatrix
, pResMat
, nParmCols
, nParmRows
);
514 { // match matrix offsets
516 ScMatrixRef pMat
= PopMatrix();
519 fVal
= CreateDoubleError( nGlobalError
);
521 pResMat
->PutDouble( fVal
, nC
, nR
);
525 fVal
= CreateDoubleError( errUnknownVariable
);
526 pResMat
->PutDouble( fVal
, nC
, nR
);
531 pMat
->GetDimensions( nCols
, nRows
);
532 if ((nCols
<= nC
&& nCols
!= 1) ||
533 (nRows
<= nR
&& nRows
!= 1))
535 fVal
= CreateDoubleError( NOTAVAILABLE
);
536 pResMat
->PutDouble( fVal
, nC
, nR
);
540 if ( pMat
->IsValue( nC
, nR
) )
542 fVal
= pMat
->GetDouble( nC
, nR
);
543 pResMat
->PutDouble( fVal
, nC
, nR
);
545 else if ( pMat
->IsEmpty( nC
, nR
) )
546 pResMat
->PutEmpty( nC
, nR
);
549 const String
& rStr
= pMat
->GetString( nC
, nR
);
550 pResMat
->PutString( rStr
, nC
, nR
);
553 lcl_AdjustJumpMatrix( pJumpMatrix
, pResMat
, nCols
, nRows
);
560 double fVal
= CreateDoubleError( nGlobalError
);
562 pResMat
->PutDouble( fVal
, nC
, nR
);
568 double fVal
= CreateDoubleError( errIllegalArgument
);
569 pResMat
->PutDouble( fVal
, nC
, nR
);
574 bool bCont
= pJumpMatrix
->Next( nC
, nR
);
578 short nStart
, nNext
, nStop
;
579 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
580 while ( bCont
&& nStart
== nNext
)
581 { // push all results that have no jump path
584 // a FALSE without path results in an empty path value
586 pResMat
->PutEmptyPath( nC
, nR
);
588 pResMat
->PutDouble( fBool
, nC
, nR
);
590 bCont
= pJumpMatrix
->Next( nC
, nR
);
592 pJumpMatrix
->GetJump( nC
, nR
, fBool
, nStart
, nNext
, nStop
);
594 if ( bCont
&& nStart
!= nNext
)
596 const ScTokenVec
* pParams
= pJumpMatrix
->GetJumpParameters();
599 for ( ScTokenVec::const_iterator i
= pParams
->begin();
600 i
!= pParams
->end(); ++i
)
602 // This is not the current state of the interpreter, so
603 // push without error, and elements' errors are coded into
605 PushWithoutError( *(*i
));
608 aCode
.Jump( nStart
, nNext
, nStop
);
612 { // we're done with it, throw away jump matrix, keep result
615 PushMatrix( pResMat
);
616 // Remove jump matrix from map and remember result matrix in case it
617 // could be reused in another path of the same condition.
620 pTokenMatrixMap
->erase( pCur
);
621 pTokenMatrixMap
->insert( ScTokenMatrixMap::value_type( pCur
,
630 double ScInterpreter::CompareFunc( const ScCompare
& rComp
)
632 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareFunc" );
633 // Keep DoubleError if encountered
634 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
635 if ( !rComp
.bEmpty
[0] && rComp
.bVal
[0] && !::rtl::math::isFinite( rComp
.nVal
[0]))
636 return rComp
.nVal
[0];
637 if ( !rComp
.bEmpty
[1] && rComp
.bVal
[1] && !::rtl::math::isFinite( rComp
.nVal
[1]))
638 return rComp
.nVal
[1];
641 if ( rComp
.bEmpty
[ 0 ] )
643 if ( rComp
.bEmpty
[ 1 ] )
644 ; // empty cell == empty cell, fRes 0
645 else if( rComp
.bVal
[ 1 ] )
647 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 1 ], 0.0 ) )
649 if ( rComp
.nVal
[ 1 ] < 0.0 )
650 fRes
= 1; // empty cell > -x
652 fRes
= -1; // empty cell < x
654 // else: empty cell == 0.0
658 if ( rComp
.pVal
[ 1 ]->Len() )
659 fRes
= -1; // empty cell < "..."
660 // else: empty cell == ""
663 else if ( rComp
.bEmpty
[ 1 ] )
665 if( rComp
.bVal
[ 0 ] )
667 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 0 ], 0.0 ) )
669 if ( rComp
.nVal
[ 0 ] < 0.0 )
670 fRes
= -1; // -x < empty cell
672 fRes
= 1; // x > empty cell
674 // else: empty cell == 0.0
678 if ( rComp
.pVal
[ 0 ]->Len() )
679 fRes
= 1; // "..." > empty cell
680 // else: "" == empty cell
683 else if( rComp
.bVal
[ 0 ] )
685 if( rComp
.bVal
[ 1 ] )
687 if ( !::rtl::math::approxEqual( rComp
.nVal
[ 0 ], rComp
.nVal
[ 1 ] ) )
689 if( rComp
.nVal
[ 0 ] - rComp
.nVal
[ 1 ] < 0 )
696 fRes
= -1; // number is less than string
698 else if( rComp
.bVal
[ 1 ] )
699 fRes
= 1; // number is less than string
702 if (pDok
->GetDocOptions().IsIgnoreCase())
703 fRes
= (double) ScGlobal::pCollator
->compareString(
704 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
706 fRes
= (double) ScGlobal::pCaseCollator
->compareString(
707 *rComp
.pVal
[ 0 ], *rComp
.pVal
[ 1 ] );
713 double ScInterpreter::Compare()
715 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::Compare" );
717 ScCompare
aComp( &aVal1
, &aVal2
);
718 for( short i
= 1; i
>= 0; i
-- )
720 switch ( GetRawStackType() )
723 aComp
.bEmpty
[ i
] = TRUE
;
727 aComp
.nVal
[ i
] = GetDouble();
728 aComp
.bVal
[ i
] = TRUE
;
731 *aComp
.pVal
[ i
] = GetString();
732 aComp
.bVal
[ i
] = FALSE
;
738 if ( !PopDoubleRefOrSingleRef( aAdr
) )
740 ScBaseCell
* pCell
= GetCell( aAdr
);
741 if (HasCellEmptyData( pCell
))
742 aComp
.bEmpty
[ i
] = TRUE
;
743 else if (HasCellStringData( pCell
))
745 GetCellString( *aComp
.pVal
[ i
], pCell
);
746 aComp
.bVal
[ i
] = FALSE
;
750 aComp
.nVal
[ i
] = GetCellValue( aAdr
, pCell
);
751 aComp
.bVal
[ i
] = TRUE
;
756 SetError( errIllegalParameter
);
762 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
763 return CompareFunc( aComp
);
767 ScMatrixRef
ScInterpreter::CompareMat()
769 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CompareMat" );
771 ScCompare
aComp( &aVal1
, &aVal2
);
774 for( short i
= 1; i
>= 0; i
-- )
776 switch (GetRawStackType())
779 aComp
.bEmpty
[ i
] = TRUE
;
783 aComp
.nVal
[ i
] = GetDouble();
784 aComp
.bVal
[ i
] = TRUE
;
787 *aComp
.pVal
[ i
] = GetString();
788 aComp
.bVal
[ i
] = FALSE
;
792 PopSingleRef( aAdr
);
793 ScBaseCell
* pCell
= GetCell( aAdr
);
794 if (HasCellEmptyData( pCell
))
795 aComp
.bEmpty
[ i
] = TRUE
;
796 else if (HasCellStringData( pCell
))
798 GetCellString( *aComp
.pVal
[ i
], pCell
);
799 aComp
.bVal
[ i
] = FALSE
;
803 aComp
.nVal
[ i
] = GetCellValue( aAdr
, pCell
);
804 aComp
.bVal
[ i
] = TRUE
;
810 pMat
[ i
] = GetMatrix();
812 SetError( errIllegalParameter
);
814 pMat
[i
]->SetErrorInterpreter( NULL
);
815 // errors are transported as DoubleError inside matrix
818 SetError( errIllegalParameter
);
822 ScMatrixRef pResMat
= NULL
;
825 if ( pMat
[0] && pMat
[1] )
829 pMat
[0]->GetDimensions( nC0
, nR0
);
830 pMat
[1]->GetDimensions( nC1
, nR1
);
831 SCSIZE nC
= Max( nC0
, nC1
);
832 SCSIZE nR
= Max( nR0
, nR1
);
833 pResMat
= GetNewMat( nC
, nR
);
836 for ( SCSIZE j
=0; j
<nC
; j
++ )
838 for ( SCSIZE k
=0; k
<nR
; k
++ )
840 SCSIZE nCol
= j
, nRow
= k
;
841 if ( pMat
[0]->ValidColRowOrReplicated( nCol
, nRow
) &&
842 pMat
[1]->ValidColRowOrReplicated( nCol
, nRow
))
844 for ( short i
=1; i
>=0; i
-- )
846 if ( pMat
[i
]->IsString(j
,k
) )
848 aComp
.bVal
[i
] = FALSE
;
849 *aComp
.pVal
[i
] = pMat
[i
]->GetString(j
,k
);
850 aComp
.bEmpty
[i
] = pMat
[i
]->IsEmpty(j
,k
);
854 aComp
.bVal
[i
] = TRUE
;
855 aComp
.nVal
[i
] = pMat
[i
]->GetDouble(j
,k
);
856 aComp
.bEmpty
[i
] = FALSE
;
859 pResMat
->PutDouble( CompareFunc( aComp
), j
,k
);
862 pResMat
->PutString( ScGlobal::GetRscString(STR_NO_VALUE
), j
,k
);
866 else if ( pMat
[0] || pMat
[1] )
868 short i
= ( pMat
[0] ? 0 : 1);
870 pMat
[i
]->GetDimensions( nC
, nR
);
871 pResMat
= GetNewMat( nC
, nR
);
875 for ( SCSIZE j
=0; j
<n
; j
++ )
877 if ( pMat
[i
]->IsValue(j
) )
879 aComp
.bVal
[i
] = TRUE
;
880 aComp
.nVal
[i
] = pMat
[i
]->GetDouble(j
);
881 aComp
.bEmpty
[i
] = FALSE
;
885 aComp
.bVal
[i
] = FALSE
;
886 *aComp
.pVal
[i
] = pMat
[i
]->GetString(j
);
887 aComp
.bEmpty
[i
] = pMat
[i
]->IsEmpty(j
);
889 pResMat
->PutDouble( CompareFunc( aComp
), j
);
893 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
898 void ScInterpreter::ScEqual()
900 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScEqual" );
901 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
903 ScMatrixRef pMat
= CompareMat();
905 PushIllegalParameter();
908 pMat
->CompareEqual();
913 PushInt( Compare() == 0 );
917 void ScInterpreter::ScNotEqual()
919 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNotEqual" );
920 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
922 ScMatrixRef pMat
= CompareMat();
924 PushIllegalParameter();
927 pMat
->CompareNotEqual();
932 PushInt( Compare() != 0 );
936 void ScInterpreter::ScLess()
938 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLess" );
939 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
941 ScMatrixRef pMat
= CompareMat();
943 PushIllegalParameter();
951 PushInt( Compare() < 0 );
955 void ScInterpreter::ScGreater()
957 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGreater" );
958 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
960 ScMatrixRef pMat
= CompareMat();
962 PushIllegalParameter();
965 pMat
->CompareGreater();
970 PushInt( Compare() > 0 );
974 void ScInterpreter::ScLessEqual()
976 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLessEqual" );
977 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
979 ScMatrixRef pMat
= CompareMat();
981 PushIllegalParameter();
984 pMat
->CompareLessEqual();
989 PushInt( Compare() <= 0 );
993 void ScInterpreter::ScGreaterEqual()
995 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScGreaterEqual" );
996 if ( GetStackType(1) == svMatrix
|| GetStackType(2) == svMatrix
)
998 ScMatrixRef pMat
= CompareMat();
1000 PushIllegalParameter();
1003 pMat
->CompareGreaterEqual();
1008 PushInt( Compare() >= 0 );
1012 void ScInterpreter::ScAnd()
1014 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAnd" );
1015 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1016 short nParamCount
= GetByte();
1017 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1019 BOOL bHaveValue
= FALSE
;
1021 size_t nRefInList
= 0;
1022 while( nParamCount
-- > 0)
1024 if ( !nGlobalError
)
1026 switch ( GetStackType() )
1030 nRes
&= ( PopDouble() != 0.0 );
1034 SetError( errNoValue
);
1039 PopSingleRef( aAdr
);
1040 if ( !nGlobalError
)
1042 ScBaseCell
* pCell
= GetCell( aAdr
);
1043 if ( HasCellValueData( pCell
) )
1046 nRes
&= ( GetCellValue( aAdr
, pCell
) != 0.0 );
1048 // else: Xcl setzt hier keinen Fehler
1056 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1057 if ( !nGlobalError
)
1061 ScValueIterator
aValIter( pDok
, aRange
);
1062 if ( aValIter
.GetFirst( fVal
, nErr
) )
1067 nRes
&= ( fVal
!= 0.0 );
1068 } while ( (nErr
== 0) &&
1069 aValIter
.GetNext( fVal
, nErr
) );
1077 ScMatrixRef pMat
= GetMatrix();
1081 double fVal
= pMat
->And();
1082 USHORT nErr
= GetDoubleErrorValue( fVal
);
1089 nRes
&= (fVal
!= 0.0);
1091 // else: GetMatrix did set errIllegalParameter
1096 SetError( errIllegalParameter
);
1110 void ScInterpreter::ScOr()
1112 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOr" );
1113 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1114 short nParamCount
= GetByte();
1115 if ( MustHaveParamCountMin( nParamCount
, 1 ) )
1117 BOOL bHaveValue
= FALSE
;
1119 size_t nRefInList
= 0;
1120 while( nParamCount
-- > 0)
1122 if ( !nGlobalError
)
1124 switch ( GetStackType() )
1128 nRes
|= ( PopDouble() != 0.0 );
1132 SetError( errNoValue
);
1137 PopSingleRef( aAdr
);
1138 if ( !nGlobalError
)
1140 ScBaseCell
* pCell
= GetCell( aAdr
);
1141 if ( HasCellValueData( pCell
) )
1144 nRes
|= ( GetCellValue( aAdr
, pCell
) != 0.0 );
1146 // else: Xcl setzt hier keinen Fehler
1154 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
1155 if ( !nGlobalError
)
1159 ScValueIterator
aValIter( pDok
, aRange
);
1160 if ( aValIter
.GetFirst( fVal
, nErr
) )
1165 nRes
|= ( fVal
!= 0.0 );
1166 } while ( (nErr
== 0) &&
1167 aValIter
.GetNext( fVal
, nErr
) );
1176 ScMatrixRef pMat
= GetMatrix();
1180 double fVal
= pMat
->Or();
1181 USHORT nErr
= GetDoubleErrorValue( fVal
);
1188 nRes
|= (fVal
!= 0.0);
1190 // else: GetMatrix did set errIllegalParameter
1195 SetError( errIllegalParameter
);
1209 void ScInterpreter::ScNeg()
1211 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNeg" );
1212 // Simple negation doesn't change current format type to number, keep
1214 nFuncFmtType
= nCurFmtType
;
1215 switch ( GetStackType() )
1219 ScMatrixRef pMat
= GetMatrix();
1221 PushIllegalParameter();
1225 pMat
->GetDimensions( nC
, nR
);
1226 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1228 PushIllegalArgument();
1231 SCSIZE nCount
= nC
* nR
;
1232 for ( SCSIZE j
=0; j
<nCount
; ++j
)
1234 if ( pMat
->IsValueOrEmpty(j
) )
1235 pResMat
->PutDouble( -pMat
->GetDouble(j
), j
);
1238 ScGlobal::GetRscString( STR_NO_VALUE
), j
);
1240 PushMatrix( pResMat
);
1246 PushDouble( -GetDouble() );
1251 void ScInterpreter::ScPercentSign()
1253 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPercentSign" );
1254 nFuncFmtType
= NUMBERFORMAT_PERCENT
;
1255 const FormulaToken
* pSaveCur
= pCur
;
1256 BYTE nSavePar
= cPar
;
1259 FormulaByteToken
aDivOp( ocDiv
, cPar
);
1267 void ScInterpreter::ScNot()
1269 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScNot" );
1270 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1271 switch ( GetStackType() )
1275 ScMatrixRef pMat
= GetMatrix();
1277 PushIllegalParameter();
1281 pMat
->GetDimensions( nC
, nR
);
1282 ScMatrixRef pResMat
= GetNewMat( nC
, nR
);
1284 PushIllegalArgument();
1287 SCSIZE nCount
= nC
* nR
;
1288 for ( SCSIZE j
=0; j
<nCount
; ++j
)
1290 if ( pMat
->IsValueOrEmpty(j
) )
1291 pResMat
->PutDouble( (pMat
->GetDouble(j
) == 0.0), j
);
1294 ScGlobal::GetRscString( STR_NO_VALUE
), j
);
1296 PushMatrix( pResMat
);
1302 PushInt( GetDouble() == 0.0 );
1307 void ScInterpreter::ScPi()
1309 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPi" );
1314 void ScInterpreter::ScRandom()
1316 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRandom" );
1317 PushDouble((double)rand() / ((double)RAND_MAX
+1.0));
1321 void ScInterpreter::ScTrue()
1323 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrue" );
1324 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1329 void ScInterpreter::ScFalse()
1331 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFalse" );
1332 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1337 void ScInterpreter::ScDeg()
1339 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDeg" );
1340 PushDouble((GetDouble() / F_PI
) * 180.0);
1344 void ScInterpreter::ScRad()
1346 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRad" );
1347 PushDouble(GetDouble() * (F_PI
/ 180));
1351 void ScInterpreter::ScSin()
1353 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSin" );
1354 PushDouble(::rtl::math::sin(GetDouble()));
1358 void ScInterpreter::ScCos()
1360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCos" );
1361 PushDouble(::rtl::math::cos(GetDouble()));
1365 void ScInterpreter::ScTan()
1367 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTan" );
1368 PushDouble(::rtl::math::tan(GetDouble()));
1372 void ScInterpreter::ScCot()
1374 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCot" );
1375 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1379 void ScInterpreter::ScArcSin()
1381 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcSin" );
1382 PushDouble(asin(GetDouble()));
1386 void ScInterpreter::ScArcCos()
1388 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCos" );
1389 PushDouble(acos(GetDouble()));
1393 void ScInterpreter::ScArcTan()
1395 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTan" );
1396 PushDouble(atan(GetDouble()));
1400 void ScInterpreter::ScArcCot()
1402 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCot" );
1403 PushDouble((F_PI2
) - atan(GetDouble()));
1407 void ScInterpreter::ScSinHyp()
1409 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSinHyp" );
1410 PushDouble(sinh(GetDouble()));
1414 void ScInterpreter::ScCosHyp()
1416 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCosHyp" );
1417 PushDouble(cosh(GetDouble()));
1421 void ScInterpreter::ScTanHyp()
1423 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTanHyp" );
1424 PushDouble(tanh(GetDouble()));
1428 void ScInterpreter::ScCotHyp()
1430 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCotHyp" );
1431 PushDouble(1.0 / tanh(GetDouble()));
1435 void ScInterpreter::ScArcSinHyp()
1437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcSinHyp" );
1438 double nVal
= GetDouble();
1439 PushDouble(log(nVal
+ sqrt((nVal
* nVal
) + 1.0)));
1443 void ScInterpreter::ScArcCosHyp()
1445 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCosHyp" );
1446 double nVal
= GetDouble();
1448 PushIllegalArgument();
1450 PushDouble(log(nVal
+ sqrt((nVal
* nVal
) - 1.0)));
1454 void ScInterpreter::ScArcTanHyp()
1456 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcTanHyp" );
1457 double fVal
= GetDouble();
1458 if (fabs(fVal
) >= 1.0)
1459 PushIllegalArgument();
1461 PushDouble( ::rtl::math::atanh( fVal
));
1465 void ScInterpreter::ScArcCotHyp()
1467 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScArcCotHyp" );
1468 double nVal
= GetDouble();
1469 if (fabs(nVal
) <= 1.0)
1470 PushIllegalArgument();
1472 PushDouble(0.5 * log((nVal
+ 1.0) / (nVal
- 1.0)));
1476 void ScInterpreter::ScExp()
1478 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExp" );
1479 PushDouble(exp(GetDouble()));
1483 void ScInterpreter::ScSqrt()
1485 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSqrt" );
1486 double fVal
= GetDouble();
1488 PushDouble(sqrt(fVal
));
1490 PushIllegalArgument();
1494 void ScInterpreter::ScIsEmpty()
1496 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsEmpty" );
1498 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1499 switch ( GetRawStackType() )
1503 FormulaTokenRef p
= PopToken();
1504 if (!static_cast<const ScEmptyCellToken
*>(p
.get())->IsInherited())
1512 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1514 // NOTE: this could test also on inherited emptiness, but then the
1515 // cell tested wouldn't be empty. Must correspond with
1516 // ScCountEmptyCells().
1517 // if (HasCellEmptyData( GetCell( aAdr)))
1518 CellType eCellType
= GetCellType( GetCell( aAdr
) );
1519 if((eCellType
== CELLTYPE_NONE
) || (eCellType
== CELLTYPE_NOTE
))
1525 ScMatrixRef pMat
= PopMatrix();
1528 else if ( !pJumpMatrix
)
1529 nRes
= pMat
->IsEmpty( 0 );
1532 SCSIZE nCols
, nRows
, nC
, nR
;
1533 pMat
->GetDimensions( nCols
, nRows
);
1534 pJumpMatrix
->GetPos( nC
, nR
);
1535 if ( nC
< nCols
&& nR
< nRows
)
1536 nRes
= pMat
->IsEmpty( nC
, nR
);
1537 // else: FALSE, not empty (which is what Xcl does)
1549 short ScInterpreter::IsString()
1551 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IsString" );
1552 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1554 switch ( GetRawStackType() )
1564 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1566 ScBaseCell
* pCell
= GetCell( aAdr
);
1567 if (GetCellErrCode( pCell
) == 0)
1569 switch ( GetCellType( pCell
) )
1571 case CELLTYPE_STRING
:
1572 case CELLTYPE_EDIT
:
1575 case CELLTYPE_FORMULA
:
1576 nRes
= !((ScFormulaCell
*)pCell
)->IsValue() &&
1577 !((ScFormulaCell
*)pCell
)->IsEmpty();
1587 ScMatrixRef pMat
= PopMatrix();
1590 else if ( !pJumpMatrix
)
1591 nRes
= pMat
->IsString(0) && !pMat
->IsEmpty(0);
1594 SCSIZE nCols
, nRows
, nC
, nR
;
1595 pMat
->GetDimensions( nCols
, nRows
);
1596 pJumpMatrix
->GetPos( nC
, nR
);
1597 if ( nC
< nCols
&& nR
< nRows
)
1598 nRes
= pMat
->IsString( nC
, nR
) && !pMat
->IsEmpty( nC
, nR
);
1610 void ScInterpreter::ScIsString()
1612 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsString" );
1613 PushInt( IsString() );
1617 void ScInterpreter::ScIsNonString()
1619 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsNonString" );
1620 PushInt( !IsString() );
1624 void ScInterpreter::ScIsLogical()
1626 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsLogical" );
1628 switch ( GetStackType() )
1634 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1636 ScBaseCell
* pCell
= GetCell( aAdr
);
1637 if (GetCellErrCode( pCell
) == 0)
1639 if (HasCellValueData(pCell
))
1641 ULONG nFormat
= GetCellNumberFormat( aAdr
, pCell
);
1642 nRes
= ( pFormatter
->GetType(nFormat
)
1643 == NUMBERFORMAT_LOGICAL
);
1649 // TODO: we don't have type information for arrays except
1650 // numerical/string.
1654 if ( !nGlobalError
)
1655 nRes
= ( nCurFmtType
== NUMBERFORMAT_LOGICAL
);
1657 nCurFmtType
= nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1663 void ScInterpreter::ScType()
1665 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScType" );
1667 switch ( GetStackType() )
1673 if ( !PopDoubleRefOrSingleRef( aAdr
) )
1675 ScBaseCell
* pCell
= GetCell( aAdr
);
1676 if (GetCellErrCode( pCell
) == 0)
1678 switch ( GetCellType( pCell
) )
1680 // NOTE: this is Xcl nonsense!
1681 case CELLTYPE_NOTE
:
1682 nType
= 1; // empty cell is value (0)
1684 case CELLTYPE_STRING
:
1685 case CELLTYPE_EDIT
:
1688 case CELLTYPE_VALUE
:
1690 ULONG nFormat
= GetCellNumberFormat( aAdr
, pCell
);
1691 if (pFormatter
->GetType(nFormat
)
1692 == NUMBERFORMAT_LOGICAL
)
1698 case CELLTYPE_FORMULA
:
1702 PushIllegalArgument();
1728 // we could return the type of one element if in JumpMatrix or
1729 // ForceArray mode, but Xcl doesn't ...
1745 inline BOOL
lcl_FormatHasNegColor( const SvNumberformat
* pFormat
)
1747 return pFormat
&& pFormat
->GetColor( 1 );
1751 inline BOOL
lcl_FormatHasOpenPar( const SvNumberformat
* pFormat
)
1753 return pFormat
&& (pFormat
->GetFormatstring().Search( '(' ) != STRING_NOTFOUND
);
1757 void ScInterpreter::ScCell()
1758 { // ATTRIBUTE ; [REF]
1759 BYTE nParamCount
= GetByte();
1760 if( MustHaveParamCount( nParamCount
, 1, 2 ) )
1762 ScAddress
aCellPos( aPos
);
1763 BOOL bError
= FALSE
;
1764 if( nParamCount
== 2 )
1765 bError
= !PopDoubleRefOrSingleRef( aCellPos
);
1766 String
aInfoType( GetString() );
1767 if( bError
|| nGlobalError
)
1768 PushIllegalParameter();
1772 ScBaseCell
* pCell
= GetCell( aCellPos
);
1774 ScCellKeywordTranslator::transKeyword(aInfoType
, ScGlobal::pLocale
, ocCell
);
1776 // *** ADDRESS INFO ***
1777 if( aInfoType
.EqualsAscii( "COL" ) )
1778 { // column number (1-based)
1779 PushInt( aCellPos
.Col() + 1 );
1781 else if( aInfoType
.EqualsAscii( "ROW" ) )
1782 { // row number (1-based)
1783 PushInt( aCellPos
.Row() + 1 );
1785 else if( aInfoType
.EqualsAscii( "SHEET" ) )
1786 { // table number (1-based)
1787 PushInt( aCellPos
.Tab() + 1 );
1789 else if( aInfoType
.EqualsAscii( "ADDRESS" ) )
1790 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
1791 USHORT nFlags
= (aCellPos
.Tab() == aPos
.Tab()) ? (SCA_ABS
) : (SCA_ABS_3D
);
1792 aCellPos
.Format( aFuncResult
, nFlags
, pDok
, pDok
->GetAddressConvention() );
1793 PushString( aFuncResult
);
1795 else if( aInfoType
.EqualsAscii( "FILENAME" ) )
1796 { // file name and table name: 'FILENAME'#$TABLE
1797 SCTAB nTab
= aCellPos
.Tab();
1798 if( nTab
< pDok
->GetTableCount() )
1800 if( pDok
->GetLinkMode( nTab
) == SC_LINK_VALUE
)
1801 pDok
->GetName( nTab
, aFuncResult
);
1804 SfxObjectShell
* pShell
= pDok
->GetDocumentShell();
1805 if( pShell
&& pShell
->GetMedium() )
1807 aFuncResult
= (sal_Unicode
) '\'';
1808 const INetURLObject
& rURLObj
= pShell
->GetMedium()->GetURLObject();
1809 aFuncResult
+= String( rURLObj
.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS
) );
1810 aFuncResult
.AppendAscii( "'#$" );
1812 pDok
->GetName( nTab
, aTabName
);
1813 aFuncResult
+= aTabName
;
1817 PushString( aFuncResult
);
1819 else if( aInfoType
.EqualsAscii( "COORD" ) )
1820 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
1821 // Yes, passing tab as col is intentional!
1822 ScAddress( static_cast<SCCOL
>(aCellPos
.Tab()), 0, 0 ).Format(
1823 aFuncResult
, (SCA_COL_ABSOLUTE
|SCA_VALID_COL
), NULL
, pDok
->GetAddressConvention() );
1826 aCellPos
.Format( aCellStr
, (SCA_COL_ABSOLUTE
|SCA_VALID_COL
|SCA_ROW_ABSOLUTE
|SCA_VALID_ROW
),
1827 NULL
, pDok
->GetAddressConvention() );
1828 aFuncResult
+= aCellStr
;
1829 PushString( aFuncResult
);
1832 // *** CELL PROPERTIES ***
1833 else if( aInfoType
.EqualsAscii( "CONTENTS" ) )
1834 { // contents of the cell, no formatting
1835 if( pCell
&& pCell
->HasStringData() )
1837 GetCellString( aFuncResult
, pCell
);
1838 PushString( aFuncResult
);
1841 PushDouble( GetCellValue( aCellPos
, pCell
) );
1843 else if( aInfoType
.EqualsAscii( "TYPE" ) )
1844 { // b = blank; l = string (label); v = otherwise (value)
1845 if( HasCellStringData( pCell
) )
1848 aFuncResult
= HasCellValueData( pCell
) ? 'v' : 'b';
1849 PushString( aFuncResult
);
1851 else if( aInfoType
.EqualsAscii( "WIDTH" ) )
1852 { // column width (rounded off as count of zero characters in standard font and size)
1853 Printer
* pPrinter
= pDok
->GetPrinter();
1854 MapMode
aOldMode( pPrinter
->GetMapMode() );
1855 Font
aOldFont( pPrinter
->GetFont() );
1858 pPrinter
->SetMapMode( MAP_TWIP
);
1859 // font color doesn't matter here
1860 pDok
->GetDefPattern()->GetFont( aDefFont
, SC_AUTOCOL_BLACK
, pPrinter
);
1861 pPrinter
->SetFont( aDefFont
);
1862 long nZeroWidth
= pPrinter
->GetTextWidth( String( '0' ) );
1863 pPrinter
->SetFont( aOldFont
);
1864 pPrinter
->SetMapMode( aOldMode
);
1865 int nZeroCount
= (int)(pDok
->GetColWidth( aCellPos
.Col(), aCellPos
.Tab() ) / nZeroWidth
);
1866 PushInt( nZeroCount
);
1868 else if( aInfoType
.EqualsAscii( "PREFIX" ) )
1869 { // ' = left; " = right; ^ = centered
1870 if( HasCellStringData( pCell
) )
1872 const SvxHorJustifyItem
* pJustAttr
= (const SvxHorJustifyItem
*)
1873 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_HOR_JUSTIFY
);
1874 switch( pJustAttr
->GetValue() )
1876 case SVX_HOR_JUSTIFY_STANDARD
:
1877 case SVX_HOR_JUSTIFY_LEFT
:
1878 case SVX_HOR_JUSTIFY_BLOCK
: aFuncResult
= '\''; break;
1879 case SVX_HOR_JUSTIFY_CENTER
: aFuncResult
= '^'; break;
1880 case SVX_HOR_JUSTIFY_RIGHT
: aFuncResult
= '"'; break;
1881 case SVX_HOR_JUSTIFY_REPEAT
: aFuncResult
= '\\'; break;
1884 PushString( aFuncResult
);
1886 else if( aInfoType
.EqualsAscii( "PROTECT" ) )
1887 { // 1 = cell locked
1888 const ScProtectionAttr
* pProtAttr
= (const ScProtectionAttr
*)
1889 pDok
->GetAttr( aCellPos
.Col(), aCellPos
.Row(), aCellPos
.Tab(), ATTR_PROTECTION
);
1890 PushInt( pProtAttr
->GetProtection() ? 1 : 0 );
1893 // *** FORMATTING ***
1894 else if( aInfoType
.EqualsAscii( "FORMAT" ) )
1895 { // specific format code for standard formats
1896 ULONG nFormat
= pDok
->GetNumberFormat( aCellPos
);
1897 BOOL bAppendPrec
= TRUE
;
1898 USHORT nPrec
, nLeading
;
1899 BOOL bThousand
, bIsRed
;
1900 pFormatter
->GetFormatSpecialInfo( nFormat
, bThousand
, bIsRed
, nPrec
, nLeading
);
1902 switch( pFormatter
->GetType( nFormat
) )
1904 case NUMBERFORMAT_NUMBER
: aFuncResult
= (bThousand
? ',' : 'F'); break;
1905 case NUMBERFORMAT_CURRENCY
: aFuncResult
= 'C'; break;
1906 case NUMBERFORMAT_SCIENTIFIC
: aFuncResult
= 'S'; break;
1907 case NUMBERFORMAT_PERCENT
: aFuncResult
= 'P'; break;
1910 bAppendPrec
= FALSE
;
1911 switch( pFormatter
->GetIndexTableOffset( nFormat
) )
1913 case NF_DATE_SYSTEM_SHORT
:
1914 case NF_DATE_SYS_DMMMYY
:
1915 case NF_DATE_SYS_DDMMYY
:
1916 case NF_DATE_SYS_DDMMYYYY
:
1917 case NF_DATE_SYS_DMMMYYYY
:
1918 case NF_DATE_DIN_DMMMYYYY
:
1919 case NF_DATE_SYS_DMMMMYYYY
:
1920 case NF_DATE_DIN_DMMMMYYYY
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
1921 case NF_DATE_SYS_DDMMM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
1922 case NF_DATE_SYS_MMYY
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
1923 case NF_DATETIME_SYSTEM_SHORT_HHMM
:
1924 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS
:
1925 aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
1926 case NF_DATE_DIN_MMDD
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
1927 case NF_TIME_HHMMSSAMPM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
1928 case NF_TIME_HHMMAMPM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
1929 case NF_TIME_HHMMSS
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
1930 case NF_TIME_HHMM
: aFuncResult
.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
1931 default: aFuncResult
= 'G';
1936 aFuncResult
+= String::CreateFromInt32( nPrec
);
1937 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( nFormat
);
1938 if( lcl_FormatHasNegColor( pFormat
) )
1940 if( lcl_FormatHasOpenPar( pFormat
) )
1941 aFuncResult
.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
1942 PushString( aFuncResult
);
1944 else if( aInfoType
.EqualsAscii( "COLOR" ) )
1945 { // 1 = negative values are colored, otherwise 0
1946 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
1947 PushInt( lcl_FormatHasNegColor( pFormat
) ? 1 : 0 );
1949 else if( aInfoType
.EqualsAscii( "PARENTHESES" ) )
1950 { // 1 = format string contains a '(' character, otherwise 0
1951 const SvNumberformat
* pFormat
= pFormatter
->GetEntry( pDok
->GetNumberFormat( aCellPos
) );
1952 PushInt( lcl_FormatHasOpenPar( pFormat
) ? 1 : 0 );
1955 PushIllegalArgument();
1961 void ScInterpreter::ScIsRef()
1963 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCell" );
1964 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
1966 switch ( GetStackType() )
1971 PopSingleRef( aAdr
);
1972 if ( !nGlobalError
)
1979 PopDoubleRef( aRange
);
1980 if ( !nGlobalError
)
1986 FormulaTokenRef x
= PopToken();
1987 if ( !nGlobalError
)
1988 nRes
= !static_cast<ScToken
*>(x
.get())->GetRefList()->empty();
1999 void ScInterpreter::ScIsValue()
2001 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsValue" );
2002 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2004 switch ( GetRawStackType() )
2014 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2016 ScBaseCell
* pCell
= GetCell( aAdr
);
2017 if (GetCellErrCode( pCell
) == 0)
2019 switch ( GetCellType( pCell
) )
2021 case CELLTYPE_VALUE
:
2024 case CELLTYPE_FORMULA
:
2025 nRes
= ((ScFormulaCell
*)pCell
)->IsValue() &&
2026 !((ScFormulaCell
*)pCell
)->IsEmpty();
2036 ScMatrixRef pMat
= PopMatrix();
2039 else if ( !pJumpMatrix
)
2041 if (pMat
->GetErrorIfNotString( 0 ) == 0)
2042 nRes
= pMat
->IsValue( 0 );
2046 SCSIZE nCols
, nRows
, nC
, nR
;
2047 pMat
->GetDimensions( nCols
, nRows
);
2048 pJumpMatrix
->GetPos( nC
, nR
);
2049 if ( nC
< nCols
&& nR
< nRows
)
2050 if (pMat
->GetErrorIfNotString( nC
, nR
) == 0)
2051 nRes
= pMat
->IsValue( nC
, nR
);
2063 void ScInterpreter::ScIsFormula()
2065 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsFormula" );
2066 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2068 switch ( GetStackType() )
2074 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2076 nRes
= (GetCellType( GetCell( aAdr
) ) == CELLTYPE_FORMULA
);
2087 void ScInterpreter::ScFormula()
2089 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFormula" );
2091 switch ( GetStackType() )
2097 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2099 ScBaseCell
* pCell
= GetCell( aAdr
);
2100 switch ( GetCellType( pCell
) )
2102 case CELLTYPE_FORMULA
:
2103 ((ScFormulaCell
*)pCell
)->GetFormula( aFormula
);
2106 SetError( NOTAVAILABLE
);
2112 SetError( NOTAVAILABLE
);
2114 PushString( aFormula
);
2119 void ScInterpreter::ScIsNV()
2121 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsNV" );
2122 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2124 switch ( GetStackType() )
2130 PopDoubleRefOrSingleRef( aAdr
);
2131 if ( nGlobalError
== NOTAVAILABLE
)
2135 ScBaseCell
* pCell
= GetCell( aAdr
);
2136 USHORT nErr
= GetCellErrCode( pCell
);
2137 nRes
= (nErr
== NOTAVAILABLE
);
2143 ScMatrixRef pMat
= PopMatrix();
2146 else if ( !pJumpMatrix
)
2147 nRes
= (pMat
->GetErrorIfNotString( 0 ) == NOTAVAILABLE
);
2150 SCSIZE nCols
, nRows
, nC
, nR
;
2151 pMat
->GetDimensions( nCols
, nRows
);
2152 pJumpMatrix
->GetPos( nC
, nR
);
2153 if ( nC
< nCols
&& nR
< nRows
)
2154 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) == NOTAVAILABLE
);
2160 if ( nGlobalError
== NOTAVAILABLE
)
2168 void ScInterpreter::ScIsErr()
2170 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsErr" );
2171 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2173 switch ( GetStackType() )
2179 PopDoubleRefOrSingleRef( aAdr
);
2180 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2184 ScBaseCell
* pCell
= GetCell( aAdr
);
2185 USHORT nErr
= GetCellErrCode( pCell
);
2186 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2192 ScMatrixRef pMat
= PopMatrix();
2193 if ( nGlobalError
|| !pMat
)
2194 nRes
= ((nGlobalError
&& nGlobalError
!= NOTAVAILABLE
) || !pMat
);
2195 else if ( !pJumpMatrix
)
2197 USHORT nErr
= pMat
->GetErrorIfNotString( 0 );
2198 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2202 SCSIZE nCols
, nRows
, nC
, nR
;
2203 pMat
->GetDimensions( nCols
, nRows
);
2204 pJumpMatrix
->GetPos( nC
, nR
);
2205 if ( nC
< nCols
&& nR
< nRows
)
2207 USHORT nErr
= pMat
->GetErrorIfNotString( nC
, nR
);
2208 nRes
= (nErr
&& nErr
!= NOTAVAILABLE
);
2215 if ( nGlobalError
&& nGlobalError
!= NOTAVAILABLE
)
2223 void ScInterpreter::ScIsError()
2225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsError" );
2226 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2228 switch ( GetStackType() )
2234 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2243 ScBaseCell
* pCell
= GetCell( aAdr
);
2244 nRes
= (GetCellErrCode( pCell
) != 0);
2250 ScMatrixRef pMat
= PopMatrix();
2251 if ( nGlobalError
|| !pMat
)
2253 else if ( !pJumpMatrix
)
2254 nRes
= (pMat
->GetErrorIfNotString( 0 ) != 0);
2257 SCSIZE nCols
, nRows
, nC
, nR
;
2258 pMat
->GetDimensions( nCols
, nRows
);
2259 pJumpMatrix
->GetPos( nC
, nR
);
2260 if ( nC
< nCols
&& nR
< nRows
)
2261 nRes
= (pMat
->GetErrorIfNotString( nC
, nR
) != 0);
2275 short ScInterpreter::IsEven()
2277 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IsEven" );
2278 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
2281 switch ( GetStackType() )
2287 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2289 ScBaseCell
* pCell
= GetCell( aAdr
);
2290 USHORT nErr
= GetCellErrCode( pCell
);
2295 switch ( GetCellType( pCell
) )
2297 case CELLTYPE_VALUE
:
2298 fVal
= GetCellValue( aAdr
, pCell
);
2301 case CELLTYPE_FORMULA
:
2302 if( ((ScFormulaCell
*)pCell
)->IsValue() )
2304 fVal
= GetCellValue( aAdr
, pCell
);
2322 ScMatrixRef pMat
= PopMatrix();
2325 else if ( !pJumpMatrix
)
2327 nRes
= pMat
->IsValue( 0 );
2329 fVal
= pMat
->GetDouble( 0 );
2333 SCSIZE nCols
, nRows
, nC
, nR
;
2334 pMat
->GetDimensions( nCols
, nRows
);
2335 pJumpMatrix
->GetPos( nC
, nR
);
2336 if ( nC
< nCols
&& nR
< nRows
)
2338 nRes
= pMat
->IsValue( nC
, nR
);
2340 fVal
= pMat
->GetDouble( nC
, nR
);
2343 SetError( errNoValue
);
2351 SetError( errIllegalParameter
);
2353 nRes
= ( fmod( ::rtl::math::approxFloor( fabs( fVal
) ), 2.0 ) < 0.5 );
2358 void ScInterpreter::ScIsEven()
2360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsEven" );
2361 PushInt( IsEven() );
2365 void ScInterpreter::ScIsOdd()
2367 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIsOdd" );
2368 PushInt( !IsEven() );
2372 void ScInterpreter::ScN()
2374 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScN" );
2375 USHORT nErr
= nGlobalError
;
2378 if ( GetRawStackType() == svString
)
2385 if ( nGlobalError
== NOTAVAILABLE
|| nGlobalError
== errIllegalArgument
)
2386 nGlobalError
= 0; // N(#NA) and N("text") are ok
2387 if ( !nGlobalError
&& nErr
!= NOTAVAILABLE
)
2388 nGlobalError
= nErr
;
2393 void ScInterpreter::ScTrim()
2394 { // trimmt nicht nur sondern schnibbelt auch doppelte raus!
2395 String
aVal( GetString() );
2396 aVal
.EraseLeadingChars();
2397 aVal
.EraseTrailingChars();
2399 register const sal_Unicode
* p
= aVal
.GetBuffer();
2400 register const sal_Unicode
* const pEnd
= p
+ aVal
.Len();
2403 if ( *p
!= ' ' || p
[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
2411 void ScInterpreter::ScUpper()
2413 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTrim" );
2414 String aString
= GetString();
2415 ScGlobal::pCharClass
->toUpper(aString
);
2416 PushString(aString
);
2420 void ScInterpreter::ScPropper()
2422 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScPropper" );
2423 //2do: what to do with I18N-CJK ?!?
2424 String
aStr( GetString() );
2425 const xub_StrLen nLen
= aStr
.Len();
2426 // #i82487# don't try to write to empty string's BufferAccess
2427 // (would crash now that the empty string is const)
2430 String
aUpr( ScGlobal::pCharClass
->upper( aStr
) );
2431 String
aLwr( ScGlobal::pCharClass
->lower( aStr
) );
2432 register sal_Unicode
* pStr
= aStr
.GetBufferAccess();
2433 const sal_Unicode
* pUpr
= aUpr
.GetBuffer();
2434 const sal_Unicode
* pLwr
= aLwr
.GetBuffer();
2436 String
aTmpStr( 'x' );
2437 xub_StrLen nPos
= 1;
2438 while( nPos
< nLen
)
2440 aTmpStr
.SetChar( 0, pStr
[nPos
-1] );
2441 if ( !ScGlobal::pCharClass
->isLetter( aTmpStr
, 0 ) )
2442 pStr
[nPos
] = pUpr
[nPos
];
2444 pStr
[nPos
] = pLwr
[nPos
];
2447 aStr
.ReleaseBufferAccess( nLen
);
2453 void ScInterpreter::ScLower()
2455 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLower" );
2456 String
aString( GetString() );
2457 ScGlobal::pCharClass
->toLower(aString
);
2458 PushString(aString
);
2462 void ScInterpreter::ScLen()
2464 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLen" );
2465 String
aStr( GetString() );
2466 PushDouble( aStr
.Len() );
2470 void ScInterpreter::ScT()
2472 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScT" );
2473 switch ( GetStackType() )
2479 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2484 BOOL bValue
= FALSE
;
2485 ScBaseCell
* pCell
= GetCell( aAdr
);
2486 if ( GetCellErrCode( pCell
) == 0 )
2488 switch ( GetCellType( pCell
) )
2490 case CELLTYPE_VALUE
:
2493 case CELLTYPE_FORMULA
:
2494 bValue
= ((ScFormulaCell
*)pCell
)->IsValue();
2501 PushString( EMPTY_STRING
);
2505 GetCellString( aTempStr
, pCell
);
2506 PushString( aTempStr
);
2513 PushString( EMPTY_STRING
);
2520 PushError( errUnknownOpCode
);
2525 void ScInterpreter::ScValue()
2527 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScValue" );
2528 String aInputString
;
2531 switch ( GetRawStackType() )
2539 return; // leave on stack
2546 if ( !PopDoubleRefOrSingleRef( aAdr
) )
2551 ScBaseCell
* pCell
= GetCell( aAdr
);
2552 if ( pCell
&& pCell
->HasStringData() )
2553 GetCellString( aInputString
, pCell
);
2554 else if ( pCell
&& pCell
->HasValueData() )
2556 PushDouble( GetCellValue(aAdr
, pCell
) );
2568 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
2572 case SC_MATVAL_EMPTY
:
2575 case SC_MATVAL_VALUE
:
2576 case SC_MATVAL_BOOLEAN
:
2580 case SC_MATVAL_STRING
:
2584 PushIllegalArgument();
2589 aInputString
= GetString();
2593 sal_uInt32 nFIndex
= 0; // 0 for default locale
2594 if (pFormatter
->IsNumberFormat(aInputString
, nFIndex
, fVal
))
2597 PushIllegalArgument();
2601 //2do: this should be a proper unicode string method
2602 inline BOOL
lcl_ScInterpreter_IsPrintable( sal_Unicode c
)
2604 return 0x20 <= c
&& c
!= 0x7f;
2607 void ScInterpreter::ScClean()
2609 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScClean" );
2610 String
aStr( GetString() );
2611 for ( xub_StrLen i
= 0; i
< aStr
.Len(); i
++ )
2613 if ( !lcl_ScInterpreter_IsPrintable( aStr
.GetChar( i
) ) )
2620 void ScInterpreter::ScCode()
2622 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCode" );
2623 //2do: make it full range unicode?
2624 const String
& rStr
= GetString();
2625 PushInt( (sal_uChar
) ByteString::ConvertFromUnicode( rStr
.GetChar(0), gsl_getSystemTextEncoding() ) );
2629 void ScInterpreter::ScChar()
2631 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScChar" );
2632 //2do: make it full range unicode?
2633 double fVal
= GetDouble();
2634 if (fVal
< 0.0 || fVal
>= 256.0)
2635 PushIllegalArgument();
2639 aStr
.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char
) fVal
, gsl_getSystemTextEncoding() ) );
2645 /* #i70213# fullwidth/halfwidth conversion provided by
2646 * Takashi Nakamoto <bluedwarf@ooo>
2647 * erAck: added Excel compatibility conversions as seen in issue's test case. */
2649 static ::rtl::OUString
lcl_convertIntoHalfWidth( const ::rtl::OUString
& rStr
)
2651 static bool bFirstASCCall
= true;
2652 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2656 aTrans
.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM
);
2657 bFirstASCCall
= false;
2660 return aTrans
.transliterate( rStr
, 0, (USHORT
) rStr
.getLength(), NULL
);
2664 static ::rtl::OUString
lcl_convertIntoFullWidth( const ::rtl::OUString
& rStr
)
2666 static bool bFirstJISCall
= true;
2667 static utl::TransliterationWrapper
aTrans( ::comphelper::getProcessServiceFactory(), 0 );
2671 aTrans
.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM
);
2672 bFirstJISCall
= false;
2675 return aTrans
.transliterate( rStr
, 0, (USHORT
) rStr
.getLength(), NULL
);
2680 * Summary: Converts half-width to full-width ASCII and katakana characters.
2681 * Semantics: Conversion is done for half-width ASCII and katakana characters,
2682 * other characters are simply copied from T to the result. This is the
2683 * complementary function to ASC.
2684 * For references regarding halfwidth and fullwidth characters see
2685 * http://www.unicode.org/reports/tr11/
2686 * http://www.unicode.org/charts/charindex2.html#H
2687 * http://www.unicode.org/charts/charindex2.html#F
2689 void ScInterpreter::ScJis()
2691 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScJis" );
2692 if (MustHaveParamCount( GetByte(), 1))
2693 PushString( lcl_convertIntoFullWidth( GetString()));
2698 * Summary: Converts full-width to half-width ASCII and katakana characters.
2699 * Semantics: Conversion is done for full-width ASCII and katakana characters,
2700 * other characters are simply copied from T to the result. This is the
2701 * complementary function to JIS.
2703 void ScInterpreter::ScAsc()
2705 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAsc" );
2706 if (MustHaveParamCount( GetByte(), 1))
2707 PushString( lcl_convertIntoHalfWidth( GetString()));
2711 void ScInterpreter::ScMin( BOOL bTextAsZero
)
2713 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMin" );
2714 short nParamCount
= GetByte();
2715 if (!MustHaveParamCountMin( nParamCount
, 1))
2717 double nMin
= ::std::numeric_limits
<double>::max();
2721 size_t nRefInList
= 0;
2722 while (nParamCount
-- > 0)
2724 switch (GetStackType())
2729 if (nMin
> nVal
) nMin
= nVal
;
2730 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2735 PopSingleRef( aAdr
);
2736 ScBaseCell
* pCell
= GetCell( aAdr
);
2737 if (HasCellValueData(pCell
))
2739 nVal
= GetCellValue( aAdr
, pCell
);
2741 if (nMin
> nVal
) nMin
= nVal
;
2743 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
2754 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2755 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
2756 if (aValIter
.GetFirst(nVal
, nErr
))
2760 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
2761 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
2772 ScMatrixRef pMat
= PopMatrix();
2776 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2777 pMat
->GetDimensions(nC
, nR
);
2778 if (pMat
->IsNumeric())
2780 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2781 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2783 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2784 if (nMin
> nVal
) nMin
= nVal
;
2789 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2791 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2793 if (!pMat
->IsString(nMatCol
,nMatRow
))
2795 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2796 if (nMin
> nVal
) nMin
= nVal
;
2798 else if ( bTextAsZero
)
2818 SetError(errIllegalParameter
);
2823 SetError(errIllegalParameter
);
2832 #if defined(WIN) && defined(MSC)
2833 #pragma optimize("",off)
2836 void ScInterpreter::ScMax( BOOL bTextAsZero
)
2838 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMax" );
2839 short nParamCount
= GetByte();
2840 if (!MustHaveParamCountMin( nParamCount
, 1))
2842 double nMax
= -(::std::numeric_limits
<double>::max());
2846 size_t nRefInList
= 0;
2847 while (nParamCount
-- > 0)
2849 switch (GetStackType())
2854 if (nMax
< nVal
) nMax
= nVal
;
2855 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2860 PopSingleRef( aAdr
);
2861 ScBaseCell
* pCell
= GetCell( aAdr
);
2862 if (HasCellValueData(pCell
))
2864 nVal
= GetCellValue( aAdr
, pCell
);
2866 if (nMax
< nVal
) nMax
= nVal
;
2868 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
2879 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
2880 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
2881 if (aValIter
.GetFirst(nVal
, nErr
))
2885 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
2886 while ((nErr
== 0) && aValIter
.GetNext(nVal
, nErr
))
2897 ScMatrixRef pMat
= PopMatrix();
2900 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
2902 pMat
->GetDimensions(nC
, nR
);
2903 if (pMat
->IsNumeric())
2905 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2906 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2908 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2909 if (nMax
< nVal
) nMax
= nVal
;
2914 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
2916 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
2918 if (!pMat
->IsString(nMatCol
,nMatRow
))
2920 nVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
2921 if (nMax
< nVal
) nMax
= nVal
;
2923 else if ( bTextAsZero
)
2943 SetError(errIllegalParameter
);
2948 SetError(errIllegalParameter
);
2956 #if defined(WIN) && defined(MSC)
2957 #pragma optimize("",on)
2961 double ScInterpreter::IterateParameters( ScIterFunc eFunc
, BOOL bTextAsZero
)
2963 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::IterateParameters" );
2964 short nParamCount
= GetByte();
2965 double fRes
= ( eFunc
== ifPRODUCT
) ? 1.0 : 0.0;
2972 size_t nRefInList
= 0;
2973 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
2975 while (nParamCount
-- > 0)
2977 StackVar eStackType
= GetStackType();
2983 if( eFunc
== ifCOUNT
&& eStackType
== svString
)
2985 String
aStr( PopString() );
2986 sal_uInt32 nFIndex
= 0; // damit default Land/Spr.
2987 if ( bTextAsZero
|| pFormatter
->IsNumberFormat(aStr
, nFIndex
, fVal
))
2990 else if (eFunc
== ifCOUNT2
)
2991 // COUNTA - we should count both number and string.
2995 if ( bTextAsZero
&& eStackType
== svString
)
2999 if ( eFunc
== ifPRODUCT
)
3012 if ( bNull
&& fVal
!= 0.0 )
3020 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3021 case ifPRODUCT
: fRes
*= fVal
; break;
3026 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3031 PopSingleRef( aAdr
);
3032 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3035 if ( eFunc
== ifCOUNT2
)
3039 ScBaseCell
* pCell
= GetCell( aAdr
);
3042 if( eFunc
== ifCOUNT2
)
3044 CellType eCellType
= pCell
->GetCellType();
3045 if (eCellType
!= CELLTYPE_NONE
&& eCellType
!= CELLTYPE_NOTE
)
3050 else if ( pCell
->HasValueData() )
3053 fVal
= GetCellValue( aAdr
, pCell
);
3059 if ( bNull
&& fVal
!= 0.0 )
3067 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3068 case ifPRODUCT
: fRes
*= fVal
; break;
3076 default: ; // nothing
3079 else if ( bTextAsZero
&& pCell
->HasStringData() )
3082 if ( eFunc
== ifPRODUCT
)
3092 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3093 if ( nGlobalError
&& ( eFunc
== ifCOUNT2
|| eFunc
== ifCOUNT
) )
3096 if ( eFunc
== ifCOUNT2
)
3100 if( eFunc
== ifCOUNT2
)
3103 ScCellIterator
aIter( pDok
, aRange
, glSubTotal
);
3104 if ( (pCell
= aIter
.GetFirst()) != NULL
)
3108 CellType eType
= pCell
->GetCellType();
3109 if( eType
!= CELLTYPE_NONE
&& eType
!= CELLTYPE_NOTE
)
3112 while ( (pCell
= aIter
.GetNext()) != NULL
);
3119 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3120 if (aValIter
.GetFirst(fVal
, nErr
))
3122 // Schleife aus Performance-Gruenden nach innen verlegt:
3123 aValIter
.GetCurNumFmtInfo( nFuncFmtType
, nFuncFmtIndex
);
3131 if ( bNull
&& fVal
!= 0.0 )
3140 while (aValIter
.GetNext(fVal
, nErr
));
3146 fRes
+= fVal
* fVal
;
3149 while (aValIter
.GetNext(fVal
, nErr
));
3158 while (aValIter
.GetNext(fVal
, nErr
));
3166 while (aValIter
.GetNext(fVal
, nErr
));
3168 default: ; // nothing
3177 ScMatrixRef pMat
= PopMatrix();
3181 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3182 pMat
->GetDimensions(nC
, nR
);
3183 if( eFunc
== ifCOUNT2
)
3184 nCount
+= (ULONG
) nC
* nR
;
3187 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3189 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3191 if (!pMat
->IsString(nMatCol
,nMatRow
))
3194 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3199 if ( bNull
&& fVal
!= 0.0 )
3207 case ifSUMSQ
: fRes
+= fVal
* fVal
; break;
3208 case ifPRODUCT
: fRes
*= fVal
; break;
3209 default: ; // nothing
3212 else if ( bTextAsZero
)
3215 if ( eFunc
== ifPRODUCT
)
3227 if ( eFunc
== ifCOUNT
)
3231 else if ( eFunc
== ifCOUNT2
)
3239 while (nParamCount
-- > 0)
3241 SetError(errIllegalParameter
);
3246 case ifSUM
: fRes
= ::rtl::math::approxAdd( fRes
, fMem
); break;
3247 case ifAVERAGE
: fRes
= div(::rtl::math::approxAdd( fRes
, fMem
), nCount
); break;
3249 case ifCOUNT
: fRes
= nCount
; break;
3250 case ifPRODUCT
: if ( !nCount
) fRes
= 0.0; break;
3251 default: ; // nothing
3253 // Bei Summen etc. macht ein BOOL-Ergebnis keinen Sinn
3254 // und Anzahl ist immer Number (#38345#)
3255 if( eFunc
== ifCOUNT
|| nFuncFmtType
== NUMBERFORMAT_LOGICAL
)
3256 nFuncFmtType
= NUMBERFORMAT_NUMBER
;
3261 void ScInterpreter::ScSumSQ()
3263 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumSQ" );
3264 PushDouble( IterateParameters( ifSUMSQ
) );
3268 void ScInterpreter::ScSum()
3270 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSum" );
3271 PushDouble( IterateParameters( ifSUM
) );
3275 void ScInterpreter::ScProduct()
3277 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScProduct" );
3278 PushDouble( IterateParameters( ifPRODUCT
) );
3282 void ScInterpreter::ScAverage( BOOL bTextAsZero
)
3284 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAverage" );
3285 PushDouble( IterateParameters( ifAVERAGE
, bTextAsZero
) );
3289 void ScInterpreter::ScCount()
3291 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCount" );
3292 PushDouble( IterateParameters( ifCOUNT
) );
3296 void ScInterpreter::ScCount2()
3298 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCount2" );
3299 PushDouble( IterateParameters( ifCOUNT2
) );
3303 void ScInterpreter::GetStVarParams( double& rVal
, double& rValCount
,
3306 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetStVarParams" );
3307 short nParamCount
= GetByte();
3309 std::vector
<double> values
;
3317 size_t nRefInList
= 0;
3318 while (nParamCount
-- > 0)
3320 switch (GetStackType())
3325 values
.push_back(fVal
);
3332 PopSingleRef( aAdr
);
3333 ScBaseCell
* pCell
= GetCell( aAdr
);
3334 if (HasCellValueData(pCell
))
3336 fVal
= GetCellValue( aAdr
, pCell
);
3337 values
.push_back(fVal
);
3341 else if ( bTextAsZero
&& HasCellStringData( pCell
) )
3343 values
.push_back(0.0);
3352 PopDoubleRef( aRange
, nParamCount
, nRefInList
);
3353 ScValueIterator
aValIter( pDok
, aRange
, glSubTotal
, bTextAsZero
);
3354 if (aValIter
.GetFirst(fVal
, nErr
))
3358 values
.push_back(fVal
);
3362 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
3368 ScMatrixRef pMat
= PopMatrix();
3372 pMat
->GetDimensions(nC
, nR
);
3373 for (SCSIZE nMatCol
= 0; nMatCol
< nC
; nMatCol
++)
3375 for (SCSIZE nMatRow
= 0; nMatRow
< nR
; nMatRow
++)
3377 if (!pMat
->IsString(nMatCol
,nMatRow
))
3379 fVal
= pMat
->GetDouble(nMatCol
,nMatRow
);
3380 values
.push_back(fVal
);
3384 else if ( bTextAsZero
)
3386 values
.push_back(0.0);
3399 values
.push_back(0.0);
3403 SetError(errIllegalParameter
);
3408 SetError(errIllegalParameter
);
3412 ::std::vector
<double>::size_type n
= values
.size();
3414 for (::std::vector
<double>::size_type i
= 0; i
< n
; i
++)
3415 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
3421 void ScInterpreter::ScVar( BOOL bTextAsZero
)
3423 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVar" );
3426 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3428 if (nValCount
<= 1.0)
3429 PushError( errDivisionByZero
);
3431 PushDouble( nVal
/ (nValCount
- 1.0));
3435 void ScInterpreter::ScVarP( BOOL bTextAsZero
)
3437 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVarP" );
3440 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3442 PushDouble( div( nVal
, nValCount
));
3446 void ScInterpreter::ScStDev( BOOL bTextAsZero
)
3448 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStDev" );
3451 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3452 if (nValCount
<= 1.0)
3453 PushError( errDivisionByZero
);
3455 PushDouble( sqrt( nVal
/ (nValCount
- 1.0)));
3459 void ScInterpreter::ScStDevP( BOOL bTextAsZero
)
3461 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScStDevP" );
3464 GetStVarParams( nVal
, nValCount
, bTextAsZero
);
3465 if (nValCount
== 0.0)
3466 PushError( errDivisionByZero
);
3468 PushDouble( sqrt( nVal
/ nValCount
));
3470 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3472 * Besides that the special NAN gets lost in the call through sqrt(),
3473 * unxlngi6.pro then looped back and forth somewhere between div() and
3474 * ::rtl::math::setNan(). Tests showed that
3476 * sqrt( div( 1, 0));
3478 * produced a loop, but
3480 * double f1 = div( 1, 0);
3483 * was fine. There seems to be some compiler optimization problem. It does
3484 * not occur when compiled with debug=t.
3489 void ScInterpreter::ScColumns()
3491 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScColumns" );
3492 BYTE nParamCount
= GetByte();
3500 while (nParamCount
-- > 0)
3502 switch ( GetStackType() )
3509 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3510 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1) *
3511 static_cast<ULONG
>(nCol2
- nCol1
+ 1);
3515 ScMatrixRef pMat
= PopMatrix();
3519 pMat
->GetDimensions(nC
, nR
);
3526 SetError(errIllegalParameter
);
3529 PushDouble((double)nVal
);
3533 void ScInterpreter::ScRows()
3535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRows" );
3536 BYTE nParamCount
= GetByte();
3544 while (nParamCount
-- > 0)
3546 switch ( GetStackType() )
3553 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3554 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1) *
3555 static_cast<ULONG
>(nRow2
- nRow1
+ 1);
3559 ScMatrixRef pMat
= PopMatrix();
3563 pMat
->GetDimensions(nC
, nR
);
3570 SetError(errIllegalParameter
);
3573 PushDouble((double)nVal
);
3576 void ScInterpreter::ScTables()
3578 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTables" );
3579 BYTE nParamCount
= GetByte();
3581 if ( nParamCount
== 0 )
3582 nVal
= pDok
->GetTableCount();
3592 while (nParamCount
-- > 0)
3594 switch ( GetStackType() )
3601 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3602 nVal
+= static_cast<ULONG
>(nTab2
- nTab1
+ 1);
3610 SetError( errIllegalParameter
);
3614 PushDouble( (double) nVal
);
3618 void ScInterpreter::ScColumn()
3620 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScColumn" );
3621 BYTE nParamCount
= GetByte();
3622 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3625 if (nParamCount
== 0)
3627 nVal
= aPos
.Col() + 1;
3632 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3633 ScMatrixRef pResMat
= GetNewMat( static_cast<SCSIZE
>(nCols
), 1);
3636 for (SCCOL i
=0; i
< nCols
; ++i
)
3637 pResMat
->PutDouble( nVal
+ i
, static_cast<SCSIZE
>(i
), 0);
3638 PushMatrix( pResMat
);
3645 switch ( GetStackType() )
3652 PopSingleRef( nCol1
, nRow1
, nTab1
);
3653 nVal
= (double) (nCol1
+ 1);
3664 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3667 ScMatrixRef pResMat
= GetNewMat(
3668 static_cast<SCSIZE
>(nCol2
-nCol1
+1), 1);
3671 for (SCCOL i
= nCol1
; i
<= nCol2
; i
++)
3672 pResMat
->PutDouble((double)(i
+1),
3673 static_cast<SCSIZE
>(i
-nCol1
), 0);
3674 PushMatrix(pResMat
);
3681 nVal
= (double) (nCol1
+ 1);
3685 SetError( errIllegalParameter
);
3694 void ScInterpreter::ScRow()
3696 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRow" );
3697 BYTE nParamCount
= GetByte();
3698 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3701 if (nParamCount
== 0)
3703 nVal
= aPos
.Row() + 1;
3708 pMyFormulaCell
->GetMatColsRows( nCols
, nRows
);
3709 ScMatrixRef pResMat
= GetNewMat( 1, static_cast<SCSIZE
>(nRows
));
3712 for (SCROW i
=0; i
< nRows
; i
++)
3713 pResMat
->PutDouble( nVal
+ i
, 0, static_cast<SCSIZE
>(i
));
3714 PushMatrix( pResMat
);
3721 switch ( GetStackType() )
3728 PopSingleRef( nCol1
, nRow1
, nTab1
);
3729 nVal
= (double) (nRow1
+ 1);
3740 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3743 ScMatrixRef pResMat
= GetNewMat( 1,
3744 static_cast<SCSIZE
>(nRow2
-nRow1
+1));
3747 for (SCROW i
= nRow1
; i
<= nRow2
; i
++)
3748 pResMat
->PutDouble((double)(i
+1), 0,
3749 static_cast<SCSIZE
>(i
-nRow1
));
3750 PushMatrix(pResMat
);
3757 nVal
= (double) (nRow1
+ 1);
3761 SetError( errIllegalParameter
);
3769 void ScInterpreter::ScTable()
3771 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScTable" );
3772 BYTE nParamCount
= GetByte();
3773 if ( MustHaveParamCount( nParamCount
, 0, 1 ) )
3776 if ( nParamCount
== 0 )
3777 nVal
= aPos
.Tab() + 1;
3780 switch ( GetStackType() )
3784 String
aStr( PopString() );
3785 if ( pDok
->GetTable( aStr
, nVal
) )
3788 SetError( errIllegalArgument
);
3796 PopSingleRef( nCol1
, nRow1
, nTab1
);
3808 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3813 SetError( errIllegalParameter
);
3818 PushDouble( (double) nVal
);
3822 /** returns -1 when the matrix value is smaller than the query value, 0 when
3823 they are equal, and 1 when the matrix value is larger than the query
3825 static sal_Int32
lcl_CompareMatrix2Query( SCSIZE i
, const ScMatrix
& rMat
,
3826 const ScQueryEntry
& rEntry
)
3828 if (rMat
.IsEmpty(i
))
3830 /* TODO: in case we introduced query for real empty this would have to
3832 return -1; // empty always less than anything else
3835 /* FIXME: what is an empty path (result of IF(false;true_path) in
3838 if (rMat
.IsValue(i
))
3840 if (rEntry
.bQueryByString
)
3841 return -1; // numeric always less than string
3843 const double nVal1
= rMat
.GetDouble(i
);
3844 const double nVal2
= rEntry
.nVal
;
3848 return nVal1
< nVal2
? -1 : 1;
3851 if (!rEntry
.bQueryByString
)
3852 return 1; // string always greater than numeric
3855 // this should not happen!
3858 const String
& rStr1
= rMat
.GetString(i
);
3859 const String
& rStr2
= *rEntry
.pStr
;
3861 return ScGlobal::pCollator
->compareString( rStr1
, rStr2
); // case-insensitive
3864 /** returns the last item with the identical value as the original item
3866 static void lcl_GetLastMatch( SCSIZE
& rIndex
, const ScMatrix
& rMat
,
3867 SCSIZE nMatCount
, bool bReverse
)
3869 if (rMat
.IsValue(rIndex
))
3871 double nVal
= rMat
.GetDouble(rIndex
);
3873 while (rIndex
> 0 && rMat
.IsValue(rIndex
-1) &&
3874 nVal
== rMat
.GetDouble(rIndex
-1))
3877 while (rIndex
< nMatCount
-1 && rMat
.IsValue(rIndex
+1) &&
3878 nVal
== rMat
.GetDouble(rIndex
+1))
3881 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
3882 else if (rMat
.IsEmptyPath(rIndex
))
3885 while (rIndex
> 0 && rMat
.IsEmptyPath(rIndex
-1))
3888 while (rIndex
< nMatCount
-1 && rMat
.IsEmptyPath(rIndex
+1))
3891 else if (rMat
.IsEmpty(rIndex
))
3894 while (rIndex
> 0 && rMat
.IsEmpty(rIndex
-1))
3897 while (rIndex
< nMatCount
-1 && rMat
.IsEmpty(rIndex
+1))
3900 else if (rMat
.IsString(rIndex
))
3902 String
aStr( rMat
.GetString(rIndex
));
3904 while (rIndex
> 0 && rMat
.IsString(rIndex
-1) &&
3905 aStr
== rMat
.GetString(rIndex
-1))
3908 while (rIndex
< nMatCount
-1 && rMat
.IsString(rIndex
+1) &&
3909 aStr
== rMat
.GetString(rIndex
+1))
3914 DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
3918 void ScInterpreter::ScMatch()
3920 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMatch" );
3921 ScMatrixRef pMatSrc
= NULL
;
3923 BYTE nParamCount
= GetByte();
3924 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
3927 if (nParamCount
== 3)
3937 if (GetStackType() == svDoubleRef
)
3939 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
3940 if (nTab1
!= nTab2
|| (nCol1
!= nCol2
&& nRow1
!= nRow2
))
3942 PushIllegalParameter();
3946 else if (GetStackType() == svMatrix
)
3948 pMatSrc
= PopMatrix();
3951 PushIllegalParameter();
3957 PushIllegalParameter();
3960 if (nGlobalError
== 0)
3964 ScQueryParam rParam
;
3965 rParam
.nCol1
= nCol1
;
3966 rParam
.nRow1
= nRow1
;
3967 rParam
.nCol2
= nCol2
;
3968 rParam
.nTab
= nTab1
;
3969 rParam
.bMixedComparison
= TRUE
;
3971 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
3972 rEntry
.bDoQuery
= TRUE
;
3974 rEntry
.eOp
= SC_GREATER_EQUAL
;
3975 else if (fTyp
> 0.0)
3976 rEntry
.eOp
= SC_LESS_EQUAL
;
3977 switch ( GetStackType() )
3982 rEntry
.bQueryByString
= FALSE
;
3989 rEntry
.bQueryByString
= TRUE
;
3990 *rEntry
.pStr
= sStr
;
3997 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4002 ScBaseCell
* pCell
= GetCell( aAdr
);
4003 if (HasCellValueData(pCell
))
4005 fVal
= GetCellValue( aAdr
, pCell
);
4006 rEntry
.bQueryByString
= FALSE
;
4011 GetCellString(sStr
, pCell
);
4012 rEntry
.bQueryByString
= TRUE
;
4013 *rEntry
.pStr
= sStr
;
4019 ScMatValType nType
= GetDoubleOrStringFromMatrix(
4020 rEntry
.nVal
, *rEntry
.pStr
);
4021 rEntry
.bQueryByString
= ScMatrix::IsNonValueType( nType
);
4026 PushIllegalParameter();
4030 if ( rEntry
.bQueryByString
)
4032 BOOL bIsVBAMode
= FALSE
;
4035 SfxObjectShell
* pDocSh
= pDok
->GetDocumentShell();
4037 bIsVBAMode
= pDocSh
->GetBasic()->isVBAEnabled();
4039 // #TODO handle MSO wildcards
4041 rParam
.bRegExp
= FALSE
;
4043 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4046 if (pMatSrc
) // The source data is matrix array.
4049 pMatSrc
->GetDimensions( nC
, nR
);
4050 if (nC
> 1 && nR
> 1)
4052 // The source matrix must be a vector.
4053 PushIllegalParameter();
4056 SCSIZE nMatCount
= (nC
== 1) ? nR
: nC
;
4058 // simple serial search for equality mode (source data doesn't
4059 // need to be sorted).
4061 if (rEntry
.eOp
== SC_EQUAL
)
4063 for (SCSIZE i
= 0; i
< nMatCount
; ++i
)
4065 if (lcl_CompareMatrix2Query( i
, *pMatSrc
, rEntry
) == 0)
4067 PushDouble(i
+1); // found !
4071 PushNA(); // not found
4075 // binary search for non-equality mode (the source data is
4076 // assumed to be sorted).
4078 bool bAscOrder
= (rEntry
.eOp
== SC_LESS_EQUAL
);
4079 SCSIZE nFirst
= 0, nLast
= nMatCount
-1, nHitIndex
= 0;
4080 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
4082 SCSIZE nMid
= nFirst
+ nLen
/2;
4083 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, *pMatSrc
, rEntry
);
4086 // exact match. find the last item with the same value.
4087 lcl_GetLastMatch( nMid
, *pMatSrc
, nMatCount
, !bAscOrder
);
4088 PushDouble( nMid
+1);
4092 if (nLen
== 1) // first and last items are next to each other.
4095 nHitIndex
= bAscOrder
? nLast
: nFirst
;
4097 nHitIndex
= bAscOrder
? nFirst
: nLast
;
4117 if (nHitIndex
== nMatCount
-1) // last item
4119 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nHitIndex
, *pMatSrc
, rEntry
);
4120 if ((bAscOrder
&& nCmp
<= 0) || (!bAscOrder
&& nCmp
>= 0))
4122 // either the last item is an exact match or the real
4123 // hit is beyond the last item.
4124 PushDouble( nHitIndex
+1);
4129 if (nHitIndex
> 0) // valid hit must be 2nd item or higher
4131 PushDouble( nHitIndex
); // non-exact match
4139 SCCOLROW nDelta
= 0;
4141 { // search row in column
4142 rParam
.nRow2
= nRow2
;
4143 rEntry
.nField
= nCol1
;
4144 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
4145 if (!LookupQueryWithCache( aResultPos
, rParam
))
4150 nDelta
= aResultPos
.Row() - nRow1
;
4153 { // search column in row
4155 rParam
.bByRow
= FALSE
;
4156 rParam
.nRow2
= nRow1
;
4157 rEntry
.nField
= nCol1
;
4158 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4159 // Advance Entry.nField in Iterator if column changed
4160 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4163 if ( aCellIter
.GetFirst() )
4164 nC
= aCellIter
.GetCol();
4174 if ( !aCellIter
.FindEqualOrSortedLastInRange( nC
, nR
) )
4180 nDelta
= nC
- nCol1
;
4182 PushDouble((double) (nDelta
+ 1));
4185 PushIllegalParameter();
4190 void ScInterpreter::ScCountEmptyCells()
4192 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCountEmptyCells" );
4193 if ( MustHaveParamCount( GetByte(), 1 ) )
4195 ULONG nMaxCount
= 0, nCount
= 0;
4197 switch (GetStackType())
4203 PopSingleRef( aAdr
);
4204 eCellType
= GetCellType( GetCell( aAdr
) );
4205 if (eCellType
!= CELLTYPE_NONE
&& eCellType
!= CELLTYPE_NOTE
)
4214 size_t nRefInList
= 0;
4215 while (nParam
-- > 0)
4217 PopDoubleRef( aRange
, nParam
, nRefInList
);
4219 static_cast<ULONG
>(aRange
.aEnd
.Row() - aRange
.aStart
.Row() + 1) *
4220 static_cast<ULONG
>(aRange
.aEnd
.Col() - aRange
.aStart
.Col() + 1) *
4221 static_cast<ULONG
>(aRange
.aEnd
.Tab() - aRange
.aStart
.Tab() + 1);
4223 ScCellIterator
aDocIter( pDok
, aRange
, glSubTotal
);
4224 if ( (pCell
= aDocIter
.GetFirst()) != NULL
)
4228 if ((eCellType
= pCell
->GetCellType()) != CELLTYPE_NONE
4229 && eCellType
!= CELLTYPE_NOTE
)
4231 } while ( (pCell
= aDocIter
.GetNext()) != NULL
);
4236 default : SetError(errIllegalParameter
); break;
4238 PushDouble(nMaxCount
- nCount
);
4243 void ScInterpreter::ScCountIf()
4245 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCountIf" );
4246 if ( MustHaveParamCount( GetByte(), 2 ) )
4250 BOOL bIsString
= TRUE
;
4251 switch ( GetStackType() )
4257 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4262 ScBaseCell
* pCell
= GetCell( aAdr
);
4263 switch ( GetCellType( pCell
) )
4265 case CELLTYPE_VALUE
:
4266 fVal
= GetCellValue( aAdr
, pCell
);
4269 case CELLTYPE_FORMULA
:
4270 if( ((ScFormulaCell
*)pCell
)->IsValue() )
4272 fVal
= GetCellValue( aAdr
, pCell
);
4276 GetCellString(rString
, pCell
);
4278 case CELLTYPE_STRING
:
4279 case CELLTYPE_EDIT
:
4280 GetCellString(rString
, pCell
);
4290 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
4292 bIsString
= ScMatrix::IsNonValueType( nType
);
4296 rString
= GetString();
4306 size_t nRefInList
= 0;
4307 while (nParam
-- > 0)
4315 switch ( GetStackType() )
4321 PopDoubleRef( aRange
, nParam
, nRefInList
);
4322 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4326 PopSingleRef( nCol1
, nRow1
, nTab1
);
4332 PushIllegalParameter();
4335 if ( nTab1
!= nTab2
)
4337 PushIllegalParameter();
4342 PushIllegalParameter();
4345 if (nGlobalError
== 0)
4347 ScQueryParam rParam
;
4348 rParam
.nRow1
= nRow1
;
4349 rParam
.nRow2
= nRow2
;
4351 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4352 rEntry
.bDoQuery
= TRUE
;
4355 rEntry
.bQueryByString
= FALSE
;
4357 rEntry
.eOp
= SC_EQUAL
;
4361 rParam
.FillInExcelSyntax(rString
, 0);
4362 sal_uInt32 nIndex
= 0;
4363 rEntry
.bQueryByString
=
4364 !(pFormatter
->IsNumberFormat(
4365 *rEntry
.pStr
, nIndex
, rEntry
.nVal
));
4366 if ( rEntry
.bQueryByString
)
4367 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4369 rParam
.nCol1
= nCol1
;
4370 rParam
.nCol2
= nCol2
;
4371 rEntry
.nField
= nCol1
;
4372 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4373 // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
4374 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4375 if ( aCellIter
.GetFirst() )
4380 } while ( aCellIter
.GetNext() );
4385 PushIllegalParameter();
4394 void ScInterpreter::ScSumIf()
4396 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSumIf" );
4397 BYTE nParamCount
= GetByte();
4398 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
4404 bool bSumExtraRange
= (nParamCount
== 3);
4407 // Save only the upperleft cell in case of cell range. The geometry
4408 // of the 3rd parameter is taken from the 1st parameter.
4410 switch ( GetStackType() )
4417 PopDoubleRef( nCol3
, nRow3
, nTab3
, nColJunk
, nRowJunk
, nTabJunk
);
4418 if ( nTabJunk
!= nTab3
)
4420 PushIllegalParameter();
4426 PopSingleRef( nCol3
, nRow3
, nTab3
);
4429 PushIllegalParameter();
4435 BOOL bIsString
= TRUE
;
4436 switch ( GetStackType() )
4442 if ( !PopDoubleRefOrSingleRef( aAdr
) )
4447 ScBaseCell
* pCell
= GetCell( aAdr
);
4448 switch ( GetCellType( pCell
) )
4450 case CELLTYPE_VALUE
:
4451 fVal
= GetCellValue( aAdr
, pCell
);
4454 case CELLTYPE_FORMULA
:
4455 if( ((ScFormulaCell
*)pCell
)->IsValue() )
4457 fVal
= GetCellValue( aAdr
, pCell
);
4461 GetCellString(rString
, pCell
);
4463 case CELLTYPE_STRING
:
4464 case CELLTYPE_EDIT
:
4465 GetCellString(rString
, pCell
);
4474 rString
= GetString();
4478 ScMatValType nType
= GetDoubleOrStringFromMatrix( fVal
,
4480 bIsString
= ScMatrix::IsNonValueType( nType
);
4494 size_t nRefInList
= 0;
4495 while (nParam
-- > 0)
4503 switch ( GetStackType() )
4508 PushIllegalParameter();
4514 PopDoubleRef( aRange
, nParam
, nRefInList
);
4515 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4519 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
4522 PopSingleRef( nCol1
, nRow1
, nTab1
);
4528 PushIllegalParameter();
4531 if ( nTab1
!= nTab2
)
4533 PushIllegalParameter();
4539 // Take the range geometry of the 1st parameter and apply it to
4540 // the 3rd. If parts of the resulting range would point outside
4541 // the sheet, don't complain but silently ignore and simply cut
4542 // them away, this is what Xcl does :-/
4544 // For the cut-away part we also don't need to determine the
4545 // criteria match, so shrink the source range accordingly,
4546 // instead of the result range.
4547 SCCOL nColDelta
= nCol2
- nCol1
;
4548 SCROW nRowDelta
= nRow2
- nRow1
;
4549 if (nCol3
+ nColDelta
> MAXCOL
)
4551 SCCOL nNewDelta
= MAXCOL
- nCol3
;
4552 nCol2
= nCol1
+ nNewDelta
;
4555 if (nRow3
+ nRowDelta
> MAXROW
)
4557 SCROW nNewDelta
= MAXROW
- nRow3
;
4558 nRow2
= nRow1
+ nNewDelta
;
4568 if (nGlobalError
== 0)
4570 ScQueryParam rParam
;
4571 rParam
.nRow1
= nRow1
;
4572 rParam
.nRow2
= nRow2
;
4574 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
4575 rEntry
.bDoQuery
= TRUE
;
4578 rEntry
.bQueryByString
= FALSE
;
4580 rEntry
.eOp
= SC_EQUAL
;
4584 rParam
.FillInExcelSyntax(rString
, 0);
4585 sal_uInt32 nIndex
= 0;
4586 rEntry
.bQueryByString
=
4587 !(pFormatter
->IsNumberFormat(
4588 *rEntry
.pStr
, nIndex
, rEntry
.nVal
));
4589 if ( rEntry
.bQueryByString
)
4590 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4593 aAdr
.SetTab( nTab3
);
4594 rParam
.nCol1
= nCol1
;
4595 rParam
.nCol2
= nCol2
;
4596 rEntry
.nField
= nCol1
;
4597 SCCOL nColDiff
= nCol3
- nCol1
;
4598 SCROW nRowDiff
= nRow3
- nRow1
;
4599 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
4600 // Increment Entry.nField in iterator when switching to next column.
4601 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
4602 if ( aCellIter
.GetFirst() )
4606 aAdr
.SetCol( aCellIter
.GetCol() + nColDiff
);
4607 aAdr
.SetRow( aCellIter
.GetRow() + nRowDiff
);
4608 ScBaseCell
* pCell
= GetCell( aAdr
);
4609 if ( HasCellValueData(pCell
) )
4611 fVal
= GetCellValue( aAdr
, pCell
);
4612 if ( bNull
&& fVal
!= 0.0 )
4620 } while ( aCellIter
.GetNext() );
4625 PushIllegalParameter();
4629 PushDouble( ::rtl::math::approxAdd( fSum
, fMem
) );
4634 void ScInterpreter::ScLookup()
4636 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLookup" );
4637 BYTE nParamCount
= GetByte();
4638 if ( !MustHaveParamCount( nParamCount
, 2, 3 ) )
4641 ScMatrixRef pDataMat
= NULL
, pResMat
= NULL
;
4642 SCCOL nCol1
= 0, nCol2
= 0, nResCol1
= 0, nResCol2
= 0;
4643 SCROW nRow1
= 0, nRow2
= 0, nResRow1
= 0, nResRow2
= 0;
4644 SCTAB nTab1
= 0, nResTab
= 0;
4645 SCSIZE nLenMajor
= 0; // length of major direction
4646 bool bVertical
= true; // whether to lookup vertically or horizontally
4648 if (nParamCount
== 3)
4650 switch (GetStackType())
4655 PopDoubleRef(nResCol1
, nResRow1
, nResTab
,
4656 nResCol2
, nResRow2
, nTabJunk
);
4657 if (nResTab
!= nTabJunk
||
4658 ((nResRow2
- nResRow1
) > 0 && (nResCol2
- nResCol1
) > 0))
4660 // The result array must be a vector.
4661 PushIllegalParameter();
4668 pResMat
= PopMatrix();
4671 PushIllegalParameter();
4675 pResMat
->GetDimensions(nC
, nR
);
4676 if (nC
!= 1 && nR
!= 1)
4678 // Result matrix must be a vector.
4679 PushIllegalParameter();
4685 PushIllegalParameter();
4690 // Get the data-result range and also determine whether this is vertical
4691 // lookup or horizontal lookup.
4693 switch (GetStackType())
4698 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTabJunk
);
4699 if (nTab1
!= nTabJunk
)
4701 PushIllegalParameter();
4704 bVertical
= (nRow2
- nRow1
) >= (nCol2
- nCol1
);
4705 nLenMajor
= bVertical
? nRow2
- nRow1
+ 1 : nCol2
- nCol1
+ 1;
4710 pDataMat
= PopMatrix();
4713 PushIllegalParameter();
4718 pDataMat
->GetDimensions(nC
, nR
);
4719 bVertical
= (nR
>= nC
);
4720 nLenMajor
= bVertical
? nR
: nC
;
4724 PushIllegalParameter();
4731 PushIllegalParameter();
4735 // Get the lookup value.
4737 ScQueryParam aParam
;
4738 ScQueryEntry
& rEntry
= aParam
.GetEntry(0);
4739 if ( !FillEntry(rEntry
) )
4742 // Now, perform the search to compute the delta position (nDelta).
4746 // Data array is given as a matrix.
4747 rEntry
.bDoQuery
= true;
4748 rEntry
.eOp
= SC_LESS_EQUAL
;
4749 bool bFound
= false;
4752 pDataMat
->GetDimensions(nC
, nR
);
4754 // In case of non-vector matrix, only search the first row or column.
4755 ScMatrixRef pDataMat2
;
4758 ScMatrixRef
pTempMat(new ScMatrix(1, nR
));
4759 for (SCSIZE i
= 0; i
< nR
; ++i
)
4760 if (pDataMat
->IsValue(0, i
))
4761 pTempMat
->PutDouble(pDataMat
->GetDouble(0, i
), 0, i
);
4763 pTempMat
->PutString(pDataMat
->GetString(0, i
), 0, i
);
4764 pDataMat2
= pTempMat
;
4768 ScMatrixRef
pTempMat(new ScMatrix(nC
, 1));
4769 for (SCSIZE i
= 0; i
< nC
; ++i
)
4770 if (pDataMat
->IsValue(i
, 0))
4771 pTempMat
->PutDouble(pDataMat
->GetDouble(i
, 0), i
, 0);
4773 pTempMat
->PutString(pDataMat
->GetString(i
, 0), i
, 0);
4774 pDataMat2
= pTempMat
;
4777 // binary search for non-equality mode (the source data is
4778 // assumed to be sorted in ascending order).
4780 SCCOLROW nDelta
= -1;
4782 SCSIZE nFirst
= 0, nLast
= nLenMajor
-1; //, nHitIndex = 0;
4783 for (SCSIZE nLen
= nLast
-nFirst
; nLen
> 0; nLen
= nLast
-nFirst
)
4785 SCSIZE nMid
= nFirst
+ nLen
/2;
4786 sal_Int32 nCmp
= lcl_CompareMatrix2Query( nMid
, *pDataMat2
, rEntry
);
4789 // exact match. find the last item with the same value.
4790 lcl_GetLastMatch( nMid
, *pDataMat2
, nLenMajor
, false);
4796 if (nLen
== 1) // first and last items are next to each other.
4798 nDelta
= nCmp
< 0 ? nLast
- 1 : nFirst
- 1;
4799 // If already the 1st item is greater there's nothing found.
4800 bFound
= (nDelta
>= 0);
4810 if (nDelta
== static_cast<SCCOLROW
>(nLenMajor
-2)) // last item
4812 sal_Int32 nCmp
= lcl_CompareMatrix2Query(nDelta
+1, *pDataMat2
, rEntry
);
4815 // either the last item is an exact match or the real
4816 // hit is beyond the last item.
4821 else if (nDelta
> 0) // valid hit must be 2nd item or higher
4833 // Now that we've found the delta, push the result back to the cell.
4837 // result array is matrix.
4838 if (static_cast<SCSIZE
>(nDelta
) >= pResMat
->GetElementCount())
4843 if (pResMat
->IsValue(nDelta
))
4844 PushDouble(pResMat
->GetDouble(nDelta
));
4846 PushString(pResMat
->GetString(nDelta
));
4848 else if (nParamCount
== 3)
4850 // result array is cell range.
4852 aAdr
.SetTab(nResTab
);
4853 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
4856 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
4857 if (nTempRow
> MAXROW
)
4862 aAdr
.SetCol(nResCol1
);
4863 aAdr
.SetRow(nTempRow
);
4867 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
4868 if (nTempCol
> MAXCOL
)
4873 aAdr
.SetCol(nTempCol
);
4874 aAdr
.SetRow(nResRow1
);
4876 PushCellResultToken(true, aAdr
, NULL
, NULL
);
4880 // no result array. Use the data array to get the final value from.
4883 if (pDataMat
->IsValue(nC
-1, nDelta
))
4884 PushDouble(pDataMat
->GetDouble(nC
-1, nDelta
));
4886 PushString(pDataMat
->GetString(nC
-1, nDelta
));
4890 if (pDataMat
->IsValue(nDelta
, nR
-1))
4891 PushDouble(pDataMat
->GetDouble(nDelta
, nR
-1));
4893 PushString(pDataMat
->GetString(nDelta
, nR
-1));
4900 // Perform cell range search.
4902 aParam
.nCol1
= nCol1
;
4903 aParam
.nRow1
= nRow1
;
4904 aParam
.nCol2
= bVertical
? nCol1
: nCol2
;
4905 aParam
.nRow2
= bVertical
? nRow2
: nRow1
;
4906 aParam
.bByRow
= bVertical
;
4907 aParam
.bMixedComparison
= true;
4909 rEntry
.bDoQuery
= TRUE
;
4910 rEntry
.eOp
= SC_LESS_EQUAL
;
4911 rEntry
.nField
= nCol1
;
4912 if ( rEntry
.bQueryByString
)
4913 aParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
4915 ScQueryCellIterator
aCellIter(pDok
, nTab1
, aParam
, FALSE
);
4918 // Advance Entry.nField in iterator upon switching columns if
4920 aCellIter
.SetAdvanceQueryParamEntryField(!bVertical
);
4921 if ( !aCellIter
.FindEqualOrSortedLastInRange(nC
, nR
) )
4927 SCCOLROW nDelta
= bVertical
? static_cast<SCSIZE
>(nR
-nRow1
) : static_cast<SCSIZE
>(nC
-nCol1
);
4931 // Use the matrix result array.
4932 if (pResMat
->IsValue(nDelta
))
4933 PushDouble(pResMat
->GetDouble(nDelta
));
4935 PushString(pResMat
->GetString(nDelta
));
4937 else if (nParamCount
== 3)
4939 // Use the result array vector. Note that the result array is assumed
4940 // to be a vector (i.e. 1-dimensinoal array).
4943 aAdr
.SetTab(nResTab
);
4944 bool bResVertical
= (nResRow2
- nResRow1
) > 0;
4947 SCROW nTempRow
= static_cast<SCROW
>(nResRow1
+ nDelta
);
4948 if (nTempRow
> MAXROW
)
4953 aAdr
.SetCol(nResCol1
);
4954 aAdr
.SetRow(nTempRow
);
4958 SCCOL nTempCol
= static_cast<SCCOL
>(nResCol1
+ nDelta
);
4959 if (nTempCol
> MAXCOL
)
4964 aAdr
.SetCol(nTempCol
);
4965 aAdr
.SetRow(nResRow1
);
4967 PushCellResultToken(true, aAdr
, NULL
, NULL
);
4971 // Regardless of whether or not the result array exists, the last
4972 // array is always used as the "result" array.
4978 SCROW nTempRow
= static_cast<SCROW
>(nRow1
+ nDelta
);
4979 if (nTempRow
> MAXROW
)
4985 aAdr
.SetRow(nTempRow
);
4989 SCCOL nTempCol
= static_cast<SCCOL
>(nCol1
+ nDelta
);
4990 if (nTempCol
> MAXCOL
)
4995 aAdr
.SetCol(nTempCol
);
4998 PushCellResultToken(true, aAdr
, NULL
, NULL
);
5003 void ScInterpreter::ScHLookup()
5005 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScHLookup" );
5006 CalculateLookup(TRUE
);
5008 void ScInterpreter::CalculateLookup(BOOL HLookup
)
5010 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::CalculateLookup" );
5011 BYTE nParamCount
= GetByte();
5012 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
5015 if (nParamCount
== 4)
5016 bSorted
= GetBool();
5019 double fIndex
= ::rtl::math::approxFloor( GetDouble() ) - 1.0;
5020 ScMatrixRef pMat
= NULL
;
5021 SCSIZE nC
= 0, nR
= 0;
5028 if (GetStackType() == svDoubleRef
)
5030 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5033 PushIllegalParameter();
5037 else if (GetStackType() == svMatrix
)
5041 pMat
->GetDimensions(nC
, nR
);
5044 PushIllegalParameter();
5050 PushIllegalParameter();
5053 if ( fIndex
< 0.0 || (HLookup
? (pMat
? (fIndex
>= nR
) : (fIndex
+nRow1
> nRow2
)) : (pMat
? (fIndex
>= nC
) : (fIndex
+nCol1
> nCol2
)) ) )
5055 PushIllegalArgument();
5058 SCROW nZIndex
= static_cast<SCROW
>(fIndex
);
5059 SCCOL nSpIndex
= static_cast<SCCOL
>(fIndex
);
5063 nZIndex
+= nRow1
; // Wertzeile
5064 nSpIndex
= sal::static_int_cast
<SCCOL
>( nSpIndex
+ nCol1
); // value column
5067 if (nGlobalError
== 0)
5069 ScQueryParam rParam
;
5070 rParam
.nCol1
= nCol1
;
5071 rParam
.nRow1
= nRow1
;
5074 rParam
.nCol2
= nCol2
;
5075 rParam
.nRow2
= nRow1
; // nur in der ersten Zeile suchen
5076 rParam
.bByRow
= FALSE
;
5080 rParam
.nCol2
= nCol1
; // nur in der ersten Spalte suchen
5081 rParam
.nRow2
= nRow2
;
5082 rParam
.nTab
= nTab1
;
5084 rParam
.bMixedComparison
= TRUE
;
5086 ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
5087 rEntry
.bDoQuery
= TRUE
;
5089 rEntry
.eOp
= SC_LESS_EQUAL
;
5090 if ( !FillEntry(rEntry
) )
5092 if ( rEntry
.bQueryByString
)
5093 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5096 SCSIZE nMatCount
= HLookup
? nC
: nR
;
5097 SCSIZE nDelta
= SCSIZE_MAX
;
5098 if (rEntry
.bQueryByString
)
5101 //! TODO: enable regex on matrix strings
5103 String aParamStr
= *rEntry
.pStr
;
5106 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5108 if (HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
5111 ScGlobal::pCollator
->compareString( HLookup
? pMat
->GetString(i
,0) : pMat
->GetString(0,i
), aParamStr
);
5114 else if (i
>0) // #i2168# ignore first mismatch
5123 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5125 if (HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
))
5127 if ( ScGlobal::pTransliteration
->isEqual(
5128 HLookup
? pMat
->GetString(i
,0) : pMat
->GetString(0,i
), aParamStr
) )
5141 // #i2168# ignore strings
5142 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5144 if (!(HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
5146 if ((HLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) <= rEntry
.nVal
)
5155 for (SCSIZE i
= 0; i
< nMatCount
; i
++)
5157 if (!(HLookup
? pMat
->IsString(i
, 0) : pMat
->IsString(0, i
)))
5159 if ((HLookup
? pMat
->GetDouble(i
,0) : pMat
->GetDouble(0,i
)) == rEntry
.nVal
)
5168 if ( nDelta
!= SCSIZE_MAX
)
5170 SCSIZE nX
= static_cast<SCSIZE
>(nSpIndex
);
5175 nY
= static_cast<SCSIZE
>(nZIndex
);
5177 if ( pMat
->IsString( nX
, nY
) )
5178 PushString(pMat
->GetString( nX
,nY
));
5180 PushDouble(pMat
->GetDouble( nX
,nY
));
5187 rEntry
.nField
= nCol1
;
5188 BOOL bFound
= FALSE
;
5192 rEntry
.eOp
= SC_LESS_EQUAL
;
5195 ScQueryCellIterator
aCellIter(pDok
, nTab1
, rParam
, FALSE
);
5196 // advance Entry.nField in Iterator upon switching columns
5197 aCellIter
.SetAdvanceQueryParamEntryField( TRUE
);
5201 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow1_temp
);
5203 else if ( aCellIter
.GetFirst() )
5206 nCol
= aCellIter
.GetCol();
5212 ScAddress
aResultPos( nCol1
, nRow1
, nTab1
);
5213 bFound
= LookupQueryWithCache( aResultPos
, rParam
);
5214 nRow
= aResultPos
.Row();
5219 ScAddress
aAdr( nCol
, nRow
, nTab1
);
5220 PushCellResultToken( true, aAdr
, NULL
, NULL
);
5227 PushIllegalParameter();
5231 bool ScInterpreter::FillEntry(ScQueryEntry
& rEntry
)
5233 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::FillEntry" );
5234 switch ( GetStackType() )
5238 rEntry
.bQueryByString
= FALSE
;
5239 rEntry
.nVal
= GetDouble();
5244 const String sStr
= GetString();
5245 rEntry
.bQueryByString
= TRUE
;
5246 *rEntry
.pStr
= sStr
;
5253 if ( !PopDoubleRefOrSingleRef( aAdr
) )
5258 ScBaseCell
* pCell
= GetCell( aAdr
);
5259 if (HasCellValueData(pCell
))
5261 rEntry
.bQueryByString
= FALSE
;
5262 rEntry
.nVal
= GetCellValue( aAdr
, pCell
);
5266 if ( GetCellType( pCell
) == CELLTYPE_NOTE
)
5268 rEntry
.bQueryByString
= FALSE
;
5274 GetCellString(sStr
, pCell
);
5275 rEntry
.bQueryByString
= TRUE
;
5276 *rEntry
.pStr
= sStr
;
5283 const ScMatValType nType
= GetDoubleOrStringFromMatrix(rEntry
.nVal
, *rEntry
.pStr
);
5284 rEntry
.bQueryByString
= ScMatrix::IsNonValueType( nType
);
5289 PushIllegalParameter();
5292 } // switch ( GetStackType() )
5295 void ScInterpreter::ScVLookup()
5297 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScVLookup" );
5298 CalculateLookup(FALSE
);
5301 #if defined(WIN) && defined(MSC)
5302 #pragma optimize("",off)
5305 void ScInterpreter::ScSubTotal()
5307 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSubTotal" );
5308 BYTE nParamCount
= GetByte();
5309 if ( MustHaveParamCountMin( nParamCount
, 2 ) )
5311 // We must fish the 1st parameter deep from the stack! And push it on top.
5312 const FormulaToken
* p
= pStack
[ sp
- nParamCount
];
5313 PushTempToken( *p
);
5314 int nFunc
= (int) ::rtl::math::approxFloor( GetDouble() );
5315 if( nFunc
< 1 || nFunc
> 11 )
5316 PushIllegalArgument(); // simulate return on stack, not SetError(...)
5319 cPar
= nParamCount
- 1;
5323 case SUBTOTAL_FUNC_AVE
: ScAverage(); break;
5324 case SUBTOTAL_FUNC_CNT
: ScCount(); break;
5325 case SUBTOTAL_FUNC_CNT2
: ScCount2(); break;
5326 case SUBTOTAL_FUNC_MAX
: ScMax(); break;
5327 case SUBTOTAL_FUNC_MIN
: ScMin(); break;
5328 case SUBTOTAL_FUNC_PROD
: ScProduct(); break;
5329 case SUBTOTAL_FUNC_STD
: ScStDev(); break;
5330 case SUBTOTAL_FUNC_STDP
: ScStDevP(); break;
5331 case SUBTOTAL_FUNC_SUM
: ScSum(); break;
5332 case SUBTOTAL_FUNC_VAR
: ScVar(); break;
5333 case SUBTOTAL_FUNC_VARP
: ScVarP(); break;
5334 default : PushIllegalArgument(); break;
5338 // Get rid of the 1st (fished) parameter.
5339 double nVal
= GetDouble();
5344 #if defined(WIN) && defined(MSC)
5345 #pragma optimize("",on)
5349 BOOL
ScInterpreter::GetDBParams(SCTAB
& rTab
, ScQueryParam
& rParam
,
5350 BOOL
& rMissingField
)
5352 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDBParams" );
5354 BOOL bAllowMissingField
= FALSE
;
5355 if ( rMissingField
)
5357 bAllowMissingField
= TRUE
;
5358 rMissingField
= FALSE
;
5360 if ( GetByte() == 3 )
5369 PopDoubleRef(nQCol1
, nQRow1
, nQTab1
, nQCol2
, nQRow2
, nQTab2
);
5374 ScRange aMissingRange
;
5375 BOOL bRangeFake
= FALSE
;
5376 switch (GetStackType())
5379 nVal
= ::rtl::math::approxFloor( GetDouble() );
5380 if ( bAllowMissingField
&& nVal
== 0.0 )
5381 rMissingField
= TRUE
; // fake missing parameter
5390 PopSingleRef( aAdr
);
5391 ScBaseCell
* pCell
= GetCell( aAdr
);
5392 if (HasCellValueData(pCell
))
5393 nVal
= GetCellValue( aAdr
, pCell
);
5397 GetCellString(aStr
, pCell
);
5402 if ( bAllowMissingField
)
5403 { // fake missing parameter for old SO compatibility
5405 PopDoubleRef( aMissingRange
);
5410 SetError( errIllegalParameter
);
5415 if ( bAllowMissingField
)
5416 rMissingField
= TRUE
;
5418 SetError( errIllegalParameter
);
5422 SetError( errIllegalParameter
);
5431 PopDoubleRef(nDBCol1
, nDBRow1
, nDBTab1
, nDBCol2
, nDBRow2
, nDBTab2
);
5433 if ( nGlobalError
== 0 && bRangeFake
)
5435 // range parameter must match entire database range
5436 if ( aMissingRange
== ScRange( nDBCol1
, nDBRow1
, nDBTab1
, nDBCol2
,
5438 rMissingField
= TRUE
;
5440 SetError( errIllegalParameter
);
5443 if (nGlobalError
== 0)
5445 SCCOL nField
= nDBCol1
;
5447 if ( rMissingField
)
5451 if ( nVal
<= 0 || nVal
> (nDBCol2
- nDBCol1
+ 1) )
5454 nField
= Min(nDBCol2
, (SCCOL
)(nDBCol1
+ (SCCOL
)nVal
- 1));
5460 ScAddress
aLook( nDBCol1
, nDBRow1
, nDBTab1
);
5461 while (!bFound
&& (aLook
.Col() <= nDBCol2
))
5463 ScBaseCell
* pCell
= GetCell( aLook
);
5464 GetCellString( aCellStr
, pCell
);
5465 bFound
= ScGlobal::pTransliteration
->isEqual( aCellStr
, aStr
);
5469 nField
= aLook
.Col();
5473 rParam
.nCol1
= nDBCol1
;
5474 rParam
.nRow1
= nDBRow1
;
5475 rParam
.nCol2
= nDBCol2
;
5476 rParam
.nRow2
= nDBRow2
;
5477 rParam
.nTab
= nDBTab1
;
5478 rParam
.bHasHeader
= TRUE
;
5479 rParam
.bByRow
= TRUE
;
5480 rParam
.bInplace
= TRUE
;
5481 rParam
.bCaseSens
= FALSE
;
5482 rParam
.bRegExp
= FALSE
;
5483 rParam
.bDuplicate
= TRUE
;
5484 if (pDok
->CreateQueryParam(nQCol1
, nQRow1
, nQCol2
, nQRow2
, nQTab1
, rParam
))
5486 // An allowed missing field parameter sets the result field
5487 // to any of the query fields, just to be able to return
5488 // some cell from the iterator.
5489 if ( rMissingField
)
5490 nField
= static_cast<SCCOL
>(rParam
.GetEntry(0).nField
);
5492 rParam
.nCol1
= nField
;
5493 rParam
.nCol2
= nField
;
5496 SCSIZE nCount
= rParam
.GetEntryCount();
5497 for ( SCSIZE i
=0; i
< nCount
; i
++ )
5499 ScQueryEntry
& rEntry
= rParam
.GetEntry(i
);
5500 if ( rEntry
.bDoQuery
)
5502 sal_uInt32 nIndex
= 0;
5503 rEntry
.bQueryByString
= !pFormatter
->IsNumberFormat(
5504 *rEntry
.pStr
, nIndex
, rEntry
.nVal
);
5505 if ( rEntry
.bQueryByString
&& !rParam
.bRegExp
)
5506 rParam
.bRegExp
= MayBeRegExp( *rEntry
.pStr
, pDok
);
5519 void ScInterpreter::DBIterator( ScIterFunc eFunc
)
5521 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::DBIterator" );
5527 ScQueryParam aQueryParam
;
5528 BOOL bMissingField
= FALSE
;
5529 if ( GetDBParams( nTab1
, aQueryParam
, bMissingField
) )
5533 ScQueryValueIterator
aValIter(pDok
, nTab1
, aQueryParam
);
5534 if ( aValIter
.GetFirst(nVal
, nErr
) && !nErr
)
5538 case ifPRODUCT
: nErg
= 1; break;
5539 case ifMAX
: nErg
= -MAXDOUBLE
; break;
5540 case ifMIN
: nErg
= MAXDOUBLE
; break;
5541 default: ; // nothing
5550 if ( bNull
&& nVal
!= 0.0 )
5558 case ifSUMSQ
: nErg
+= nVal
* nVal
; break;
5559 case ifPRODUCT
: nErg
*= nVal
; break;
5560 case ifMAX
: if( nVal
> nErg
) nErg
= nVal
; break;
5561 case ifMIN
: if( nVal
< nErg
) nErg
= nVal
; break;
5562 default: ; // nothing
5565 while ( aValIter
.GetNext(nVal
, nErr
) && !nErr
);
5570 SetError( errIllegalParameter
);
5573 case ifCOUNT
: nErg
= nCount
; break;
5574 case ifSUM
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
); break;
5575 case ifAVERAGE
: nErg
= ::rtl::math::approxAdd( nErg
, fMem
) / nCount
; break;
5576 default: ; // nothing
5582 void ScInterpreter::ScDBSum()
5584 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBSum" );
5585 DBIterator( ifSUM
);
5589 void ScInterpreter::ScDBCount()
5591 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBCount" );
5593 ScQueryParam aQueryParam
;
5594 BOOL bMissingField
= TRUE
;
5595 if ( GetDBParams( nTab
, aQueryParam
, bMissingField
) )
5598 if ( bMissingField
)
5599 { // count all matching records
5600 // TODO: currently the QueryIterators only return cell pointers of
5601 // existing cells, so if a query matches an empty cell there's
5602 // nothing returned, and therefor not counted!
5603 // Since this has ever been the case and this code here only came
5604 // into existance to fix #i6899 and it never worked before we'll
5605 // have to live with it until we reimplement the iterators to also
5606 // return empty cells, which would mean to adapt all callers of
5608 ScQueryCellIterator
aCellIter( pDok
, nTab
, aQueryParam
);
5609 if ( aCellIter
.GetFirst() )
5614 } while ( aCellIter
.GetNext() );
5618 { // count only matching records with a value in the "result" field
5621 ScQueryValueIterator
aValIter( pDok
, nTab
, aQueryParam
);
5622 if ( aValIter
.GetFirst( nVal
, nErr
) && !nErr
)
5627 } while ( aValIter
.GetNext( nVal
, nErr
) && !nErr
);
5631 PushDouble( nCount
);
5634 PushIllegalParameter();
5638 void ScInterpreter::ScDBCount2()
5640 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBCount2" );
5642 ScQueryParam aQueryParam
;
5643 BOOL bMissingField
= TRUE
;
5644 if (GetDBParams( nTab
, aQueryParam
, bMissingField
))
5647 ScQueryCellIterator
aCellIter(pDok
, nTab
, aQueryParam
);
5648 if ( aCellIter
.GetFirst() )
5653 } while ( aCellIter
.GetNext() );
5658 PushIllegalParameter();
5662 void ScInterpreter::ScDBAverage()
5664 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBAverage" );
5665 DBIterator( ifAVERAGE
);
5669 void ScInterpreter::ScDBMax()
5671 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBMax" );
5672 DBIterator( ifMAX
);
5676 void ScInterpreter::ScDBMin()
5678 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBMin" );
5679 DBIterator( ifMIN
);
5683 void ScInterpreter::ScDBProduct()
5685 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBProduct" );
5686 DBIterator( ifPRODUCT
);
5690 void ScInterpreter::GetDBStVarParams( double& rVal
, double& rValCount
)
5692 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::GetDBStVarParams" );
5693 std::vector
<double> values
;
5700 ScQueryParam aQueryParam
;
5701 BOOL bMissingField
= FALSE
;
5702 if (GetDBParams( nTab
, aQueryParam
, bMissingField
))
5706 ScQueryValueIterator
aValIter(pDok
, nTab
, aQueryParam
);
5707 if (aValIter
.GetFirst(fVal
, nErr
) && !nErr
)
5712 values
.push_back(fVal
);
5715 while ((nErr
== 0) && aValIter
.GetNext(fVal
, nErr
));
5720 SetError( errIllegalParameter
);
5722 vMean
= fSum
/ values
.size();
5724 for (size_t i
= 0; i
< values
.size(); i
++)
5725 vSum
+= (values
[i
] - vMean
) * (values
[i
] - vMean
);
5731 void ScInterpreter::ScDBStdDev()
5733 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBStdDev" );
5734 double fVal
, fCount
;
5735 GetDBStVarParams( fVal
, fCount
);
5736 PushDouble( sqrt(fVal
/(fCount
-1)));
5740 void ScInterpreter::ScDBStdDevP()
5742 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBStdDevP" );
5743 double fVal
, fCount
;
5744 GetDBStVarParams( fVal
, fCount
);
5745 PushDouble( sqrt(fVal
/fCount
));
5749 void ScInterpreter::ScDBVar()
5751 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBVar" );
5752 double fVal
, fCount
;
5753 GetDBStVarParams( fVal
, fCount
);
5754 PushDouble(fVal
/(fCount
-1));
5758 void ScInterpreter::ScDBVarP()
5760 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScDBVarP" );
5761 double fVal
, fCount
;
5762 GetDBStVarParams( fVal
, fCount
);
5763 PushDouble(fVal
/fCount
);
5767 void ScInterpreter::ScIndirect()
5769 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndirect" );
5770 BYTE nParamCount
= GetByte();
5771 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
5773 bool bTryXlA1
= true; // whether to try XL_A1 style as well.
5774 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
;
5775 if (nParamCount
== 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
5777 eConv
= FormulaGrammar::CONV_XL_R1C1
;
5780 const ScAddress::Details
aDetails( eConv
, aPos
);
5781 const ScAddress::Details
aDetailsXlA1( FormulaGrammar::CONV_XL_A1
, aPos
);
5782 SCTAB nTab
= aPos
.Tab();
5783 String
sRefStr( GetString() );
5784 ScRefAddress aRefAd
, aRefAd2
;
5785 if ( ConvertDoubleRef( pDok
, sRefStr
, nTab
, aRefAd
, aRefAd2
, aDetails
) ||
5786 (bTryXlA1
&& ConvertDoubleRef( pDok
, sRefStr
, nTab
, aRefAd
,
5787 aRefAd2
, aDetailsXlA1
)))
5788 PushDoubleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab(),
5789 aRefAd2
.Col(), aRefAd2
.Row(), aRefAd2
.Tab() );
5790 else if ( ConvertSingleRef ( pDok
, sRefStr
, nTab
, aRefAd
, aDetails
) ||
5791 (bTryXlA1
&& ConvertSingleRef ( pDok
, sRefStr
, nTab
, aRefAd
,
5793 PushSingleRef( aRefAd
.Col(), aRefAd
.Row(), aRefAd
.Tab() );
5798 ScRangeName
* pNames
= pDok
->GetRangeName();
5803 if (!pNames
->SearchName( sRefStr
, nPos
))
5806 ScRangeData
* rData
= (*pNames
)[nPos
];
5810 // We need this in order to obtain a good range.
5811 rData
->ValidateTabRefs();
5815 // This is some really odd Excel behavior and renders named
5816 // ranges containing relative references totally useless.
5817 if (!rData
->IsReference(aRange
, ScAddress( aPos
.Tab(), 0, 0)))
5820 // This is the usual way to treat named ranges containing
5821 // relative references.
5822 if (!rData
->IsReference( aRange
, aPos
))
5826 if (aRange
.aStart
== aRange
.aEnd
)
5827 PushSingleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
5828 aRange
.aStart
.Tab());
5830 PushDoubleRef( aRange
.aStart
.Col(), aRange
.aStart
.Row(),
5831 aRange
.aStart
.Tab(), aRange
.aEnd
.Col(),
5832 aRange
.aEnd
.Row(), aRange
.aEnd
.Tab());
5839 PushIllegalArgument();
5845 void ScInterpreter::ScAddressFunc()
5847 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAddressFunc" );
5850 BYTE nParamCount
= GetByte();
5851 if( !MustHaveParamCount( nParamCount
, 2, 5 ) )
5854 if( nParamCount
>= 5 )
5855 sTabStr
= GetString();
5857 FormulaGrammar::AddressConvention eConv
= FormulaGrammar::CONV_OOO
; // default
5858 if( nParamCount
>= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
5859 eConv
= FormulaGrammar::CONV_XL_R1C1
;
5861 USHORT nFlags
= SCA_COL_ABSOLUTE
| SCA_ROW_ABSOLUTE
; // default
5862 if( nParamCount
>= 3 )
5864 USHORT n
= (USHORT
) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
5872 case 1 : break; // default
5874 case 2 : nFlags
= SCA_ROW_ABSOLUTE
; break;
5876 case 3 : nFlags
= SCA_COL_ABSOLUTE
; break;
5878 case 4 : nFlags
= 0; break; // both relative
5881 nFlags
|= SCA_VALID
| SCA_VALID_ROW
| SCA_VALID_COL
;
5883 SCCOL nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
5884 SCROW nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
5885 if( eConv
== FormulaGrammar::CONV_XL_R1C1
)
5887 // YUCK! The XL interface actually treats rel R1C1 refs differently
5889 if( !(nFlags
& SCA_COL_ABSOLUTE
) )
5890 nCol
+= aPos
.Col() + 1;
5891 if( !(nFlags
& SCA_ROW_ABSOLUTE
) )
5892 nRow
+= aPos
.Row() + 1;
5897 if(!ValidCol( nCol
) || !ValidRow( nRow
))
5899 PushIllegalArgument();
5904 const ScAddress::Details
aDetails( eConv
, aPos
);
5905 const ScAddress
aAdr( nCol
, nRow
, 0);
5906 aAdr
.Format( aRefStr
, nFlags
, pDok
, aDetails
);
5908 if( nParamCount
>= 5 )
5910 ScCompiler::CheckTabQuotes( sTabStr
, eConv
);
5911 sTabStr
+= static_cast<sal_Unicode
>(eConv
== FormulaGrammar::CONV_XL_R1C1
? '!' : '.');
5913 PushString( sTabStr
);
5916 PushString( aRefStr
);
5920 void ScInterpreter::ScOffset()
5922 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScOffset" );
5923 BYTE nParamCount
= GetByte();
5924 if ( MustHaveParamCount( nParamCount
, 3, 5 ) )
5926 long nColNew
= -1, nRowNew
= -1, nColPlus
, nRowPlus
;
5927 if (nParamCount
== 5)
5928 nColNew
= (long) ::rtl::math::approxFloor(GetDouble());
5929 if (nParamCount
>= 4)
5930 nRowNew
= (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
5931 nColPlus
= (long) ::rtl::math::approxFloor(GetDouble());
5932 nRowPlus
= (long) ::rtl::math::approxFloor(GetDouble());
5939 if (nColNew
== 0 || nRowNew
== 0)
5941 PushIllegalArgument();
5944 if (GetStackType() == svSingleRef
)
5946 PopSingleRef(nCol1
, nRow1
, nTab1
);
5947 if (nParamCount
== 3 || (nColNew
< 0 && nRowNew
< 0))
5949 nCol1
= (SCCOL
)((long) nCol1
+ nColPlus
);
5950 nRow1
= (SCROW
)((long) nRow1
+ nRowPlus
);
5951 if (!ValidCol(nCol1
) || !ValidRow(nRow1
))
5952 PushIllegalArgument();
5954 PushSingleRef(nCol1
, nRow1
, nTab1
);
5962 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
); // ! nCol1 wird veraendert!
5963 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
5964 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
5965 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
5966 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
5967 !ValidCol(nCol2
) || !ValidRow(nRow2
))
5968 PushIllegalArgument();
5970 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
5973 else if (GetStackType() == svDoubleRef
)
5975 PopDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
5977 nColNew
= nCol2
- nCol1
+ 1;
5979 nRowNew
= nRow2
- nRow1
+ 1;
5980 nCol1
= (SCCOL
)((long)nCol1
+nColPlus
);
5981 nRow1
= (SCROW
)((long)nRow1
+nRowPlus
);
5982 nCol2
= (SCCOL
)((long)nCol1
+nColNew
-1);
5983 nRow2
= (SCROW
)((long)nRow1
+nRowNew
-1);
5984 if (!ValidCol(nCol1
) || !ValidRow(nRow1
) ||
5985 !ValidCol(nCol2
) || !ValidRow(nRow2
) || nTab1
!= nTab2
)
5986 PushIllegalArgument();
5988 PushDoubleRef(nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
5991 PushIllegalParameter();
5996 void ScInterpreter::ScIndex()
5998 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScIndex" );
5999 BYTE nParamCount
= GetByte();
6000 if ( MustHaveParamCount( nParamCount
, 1, 4 ) )
6006 if (nParamCount
== 4)
6007 nArea
= (long) ::rtl::math::approxFloor(GetDouble());
6010 if (nParamCount
>= 3)
6011 nCol
= (SCCOL
) ::rtl::math::approxFloor(GetDouble());
6014 if (nParamCount
>= 2)
6015 nRow
= (SCROW
) ::rtl::math::approxFloor(GetDouble());
6018 if (GetStackType() == svRefList
)
6019 nAreaCount
= (sp
? static_cast<ScToken
*>(pStack
[sp
-1])->GetRefList()->size() : 0);
6021 nAreaCount
= 1; // one reference or array or whatever
6022 if (nAreaCount
== 0 || (size_t)nArea
> nAreaCount
)
6024 PushError( errNoRef
);
6027 else if (nArea
< 1 || nCol
< 0 || nRow
< 0)
6029 PushIllegalArgument();
6032 switch (GetStackType())
6037 SetError(errIllegalArgument
);
6039 ScMatrixRef pMat
= GetMatrix();
6043 pMat
->GetDimensions(nC
, nR
);
6044 // Access one element of a vector independent of col/row
6046 bool bVector
= ((nCol
== 0 || nRow
== 0) && (nC
== 1 || nR
== 1));
6047 SCSIZE nElement
= ::std::max( static_cast<SCSIZE
>(nCol
),
6048 static_cast<SCSIZE
>(nRow
));
6049 if (nC
== 0 || nR
== 0 ||
6050 (!bVector
&& (static_cast<SCSIZE
>(nCol
) > nC
||
6051 static_cast<SCSIZE
>(nRow
) > nR
)) ||
6052 (bVector
&& nElement
> nC
* nR
))
6053 PushIllegalArgument();
6054 else if (nCol
== 0 && nRow
== 0)
6059 if (pMat
->IsString( nElement
))
6060 PushString( pMat
->GetString( nElement
));
6062 PushDouble( pMat
->GetDouble( nElement
));
6066 ScMatrixRef pResMat
= GetNewMat(nC
, 1);
6069 SCSIZE nRowMinus1
= static_cast<SCSIZE
>(nRow
- 1);
6070 for (SCSIZE i
= 0; i
< nC
; i
++)
6071 if (!pMat
->IsString(i
, nRowMinus1
))
6072 pResMat
->PutDouble(pMat
->GetDouble(i
,
6075 pResMat
->PutString(pMat
->GetString(i
,
6077 PushMatrix(pResMat
);
6080 PushIllegalArgument();
6084 ScMatrixRef pResMat
= GetNewMat(1, nR
);
6087 SCSIZE nColMinus1
= static_cast<SCSIZE
>(nCol
- 1);
6088 for (SCSIZE i
= 0; i
< nR
; i
++)
6089 if (!pMat
->IsString(nColMinus1
, i
))
6090 pResMat
->PutDouble(pMat
->GetDouble(nColMinus1
,
6093 pResMat
->PutString(pMat
->GetString(nColMinus1
,
6095 PushMatrix(pResMat
);
6098 PushIllegalArgument();
6102 if (!pMat
->IsString( static_cast<SCSIZE
>(nCol
-1),
6103 static_cast<SCSIZE
>(nRow
-1)))
6104 PushDouble( pMat
->GetDouble(
6105 static_cast<SCSIZE
>(nCol
-1),
6106 static_cast<SCSIZE
>(nRow
-1)));
6108 PushString( pMat
->GetString(
6109 static_cast<SCSIZE
>(nCol
-1),
6110 static_cast<SCSIZE
>(nRow
-1)));
6120 PopSingleRef( nCol1
, nRow1
, nTab1
);
6121 if (nCol
> 1 || nRow
> 1)
6122 PushIllegalArgument();
6124 PushSingleRef( nCol1
, nRow1
, nTab1
);
6136 BOOL bRowArray
= FALSE
;
6137 if (GetStackType() == svRefList
)
6139 FormulaTokenRef xRef
= PopToken();
6140 if (nGlobalError
|| !xRef
)
6142 PushIllegalParameter();
6145 ScRange
aRange( ScAddress::UNINITIALIZED
);
6146 DoubleRefToRange( (*(static_cast<ScToken
*>(xRef
.get())->GetRefList()))[nArea
-1], aRange
);
6147 aRange
.GetVars( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6148 if ( nParamCount
== 2 && nRow1
== nRow2
)
6153 PopDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab2
);
6154 if ( nParamCount
== 2 && nRow1
== nRow2
)
6157 if ( nTab1
!= nTab2
||
6158 (nCol
> 0 && nCol1
+nCol
-1 > nCol2
) ||
6159 (nRow
> 0 && nRow1
+nRow
-1 > nRow2
&& !bRowArray
) ||
6160 ( nRow
> nCol2
- nCol1
+ 1 && bRowArray
))
6161 PushIllegalArgument();
6162 else if (nCol
== 0 && nRow
== 0)
6164 if ( nCol1
== nCol2
&& nRow1
== nRow2
)
6165 PushSingleRef( nCol1
, nRow1
, nTab1
);
6167 PushDoubleRef( nCol1
, nRow1
, nTab1
, nCol2
, nRow2
, nTab1
);
6171 if ( nRow1
== nRow2
)
6172 PushSingleRef( nCol1
+nCol
-1, nRow1
, nTab1
);
6174 PushDoubleRef( nCol1
+nCol
-1, nRow1
, nTab1
,
6175 nCol1
+nCol
-1, nRow2
, nTab1
);
6179 if ( nCol1
== nCol2
)
6180 PushSingleRef( nCol1
, nRow1
+nRow
-1, nTab1
);
6181 else if ( bRowArray
)
6185 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
6188 PushDoubleRef( nCol1
, nRow1
+nRow
-1, nTab1
,
6189 nCol2
, nRow1
+nRow
-1, nTab1
);
6192 PushSingleRef( nCol1
+nCol
-1, nRow1
+nRow
-1, nTab1
);
6196 PushIllegalParameter();
6202 void ScInterpreter::ScMultiArea()
6204 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMultiArea" );
6205 // Legacy support, convert to RefList
6206 BYTE nParamCount
= GetByte();
6207 if (MustHaveParamCountMin( nParamCount
, 1))
6209 while (!nGlobalError
&& nParamCount
-- > 1)
6217 void ScInterpreter::ScAreas()
6219 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScAreas" );
6220 BYTE nParamCount
= GetByte();
6221 if (MustHaveParamCount( nParamCount
, 1))
6224 switch (GetStackType())
6228 FormulaTokenRef xT
= PopToken();
6229 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetSingleRef());
6235 FormulaTokenRef xT
= PopToken();
6236 ValidateRef( static_cast<ScToken
*>(xT
.get())->GetDoubleRef());
6242 FormulaTokenRef xT
= PopToken();
6243 ValidateRef( *(static_cast<ScToken
*>(xT
.get())->GetRefList()));
6244 nCount
+= static_cast<ScToken
*>(xT
.get())->GetRefList()->size();
6248 SetError( errIllegalParameter
);
6250 PushDouble( double(nCount
));
6255 void ScInterpreter::ScCurrency()
6257 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScCurrency" );
6258 BYTE nParamCount
= GetByte();
6259 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6263 if (nParamCount
== 2)
6265 fDec
= ::rtl::math::approxFloor(GetDouble());
6266 if (fDec
< -15.0 || fDec
> 15.0)
6268 PushIllegalArgument();
6274 double fVal
= GetDouble();
6277 fFac
= pow( (double)10, fDec
);
6281 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
6283 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
6284 Color
* pColor
= NULL
;
6287 ULONG nIndex
= pFormatter
->GetStandardFormat(
6288 NUMBERFORMAT_CURRENCY
,
6290 if ( (USHORT
) fDec
!= pFormatter
->GetFormatPrecision( nIndex
) )
6292 String sFormatString
;
6293 pFormatter
->GenerateFormat(sFormatString
,
6296 TRUE
, // mit Tausenderpunkt
6298 (USHORT
) fDec
,// Nachkommastellen
6299 1); // 1 Vorkommanull
6300 if (!pFormatter
->GetPreviewString(sFormatString
,
6305 SetError(errIllegalArgument
);
6309 pFormatter
->GetOutputString(fVal
, nIndex
, aStr
, &pColor
);
6316 void ScInterpreter::ScReplace()
6318 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScReplace" );
6319 if ( MustHaveParamCount( GetByte(), 4 ) )
6321 String
aNewStr( GetString() );
6322 short nCount
= (short) GetDouble();
6323 short nPos
= (short) GetDouble();
6324 String
aOldStr( GetString() );
6325 if( nPos
< 1 || nCount
< 1 )
6326 PushIllegalArgument();
6329 aOldStr
.Erase( nPos
-1, nCount
);
6330 if ( CheckStringResultLen( aOldStr
, aNewStr
) )
6331 aOldStr
.Insert( aNewStr
, nPos
-1 );
6332 PushString( aOldStr
);
6338 void ScInterpreter::ScFixed()
6340 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFixed" );
6341 BYTE nParamCount
= GetByte();
6342 if ( MustHaveParamCount( nParamCount
, 1, 3 ) )
6347 if (nParamCount
== 3)
6348 bThousand
= !GetBool(); // Param TRUE: keine Tausenderpunkte
6351 if (nParamCount
>= 2)
6353 fDec
= ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
6354 if (fDec
< -15.0 || fDec
> 15.0)
6356 PushIllegalArgument();
6362 double fVal
= GetDouble();
6365 fFac
= pow( (double)10, fDec
);
6369 fVal
= ceil(fVal
*fFac
-0.5)/fFac
;
6371 fVal
= floor(fVal
*fFac
+0.5)/fFac
;
6372 Color
* pColor
= NULL
;
6373 String sFormatString
;
6376 ULONG nIndex
= pFormatter
->GetStandardFormat(
6377 NUMBERFORMAT_NUMBER
,
6379 pFormatter
->GenerateFormat(sFormatString
,
6382 bThousand
, // mit Tausenderpunkt
6384 (USHORT
) fDec
,// Nachkommastellen
6385 1); // 1 Vorkommanull
6386 if (!pFormatter
->GetPreviewString(sFormatString
,
6391 PushIllegalArgument();
6398 void ScInterpreter::ScFind()
6400 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScFind" );
6401 BYTE nParamCount
= GetByte();
6402 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
6405 if (nParamCount
== 3)
6409 String sStr
= GetString();
6410 if( fAnz
< 1.0 || fAnz
> (double) sStr
.Len() )
6414 xub_StrLen nPos
= sStr
.Search( GetString(), (xub_StrLen
) fAnz
- 1 );
6415 if (nPos
== STRING_NOTFOUND
)
6418 PushDouble((double)(nPos
+ 1));
6424 void ScInterpreter::ScExact()
6426 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScExact" );
6427 nFuncFmtType
= NUMBERFORMAT_LOGICAL
;
6428 if ( MustHaveParamCount( GetByte(), 2 ) )
6430 String
s1( GetString() );
6431 String
s2( GetString() );
6432 PushInt( s1
== s2
);
6437 void ScInterpreter::ScLeft()
6439 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScLeft" );
6440 BYTE nParamCount
= GetByte();
6441 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6444 if (nParamCount
== 2)
6446 double nVal
= ::rtl::math::approxFloor(GetDouble());
6447 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
6449 PushIllegalArgument();
6453 n
= (xub_StrLen
) nVal
;
6457 String
aStr( GetString() );
6464 void ScInterpreter::ScRight()
6466 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRight" );
6467 BYTE nParamCount
= GetByte();
6468 if ( MustHaveParamCount( nParamCount
, 1, 2 ) )
6471 if (nParamCount
== 2)
6473 double nVal
= ::rtl::math::approxFloor(GetDouble());
6474 if ( nVal
< 0.0 || nVal
> STRING_MAXLEN
)
6476 PushIllegalArgument();
6480 n
= (xub_StrLen
) nVal
;
6484 String
aStr( GetString() );
6485 if( n
< aStr
.Len() )
6486 aStr
.Erase( 0, aStr
.Len() - n
);
6492 void ScInterpreter::ScSearch()
6494 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSearch" );
6496 BYTE nParamCount
= GetByte();
6497 if ( MustHaveParamCount( nParamCount
, 2, 3 ) )
6499 if (nParamCount
== 3)
6501 fAnz
= ::rtl::math::approxFloor(GetDouble());
6502 if (fAnz
> double(STRING_MAXLEN
))
6504 PushIllegalArgument();
6510 String sStr
= GetString();
6511 String SearchStr
= GetString();
6512 xub_StrLen nPos
= (xub_StrLen
) fAnz
- 1;
6513 xub_StrLen nEndPos
= sStr
.Len();
6514 if( nPos
>= nEndPos
)
6518 utl::SearchParam::SearchType eSearchType
=
6519 (MayBeRegExp( SearchStr
, pDok
) ?
6520 utl::SearchParam::SRCH_REGEXP
: utl::SearchParam::SRCH_NORMAL
);
6521 utl::SearchParam
sPar(SearchStr
, eSearchType
, FALSE
, FALSE
, FALSE
);
6522 utl::TextSearch
sT( sPar
, *ScGlobal::pCharClass
);
6523 int nBool
= sT
.SearchFrwrd(sStr
, &nPos
, &nEndPos
);
6527 PushDouble((double)(nPos
) + 1);
6533 void ScInterpreter::ScMid()
6535 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScMid" );
6536 if ( MustHaveParamCount( GetByte(), 3 ) )
6538 double fAnz
= ::rtl::math::approxFloor(GetDouble());
6539 double fAnfang
= ::rtl::math::approxFloor(GetDouble());
6540 const String
& rStr
= GetString();
6541 if (fAnfang
< 1.0 || fAnz
< 0.0 || fAnfang
> double(STRING_MAXLEN
) || fAnz
> double(STRING_MAXLEN
))
6542 PushIllegalArgument();
6544 PushString(rStr
.Copy( (xub_StrLen
) fAnfang
- 1, (xub_StrLen
) fAnz
));
6549 void ScInterpreter::ScText()
6551 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScText" );
6552 if ( MustHaveParamCount( GetByte(), 2 ) )
6554 String sFormatString
= GetString();
6555 double fVal
= GetDouble();
6557 Color
* pColor
= NULL
;
6558 LanguageType eCellLang
;
6559 const ScPatternAttr
* pPattern
= pDok
->GetPattern(
6560 aPos
.Col(), aPos
.Row(), aPos
.Tab() );
6562 eCellLang
= ((const SvxLanguageItem
&)
6563 pPattern
->GetItem( ATTR_LANGUAGE_FORMAT
)).GetValue();
6565 eCellLang
= ScGlobal::eLnge
;
6566 if ( !pFormatter
->GetPreviewStringGuess( sFormatString
, fVal
, aStr
,
6567 &pColor
, eCellLang
) )
6568 PushIllegalArgument();
6575 void ScInterpreter::ScSubstitute()
6577 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScSubstitute" );
6578 BYTE nParamCount
= GetByte();
6579 if ( MustHaveParamCount( nParamCount
, 3, 4 ) )
6582 if (nParamCount
== 4)
6584 double fAnz
= ::rtl::math::approxFloor(GetDouble());
6585 if( fAnz
< 1 || fAnz
> STRING_MAXLEN
)
6587 PushIllegalArgument();
6591 nAnz
= (xub_StrLen
) fAnz
;
6595 String sNewStr
= GetString();
6596 String sOldStr
= GetString();
6597 String sStr
= GetString();
6598 xub_StrLen nPos
= 0;
6599 xub_StrLen nCount
= 0;
6600 xub_StrLen nNewLen
= sNewStr
.Len();
6601 xub_StrLen nOldLen
= sOldStr
.Len();
6604 nPos
= sStr
.Search( sOldStr
, nPos
);
6605 if (nPos
!= STRING_NOTFOUND
)
6608 if( !nAnz
|| nCount
== nAnz
)
6610 sStr
.Erase(nPos
,nOldLen
);
6611 if ( CheckStringResultLen( sStr
, sNewStr
) )
6613 sStr
.Insert(sNewStr
,nPos
);
6614 nPos
= sal::static_int_cast
<xub_StrLen
>( nPos
+ nNewLen
);
6630 void ScInterpreter::ScRept()
6632 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScRept" );
6633 if ( MustHaveParamCount( GetByte(), 2 ) )
6635 double fAnz
= ::rtl::math::approxFloor(GetDouble());
6636 String
aStr( GetString() );
6638 PushIllegalArgument();
6639 else if ( fAnz
* aStr
.Len() > STRING_MAXLEN
)
6641 PushError( errStringOverflow
);
6643 else if ( fAnz
== 0.0 )
6644 PushString( EMPTY_STRING
);
6647 xub_StrLen n
= (xub_StrLen
) fAnz
;
6648 const xub_StrLen nLen
= aStr
.Len();
6650 const sal_Unicode
* const pSrc
= aStr
.GetBuffer();
6651 sal_Unicode
* pDst
= aRes
.AllocBuffer( n
* nLen
);
6654 memcpy( pDst
, pSrc
, nLen
* sizeof(sal_Unicode
) );
6663 void ScInterpreter::ScConcat()
6665 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScConcat" );
6666 BYTE nParamCount
= GetByte();
6668 while( nParamCount
-- > 0)
6670 const String
& rStr
= GetString();
6671 aRes
.Insert( rStr
, 0 );
6677 void ScInterpreter::ScErrorType()
6679 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::ScErrorType" );
6681 USHORT nOldError
= nGlobalError
;
6683 switch ( GetStackType() )
6687 FormulaTokenRef x
= PopToken();
6689 nErr
= nGlobalError
;
6692 const ScRefList
* pRefList
= static_cast<ScToken
*>(x
.get())->GetRefList();
6693 size_t n
= pRefList
->size();
6701 DoubleRefToRange( (*pRefList
)[0], aRange
);
6703 nErr
= nGlobalError
;
6707 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
6708 nErr
= pDok
->GetErrCode( aAdr
);
6710 nErr
= nGlobalError
;
6719 PopDoubleRef( aRange
);
6721 nErr
= nGlobalError
;
6725 if ( DoubleRefToPosSingleRef( aRange
, aAdr
) )
6726 nErr
= pDok
->GetErrCode( aAdr
);
6728 nErr
= nGlobalError
;
6735 PopSingleRef( aAdr
);
6737 nErr
= nGlobalError
;
6739 nErr
= pDok
->GetErrCode( aAdr
);
6744 nErr
= nGlobalError
;
6753 nGlobalError
= nOldError
;
6759 BOOL
ScInterpreter::MayBeRegExp( const String
& rStr
, const ScDocument
* pDoc
)
6761 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::MayBeRegExp" );
6762 if ( pDoc
&& !pDoc
->GetDocOptions().IsFormulaRegexEnabled() )
6764 if ( !rStr
.Len() || (rStr
.Len() == 1 && rStr
.GetChar(0) != '.') )
6765 return FALSE
; // einzelnes Metazeichen kann keine RegExp sein
6766 static const sal_Unicode cre
[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
6767 const sal_Unicode
* p1
= rStr
.GetBuffer();
6769 while ( ( c1
= *p1
++ ) != 0 )
6771 const sal_Unicode
* p2
= cre
;
6781 static bool lcl_LookupQuery( ScAddress
& o_rResultPos
, ScDocument
* pDoc
,
6782 const ScQueryParam
& rParam
, const ScQueryEntry
& rEntry
)
6784 bool bFound
= false;
6785 ScQueryCellIterator
aCellIter( pDoc
, rParam
.nTab
, rParam
, FALSE
);
6786 if (rEntry
.eOp
!= SC_EQUAL
)
6788 // range lookup <= or >=
6791 bFound
= aCellIter
.FindEqualOrSortedLastInRange( nCol
, nRow
);
6794 o_rResultPos
.SetCol( nCol
);
6795 o_rResultPos
.SetRow( nRow
);
6798 else if (aCellIter
.GetFirst())
6802 o_rResultPos
.SetCol( aCellIter
.GetCol());
6803 o_rResultPos
.SetRow( aCellIter
.GetRow());
6808 #define erDEBUG_LOOKUPCACHE 0
6809 #if erDEBUG_LOOKUPCACHE
6811 using ::std::fprintf
;
6812 using ::std::fflush
;
6813 static struct LookupCacheDebugCounter
6815 unsigned long nMiss
;
6817 LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
6818 ~LookupCacheDebugCounter()
6820 fprintf( stderr
, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
6821 nMiss
, nHit
, nHit
+nMiss
, (nMiss
>0 ? nHit
/nMiss
: 0),
6822 ((nHit
+nMiss
)>0 ? (100*nHit
)/(nHit
+nMiss
) : 0));
6825 } aLookupCacheDebugCounter
;
6828 bool ScInterpreter::LookupQueryWithCache( ScAddress
& o_rResultPos
,
6829 const ScQueryParam
& rParam
) const
6831 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger
, "sc", "Eike.Rathke@sun.com", "ScInterpreter::LookupQueryWithCache" );
6832 bool bFound
= false;
6833 const ScQueryEntry
& rEntry
= rParam
.GetEntry(0);
6834 bool bColumnsMatch
= (rParam
.nCol1
== rEntry
.nField
);
6835 DBG_ASSERT( bColumnsMatch
, "ScInterpreter::LookupQueryWithCache: columns don't match");
6837 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
6840 ScRange
aLookupRange( rParam
.nCol1
, rParam
.nRow1
, rParam
.nTab
,
6841 rParam
.nCol2
, rParam
.nRow2
, rParam
.nTab
);
6842 ScLookupCache
& rCache
= pDok
->GetLookupCache( aLookupRange
);
6843 ScLookupCache::QueryCriteria
aCriteria( rEntry
);
6844 ScLookupCache::Result eCacheResult
= rCache
.lookup( o_rResultPos
,
6846 switch (eCacheResult
)
6848 case ScLookupCache::NOT_CACHED
:
6849 case ScLookupCache::CRITERIA_DIFFERENT
:
6850 #if erDEBUG_LOOKUPCACHE
6851 ++aLookupCacheDebugCounter
.nMiss
;
6852 #if erDEBUG_LOOKUPCACHE > 1
6853 fprintf( stderr
, "miss %d,%d,%d\n", (int)aPos
.Col(), (int)aPos
.Row(), (int)aPos
.Tab());
6856 bFound
= lcl_LookupQuery( o_rResultPos
, pDok
, rParam
, rEntry
);
6857 if (eCacheResult
== ScLookupCache::NOT_CACHED
)
6858 rCache
.insert( o_rResultPos
, aCriteria
, aPos
, bFound
);
6860 case ScLookupCache::FOUND
:
6861 #if erDEBUG_LOOKUPCACHE
6862 ++aLookupCacheDebugCounter
.nHit
;
6863 #if erDEBUG_LOOKUPCACHE > 1
6864 fprintf( stderr
, "hit %d,%d,%d\n", (int)aPos
.Col(), (int)aPos
.Row(), (int)aPos
.Tab());
6869 case ScLookupCache::NOT_AVAILABLE
:
6870 ; // nothing, bFound remains FALSE