1 /**************************************************************
2 *
3 * Licensed to the Apache Software Foundation (ASF) under one
4 * or more contributor license agreements. See the NOTICE file
5 * distributed with this work for additional information
6 * regarding copyright ownership. The ASF licenses this file
7 * to you under the Apache License, Version 2.0 (the
8 * "License"); you may not use this file except in compliance
9 * with the License. You may obtain a copy of the License at
10 *
11 * http://www.apache.org/licenses/LICENSE-2.0
12 *
13 * Unless required by applicable law or agreed to in writing,
14 * software distributed under the License is distributed on an
15 * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16 * KIND, either express or implied. See the License for the
17 * specific language governing permissions and limitations
18 * under the License.
19 *
20 *************************************************************/
21
22
23
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_sc.hxx"
26
27 // INCLUDE ---------------------------------------------------------------
28
29 #include "scitems.hxx"
30 #include <editeng/langitem.hxx>
31 #include <svx/algitem.hxx>
32 #include <unotools/textsearch.hxx>
33 #include <svl/zforlist.hxx>
34 #include <svl/zformat.hxx>
35 #include <tools/urlobj.hxx>
36 #include <unotools/charclass.hxx>
37 #include <sfx2/docfile.hxx>
38 #include <sfx2/printer.hxx>
39 #include <unotools/collatorwrapper.hxx>
40 #include <unotools/transliterationwrapper.hxx>
41 #include <rtl/ustring.hxx>
42 #include <rtl/logfile.hxx>
43 #include <rtl/random.h>
44 #include <unicode/uchar.h>
45
46 #include "interpre.hxx"
47 #include "patattr.hxx"
48 #include "global.hxx"
49 #include "document.hxx"
50 #include "dociter.hxx"
51 #include "cell.hxx"
52 #include "scmatrix.hxx"
53 #include "docoptio.hxx"
54 #include "globstr.hrc"
55 #include "attrib.hxx"
56 #include "jumpmatrix.hxx"
57
58 #ifndef _COMPHELPER_PROCESSFACTORY_HXX_
59 #include <comphelper/processfactory.hxx>
60 #endif
61
62 #include <stdlib.h>
63 #include <string.h>
64 #include <math.h>
65 #include <vector>
66 #include <memory>
67 #include "cellkeytranslator.hxx"
68 #include "lookupcache.hxx"
69 #include "rangenam.hxx"
70 #include "compiler.hxx"
71 #include "externalrefmgr.hxx"
72 #include "doubleref.hxx"
73 #include "queryparam.hxx"
74
75 #include <boost/math/special_functions/acosh.hpp>
76 #include <boost/math/special_functions/asinh.hpp>
77 #include <boost/math/special_functions/atanh.hpp>
78
79 #define SC_DOUBLE_MAXVALUE 1.7e307
80
81 IMPL_FIXEDMEMPOOL_NEWDEL( ScTokenStack, 8, 4 )
82 IMPL_FIXEDMEMPOOL_NEWDEL( ScInterpreter, 32, 16 )
83
84 ScTokenStack* ScInterpreter::pGlobalStack = NULL;
85 sal_Bool ScInterpreter::bGlobalStackInUse = sal_False;
86
87 using namespace formula;
88 using ::std::auto_ptr;
89
90 //-----------------------------------------------------------------------------
91 // Funktionen
92 //-----------------------------------------------------------------------------
93
94
ScIfJump()95 void ScInterpreter::ScIfJump()
96 {
97 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIfJump" );
98 const short* pJump = pCur->GetJump();
99 short nJumpCount = pJump[ 0 ];
100 MatrixDoubleRefToMatrix();
101 switch ( GetStackType() )
102 {
103 case svMatrix:
104 {
105 ScMatrixRef pMat = PopMatrix();
106 if ( !pMat )
107 PushIllegalParameter();
108 else
109 {
110 FormulaTokenRef xNew;
111 ScTokenMatrixMap::const_iterator aMapIter;
112 // DoubleError handled by JumpMatrix
113 pMat->SetErrorInterpreter( NULL);
114 SCSIZE nCols, nRows;
115 pMat->GetDimensions( nCols, nRows );
116 if ( nCols == 0 || nRows == 0 )
117 PushIllegalArgument();
118 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
119 pCur)) != pTokenMatrixMap->end()))
120 xNew = (*aMapIter).second;
121 else
122 {
123 ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
124 for ( SCSIZE nC=0; nC < nCols; ++nC )
125 {
126 for ( SCSIZE nR=0; nR < nRows; ++nR )
127 {
128 double fVal;
129 bool bTrue;
130 ScMatValType nType = 0;
131 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
132 nType);
133 bool bIsValue = ScMatrix::IsValueType( nType);
134 if ( bIsValue )
135 {
136 fVal = pMatVal->fVal;
137 bIsValue = ::rtl::math::isFinite( fVal );
138 bTrue = bIsValue && (fVal != 0.0);
139 if ( bTrue )
140 fVal = 1.0;
141 }
142 else
143 {
144 // Treat empty and empty path as 0, but string
145 // as error.
146 bIsValue = !ScMatrix::IsRealStringType( nType);
147 bTrue = false;
148 fVal = (bIsValue ? 0.0 : CreateDoubleError( errNoValue));
149 }
150 if ( bTrue )
151 { // TRUE
152 if( nJumpCount >= 2 )
153 { // THEN path
154 pJumpMat->SetJump( nC, nR, fVal,
155 pJump[ 1 ],
156 pJump[ nJumpCount ]);
157 }
158 else
159 { // no parameter given for THEN
160 pJumpMat->SetJump( nC, nR, fVal,
161 pJump[ nJumpCount ],
162 pJump[ nJumpCount ]);
163 }
164 }
165 else
166 { // FALSE
167 if( nJumpCount == 3 && bIsValue )
168 { // ELSE path
169 pJumpMat->SetJump( nC, nR, fVal,
170 pJump[ 2 ],
171 pJump[ nJumpCount ]);
172 }
173 else
174 { // no parameter given for ELSE,
175 // or DoubleError
176 pJumpMat->SetJump( nC, nR, fVal,
177 pJump[ nJumpCount ],
178 pJump[ nJumpCount ]);
179 }
180 }
181 }
182 }
183 xNew = new ScJumpMatrixToken( pJumpMat );
184 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(pCur, xNew));
185 }
186 PushTempToken( xNew);
187 // set endpoint of path for main code line
188 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
189 }
190 }
191 break;
192 default:
193 {
194 if ( GetBool() )
195 { // TRUE
196 if( nJumpCount >= 2 )
197 { // THEN path
198 aCode.Jump( pJump[ 1 ], pJump[ nJumpCount ] );
199 }
200 else
201 { // no parameter given for THEN
202 nFuncFmtType = NUMBERFORMAT_LOGICAL;
203 PushInt(1);
204 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
205 }
206 }
207 else
208 { // FALSE
209 if( nJumpCount == 3 )
210 { // ELSE path
211 aCode.Jump( pJump[ 2 ], pJump[ nJumpCount ] );
212 }
213 else
214 { // no parameter given for ELSE
215 nFuncFmtType = NUMBERFORMAT_LOGICAL;
216 PushInt(0);
217 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
218 }
219 }
220 }
221 }
222 }
223
224
ScChoseJump()225 void ScInterpreter::ScChoseJump()
226 {
227 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChoseJump" );
228 // We have to set a jump, if there was none chosen because of an error set
229 // it to endpoint.
230 bool bHaveJump = false;
231 const short* pJump = pCur->GetJump();
232 short nJumpCount = pJump[ 0 ];
233 MatrixDoubleRefToMatrix();
234 switch ( GetStackType() )
235 {
236 case svMatrix:
237 {
238 ScMatrixRef pMat = PopMatrix();
239 if ( !pMat )
240 PushIllegalParameter();
241 else
242 {
243 FormulaTokenRef xNew;
244 ScTokenMatrixMap::const_iterator aMapIter;
245 // DoubleError handled by JumpMatrix
246 pMat->SetErrorInterpreter( NULL);
247 SCSIZE nCols, nRows;
248 pMat->GetDimensions( nCols, nRows );
249 if ( nCols == 0 || nRows == 0 )
250 PushIllegalParameter();
251 else if (pTokenMatrixMap && ((aMapIter = pTokenMatrixMap->find(
252 pCur)) != pTokenMatrixMap->end()))
253 xNew = (*aMapIter).second;
254 else
255 {
256 ScJumpMatrix* pJumpMat = new ScJumpMatrix( nCols, nRows );
257 for ( SCSIZE nC=0; nC < nCols; ++nC )
258 {
259 for ( SCSIZE nR=0; nR < nRows; ++nR )
260 {
261 double fVal;
262 ScMatValType nType;
263 const ScMatrixValue* pMatVal = pMat->Get( nC, nR,
264 nType);
265 bool bIsValue = ScMatrix::IsValueType( nType);
266 if ( bIsValue )
267 {
268 fVal = pMatVal->fVal;
269 bIsValue = ::rtl::math::isFinite( fVal );
270 if ( bIsValue )
271 {
272 fVal = ::rtl::math::approxFloor( fVal);
273 if ( (fVal < 1) || (fVal >= nJumpCount))
274 {
275 bIsValue = sal_False;
276 fVal = CreateDoubleError(
277 errIllegalArgument);
278 }
279 }
280 }
281 else
282 {
283 fVal = CreateDoubleError( errNoValue);
284 }
285 if ( bIsValue )
286 {
287 pJumpMat->SetJump( nC, nR, fVal,
288 pJump[ (short)fVal ],
289 pJump[ nJumpCount ]);
290 }
291 else
292 {
293 pJumpMat->SetJump( nC, nR, fVal,
294 pJump[ nJumpCount ],
295 pJump[ nJumpCount ]);
296 }
297 }
298 }
299 xNew = new ScJumpMatrixToken( pJumpMat );
300 GetTokenMatrixMap().insert( ScTokenMatrixMap::value_type(
301 pCur, xNew));
302 }
303 PushTempToken( xNew);
304 // set endpoint of path for main code line
305 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
306 bHaveJump = true;
307 }
308 }
309 break;
310 default:
311 {
312 double nJumpIndex = ::rtl::math::approxFloor( GetDouble() );
313 if (!nGlobalError && (nJumpIndex >= 1) && (nJumpIndex < nJumpCount))
314 {
315 aCode.Jump( pJump[ (short) nJumpIndex ], pJump[ nJumpCount ] );
316 bHaveJump = true;
317 }
318 else
319 PushIllegalArgument();
320 }
321 }
322 if (!bHaveJump)
323 aCode.Jump( pJump[ nJumpCount ], pJump[ nJumpCount ] );
324 }
325
lcl_AdjustJumpMatrix(ScJumpMatrix * pJumpM,ScMatrixRef & pResMat,SCSIZE nParmCols,SCSIZE nParmRows)326 void lcl_AdjustJumpMatrix( ScJumpMatrix* pJumpM, ScMatrixRef& pResMat, SCSIZE nParmCols, SCSIZE nParmRows )
327 {
328 SCSIZE nJumpCols, nJumpRows;
329 SCSIZE nResCols, nResRows;
330 SCSIZE nAdjustCols, nAdjustRows;
331 pJumpM->GetDimensions( nJumpCols, nJumpRows );
332 pJumpM->GetResMatDimensions( nResCols, nResRows );
333 if (( nJumpCols == 1 && nParmCols > nResCols ) ||
334 ( nJumpRows == 1 && nParmRows > nResRows ))
335 {
336 if ( nJumpCols == 1 && nJumpRows == 1 )
337 {
338 nAdjustCols = nParmCols > nResCols ? nParmCols : nResCols;
339 nAdjustRows = nParmRows > nResRows ? nParmRows : nResRows;
340 }
341 else if ( nJumpCols == 1 )
342 {
343 nAdjustCols = nParmCols;
344 nAdjustRows = nResRows;
345 }
346 else
347 {
348 nAdjustCols = nResCols;
349 nAdjustRows = nParmRows;
350 }
351 pJumpM->SetNewResMat( nAdjustCols, nAdjustRows );
352 pResMat = pJumpM->GetResultMatrix();
353 }
354 }
355
JumpMatrix(short nStackLevel)356 bool ScInterpreter::JumpMatrix( short nStackLevel )
357 {
358 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::JumpMatrix" );
359 pJumpMatrix = static_cast<ScToken*>(pStack[sp-nStackLevel])->GetJumpMatrix();
360 ScMatrixRef pResMat = pJumpMatrix->GetResultMatrix();
361 SCSIZE nC, nR;
362 if ( nStackLevel == 2 )
363 {
364 if ( aCode.HasStacked() )
365 aCode.Pop(); // pop what Jump() pushed
366 else
367 {
368 DBG_ERRORFILE( "ScInterpreter::JumpMatrix: pop goes the weasel" );
369 }
370
371 if ( !pResMat )
372 {
373 Pop();
374 SetError( errUnknownStackVariable );
375 }
376 else
377 {
378 pJumpMatrix->GetPos( nC, nR );
379 switch ( GetStackType() )
380 {
381 case svDouble:
382 {
383 double fVal = GetDouble();
384 if ( nGlobalError )
385 {
386 fVal = CreateDoubleError( nGlobalError );
387 nGlobalError = 0;
388 }
389 pResMat->PutDouble( fVal, nC, nR );
390 }
391 break;
392 case svString:
393 {
394 const String& rStr = GetString();
395 if ( nGlobalError )
396 {
397 pResMat->PutDouble( CreateDoubleError( nGlobalError),
398 nC, nR);
399 nGlobalError = 0;
400 }
401 else
402 pResMat->PutString( rStr, nC, nR );
403 }
404 break;
405 case svSingleRef:
406 {
407 ScAddress aAdr;
408 PopSingleRef( aAdr );
409 if ( nGlobalError )
410 {
411 pResMat->PutDouble( CreateDoubleError( nGlobalError),
412 nC, nR);
413 nGlobalError = 0;
414 }
415 else
416 {
417 ScBaseCell* pCell = GetCell( aAdr );
418 if (HasCellEmptyData( pCell))
419 pResMat->PutEmpty( nC, nR );
420 else if (HasCellValueData( pCell))
421 {
422 double fVal = GetCellValue( aAdr, pCell);
423 if ( nGlobalError )
424 {
425 fVal = CreateDoubleError(
426 nGlobalError);
427 nGlobalError = 0;
428 }
429 pResMat->PutDouble( fVal, nC, nR );
430 }
431 else
432 {
433 String aStr;
434 GetCellString( aStr, pCell );
435 if ( nGlobalError )
436 {
437 pResMat->PutDouble( CreateDoubleError(
438 nGlobalError), nC, nR);
439 nGlobalError = 0;
440 }
441 else
442 pResMat->PutString( aStr, nC, nR);
443 }
444 }
445 }
446 break;
447 case svDoubleRef:
448 { // upper left plus offset within matrix
449 double fVal;
450 ScRange aRange;
451 PopDoubleRef( aRange );
452 if ( nGlobalError )
453 {
454 fVal = CreateDoubleError( nGlobalError );
455 nGlobalError = 0;
456 pResMat->PutDouble( fVal, nC, nR );
457 }
458 else
459 {
460 // Do not modify the original range because we use it
461 // to adjust the size of the result matrix if necessary.
462 ScAddress aAdr( aRange.aStart);
463 sal_uLong nCol = (sal_uLong)aAdr.Col() + nC;
464 sal_uLong nRow = (sal_uLong)aAdr.Row() + nR;
465 if ((nCol > static_cast<sal_uLong>(aRange.aEnd.Col()) &&
466 aRange.aEnd.Col() != aRange.aStart.Col())
467 || (nRow > static_cast<sal_uLong>(aRange.aEnd.Row()) &&
468 aRange.aEnd.Row() != aRange.aStart.Row()))
469 {
470 fVal = CreateDoubleError( NOTAVAILABLE );
471 pResMat->PutDouble( fVal, nC, nR );
472 }
473 else
474 {
475 // Replicate column and/or row of a vector if it is
476 // one. Note that this could be a range reference
477 // that in fact consists of only one cell, e.g. A1:A1
478 if (aRange.aEnd.Col() == aRange.aStart.Col())
479 nCol = aRange.aStart.Col();
480 if (aRange.aEnd.Row() == aRange.aStart.Row())
481 nRow = aRange.aStart.Row();
482 aAdr.SetCol( static_cast<SCCOL>(nCol) );
483 aAdr.SetRow( static_cast<SCROW>(nRow) );
484 ScBaseCell* pCell = GetCell( aAdr );
485 if (HasCellEmptyData( pCell))
486 pResMat->PutEmpty( nC, nR );
487 else if (HasCellValueData( pCell))
488 {
489 double fCellVal = GetCellValue( aAdr, pCell);
490 if ( nGlobalError )
491 {
492 fCellVal = CreateDoubleError(
493 nGlobalError);
494 nGlobalError = 0;
495 }
496 pResMat->PutDouble( fCellVal, nC, nR );
497 }
498 else
499 {
500 String aStr;
501 GetCellString( aStr, pCell );
502 if ( nGlobalError )
503 {
504 pResMat->PutDouble( CreateDoubleError(
505 nGlobalError), nC, nR);
506 nGlobalError = 0;
507 }
508 else
509 pResMat->PutString( aStr, nC, nR );
510 }
511 }
512 SCSIZE nParmCols = aRange.aEnd.Col() - aRange.aStart.Col() + 1;
513 SCSIZE nParmRows = aRange.aEnd.Row() - aRange.aStart.Row() + 1;
514 lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nParmCols, nParmRows );
515 }
516 }
517 break;
518 case svMatrix:
519 { // match matrix offsets
520 double fVal;
521 ScMatrixRef pMat = PopMatrix();
522 if ( nGlobalError )
523 {
524 fVal = CreateDoubleError( nGlobalError );
525 nGlobalError = 0;
526 pResMat->PutDouble( fVal, nC, nR );
527 }
528 else if ( !pMat )
529 {
530 fVal = CreateDoubleError( errUnknownVariable );
531 pResMat->PutDouble( fVal, nC, nR );
532 }
533 else
534 {
535 SCSIZE nCols, nRows;
536 pMat->GetDimensions( nCols, nRows );
537 if ((nCols <= nC && nCols != 1) ||
538 (nRows <= nR && nRows != 1))
539 {
540 fVal = CreateDoubleError( NOTAVAILABLE );
541 pResMat->PutDouble( fVal, nC, nR );
542 }
543 else
544 {
545 if ( pMat->IsValue( nC, nR ) )
546 {
547 fVal = pMat->GetDouble( nC, nR );
548 pResMat->PutDouble( fVal, nC, nR );
549 }
550 else if ( pMat->IsEmpty( nC, nR ) )
551 pResMat->PutEmpty( nC, nR );
552 else
553 {
554 const String& rStr = pMat->GetString( nC, nR );
555 pResMat->PutString( rStr, nC, nR );
556 }
557 }
558 lcl_AdjustJumpMatrix( pJumpMatrix, pResMat, nCols, nRows );
559 }
560 }
561 break;
562 case svError:
563 {
564 PopError();
565 double fVal = CreateDoubleError( nGlobalError);
566 nGlobalError = 0;
567 pResMat->PutDouble( fVal, nC, nR );
568 }
569 break;
570 default:
571 {
572 Pop();
573 double fVal = CreateDoubleError( errIllegalArgument);
574 pResMat->PutDouble( fVal, nC, nR );
575 }
576 }
577 }
578 }
579 bool bCont = pJumpMatrix->Next( nC, nR );
580 if ( bCont )
581 {
582 double fBool;
583 short nStart, nNext, nStop;
584 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
585 while ( bCont && nStart == nNext )
586 { // push all results that have no jump path
587 if ( pResMat )
588 {
589 // a sal_False without path results in an empty path value
590 if ( fBool == 0.0 )
591 pResMat->PutEmptyPath( nC, nR );
592 else
593 pResMat->PutDouble( fBool, nC, nR );
594 }
595 bCont = pJumpMatrix->Next( nC, nR );
596 if ( bCont )
597 pJumpMatrix->GetJump( nC, nR, fBool, nStart, nNext, nStop );
598 }
599 if ( bCont && nStart != nNext )
600 {
601 const ScTokenVec* pParams = pJumpMatrix->GetJumpParameters();
602 if ( pParams )
603 {
604 for ( ScTokenVec::const_iterator i = pParams->begin();
605 i != pParams->end(); ++i )
606 {
607 // This is not the current state of the interpreter, so
608 // push without error, and elements' errors are coded into
609 // double.
610 PushWithoutError( *(*i));
611 }
612 }
613 aCode.Jump( nStart, nNext, nStop );
614 }
615 }
616 if ( !bCont )
617 { // we're done with it, throw away jump matrix, keep result
618 pJumpMatrix = NULL;
619 Pop();
620 PushMatrix( pResMat );
621 // Remove jump matrix from map and remember result matrix in case it
622 // could be reused in another path of the same condition.
623 if (pTokenMatrixMap)
624 {
625 pTokenMatrixMap->erase( pCur);
626 pTokenMatrixMap->insert( ScTokenMatrixMap::value_type( pCur,
627 pStack[sp-1]));
628 }
629 return true;
630 }
631 return false;
632 }
633
634
ScCompareOptions(ScDocument * pDoc,const ScQueryEntry & rEntry,bool bReg)635 ScCompareOptions::ScCompareOptions( ScDocument* pDoc, const ScQueryEntry& rEntry, bool bReg ) :
636 aQueryEntry(rEntry),
637 bRegEx(bReg),
638 bMatchWholeCell(pDoc->GetDocOptions().IsMatchWholeCell()),
639 bIgnoreCase(true)
640 {
641 bRegEx = (bRegEx && (aQueryEntry.eOp == SC_EQUAL || aQueryEntry.eOp == SC_NOT_EQUAL));
642 // Interpreter functions usually are case insensitive, except the simple
643 // comparison operators, for which these options aren't used. Override in
644 // struct if needed.
645 }
646
647
CompareFunc(const ScCompare & rComp,ScCompareOptions * pOptions)648 double ScInterpreter::CompareFunc( const ScCompare& rComp, ScCompareOptions* pOptions )
649 {
650 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CompareFunc" );
651 // Keep DoubleError if encountered
652 // #i40539# if bEmpty is set, bVal/nVal are uninitialized
653 if ( !rComp.bEmpty[0] && rComp.bVal[0] && !::rtl::math::isFinite( rComp.nVal[0]))
654 return rComp.nVal[0];
655 if ( !rComp.bEmpty[1] && rComp.bVal[1] && !::rtl::math::isFinite( rComp.nVal[1]))
656 return rComp.nVal[1];
657
658 size_t nStringQuery = 0; // 0:=no, 1:=0, 2:=1
659 double fRes = 0;
660 if ( rComp.bEmpty[ 0 ] )
661 {
662 if ( rComp.bEmpty[ 1 ] )
663 ; // empty cell == empty cell, fRes 0
664 else if( rComp.bVal[ 1 ] )
665 {
666 if ( !::rtl::math::approxEqual( rComp.nVal[ 1 ], 0.0 ) )
667 {
668 if ( rComp.nVal[ 1 ] < 0.0 )
669 fRes = 1; // empty cell > -x
670 else
671 fRes = -1; // empty cell < x
672 }
673 // else: empty cell == 0.0
674 }
675 else
676 {
677 if ( rComp.pVal[ 1 ]->Len() )
678 fRes = -1; // empty cell < "..."
679 // else: empty cell == ""
680 }
681 }
682 else if ( rComp.bEmpty[ 1 ] )
683 {
684 if( rComp.bVal[ 0 ] )
685 {
686 if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], 0.0 ) )
687 {
688 if ( rComp.nVal[ 0 ] < 0.0 )
689 fRes = -1; // -x < empty cell
690 else
691 fRes = 1; // x > empty cell
692 }
693 // else: empty cell == 0.0
694 }
695 else
696 {
697 if ( rComp.pVal[ 0 ]->Len() )
698 fRes = 1; // "..." > empty cell
699 // else: "" == empty cell
700 }
701 }
702 else if( rComp.bVal[ 0 ] )
703 {
704 if( rComp.bVal[ 1 ] )
705 {
706 if ( !::rtl::math::approxEqual( rComp.nVal[ 0 ], rComp.nVal[ 1 ] ) )
707 {
708 if( rComp.nVal[ 0 ] - rComp.nVal[ 1 ] < 0 )
709 fRes = -1;
710 else
711 fRes = 1;
712 }
713 }
714 else
715 {
716 fRes = -1; // number is less than string
717 nStringQuery = 2; // 1+1
718 }
719 }
720 else if( rComp.bVal[ 1 ] )
721 {
722 fRes = 1; // string is greater than number
723 nStringQuery = 1; // 0+1
724 }
725 else
726 {
727 // Both strings.
728 if (pOptions)
729 {
730 // All similar to ScTable::ValidQuery(), *rComp.pVal[1] actually
731 // is/must be identical to *rEntry.pStr, which is essential for
732 // regex to work through GetSearchTextPtr().
733 ScQueryEntry& rEntry = pOptions->aQueryEntry;
734 DBG_ASSERT( *rComp.pVal[1] == *rEntry.pStr, "ScInterpreter::CompareFunc: broken options");
735 if (pOptions->bRegEx)
736 {
737 xub_StrLen nStart = 0;
738 xub_StrLen nStop = rComp.pVal[0]->Len();
739 bool bMatch = rEntry.GetSearchTextPtr(
740 !pOptions->bIgnoreCase)->SearchFrwrd( *rComp.pVal[0],
741 &nStart, &nStop);
742 if (bMatch && pOptions->bMatchWholeCell && (nStart != 0 || nStop != rComp.pVal[0]->Len()))
743 bMatch = false; // RegEx must match entire string.
744 fRes = (bMatch ? 0 : 1);
745 }
746 else if (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL)
747 {
748 ::utl::TransliterationWrapper* pTransliteration =
749 (pOptions->bIgnoreCase ? ScGlobal::GetpTransliteration() :
750 ScGlobal::GetCaseTransliteration());
751 bool bMatch;
752 if (pOptions->bMatchWholeCell)
753 bMatch = pTransliteration->isEqual( *rComp.pVal[0], *rComp.pVal[1]);
754 else
755 {
756 String aCell( pTransliteration->transliterate(
757 *rComp.pVal[0], ScGlobal::eLnge, 0,
758 rComp.pVal[0]->Len(), NULL));
759 String aQuer( pTransliteration->transliterate(
760 *rComp.pVal[1], ScGlobal::eLnge, 0,
761 rComp.pVal[1]->Len(), NULL));
762 bMatch = (aCell.Search( aQuer ) != STRING_NOTFOUND);
763 }
764 fRes = (bMatch ? 0 : 1);
765 }
766 else if (pOptions->bIgnoreCase)
767 fRes = (double) ScGlobal::GetCollator()->compareString(
768 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
769 else
770 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
771 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
772 }
773 else if (pDok->GetDocOptions().IsIgnoreCase())
774 fRes = (double) ScGlobal::GetCollator()->compareString(
775 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
776 else
777 fRes = (double) ScGlobal::GetCaseCollator()->compareString(
778 *rComp.pVal[ 0 ], *rComp.pVal[ 1 ] );
779 }
780 if (nStringQuery && pOptions)
781 {
782 const ScQueryEntry& rEntry = pOptions->aQueryEntry;
783 if (!rEntry.bQueryByString && rEntry.pStr->Len() &&
784 (rEntry.eOp == SC_EQUAL || rEntry.eOp == SC_NOT_EQUAL))
785 {
786 // As in ScTable::ValidQuery() match a numeric string for a
787 // number query that originated from a string, e.g. in SUMIF
788 // and COUNTIF. Transliteration is not needed here.
789 bool bEqual = rComp.pVal[nStringQuery-1]->Equals( *rEntry.pStr);
790 // match => fRes=0, else fRes=1
791 fRes = (rEntry.eOp == SC_NOT_EQUAL) ? bEqual : !bEqual;
792 }
793 }
794 return fRes;
795 }
796
797
Compare()798 double ScInterpreter::Compare()
799 {
800 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::Compare" );
801 String aVal1, aVal2;
802 ScCompare aComp( &aVal1, &aVal2 );
803 for( short i = 1; i >= 0; i-- )
804 {
805 switch ( GetRawStackType() )
806 {
807 case svEmptyCell:
808 Pop();
809 aComp.bEmpty[ i ] = sal_True;
810 break;
811 case svMissing:
812 case svDouble:
813 aComp.nVal[ i ] = GetDouble();
814 aComp.bVal[ i ] = sal_True;
815 break;
816 case svString:
817 *aComp.pVal[ i ] = GetString();
818 aComp.bVal[ i ] = sal_False;
819 break;
820 case svDoubleRef :
821 case svSingleRef :
822 {
823 ScAddress aAdr;
824 if ( !PopDoubleRefOrSingleRef( aAdr ) )
825 break;
826 ScBaseCell* pCell = GetCell( aAdr );
827 if (HasCellEmptyData( pCell))
828 aComp.bEmpty[ i ] = sal_True;
829 else if (HasCellStringData( pCell))
830 {
831 GetCellString( *aComp.pVal[ i ], pCell);
832 aComp.bVal[ i ] = sal_False;
833 }
834 else
835 {
836 aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
837 aComp.bVal[ i ] = sal_True;
838 }
839 }
840 break;
841 default:
842 SetError( errIllegalParameter);
843 break;
844 }
845 }
846 if( nGlobalError )
847 return 0;
848 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
849 return CompareFunc( aComp );
850 }
851
852
CompareMat(ScCompareOptions * pOptions)853 ScMatrixRef ScInterpreter::CompareMat( ScCompareOptions* pOptions )
854 {
855 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CompareMat" );
856 String aVal1, aVal2;
857 ScCompare aComp( &aVal1, &aVal2 );
858 ScMatrixRef pMat[2];
859 ScAddress aAdr;
860 for( short i = 1; i >= 0; i-- )
861 {
862 switch (GetRawStackType())
863 {
864 case svEmptyCell:
865 Pop();
866 aComp.bEmpty[ i ] = sal_True;
867 break;
868 case svMissing:
869 case svDouble:
870 aComp.nVal[ i ] = GetDouble();
871 aComp.bVal[ i ] = sal_True;
872 break;
873 case svString:
874 *aComp.pVal[ i ] = GetString();
875 aComp.bVal[ i ] = sal_False;
876 break;
877 case svSingleRef:
878 {
879 PopSingleRef( aAdr );
880 ScBaseCell* pCell = GetCell( aAdr );
881 if (HasCellEmptyData( pCell))
882 aComp.bEmpty[ i ] = sal_True;
883 else if (HasCellStringData( pCell))
884 {
885 GetCellString( *aComp.pVal[ i ], pCell);
886 aComp.bVal[ i ] = sal_False;
887 }
888 else
889 {
890 aComp.nVal[ i ] = GetCellValue( aAdr, pCell );
891 aComp.bVal[ i ] = sal_True;
892 }
893 }
894 break;
895 case svDoubleRef:
896 case svMatrix:
897 pMat[ i ] = GetMatrix();
898 if ( !pMat[ i ] )
899 SetError( errIllegalParameter);
900 else
901 pMat[i]->SetErrorInterpreter( NULL);
902 // errors are transported as DoubleError inside matrix
903 break;
904 default:
905 SetError( errIllegalParameter);
906 break;
907 }
908 }
909 ScMatrixRef pResMat = NULL;
910 if( !nGlobalError )
911 {
912 if ( pMat[0] && pMat[1] )
913 {
914 SCSIZE nC0, nC1;
915 SCSIZE nR0, nR1;
916 pMat[0]->GetDimensions( nC0, nR0 );
917 pMat[1]->GetDimensions( nC1, nR1 );
918 SCSIZE nC = Max( nC0, nC1 );
919 SCSIZE nR = Max( nR0, nR1 );
920 pResMat = GetNewMat( nC, nR);
921 if ( !pResMat )
922 return NULL;
923 for ( SCSIZE j=0; j<nC; j++ )
924 {
925 for ( SCSIZE k=0; k<nR; k++ )
926 {
927 SCSIZE nCol = j, nRow = k;
928 if ( pMat[0]->ValidColRowOrReplicated( nCol, nRow ) &&
929 pMat[1]->ValidColRowOrReplicated( nCol, nRow ))
930 {
931 for ( short i=1; i>=0; i-- )
932 {
933 if ( pMat[i]->IsString(j,k) )
934 {
935 aComp.bVal[i] = sal_False;
936 *aComp.pVal[i] = pMat[i]->GetString(j,k);
937 aComp.bEmpty[i] = pMat[i]->IsEmpty(j,k);
938 }
939 else
940 {
941 aComp.bVal[i] = sal_True;
942 aComp.nVal[i] = pMat[i]->GetDouble(j,k);
943 aComp.bEmpty[i] = sal_False;
944 }
945 }
946 pResMat->PutDouble( CompareFunc( aComp, pOptions ), j,k );
947 }
948 else
949 pResMat->PutString( ScGlobal::GetRscString(STR_NO_VALUE), j,k );
950 }
951 }
952 }
953 else if ( pMat[0] || pMat[1] )
954 {
955 short i = ( pMat[0] ? 0 : 1);
956 SCSIZE nC, nR;
957 pMat[i]->GetDimensions( nC, nR );
958 pResMat = GetNewMat( nC, nR);
959 if ( !pResMat )
960 return NULL;
961 SCSIZE n = nC * nR;
962 for ( SCSIZE j=0; j<n; j++ )
963 {
964 if ( pMat[i]->IsValue(j) )
965 {
966 aComp.bVal[i] = sal_True;
967 aComp.nVal[i] = pMat[i]->GetDouble(j);
968 aComp.bEmpty[i] = sal_False;
969 }
970 else
971 {
972 aComp.bVal[i] = sal_False;
973 *aComp.pVal[i] = pMat[i]->GetString(j);
974 aComp.bEmpty[i] = pMat[i]->IsEmpty(j);
975 }
976 pResMat->PutDouble( CompareFunc( aComp, pOptions ), j );
977 }
978 }
979 }
980 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
981 return pResMat;
982 }
983
984
QueryMat(ScMatrix * pMat,ScCompareOptions & rOptions)985 ScMatrixRef ScInterpreter::QueryMat( ScMatrix* pMat, ScCompareOptions& rOptions )
986 {
987 short nSaveCurFmtType = nCurFmtType;
988 short nSaveFuncFmtType = nFuncFmtType;
989 PushMatrix( pMat);
990 if (rOptions.aQueryEntry.bQueryByString)
991 PushString( *rOptions.aQueryEntry.pStr);
992 else
993 PushDouble( rOptions.aQueryEntry.nVal);
994 ScMatrixRef pResultMatrix = CompareMat( &rOptions);
995 nCurFmtType = nSaveCurFmtType;
996 nFuncFmtType = nSaveFuncFmtType;
997 if (nGlobalError || !pResultMatrix)
998 {
999 SetError( errIllegalParameter);
1000 return pResultMatrix;
1001 }
1002
1003 switch (rOptions.aQueryEntry.eOp)
1004 {
1005 case SC_EQUAL:
1006 pResultMatrix->CompareEqual();
1007 break;
1008 case SC_LESS:
1009 pResultMatrix->CompareLess();
1010 break;
1011 case SC_GREATER:
1012 pResultMatrix->CompareGreater();
1013 break;
1014 case SC_LESS_EQUAL:
1015 pResultMatrix->CompareLessEqual();
1016 break;
1017 case SC_GREATER_EQUAL:
1018 pResultMatrix->CompareGreaterEqual();
1019 break;
1020 case SC_NOT_EQUAL:
1021 pResultMatrix->CompareNotEqual();
1022 break;
1023 default:
1024 SetError( errIllegalArgument);
1025 DBG_ERROR1( "ScInterpreter::QueryMat: unhandled comparison operator: %d", (int)rOptions.aQueryEntry.eOp);
1026 }
1027 return pResultMatrix;
1028 }
1029
1030
ScEqual()1031 void ScInterpreter::ScEqual()
1032 {
1033 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScEqual" );
1034 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1035 {
1036 ScMatrixRef pMat = CompareMat();
1037 if ( !pMat )
1038 PushIllegalParameter();
1039 else
1040 {
1041 pMat->CompareEqual();
1042 PushMatrix( pMat );
1043 }
1044 }
1045 else
1046 PushInt( Compare() == 0 );
1047 }
1048
1049
ScNotEqual()1050 void ScInterpreter::ScNotEqual()
1051 {
1052 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNotEqual" );
1053 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1054 {
1055 ScMatrixRef pMat = CompareMat();
1056 if ( !pMat )
1057 PushIllegalParameter();
1058 else
1059 {
1060 pMat->CompareNotEqual();
1061 PushMatrix( pMat );
1062 }
1063 }
1064 else
1065 PushInt( Compare() != 0 );
1066 }
1067
1068
ScLess()1069 void ScInterpreter::ScLess()
1070 {
1071 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLess" );
1072 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1073 {
1074 ScMatrixRef pMat = CompareMat();
1075 if ( !pMat )
1076 PushIllegalParameter();
1077 else
1078 {
1079 pMat->CompareLess();
1080 PushMatrix( pMat );
1081 }
1082 }
1083 else
1084 PushInt( Compare() < 0 );
1085 }
1086
1087
ScGreater()1088 void ScInterpreter::ScGreater()
1089 {
1090 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGreater" );
1091 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1092 {
1093 ScMatrixRef pMat = CompareMat();
1094 if ( !pMat )
1095 PushIllegalParameter();
1096 else
1097 {
1098 pMat->CompareGreater();
1099 PushMatrix( pMat );
1100 }
1101 }
1102 else
1103 PushInt( Compare() > 0 );
1104 }
1105
1106
ScLessEqual()1107 void ScInterpreter::ScLessEqual()
1108 {
1109 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLessEqual" );
1110 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1111 {
1112 ScMatrixRef pMat = CompareMat();
1113 if ( !pMat )
1114 PushIllegalParameter();
1115 else
1116 {
1117 pMat->CompareLessEqual();
1118 PushMatrix( pMat );
1119 }
1120 }
1121 else
1122 PushInt( Compare() <= 0 );
1123 }
1124
1125
ScGreaterEqual()1126 void ScInterpreter::ScGreaterEqual()
1127 {
1128 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScGreaterEqual" );
1129 if ( GetStackType(1) == svMatrix || GetStackType(2) == svMatrix )
1130 {
1131 ScMatrixRef pMat = CompareMat();
1132 if ( !pMat )
1133 PushIllegalParameter();
1134 else
1135 {
1136 pMat->CompareGreaterEqual();
1137 PushMatrix( pMat );
1138 }
1139 }
1140 else
1141 PushInt( Compare() >= 0 );
1142 }
1143
ScBitAnd()1144 void ScInterpreter::ScBitAnd() {
1145 ScBitArithmeticOps(bitOperations::BITAND);
1146 }
1147
ScBitOr()1148 void ScInterpreter::ScBitOr() {
1149 ScBitArithmeticOps(bitOperations::BITOR);
1150 }
1151
ScBitXor()1152 void ScInterpreter::ScBitXor() {
1153 ScBitArithmeticOps(bitOperations::BITXOR);
1154 }
1155
1156 /* Helper function that calculates the result in bitwise arithmetic operations helping avoid code repetition */
doOperation(sal_uInt64 val,ScInterpreter::bitOperations::bitArithmetic bitOp,sal_uInt64 & res,sal_Bool & first)1157 static void doOperation( sal_uInt64 val, ScInterpreter::bitOperations::bitArithmetic bitOp, sal_uInt64 &res, sal_Bool &first )
1158 {
1159 if ( first )
1160 {
1161 res = val;
1162 first = sal_False;
1163 }
1164 else
1165 {
1166 if (bitOp == ScInterpreter::bitOperations::BITAND)
1167 res = res & val;
1168 else if (bitOp == ScInterpreter::bitOperations::BITOR)
1169 res = res | val;
1170 else if (bitOp == ScInterpreter::bitOperations::BITXOR)
1171 res = res ^ val;
1172 }
1173 }
1174
ScBitArithmeticOps(bitOperations::bitArithmetic bitOp)1175 void ScInterpreter::ScBitArithmeticOps(bitOperations::bitArithmetic bitOp)
1176 {
1177 nFuncFmtType = NUMBERFORMAT_NUMBER;
1178 short nParamCount = GetByte();
1179 static const sal_uInt64 max_val = SAL_CONST_UINT64( 281474976710656 );
1180 static const int NUMBER_OF_ARGUMENTS = 2;
1181
1182 if ( MustHaveParamCount( nParamCount, NUMBER_OF_ARGUMENTS ) )
1183 {
1184 double *arguments = new double[NUMBER_OF_ARGUMENTS];
1185
1186 for (int i=0; i<NUMBER_OF_ARGUMENTS; i++)
1187 {
1188 arguments[i] = ::rtl::math::approxFloor( GetDouble() );
1189 if ( arguments[i] < 0 || arguments[i] > max_val )
1190 {
1191 PushIllegalArgument();
1192 }
1193 }
1194
1195 sal_uInt64 res = 0;
1196 sal_Bool first = sal_True;
1197
1198
1199 for (int i=0; i<NUMBER_OF_ARGUMENTS; i++)
1200 {
1201 doOperation( ( sal_uInt64 )arguments[i], bitOp, res, first );
1202 }
1203
1204 delete[] arguments;
1205 PushDouble( (double) res );
1206
1207 }
1208 }
1209
ScBitRShift()1210 void ScInterpreter::ScBitRShift() {
1211 ScBitShiftOps(bitOperations::BITRSHIFT);
1212 }
1213
ScBitLShift()1214 void ScInterpreter::ScBitLShift() {
1215 ScBitShiftOps(bitOperations::BITLSHIFT);
1216 }
1217
ScBitShiftOps(bitOperations::bitShift bitOp)1218 void ScInterpreter::ScBitShiftOps(bitOperations::bitShift bitOp) {
1219 if ( MustHaveParamCount( GetByte(), 2 ) )
1220 {
1221 double n = ::rtl::math::approxFloor( GetDouble() );
1222 double val = ::rtl::math::approxFloor( GetDouble() );
1223
1224 if ( val < 0 )
1225 {
1226 PushIllegalArgument();
1227 }
1228 else
1229 {
1230 double result;
1231 if (n < 0)
1232 {
1233 if (bitOp == bitOperations::BITLSHIFT)
1234 result = (sal_uInt64) val >> (sal_uInt64) -n;
1235 else
1236 result = (sal_uInt64) val << (sal_uInt64) -n;
1237 }
1238 else if( n == 0)
1239 result = val;
1240 else
1241 {
1242 if (bitOp == bitOperations::BITLSHIFT)
1243 result = (sal_uInt64) val << (sal_uInt64) n;
1244 else
1245 result = (sal_uInt64) val >> (sal_uInt64) n;
1246
1247 }
1248 PushDouble( result );
1249 }
1250 }
1251 }
1252
ScAnd()1253 void ScInterpreter::ScAnd()
1254 {
1255 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAnd" );
1256 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1257 short nParamCount = GetByte();
1258 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1259 {
1260 sal_Bool bHaveValue = sal_False;
1261 short nRes = sal_True;
1262 size_t nRefInList = 0;
1263 while( nParamCount-- > 0)
1264 {
1265 if ( !nGlobalError )
1266 {
1267 switch ( GetStackType() )
1268 {
1269 case svDouble :
1270 bHaveValue = sal_True;
1271 nRes &= ( PopDouble() != 0.0 );
1272 break;
1273 case svString :
1274 Pop();
1275 SetError( errNoValue );
1276 break;
1277 case svSingleRef :
1278 {
1279 ScAddress aAdr;
1280 PopSingleRef( aAdr );
1281 if ( !nGlobalError )
1282 {
1283 ScBaseCell* pCell = GetCell( aAdr );
1284 if ( HasCellValueData( pCell ) )
1285 {
1286 bHaveValue = sal_True;
1287 nRes &= ( GetCellValue( aAdr, pCell ) != 0.0 );
1288 }
1289 // else: Xcl setzt hier keinen Fehler
1290 }
1291 }
1292 break;
1293 case svDoubleRef:
1294 case svRefList:
1295 {
1296 ScRange aRange;
1297 PopDoubleRef( aRange, nParamCount, nRefInList);
1298 if ( !nGlobalError )
1299 {
1300 double fVal;
1301 sal_uInt16 nErr = 0;
1302 ScValueIterator aValIter( pDok, aRange );
1303 if ( aValIter.GetFirst( fVal, nErr ) )
1304 {
1305 bHaveValue = sal_True;
1306 do
1307 {
1308 nRes &= ( fVal != 0.0 );
1309 } while ( (nErr == 0) &&
1310 aValIter.GetNext( fVal, nErr ) );
1311 }
1312 SetError( nErr );
1313 }
1314 }
1315 break;
1316 case svMatrix:
1317 {
1318 ScMatrixRef pMat = GetMatrix();
1319 if ( pMat )
1320 {
1321 bHaveValue = sal_True;
1322 double fVal = pMat->And();
1323 sal_uInt16 nErr = GetDoubleErrorValue( fVal );
1324 if ( nErr )
1325 {
1326 SetError( nErr );
1327 nRes = sal_False;
1328 }
1329 else
1330 nRes &= (fVal != 0.0);
1331 }
1332 // else: GetMatrix did set errIllegalParameter
1333 }
1334 break;
1335 default:
1336 Pop();
1337 SetError( errIllegalParameter);
1338 }
1339 }
1340 else
1341 Pop();
1342 }
1343 if ( bHaveValue )
1344 PushInt( nRes );
1345 else
1346 PushNoValue();
1347 }
1348 }
1349
1350
ScOr()1351 void ScInterpreter::ScOr()
1352 {
1353 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOr" );
1354 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1355 short nParamCount = GetByte();
1356 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1357 {
1358 sal_Bool bHaveValue = sal_False;
1359 short nRes = sal_False;
1360 size_t nRefInList = 0;
1361 while( nParamCount-- > 0)
1362 {
1363 if ( !nGlobalError )
1364 {
1365 switch ( GetStackType() )
1366 {
1367 case svDouble :
1368 bHaveValue = sal_True;
1369 nRes |= ( PopDouble() != 0.0 );
1370 break;
1371 case svString :
1372 Pop();
1373 SetError( errNoValue );
1374 break;
1375 case svSingleRef :
1376 {
1377 ScAddress aAdr;
1378 PopSingleRef( aAdr );
1379 if ( !nGlobalError )
1380 {
1381 ScBaseCell* pCell = GetCell( aAdr );
1382 if ( HasCellValueData( pCell ) )
1383 {
1384 bHaveValue = sal_True;
1385 nRes |= ( GetCellValue( aAdr, pCell ) != 0.0 );
1386 }
1387 // else: Xcl setzt hier keinen Fehler
1388 }
1389 }
1390 break;
1391 case svDoubleRef:
1392 case svRefList:
1393 {
1394 ScRange aRange;
1395 PopDoubleRef( aRange, nParamCount, nRefInList);
1396 if ( !nGlobalError )
1397 {
1398 double fVal;
1399 sal_uInt16 nErr = 0;
1400 ScValueIterator aValIter( pDok, aRange );
1401 if ( aValIter.GetFirst( fVal, nErr ) )
1402 {
1403 bHaveValue = sal_True;
1404 do
1405 {
1406 nRes |= ( fVal != 0.0 );
1407 } while ( (nErr == 0) &&
1408 aValIter.GetNext( fVal, nErr ) );
1409 }
1410 SetError( nErr );
1411 }
1412 }
1413 break;
1414 case svMatrix:
1415 {
1416 bHaveValue = sal_True;
1417 ScMatrixRef pMat = GetMatrix();
1418 if ( pMat )
1419 {
1420 bHaveValue = sal_True;
1421 double fVal = pMat->Or();
1422 sal_uInt16 nErr = GetDoubleErrorValue( fVal );
1423 if ( nErr )
1424 {
1425 SetError( nErr );
1426 nRes = sal_False;
1427 }
1428 else
1429 nRes |= (fVal != 0.0);
1430 }
1431 // else: GetMatrix did set errIllegalParameter
1432 }
1433 break;
1434 default:
1435 Pop();
1436 SetError( errIllegalParameter);
1437 }
1438 }
1439 else
1440 Pop();
1441 }
1442 if ( bHaveValue )
1443 PushInt( nRes );
1444 else
1445 PushNoValue();
1446 }
1447 }
1448
ScXor()1449 void ScInterpreter::ScXor()
1450 {
1451 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScXor" );
1452 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1453 short nParamCount = GetByte();
1454 if ( MustHaveParamCountMin( nParamCount, 1 ) )
1455 {
1456 bool bHaveValue = false;
1457 short nRes = 0;
1458 size_t nRefInList = 0;
1459 while( nParamCount-- > 0)
1460 {
1461 if ( !nGlobalError )
1462 {
1463 switch ( GetStackType() )
1464 {
1465 case svDouble :
1466 bHaveValue = true;
1467 nRes ^= ( PopDouble() != 0.0 );
1468 break;
1469 case svString :
1470 Pop();
1471 SetError( errNoValue );
1472 break;
1473 case svSingleRef :
1474 {
1475 ScAddress aAdr;
1476 PopSingleRef( aAdr );
1477 if ( !nGlobalError )
1478 {
1479 ScBaseCell* pCell = GetCell( aAdr );
1480 if ( HasCellValueData( pCell ) )
1481 {
1482 bHaveValue = true;
1483 nRes ^= ( GetCellValue( aAdr, pCell ) != 0.0 );
1484 }
1485 /* TODO: set error? Excel doesn't have XOR, but
1486 * doesn't set an error in this case for AND and
1487 * OR. */
1488 }
1489 }
1490 break;
1491 case svDoubleRef:
1492 case svRefList:
1493 {
1494 ScRange aRange;
1495 PopDoubleRef( aRange, nParamCount, nRefInList);
1496 if ( !nGlobalError )
1497 {
1498 double fVal;
1499 sal_uInt16 nErr = 0;
1500 ScValueIterator aValIter( pDok, aRange );
1501 if ( aValIter.GetFirst( fVal, nErr ) )
1502 {
1503 bHaveValue = true;
1504 do
1505 {
1506 nRes ^= ( fVal != 0.0 );
1507 } while ( (nErr == 0) &&
1508 aValIter.GetNext( fVal, nErr ) );
1509 }
1510 SetError( nErr );
1511 }
1512 }
1513 break;
1514 case svMatrix:
1515 {
1516 bHaveValue = true;
1517 ScMatrixRef pMat = GetMatrix();
1518 if ( pMat )
1519 {
1520 bHaveValue = true;
1521 double fVal = pMat->Xor();
1522 sal_uInt16 nErr = GetDoubleErrorValue( fVal );
1523 if ( nErr )
1524 {
1525 SetError( nErr );
1526 nRes = 0;
1527 }
1528 else
1529 nRes ^= (fVal != 0.0);
1530 }
1531 // else: GetMatrix did set errIllegalParameter
1532 }
1533 break;
1534 default:
1535 Pop();
1536 SetError( errIllegalParameter);
1537 }
1538 }
1539 else
1540 Pop();
1541 }
1542 if ( bHaveValue )
1543 PushInt( nRes );
1544 else
1545 PushNoValue();
1546 }
1547 }
1548
1549
ScNeg()1550 void ScInterpreter::ScNeg()
1551 {
1552 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNeg" );
1553 // Simple negation doesn't change current format type to number, keep
1554 // current type.
1555 nFuncFmtType = nCurFmtType;
1556 switch ( GetStackType() )
1557 {
1558 case svMatrix :
1559 {
1560 ScMatrixRef pMat = GetMatrix();
1561 if ( !pMat )
1562 PushIllegalParameter();
1563 else
1564 {
1565 SCSIZE nC, nR;
1566 pMat->GetDimensions( nC, nR );
1567 ScMatrixRef pResMat = GetNewMat( nC, nR);
1568 if ( !pResMat )
1569 PushIllegalArgument();
1570 else
1571 {
1572 SCSIZE nCount = nC * nR;
1573 for ( SCSIZE j=0; j<nCount; ++j )
1574 {
1575 if ( pMat->IsValueOrEmpty(j) )
1576 pResMat->PutDouble( -pMat->GetDouble(j), j );
1577 else
1578 pResMat->PutString(
1579 ScGlobal::GetRscString( STR_NO_VALUE ), j );
1580 }
1581 PushMatrix( pResMat );
1582 }
1583 }
1584 }
1585 break;
1586 default:
1587 PushDouble( -GetDouble() );
1588 }
1589 }
1590
1591
ScPercentSign()1592 void ScInterpreter::ScPercentSign()
1593 {
1594 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPercentSign" );
1595 nFuncFmtType = NUMBERFORMAT_PERCENT;
1596 const FormulaToken* pSaveCur = pCur;
1597 sal_uInt8 nSavePar = cPar;
1598 PushInt( 100 );
1599 cPar = 2;
1600 FormulaByteToken aDivOp( ocDiv, cPar );
1601 pCur = &aDivOp;
1602 ScDiv();
1603 pCur = pSaveCur;
1604 cPar = nSavePar;
1605 }
1606
1607
ScNot()1608 void ScInterpreter::ScNot()
1609 {
1610 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScNot" );
1611 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1612 switch ( GetStackType() )
1613 {
1614 case svMatrix :
1615 {
1616 ScMatrixRef pMat = GetMatrix();
1617 if ( !pMat )
1618 PushIllegalParameter();
1619 else
1620 {
1621 SCSIZE nC, nR;
1622 pMat->GetDimensions( nC, nR );
1623 ScMatrixRef pResMat = GetNewMat( nC, nR);
1624 if ( !pResMat )
1625 PushIllegalArgument();
1626 else
1627 {
1628 SCSIZE nCount = nC * nR;
1629 for ( SCSIZE j=0; j<nCount; ++j )
1630 {
1631 if ( pMat->IsValueOrEmpty(j) )
1632 pResMat->PutDouble( (pMat->GetDouble(j) == 0.0), j );
1633 else
1634 pResMat->PutString(
1635 ScGlobal::GetRscString( STR_NO_VALUE ), j );
1636 }
1637 PushMatrix( pResMat );
1638 }
1639 }
1640 }
1641 break;
1642 default:
1643 PushInt( GetDouble() == 0.0 );
1644 }
1645 }
1646
1647
ScPi()1648 void ScInterpreter::ScPi()
1649 {
1650 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPi" );
1651 PushDouble(F_PI);
1652 }
1653
1654 #define SCRANDOMQ_SIZE 4194304
1655 static sal_uInt32 nScRandomQ[SCRANDOMQ_SIZE], nScCarry = 0;
1656
1657 // Multiply with Carry
1658 sal_uInt32
b32MWC(void)1659 b32MWC(void)
1660 {
1661 sal_uInt32 t, x;
1662 static int j = (SCRANDOMQ_SIZE - 1);
1663
1664 j = (j + 1) & (SCRANDOMQ_SIZE - 1);
1665 x = nScRandomQ[j];
1666 t = (x << 28) + nScCarry;
1667 nScCarry = (x >> 4) - (t < x);
1668 return (nScRandomQ[j] = t - x);
1669 }
1670
1671 // Congruential
1672 #define CNG ( ScCNG = 69069 * ScCNG + 13579 )
1673 // Xorshift
1674 #define XS ( ScXS ^= (ScXS << 13), ScXS ^= (ScXS >> 17), ScXS ^= (ScXS << 5) )
1675
1676 #define KISS (b32MWC() + CNG + XS)
1677
ScRandom()1678 void ScInterpreter::ScRandom()
1679 {
1680 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "pfg", "ScInterpreter::ScRandom" );
1681
1682 static sal_Bool SqSeeded = sal_False;
1683 static sal_uInt32 ScCNG, ScXS = 362436069;
1684
1685 // Seeding for the PRNG
1686 if (SqSeeded == sal_False) {
1687 rtlRandomPool aPool = rtl_random_createPool();
1688 rtl_random_getBytes(aPool, &ScCNG, sizeof(ScCNG));
1689 rtl_random_getBytes(aPool, &nScRandomQ,
1690 sizeof(nScRandomQ[0]) * SCRANDOMQ_SIZE);
1691 rtl_random_destroyPool(aPool);
1692 SqSeeded = sal_True;
1693 }
1694 PushDouble(static_cast<double>(KISS) / SAL_MAX_UINT32);
1695 }
1696
ScTrue()1697 void ScInterpreter::ScTrue()
1698 {
1699 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrue" );
1700 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1701 PushInt(1);
1702 }
1703
1704
ScFalse()1705 void ScInterpreter::ScFalse()
1706 {
1707 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFalse" );
1708 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1709 PushInt(0);
1710 }
1711
1712
ScDeg()1713 void ScInterpreter::ScDeg()
1714 {
1715 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDeg" );
1716 PushDouble((GetDouble() / F_PI) * 180.0);
1717 }
1718
1719
ScRad()1720 void ScInterpreter::ScRad()
1721 {
1722 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRad" );
1723 PushDouble(GetDouble() * (F_PI / 180));
1724 }
1725
1726
ScSin()1727 void ScInterpreter::ScSin()
1728 {
1729 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSin" );
1730 PushDouble(::rtl::math::sin(GetDouble()));
1731 }
1732
1733
ScCos()1734 void ScInterpreter::ScCos()
1735 {
1736 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCos" );
1737 PushDouble(::rtl::math::cos(GetDouble()));
1738 }
1739
1740
ScTan()1741 void ScInterpreter::ScTan()
1742 {
1743 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTan" );
1744 PushDouble(::rtl::math::tan(GetDouble()));
1745 }
1746
1747
ScCot()1748 void ScInterpreter::ScCot()
1749 {
1750 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCot" );
1751 PushDouble(1.0 / ::rtl::math::tan(GetDouble()));
1752 }
1753
1754
ScArcSin()1755 void ScInterpreter::ScArcSin()
1756 {
1757 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcSin" );
1758 PushDouble(asin(GetDouble()));
1759 }
1760
1761
ScArcCos()1762 void ScInterpreter::ScArcCos()
1763 {
1764 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCos" );
1765 PushDouble(acos(GetDouble()));
1766 }
1767
1768
ScArcTan()1769 void ScInterpreter::ScArcTan()
1770 {
1771 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTan" );
1772 PushDouble(atan(GetDouble()));
1773 }
1774
1775
ScArcCot()1776 void ScInterpreter::ScArcCot()
1777 {
1778 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCot" );
1779 PushDouble((F_PI2) - atan(GetDouble()));
1780 }
1781
1782
ScSinHyp()1783 void ScInterpreter::ScSinHyp()
1784 {
1785 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSinHyp" );
1786 PushDouble(sinh(GetDouble()));
1787 }
1788
1789
ScCosHyp()1790 void ScInterpreter::ScCosHyp()
1791 {
1792 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCosHyp" );
1793 PushDouble(cosh(GetDouble()));
1794 }
1795
1796
ScTanHyp()1797 void ScInterpreter::ScTanHyp()
1798 {
1799 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTanHyp" );
1800 PushDouble(tanh(GetDouble()));
1801 }
1802
1803
ScCotHyp()1804 void ScInterpreter::ScCotHyp()
1805 {
1806 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCotHyp" );
1807 PushDouble(1.0 / tanh(GetDouble()));
1808 }
1809
1810
ScArcSinHyp()1811 void ScInterpreter::ScArcSinHyp()
1812 {
1813 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcSinHyp" );
1814 PushDouble( ::boost::math::asinh( GetDouble()));
1815 }
1816
ScArcCosHyp()1817 void ScInterpreter::ScArcCosHyp()
1818 {
1819 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCosHyp" );
1820 double fVal = GetDouble();
1821 if (fVal < 1.0)
1822 PushIllegalArgument();
1823 else
1824 PushDouble( ::boost::math::acosh( fVal));
1825 }
1826
ScArcTanHyp()1827 void ScInterpreter::ScArcTanHyp()
1828 {
1829 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcTanHyp" );
1830 double fVal = GetDouble();
1831 if (fabs(fVal) >= 1.0)
1832 PushIllegalArgument();
1833 else
1834 PushDouble( ::boost::math::atanh( fVal));
1835 }
1836
1837
ScArcCotHyp()1838 void ScInterpreter::ScArcCotHyp()
1839 {
1840 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScArcCotHyp" );
1841 double nVal = GetDouble();
1842 if (fabs(nVal) <= 1.0)
1843 PushIllegalArgument();
1844 else
1845 PushDouble(0.5 * log((nVal + 1.0) / (nVal - 1.0)));
1846 }
1847
ScCosecant()1848 void ScInterpreter::ScCosecant()
1849 {
1850 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "regina", "ScInterpreter::ScCosecant" );
1851 PushDouble(1.0 / ::rtl::math::sin(GetDouble()));
1852 }
1853
ScSecant()1854 void ScInterpreter::ScSecant()
1855 {
1856 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "regina", "ScInterpreter::ScSecant" );
1857 PushDouble(1.0 / ::rtl::math::cos(GetDouble()));
1858 }
1859
ScCosecantHyp()1860 void ScInterpreter::ScCosecantHyp()
1861 {
1862 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "regina", "ScInterpreter::ScCosecantHyp" );
1863 PushDouble(1.0 / sinh(GetDouble()));
1864 }
1865
ScSecantHyp()1866 void ScInterpreter::ScSecantHyp()
1867 {
1868 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "regina", "ScInterpreter::ScSecantHyp" );
1869 PushDouble(1.0 / cosh(GetDouble()));
1870 }
1871
1872
ScExp()1873 void ScInterpreter::ScExp()
1874 {
1875 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExp" );
1876 PushDouble(exp(GetDouble()));
1877 }
1878
1879
ScSqrt()1880 void ScInterpreter::ScSqrt()
1881 {
1882 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSqrt" );
1883 double fVal = GetDouble();
1884 if (fVal >= 0.0)
1885 PushDouble(sqrt(fVal));
1886 else
1887 PushIllegalArgument();
1888 }
1889
1890
ScIsEmpty()1891 void ScInterpreter::ScIsEmpty()
1892 {
1893 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsEmpty" );
1894 short nRes = 0;
1895 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1896 switch ( GetRawStackType() )
1897 {
1898 case svEmptyCell:
1899 {
1900 FormulaTokenRef p = PopToken();
1901 if (!static_cast<const ScEmptyCellToken*>(p.get())->IsInherited())
1902 nRes = 1;
1903 }
1904 break;
1905 case svDoubleRef :
1906 case svSingleRef :
1907 {
1908 ScAddress aAdr;
1909 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1910 break;
1911 // NOTE: this could test also on inherited emptiness, but then the
1912 // cell tested wouldn't be empty. Must correspond with
1913 // ScCountEmptyCells().
1914 // if (HasCellEmptyData( GetCell( aAdr)))
1915 CellType eCellType = GetCellType( GetCell( aAdr ) );
1916 if((eCellType == CELLTYPE_NONE) || (eCellType == CELLTYPE_NOTE))
1917 nRes = 1;
1918 }
1919 break;
1920 case svMatrix:
1921 {
1922 ScMatrixRef pMat = PopMatrix();
1923 if ( !pMat )
1924 ; // nothing
1925 else if ( !pJumpMatrix )
1926 nRes = pMat->IsEmpty( 0 );
1927 else
1928 {
1929 SCSIZE nCols, nRows, nC, nR;
1930 pMat->GetDimensions( nCols, nRows);
1931 pJumpMatrix->GetPos( nC, nR);
1932 if ( nC < nCols && nR < nRows )
1933 nRes = pMat->IsEmpty( nC, nR);
1934 // else: sal_False, not empty (which is what Xcl does)
1935 }
1936 }
1937 break;
1938 default:
1939 Pop();
1940 }
1941 nGlobalError = 0;
1942 PushInt( nRes );
1943 }
1944
1945
IsString()1946 short ScInterpreter::IsString()
1947 {
1948 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsString" );
1949 nFuncFmtType = NUMBERFORMAT_LOGICAL;
1950 short nRes = 0;
1951 switch ( GetRawStackType() )
1952 {
1953 case svString:
1954 Pop();
1955 nRes = 1;
1956 break;
1957 case svDoubleRef :
1958 case svSingleRef :
1959 {
1960 ScAddress aAdr;
1961 if ( !PopDoubleRefOrSingleRef( aAdr ) )
1962 break;
1963 ScBaseCell* pCell = GetCell( aAdr );
1964 if (GetCellErrCode( pCell ) == 0)
1965 {
1966 switch ( GetCellType( pCell ) )
1967 {
1968 case CELLTYPE_STRING :
1969 case CELLTYPE_EDIT :
1970 nRes = 1;
1971 break;
1972 case CELLTYPE_FORMULA :
1973 nRes = !((ScFormulaCell*)pCell)->IsValue() &&
1974 !((ScFormulaCell*)pCell)->IsEmpty();
1975 break;
1976 default:
1977 ; // nothing
1978 }
1979 }
1980 }
1981 break;
1982 case svMatrix:
1983 {
1984 ScMatrixRef pMat = PopMatrix();
1985 if ( !pMat )
1986 ; // nothing
1987 else if ( !pJumpMatrix )
1988 nRes = pMat->IsString(0) && !pMat->IsEmpty(0);
1989 else
1990 {
1991 SCSIZE nCols, nRows, nC, nR;
1992 pMat->GetDimensions( nCols, nRows);
1993 pJumpMatrix->GetPos( nC, nR);
1994 if ( nC < nCols && nR < nRows )
1995 nRes = pMat->IsString( nC, nR) && !pMat->IsEmpty( nC, nR);
1996 }
1997 }
1998 break;
1999 default:
2000 Pop();
2001 }
2002 nGlobalError = 0;
2003 return nRes;
2004 }
2005
2006
ScIsString()2007 void ScInterpreter::ScIsString()
2008 {
2009 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsString" );
2010 PushInt( IsString() );
2011 }
2012
2013
ScIsNonString()2014 void ScInterpreter::ScIsNonString()
2015 {
2016 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsNonString" );
2017 PushInt( !IsString() );
2018 }
2019
2020
ScIsLogical()2021 void ScInterpreter::ScIsLogical()
2022 {
2023 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsLogical" );
2024 short nRes = 0;
2025 switch ( GetStackType() )
2026 {
2027 case svDoubleRef :
2028 case svSingleRef :
2029 {
2030 ScAddress aAdr;
2031 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2032 break;
2033 ScBaseCell* pCell = GetCell( aAdr );
2034 if (GetCellErrCode( pCell ) == 0)
2035 {
2036 if (HasCellValueData(pCell))
2037 {
2038 sal_uLong nFormat = GetCellNumberFormat( aAdr, pCell );
2039 nRes = ( pFormatter->GetType(nFormat)
2040 == NUMBERFORMAT_LOGICAL);
2041 }
2042 }
2043 }
2044 break;
2045 case svMatrix:
2046 // TODO: we don't have type information for arrays except
2047 // numerical/string.
2048 // Fall thru
2049 default:
2050 PopError();
2051 if ( !nGlobalError )
2052 nRes = ( nCurFmtType == NUMBERFORMAT_LOGICAL );
2053 }
2054 nCurFmtType = nFuncFmtType = NUMBERFORMAT_LOGICAL;
2055 nGlobalError = 0;
2056 PushInt( nRes );
2057 }
2058
2059
ScType()2060 void ScInterpreter::ScType()
2061 {
2062 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScType" );
2063 short nType = 0;
2064 switch ( GetStackType() )
2065 {
2066 case svDoubleRef :
2067 case svSingleRef :
2068 {
2069 ScAddress aAdr;
2070 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2071 break;
2072 ScBaseCell* pCell = GetCell( aAdr );
2073 if (GetCellErrCode( pCell ) == 0)
2074 {
2075 switch ( GetCellType( pCell ) )
2076 {
2077 // NOTE: this is Xcl nonsense!
2078 case CELLTYPE_NOTE :
2079 nType = 1; // empty cell is value (0)
2080 break;
2081 case CELLTYPE_STRING :
2082 case CELLTYPE_EDIT :
2083 nType = 2;
2084 break;
2085 case CELLTYPE_VALUE :
2086 {
2087 sal_uLong nFormat = GetCellNumberFormat( aAdr, pCell );
2088 if (pFormatter->GetType(nFormat)
2089 == NUMBERFORMAT_LOGICAL)
2090 nType = 4;
2091 else
2092 nType = 1;
2093 }
2094 break;
2095 case CELLTYPE_FORMULA :
2096 nType = 8;
2097 break;
2098 default:
2099 PushIllegalArgument();
2100 }
2101 }
2102 else
2103 nType = 16;
2104 }
2105 break;
2106 case svString:
2107 PopError();
2108 if ( nGlobalError )
2109 {
2110 nType = 16;
2111 nGlobalError = 0;
2112 }
2113 else
2114 nType = 2;
2115 break;
2116 case svMatrix:
2117 PopMatrix();
2118 if ( nGlobalError )
2119 {
2120 nType = 16;
2121 nGlobalError = 0;
2122 }
2123 else
2124 nType = 64;
2125 // we could return the type of one element if in JumpMatrix or
2126 // ForceArray mode, but Xcl doesn't ...
2127 break;
2128 default:
2129 PopError();
2130 if ( nGlobalError )
2131 {
2132 nType = 16;
2133 nGlobalError = 0;
2134 }
2135 else
2136 nType = 1;
2137 }
2138 PushInt( nType );
2139 }
2140
2141
lcl_FormatHasNegColor(const SvNumberformat * pFormat)2142 inline sal_Bool lcl_FormatHasNegColor( const SvNumberformat* pFormat )
2143 {
2144 return pFormat && pFormat->GetColor( 1 );
2145 }
2146
2147
lcl_FormatHasOpenPar(const SvNumberformat * pFormat)2148 inline sal_Bool lcl_FormatHasOpenPar( const SvNumberformat* pFormat )
2149 {
2150 return pFormat && (pFormat->GetFormatstring().Search( '(' ) != STRING_NOTFOUND);
2151 }
2152
2153
ScCell()2154 void ScInterpreter::ScCell()
2155 { // ATTRIBUTE ; [REF]
2156 sal_uInt8 nParamCount = GetByte();
2157 if( MustHaveParamCount( nParamCount, 1, 2 ) )
2158 {
2159 ScAddress aCellPos( aPos );
2160 sal_Bool bError = sal_False;
2161 if( nParamCount == 2 )
2162 bError = !PopDoubleRefOrSingleRef( aCellPos );
2163 String aInfoType( GetString() );
2164 if( bError || nGlobalError )
2165 PushIllegalParameter();
2166 else
2167 {
2168 String aFuncResult;
2169 ScBaseCell* pCell = GetCell( aCellPos );
2170
2171 ScCellKeywordTranslator::transKeyword(aInfoType, ScGlobal::GetLocale(), ocCell);
2172
2173 // *** ADDRESS INFO ***
2174 if( aInfoType.EqualsAscii( "COL" ) )
2175 { // column number (1-based)
2176 PushInt( aCellPos.Col() + 1 );
2177 }
2178 else if( aInfoType.EqualsAscii( "ROW" ) )
2179 { // row number (1-based)
2180 PushInt( aCellPos.Row() + 1 );
2181 }
2182 else if( aInfoType.EqualsAscii( "SHEET" ) )
2183 { // table number (1-based)
2184 PushInt( aCellPos.Tab() + 1 );
2185 }
2186 else if( aInfoType.EqualsAscii( "ADDRESS" ) )
2187 { // address formatted as [['FILENAME'#]$TABLE.]$COL$ROW
2188 sal_uInt16 nFlags = (aCellPos.Tab() == aPos.Tab()) ? (SCA_ABS) : (SCA_ABS_3D);
2189 aCellPos.Format( aFuncResult, nFlags, pDok, pDok->GetAddressConvention() );
2190 PushString( aFuncResult );
2191 }
2192 else if( aInfoType.EqualsAscii( "FILENAME" ) )
2193 { // file name and table name: 'FILENAME'#$TABLE
2194 SCTAB nTab = aCellPos.Tab();
2195 if( nTab < pDok->GetTableCount() )
2196 {
2197 if( pDok->GetLinkMode( nTab ) == SC_LINK_VALUE )
2198 pDok->GetName( nTab, aFuncResult );
2199 else
2200 {
2201 SfxObjectShell* pShell = pDok->GetDocumentShell();
2202 if( pShell && pShell->GetMedium() )
2203 {
2204 aFuncResult = (sal_Unicode) '\'';
2205 const INetURLObject& rURLObj = pShell->GetMedium()->GetURLObject();
2206 aFuncResult += String( rURLObj.GetMainURL( INetURLObject::DECODE_UNAMBIGUOUS ) );
2207 aFuncResult.AppendAscii( "'#$" );
2208 String aTabName;
2209 pDok->GetName( nTab, aTabName );
2210 aFuncResult += aTabName;
2211 }
2212 }
2213 }
2214 PushString( aFuncResult );
2215 }
2216 else if( aInfoType.EqualsAscii( "COORD" ) )
2217 { // address, lotus 1-2-3 formatted: $TABLE:$COL$ROW
2218 // Yes, passing tab as col is intentional!
2219 ScAddress( static_cast<SCCOL>(aCellPos.Tab()), 0, 0 ).Format(
2220 aFuncResult, (SCA_COL_ABSOLUTE|SCA_VALID_COL), NULL, pDok->GetAddressConvention() );
2221 aFuncResult += ':';
2222 String aCellStr;
2223 aCellPos.Format( aCellStr, (SCA_COL_ABSOLUTE|SCA_VALID_COL|SCA_ROW_ABSOLUTE|SCA_VALID_ROW),
2224 NULL, pDok->GetAddressConvention() );
2225 aFuncResult += aCellStr;
2226 PushString( aFuncResult );
2227 }
2228
2229 // *** CELL PROPERTIES ***
2230 else if( aInfoType.EqualsAscii( "CONTENTS" ) )
2231 { // contents of the cell, no formatting
2232 if( pCell && pCell->HasStringData() )
2233 {
2234 GetCellString( aFuncResult, pCell );
2235 PushString( aFuncResult );
2236 }
2237 else
2238 PushDouble( GetCellValue( aCellPos, pCell ) );
2239 }
2240 else if( aInfoType.EqualsAscii( "TYPE" ) )
2241 { // b = blank; l = string (label); v = otherwise (value)
2242 if( HasCellStringData( pCell ) )
2243 aFuncResult = 'l';
2244 else
2245 aFuncResult = HasCellValueData( pCell ) ? 'v' : 'b';
2246 PushString( aFuncResult );
2247 }
2248 else if( aInfoType.EqualsAscii( "WIDTH" ) )
2249 { // column width (rounded off as count of zero characters in standard font and size)
2250 Printer* pPrinter = pDok->GetPrinter();
2251 MapMode aOldMode( pPrinter->GetMapMode() );
2252 Font aOldFont( pPrinter->GetFont() );
2253 Font aDefFont;
2254
2255 pPrinter->SetMapMode( MAP_TWIP );
2256 // font color doesn't matter here
2257 pDok->GetDefPattern()->GetFont( aDefFont, SC_AUTOCOL_BLACK, pPrinter );
2258 pPrinter->SetFont( aDefFont );
2259 long nZeroWidth = pPrinter->GetTextWidth( String( '0' ) );
2260 pPrinter->SetFont( aOldFont );
2261 pPrinter->SetMapMode( aOldMode );
2262 int nZeroCount = (int)(pDok->GetColWidth( aCellPos.Col(), aCellPos.Tab() ) / nZeroWidth);
2263 PushInt( nZeroCount );
2264 }
2265 else if( aInfoType.EqualsAscii( "PREFIX" ) )
2266 { // ' = left; " = right; ^ = centered
2267 if( HasCellStringData( pCell ) )
2268 {
2269 const SvxHorJustifyItem* pJustAttr = (const SvxHorJustifyItem*)
2270 pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_HOR_JUSTIFY );
2271 switch( pJustAttr->GetValue() )
2272 {
2273 case SVX_HOR_JUSTIFY_STANDARD:
2274 case SVX_HOR_JUSTIFY_LEFT:
2275 case SVX_HOR_JUSTIFY_BLOCK: aFuncResult = '\''; break;
2276 case SVX_HOR_JUSTIFY_CENTER: aFuncResult = '^'; break;
2277 case SVX_HOR_JUSTIFY_RIGHT: aFuncResult = '"'; break;
2278 case SVX_HOR_JUSTIFY_REPEAT: aFuncResult = '\\'; break;
2279 }
2280 }
2281 PushString( aFuncResult );
2282 }
2283 else if( aInfoType.EqualsAscii( "PROTECT" ) )
2284 { // 1 = cell locked
2285 const ScProtectionAttr* pProtAttr = (const ScProtectionAttr*)
2286 pDok->GetAttr( aCellPos.Col(), aCellPos.Row(), aCellPos.Tab(), ATTR_PROTECTION );
2287 PushInt( pProtAttr->GetProtection() ? 1 : 0 );
2288 }
2289
2290 // *** FORMATTING ***
2291 else if( aInfoType.EqualsAscii( "FORMAT" ) )
2292 { // specific format code for standard formats
2293 sal_uLong nFormat = pDok->GetNumberFormat( aCellPos );
2294 sal_Bool bAppendPrec = sal_True;
2295 sal_uInt16 nPrec, nLeading;
2296 sal_Bool bThousand, bIsRed;
2297 pFormatter->GetFormatSpecialInfo( nFormat, bThousand, bIsRed, nPrec, nLeading );
2298
2299 switch( pFormatter->GetType( nFormat ) )
2300 {
2301 case NUMBERFORMAT_NUMBER: aFuncResult = (bThousand ? ',' : 'F'); break;
2302 case NUMBERFORMAT_CURRENCY: aFuncResult = 'C'; break;
2303 case NUMBERFORMAT_SCIENTIFIC: aFuncResult = 'S'; break;
2304 case NUMBERFORMAT_PERCENT: aFuncResult = 'P'; break;
2305 default:
2306 {
2307 bAppendPrec = sal_False;
2308 switch( pFormatter->GetIndexTableOffset( nFormat ) )
2309 {
2310 case NF_DATE_SYSTEM_SHORT:
2311 case NF_DATE_SYS_DMMMYY:
2312 case NF_DATE_SYS_DDMMYY:
2313 case NF_DATE_SYS_DDMMYYYY:
2314 case NF_DATE_SYS_DMMMYYYY:
2315 case NF_DATE_DIN_DMMMYYYY:
2316 case NF_DATE_SYS_DMMMMYYYY:
2317 case NF_DATE_DIN_DMMMMYYYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D1" ) ); break;
2318 case NF_DATE_SYS_DDMMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D2" ) ); break;
2319 case NF_DATE_SYS_MMYY: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D3" ) ); break;
2320 case NF_DATETIME_SYSTEM_SHORT_HHMM:
2321 case NF_DATETIME_SYS_DDMMYYYY_HHMMSS:
2322 aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D4" ) ); break;
2323 case NF_DATE_DIN_MMDD: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D5" ) ); break;
2324 case NF_TIME_HHMMSSAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D6" ) ); break;
2325 case NF_TIME_HHMMAMPM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D7" ) ); break;
2326 case NF_TIME_HHMMSS: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D8" ) ); break;
2327 case NF_TIME_HHMM: aFuncResult.AssignAscii( RTL_CONSTASCII_STRINGPARAM( "D9" ) ); break;
2328 default: aFuncResult = 'G';
2329 }
2330 }
2331 }
2332 if( bAppendPrec )
2333 aFuncResult += String::CreateFromInt32( nPrec );
2334 const SvNumberformat* pFormat = pFormatter->GetEntry( nFormat );
2335 if( lcl_FormatHasNegColor( pFormat ) )
2336 aFuncResult += '-';
2337 if( lcl_FormatHasOpenPar( pFormat ) )
2338 aFuncResult.AppendAscii( RTL_CONSTASCII_STRINGPARAM( "()" ) );
2339 PushString( aFuncResult );
2340 }
2341 else if( aInfoType.EqualsAscii( "COLOR" ) )
2342 { // 1 = negative values are colored, otherwise 0
2343 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
2344 PushInt( lcl_FormatHasNegColor( pFormat ) ? 1 : 0 );
2345 }
2346 else if( aInfoType.EqualsAscii( "PARENTHESES" ) )
2347 { // 1 = format string contains a '(' character, otherwise 0
2348 const SvNumberformat* pFormat = pFormatter->GetEntry( pDok->GetNumberFormat( aCellPos ) );
2349 PushInt( lcl_FormatHasOpenPar( pFormat ) ? 1 : 0 );
2350 }
2351 else
2352 PushIllegalArgument();
2353 }
2354 }
2355 }
2356
2357
ScIsRef()2358 void ScInterpreter::ScIsRef()
2359 {
2360 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCell" );
2361 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2362 short nRes = 0;
2363 switch ( GetStackType() )
2364 {
2365 case svSingleRef :
2366 {
2367 ScAddress aAdr;
2368 PopSingleRef( aAdr );
2369 if ( !nGlobalError )
2370 nRes = 1;
2371 }
2372 break;
2373 case svDoubleRef :
2374 {
2375 ScRange aRange;
2376 PopDoubleRef( aRange );
2377 if ( !nGlobalError )
2378 nRes = 1;
2379 }
2380 break;
2381 case svRefList :
2382 {
2383 FormulaTokenRef x = PopToken();
2384 if ( !nGlobalError )
2385 nRes = !static_cast<ScToken*>(x.get())->GetRefList()->empty();
2386 }
2387 break;
2388 default:
2389 Pop();
2390 }
2391 nGlobalError = 0;
2392 PushInt( nRes );
2393 }
2394
2395
ScIsValue()2396 void ScInterpreter::ScIsValue()
2397 {
2398 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsValue" );
2399 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2400 short nRes = 0;
2401 switch ( GetRawStackType() )
2402 {
2403 case svDouble:
2404 Pop();
2405 nRes = 1;
2406 break;
2407 case svDoubleRef :
2408 case svSingleRef :
2409 {
2410 ScAddress aAdr;
2411 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2412 break;
2413 ScBaseCell* pCell = GetCell( aAdr );
2414 if (GetCellErrCode( pCell ) == 0)
2415 {
2416 switch ( GetCellType( pCell ) )
2417 {
2418 case CELLTYPE_VALUE :
2419 nRes = 1;
2420 break;
2421 case CELLTYPE_FORMULA :
2422 nRes = ((ScFormulaCell*)pCell)->IsValue() &&
2423 !((ScFormulaCell*)pCell)->IsEmpty();
2424 break;
2425 default:
2426 ; // nothing
2427 }
2428 }
2429 }
2430 break;
2431 case svMatrix:
2432 {
2433 ScMatrixRef pMat = PopMatrix();
2434 if ( !pMat )
2435 ; // nothing
2436 else if ( !pJumpMatrix )
2437 {
2438 if (pMat->GetErrorIfNotString( 0 ) == 0)
2439 nRes = pMat->IsValue( 0 );
2440 }
2441 else
2442 {
2443 SCSIZE nCols, nRows, nC, nR;
2444 pMat->GetDimensions( nCols, nRows);
2445 pJumpMatrix->GetPos( nC, nR);
2446 if ( nC < nCols && nR < nRows )
2447 if (pMat->GetErrorIfNotString( nC, nR) == 0)
2448 nRes = pMat->IsValue( nC, nR);
2449 }
2450 }
2451 break;
2452 default:
2453 Pop();
2454 }
2455 nGlobalError = 0;
2456 PushInt( nRes );
2457 }
2458
2459
ScIsFormula()2460 void ScInterpreter::ScIsFormula()
2461 {
2462 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsFormula" );
2463 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2464 short nRes = 0;
2465 switch ( GetStackType() )
2466 {
2467 case svDoubleRef :
2468 case svSingleRef :
2469 {
2470 ScAddress aAdr;
2471 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2472 break;
2473 nRes = (GetCellType( GetCell( aAdr ) ) == CELLTYPE_FORMULA);
2474 }
2475 break;
2476 default:
2477 Pop();
2478 }
2479 nGlobalError = 0;
2480 PushInt( nRes );
2481 }
2482
2483
ScFormula()2484 void ScInterpreter::ScFormula()
2485 {
2486 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFormula" );
2487 String aFormula;
2488 switch ( GetStackType() )
2489 {
2490 case svDoubleRef :
2491 case svSingleRef :
2492 {
2493 ScAddress aAdr;
2494 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2495 break;
2496 ScBaseCell* pCell = GetCell( aAdr );
2497 switch ( GetCellType( pCell ) )
2498 {
2499 case CELLTYPE_FORMULA :
2500 ((ScFormulaCell*)pCell)->GetFormula( aFormula );
2501 break;
2502 default:
2503 SetError( NOTAVAILABLE );
2504 }
2505 }
2506 break;
2507 default:
2508 Pop();
2509 SetError( NOTAVAILABLE );
2510 }
2511 PushString( aFormula );
2512 }
2513
2514
2515
ScIsNV()2516 void ScInterpreter::ScIsNV()
2517 {
2518 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsNV" );
2519 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2520 short nRes = 0;
2521 switch ( GetStackType() )
2522 {
2523 case svDoubleRef :
2524 case svSingleRef :
2525 {
2526 ScAddress aAdr;
2527 PopDoubleRefOrSingleRef( aAdr );
2528 if ( nGlobalError == NOTAVAILABLE )
2529 nRes = 1;
2530 else
2531 {
2532 ScBaseCell* pCell = GetCell( aAdr );
2533 sal_uInt16 nErr = GetCellErrCode( pCell );
2534 nRes = (nErr == NOTAVAILABLE);
2535 }
2536 }
2537 break;
2538 case svMatrix:
2539 {
2540 ScMatrixRef pMat = PopMatrix();
2541 if ( !pMat )
2542 ; // nothing
2543 else if ( !pJumpMatrix )
2544 nRes = (pMat->GetErrorIfNotString( 0 ) == NOTAVAILABLE);
2545 else
2546 {
2547 SCSIZE nCols, nRows, nC, nR;
2548 pMat->GetDimensions( nCols, nRows);
2549 pJumpMatrix->GetPos( nC, nR);
2550 if ( nC < nCols && nR < nRows )
2551 nRes = (pMat->GetErrorIfNotString( nC, nR) == NOTAVAILABLE);
2552 }
2553 }
2554 break;
2555 default:
2556 PopError();
2557 if ( nGlobalError == NOTAVAILABLE )
2558 nRes = 1;
2559 }
2560 nGlobalError = 0;
2561 PushInt( nRes );
2562 }
2563
2564
ScIsErr()2565 void ScInterpreter::ScIsErr()
2566 {
2567 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsErr" );
2568 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2569 short nRes = 0;
2570 switch ( GetStackType() )
2571 {
2572 case svDoubleRef :
2573 case svSingleRef :
2574 {
2575 ScAddress aAdr;
2576 PopDoubleRefOrSingleRef( aAdr );
2577 if ( nGlobalError && nGlobalError != NOTAVAILABLE )
2578 nRes = 1;
2579 else
2580 {
2581 ScBaseCell* pCell = GetCell( aAdr );
2582 sal_uInt16 nErr = GetCellErrCode( pCell );
2583 nRes = (nErr && nErr != NOTAVAILABLE);
2584 }
2585 }
2586 break;
2587 case svMatrix:
2588 {
2589 ScMatrixRef pMat = PopMatrix();
2590 if ( nGlobalError || !pMat )
2591 nRes = ((nGlobalError && nGlobalError != NOTAVAILABLE) || !pMat);
2592 else if ( !pJumpMatrix )
2593 {
2594 sal_uInt16 nErr = pMat->GetErrorIfNotString( 0 );
2595 nRes = (nErr && nErr != NOTAVAILABLE);
2596 }
2597 else
2598 {
2599 SCSIZE nCols, nRows, nC, nR;
2600 pMat->GetDimensions( nCols, nRows);
2601 pJumpMatrix->GetPos( nC, nR);
2602 if ( nC < nCols && nR < nRows )
2603 {
2604 sal_uInt16 nErr = pMat->GetErrorIfNotString( nC, nR);
2605 nRes = (nErr && nErr != NOTAVAILABLE);
2606 }
2607 }
2608 }
2609 break;
2610 default:
2611 PopError();
2612 if ( nGlobalError && nGlobalError != NOTAVAILABLE )
2613 nRes = 1;
2614 }
2615 nGlobalError = 0;
2616 PushInt( nRes );
2617 }
2618
2619
ScIsError()2620 void ScInterpreter::ScIsError()
2621 {
2622 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsError" );
2623 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2624 short nRes = 0;
2625 switch ( GetStackType() )
2626 {
2627 case svDoubleRef :
2628 case svSingleRef :
2629 {
2630 ScAddress aAdr;
2631 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2632 {
2633 nRes = 1;
2634 break;
2635 }
2636 if ( nGlobalError )
2637 nRes = 1;
2638 else
2639 {
2640 ScBaseCell* pCell = GetCell( aAdr );
2641 nRes = (GetCellErrCode( pCell ) != 0);
2642 }
2643 }
2644 break;
2645 case svMatrix:
2646 {
2647 ScMatrixRef pMat = PopMatrix();
2648 if ( nGlobalError || !pMat )
2649 nRes = 1;
2650 else if ( !pJumpMatrix )
2651 nRes = (pMat->GetErrorIfNotString( 0 ) != 0);
2652 else
2653 {
2654 SCSIZE nCols, nRows, nC, nR;
2655 pMat->GetDimensions( nCols, nRows);
2656 pJumpMatrix->GetPos( nC, nR);
2657 if ( nC < nCols && nR < nRows )
2658 nRes = (pMat->GetErrorIfNotString( nC, nR) != 0);
2659 }
2660 }
2661 break;
2662 default:
2663 PopError();
2664 if ( nGlobalError )
2665 nRes = 1;
2666 }
2667 nGlobalError = 0;
2668 PushInt( nRes );
2669 }
2670
2671
IsEven()2672 short ScInterpreter::IsEven()
2673 {
2674 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IsEven" );
2675 nFuncFmtType = NUMBERFORMAT_LOGICAL;
2676 short nRes = 0;
2677 double fVal = 0.0;
2678 switch ( GetStackType() )
2679 {
2680 case svDoubleRef :
2681 case svSingleRef :
2682 {
2683 ScAddress aAdr;
2684 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2685 break;
2686 ScBaseCell* pCell = GetCell( aAdr );
2687 sal_uInt16 nErr = GetCellErrCode( pCell );
2688 if (nErr != 0)
2689 SetError(nErr);
2690 else
2691 {
2692 switch ( GetCellType( pCell ) )
2693 {
2694 case CELLTYPE_VALUE :
2695 fVal = GetCellValue( aAdr, pCell );
2696 nRes = 1;
2697 break;
2698 case CELLTYPE_FORMULA :
2699 if( ((ScFormulaCell*)pCell)->IsValue() )
2700 {
2701 fVal = GetCellValue( aAdr, pCell );
2702 nRes = 1;
2703 }
2704 break;
2705 default:
2706 ; // nothing
2707 }
2708 }
2709 }
2710 break;
2711 case svDouble:
2712 {
2713 fVal = PopDouble();
2714 nRes = 1;
2715 }
2716 break;
2717 case svMatrix:
2718 {
2719 ScMatrixRef pMat = PopMatrix();
2720 if ( !pMat )
2721 ; // nothing
2722 else if ( !pJumpMatrix )
2723 {
2724 nRes = pMat->IsValue( 0 );
2725 if ( nRes )
2726 fVal = pMat->GetDouble( 0 );
2727 }
2728 else
2729 {
2730 SCSIZE nCols, nRows, nC, nR;
2731 pMat->GetDimensions( nCols, nRows);
2732 pJumpMatrix->GetPos( nC, nR);
2733 if ( nC < nCols && nR < nRows )
2734 {
2735 nRes = pMat->IsValue( nC, nR);
2736 if ( nRes )
2737 fVal = pMat->GetDouble( nC, nR);
2738 }
2739 else
2740 SetError( errNoValue);
2741 }
2742 }
2743 break;
2744 default:
2745 ; // nothing
2746 }
2747 if ( !nRes )
2748 SetError( errIllegalParameter);
2749 else
2750 nRes = ( fmod( ::rtl::math::approxFloor( fabs( fVal ) ), 2.0 ) < 0.5 );
2751 return nRes;
2752 }
2753
2754
ScIsEven()2755 void ScInterpreter::ScIsEven()
2756 {
2757 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsEven" );
2758 PushInt( IsEven() );
2759 }
2760
2761
ScIsOdd()2762 void ScInterpreter::ScIsOdd()
2763 {
2764 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIsOdd" );
2765 PushInt( !IsEven() );
2766 }
2767
2768
ScN()2769 void ScInterpreter::ScN()
2770 {
2771 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScN" );
2772 sal_uInt16 nErr = nGlobalError;
2773 nGlobalError = 0;
2774 // Temporarily override the ConvertStringToValue() error for
2775 // GetCellValue() / GetCellValueOrZero()
2776 sal_uInt16 nSErr = mnStringNoValueError;
2777 mnStringNoValueError = errCellNoValue;
2778 double fVal = GetDouble();
2779 mnStringNoValueError = nSErr;
2780 if ( nGlobalError == NOTAVAILABLE || nGlobalError == errCellNoValue )
2781 nGlobalError = 0; // N(#NA) and N("text") are ok
2782 if ( !nGlobalError && nErr != NOTAVAILABLE )
2783 nGlobalError = nErr;
2784 PushDouble( fVal );
2785 }
2786
2787
ScTrim()2788 void ScInterpreter::ScTrim()
2789 { // trimmt nicht nur sondern schnibbelt auch doppelte raus!
2790 String aVal( GetString() );
2791 aVal.EraseLeadingChars();
2792 aVal.EraseTrailingChars();
2793 String aStr;
2794 register const sal_Unicode* p = aVal.GetBuffer();
2795 register const sal_Unicode* const pEnd = p + aVal.Len();
2796 while ( p < pEnd )
2797 {
2798 if ( *p != ' ' || p[-1] != ' ' ) // erster kann kein ' ' sein, -1 ist also ok
2799 aStr += *p;
2800 p++;
2801 }
2802 PushString( aStr );
2803 }
2804
2805
ScUpper()2806 void ScInterpreter::ScUpper()
2807 {
2808 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTrim" );
2809 String aString = GetString();
2810 ScGlobal::pCharClass->toUpper(aString);
2811 PushString(aString);
2812 }
2813
2814
ScPropper()2815 void ScInterpreter::ScPropper()
2816 {
2817 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScPropper" );
2818 //2do: what to do with I18N-CJK ?!?
2819 String aStr( GetString() );
2820 const xub_StrLen nLen = aStr.Len();
2821 // #i82487# don't try to write to empty string's BufferAccess
2822 // (would crash now that the empty string is const)
2823 if ( nLen > 0 )
2824 {
2825 String aUpr( ScGlobal::pCharClass->upper( aStr ) );
2826 String aLwr( ScGlobal::pCharClass->lower( aStr ) );
2827 register sal_Unicode* pStr = aStr.GetBufferAccess();
2828 const sal_Unicode* pUpr = aUpr.GetBuffer();
2829 const sal_Unicode* pLwr = aLwr.GetBuffer();
2830 *pStr = *pUpr;
2831 String aTmpStr( 'x' );
2832 xub_StrLen nPos = 1;
2833 while( nPos < nLen )
2834 {
2835 aTmpStr.SetChar( 0, pStr[nPos-1] );
2836 if ( !ScGlobal::pCharClass->isLetter( aTmpStr, 0 ) )
2837 pStr[nPos] = pUpr[nPos];
2838 else
2839 pStr[nPos] = pLwr[nPos];
2840 nPos++;
2841 }
2842 aStr.ReleaseBufferAccess( nLen );
2843 }
2844 PushString( aStr );
2845 }
2846
2847
ScLower()2848 void ScInterpreter::ScLower()
2849 {
2850 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLower" );
2851 String aString( GetString() );
2852 ScGlobal::pCharClass->toLower(aString);
2853 PushString(aString);
2854 }
2855
2856
ScLen()2857 void ScInterpreter::ScLen()
2858 {
2859 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLen" );
2860 String aStr( GetString() );
2861 PushDouble( aStr.Len() );
2862 }
2863
2864
ScT()2865 void ScInterpreter::ScT()
2866 {
2867 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScT" );
2868 switch ( GetStackType() )
2869 {
2870 case svDoubleRef :
2871 case svSingleRef :
2872 {
2873 ScAddress aAdr;
2874 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2875 {
2876 PushInt(0);
2877 return ;
2878 }
2879 sal_Bool bValue = sal_False;
2880 ScBaseCell* pCell = GetCell( aAdr );
2881 if ( GetCellErrCode( pCell ) == 0 )
2882 {
2883 switch ( GetCellType( pCell ) )
2884 {
2885 case CELLTYPE_VALUE :
2886 bValue = sal_True;
2887 break;
2888 case CELLTYPE_FORMULA :
2889 bValue = ((ScFormulaCell*)pCell)->IsValue();
2890 break;
2891 default:
2892 ; // nothing
2893 }
2894 }
2895 if ( bValue )
2896 PushString( EMPTY_STRING );
2897 else
2898 {
2899 // wie GetString()
2900 GetCellString( aTempStr, pCell );
2901 PushString( aTempStr );
2902 }
2903 }
2904 break;
2905 case svDouble :
2906 {
2907 PopError();
2908 PushString( EMPTY_STRING );
2909 }
2910 break;
2911 case svString :
2912 ; // leave on stack
2913 break;
2914 default :
2915 PushError( errUnknownOpCode);
2916 }
2917 }
2918
2919
ScValue()2920 void ScInterpreter::ScValue()
2921 {
2922 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScValue" );
2923 String aInputString;
2924 double fVal;
2925
2926 switch ( GetRawStackType() )
2927 {
2928 case svMissing:
2929 case svEmptyCell:
2930 Pop();
2931 PushInt(0);
2932 return;
2933 case svDouble:
2934 return; // leave on stack
2935 //break;
2936
2937 case svSingleRef:
2938 case svDoubleRef:
2939 {
2940 ScAddress aAdr;
2941 if ( !PopDoubleRefOrSingleRef( aAdr ) )
2942 {
2943 PushInt(0);
2944 return;
2945 }
2946 ScBaseCell* pCell = GetCell( aAdr );
2947 if ( pCell && pCell->HasStringData() )
2948 GetCellString( aInputString, pCell );
2949 else if ( pCell && pCell->HasValueData() )
2950 {
2951 PushDouble( GetCellValue(aAdr, pCell) );
2952 return;
2953 }
2954 else
2955 {
2956 PushDouble(0.0);
2957 return;
2958 }
2959 }
2960 break;
2961 case svMatrix:
2962 {
2963 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal,
2964 aInputString);
2965 switch (nType)
2966 {
2967 case SC_MATVAL_EMPTY:
2968 fVal = 0.0;
2969 // fallthru
2970 case SC_MATVAL_VALUE:
2971 case SC_MATVAL_BOOLEAN:
2972 PushDouble( fVal);
2973 return;
2974 //break;
2975 case SC_MATVAL_STRING:
2976 // evaluated below
2977 break;
2978 default:
2979 PushIllegalArgument();
2980 }
2981 }
2982 break;
2983 default:
2984 aInputString = GetString();
2985 break;
2986 }
2987
2988 sal_uInt32 nFIndex = 0; // 0 for default locale
2989 if (pFormatter->IsNumberFormat(aInputString, nFIndex, fVal))
2990 PushDouble(fVal);
2991 else
2992 PushIllegalArgument();
2993 }
2994
2995
2996 //2do: this should be a proper unicode string method
lcl_ScInterpreter_IsPrintable(sal_Unicode c)2997 inline sal_Bool lcl_ScInterpreter_IsPrintable( sal_Unicode c )
2998 {
2999 return 0x20 <= c && c != 0x7f;
3000 }
3001
ScClean()3002 void ScInterpreter::ScClean()
3003 {
3004 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScClean" );
3005 String aStr( GetString() );
3006 for ( xub_StrLen i = 0; i < aStr.Len(); i++ )
3007 {
3008 if ( !lcl_ScInterpreter_IsPrintable( aStr.GetChar( i ) ) )
3009 aStr.Erase(i,1);
3010 }
3011 PushString(aStr);
3012 }
3013
3014
ScCode()3015 void ScInterpreter::ScCode()
3016 {
3017 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCode" );
3018 //2do: make it full range unicode?
3019 const String& rStr = GetString();
3020 PushInt( (sal_uChar) ByteString::ConvertFromUnicode( rStr.GetChar(0), gsl_getSystemTextEncoding() ) );
3021 }
3022
3023
ScChar()3024 void ScInterpreter::ScChar()
3025 {
3026 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScChar" );
3027 //2do: make it full range unicode?
3028 double fVal = GetDouble();
3029 if (fVal < 0.0 || fVal >= 256.0)
3030 PushIllegalArgument();
3031 else
3032 {
3033 String aStr( '0' );
3034 aStr.SetChar( 0, ByteString::ConvertToUnicode( (sal_Char) fVal, gsl_getSystemTextEncoding() ) );
3035 PushString( aStr );
3036 }
3037 }
3038
3039
3040 /* #i70213# fullwidth/halfwidth conversion provided by
3041 * Takashi Nakamoto <bluedwarf@ooo>
3042 * erAck: added Excel compatibility conversions as seen in issue's test case. */
3043
lcl_convertIntoHalfWidth(const::rtl::OUString & rStr)3044 static ::rtl::OUString lcl_convertIntoHalfWidth( const ::rtl::OUString & rStr )
3045 {
3046 static bool bFirstASCCall = true;
3047 static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
3048
3049 if( bFirstASCCall )
3050 {
3051 aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "FULLWIDTH_HALFWIDTH_LIKE_ASC" ), LANGUAGE_SYSTEM );
3052 bFirstASCCall = false;
3053 }
3054
3055 return aTrans.transliterate( rStr, 0, sal_uInt16( rStr.getLength() ), NULL );
3056 }
3057
3058
lcl_convertIntoFullWidth(const::rtl::OUString & rStr)3059 static ::rtl::OUString lcl_convertIntoFullWidth( const ::rtl::OUString & rStr )
3060 {
3061 static bool bFirstJISCall = true;
3062 static utl::TransliterationWrapper aTrans( ::comphelper::getProcessServiceFactory(), 0 );
3063
3064 if( bFirstJISCall )
3065 {
3066 aTrans.loadModuleByImplName( ::rtl::OUString::createFromAscii( "HALFWIDTH_FULLWIDTH_LIKE_JIS" ), LANGUAGE_SYSTEM );
3067 bFirstJISCall = false;
3068 }
3069
3070 return aTrans.transliterate( rStr, 0, sal_uInt16( rStr.getLength() ), NULL );
3071 }
3072
3073
3074 /* ODFF:
3075 * Summary: Converts half-width to full-width ASCII and katakana characters.
3076 * Semantics: Conversion is done for half-width ASCII and katakana characters,
3077 * other characters are simply copied from T to the result. This is the
3078 * complementary function to ASC.
3079 * For references regarding halfwidth and fullwidth characters see
3080 * http://www.unicode.org/reports/tr11/
3081 * http://www.unicode.org/charts/charindex2.html#H
3082 * http://www.unicode.org/charts/charindex2.html#F
3083 */
ScJis()3084 void ScInterpreter::ScJis()
3085 {
3086 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScJis" );
3087 if (MustHaveParamCount( GetByte(), 1))
3088 PushString( lcl_convertIntoFullWidth( GetString()));
3089 }
3090
3091
3092 /* ODFF:
3093 * Summary: Converts full-width to half-width ASCII and katakana characters.
3094 * Semantics: Conversion is done for full-width ASCII and katakana characters,
3095 * other characters are simply copied from T to the result. This is the
3096 * complementary function to JIS.
3097 */
ScAsc()3098 void ScInterpreter::ScAsc()
3099 {
3100 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAsc" );
3101 if (MustHaveParamCount( GetByte(), 1))
3102 PushString( lcl_convertIntoHalfWidth( GetString()));
3103 }
3104
ScUnicode()3105 void ScInterpreter::ScUnicode()
3106 {
3107 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnicode" );
3108 if ( MustHaveParamCount( GetByte(), 1 ) )
3109 {
3110 const rtl::OUString& rStr = GetString();
3111 if (rStr.getLength() <= 0)
3112 PushIllegalParameter();
3113 else
3114 {
3115 sal_Int32 i = 0;
3116 PushDouble( rStr.iterateCodePoints(&i) );
3117 }
3118 }
3119 }
3120
ScUnichar()3121 void ScInterpreter::ScUnichar()
3122 {
3123 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScUnichar" );
3124 if ( MustHaveParamCount( GetByte(), 1 ) )
3125 {
3126 double dVal = ::rtl::math::approxFloor( GetDouble() );
3127 if ((dVal < 0x000000) || (dVal > 0x10FFFF))
3128 PushIllegalArgument();
3129 else
3130 {
3131 sal_uInt32 nCodePoint = static_cast<sal_uInt32>( dVal );
3132 rtl::OUString aStr( &nCodePoint, 1 );
3133 PushString( aStr );
3134 }
3135 }
3136 }
3137
3138
ScMin(sal_Bool bTextAsZero)3139 void ScInterpreter::ScMin( sal_Bool bTextAsZero )
3140 {
3141 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMin" );
3142 short nParamCount = GetByte();
3143 if (!MustHaveParamCountMin( nParamCount, 1))
3144 return;
3145 double nMin = ::std::numeric_limits<double>::max();
3146 double nVal = 0.0;
3147 ScAddress aAdr;
3148 ScRange aRange;
3149 size_t nRefInList = 0;
3150 while (nParamCount-- > 0)
3151 {
3152 switch (GetStackType())
3153 {
3154 case svDouble :
3155 {
3156 nVal = GetDouble();
3157 if (nMin > nVal) nMin = nVal;
3158 nFuncFmtType = NUMBERFORMAT_NUMBER;
3159 }
3160 break;
3161 case svSingleRef :
3162 {
3163 PopSingleRef( aAdr );
3164 ScBaseCell* pCell = GetCell( aAdr );
3165 if (HasCellValueData(pCell))
3166 {
3167 nVal = GetCellValue( aAdr, pCell );
3168 CurFmtToFuncFmt();
3169 if (nMin > nVal) nMin = nVal;
3170 }
3171 else if ( bTextAsZero && HasCellStringData( pCell ) )
3172 {
3173 if ( nMin > 0.0 )
3174 nMin = 0.0;
3175 }
3176 }
3177 break;
3178 case svDoubleRef :
3179 case svRefList :
3180 {
3181 sal_uInt16 nErr = 0;
3182 PopDoubleRef( aRange, nParamCount, nRefInList);
3183 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3184 if (aValIter.GetFirst(nVal, nErr))
3185 {
3186 if (nMin > nVal)
3187 nMin = nVal;
3188 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
3189 while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
3190 {
3191 if (nMin > nVal)
3192 nMin = nVal;
3193 }
3194 SetError(nErr);
3195 }
3196 }
3197 break;
3198 case svMatrix :
3199 {
3200 ScMatrixRef pMat = PopMatrix();
3201 if (pMat)
3202 {
3203 SCSIZE nC, nR;
3204 nFuncFmtType = NUMBERFORMAT_NUMBER;
3205 pMat->GetDimensions(nC, nR);
3206 if (pMat->IsNumeric())
3207 {
3208 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3209 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3210 {
3211 nVal = pMat->GetDouble(nMatCol,nMatRow);
3212 if (nMin > nVal) nMin = nVal;
3213 }
3214 }
3215 else
3216 {
3217 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3218 {
3219 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3220 {
3221 if (!pMat->IsString(nMatCol,nMatRow))
3222 {
3223 nVal = pMat->GetDouble(nMatCol,nMatRow);
3224 if (nMin > nVal) nMin = nVal;
3225 }
3226 else if ( bTextAsZero )
3227 {
3228 if ( nMin > 0.0 )
3229 nMin = 0.0;
3230 }
3231 }
3232 }
3233 }
3234 }
3235 }
3236 break;
3237 case svString :
3238 {
3239 Pop();
3240 if ( bTextAsZero )
3241 {
3242 if ( nMin > 0.0 )
3243 nMin = 0.0;
3244 }
3245 else
3246 SetError(errIllegalParameter);
3247 }
3248 break;
3249 default :
3250 Pop();
3251 SetError(errIllegalParameter);
3252 }
3253 }
3254 if ( nVal < nMin )
3255 PushDouble(0.0);
3256 else
3257 PushDouble(nMin);
3258 }
3259
ScMax(sal_Bool bTextAsZero)3260 void ScInterpreter::ScMax( sal_Bool bTextAsZero )
3261 {
3262 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMax" );
3263 short nParamCount = GetByte();
3264 if (!MustHaveParamCountMin( nParamCount, 1))
3265 return;
3266 double nMax = -(::std::numeric_limits<double>::max());
3267 double nVal = 0.0;
3268 ScAddress aAdr;
3269 ScRange aRange;
3270 size_t nRefInList = 0;
3271 while (nParamCount-- > 0)
3272 {
3273 switch (GetStackType())
3274 {
3275 case svDouble :
3276 {
3277 nVal = GetDouble();
3278 if (nMax < nVal) nMax = nVal;
3279 nFuncFmtType = NUMBERFORMAT_NUMBER;
3280 }
3281 break;
3282 case svSingleRef :
3283 {
3284 PopSingleRef( aAdr );
3285 ScBaseCell* pCell = GetCell( aAdr );
3286 if (HasCellValueData(pCell))
3287 {
3288 nVal = GetCellValue( aAdr, pCell );
3289 CurFmtToFuncFmt();
3290 if (nMax < nVal) nMax = nVal;
3291 }
3292 else if ( bTextAsZero && HasCellStringData( pCell ) )
3293 {
3294 if ( nMax < 0.0 )
3295 nMax = 0.0;
3296 }
3297 }
3298 break;
3299 case svDoubleRef :
3300 case svRefList :
3301 {
3302 sal_uInt16 nErr = 0;
3303 PopDoubleRef( aRange, nParamCount, nRefInList);
3304 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3305 if (aValIter.GetFirst(nVal, nErr))
3306 {
3307 if (nMax < nVal)
3308 nMax = nVal;
3309 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
3310 while ((nErr == 0) && aValIter.GetNext(nVal, nErr))
3311 {
3312 if (nMax < nVal)
3313 nMax = nVal;
3314 }
3315 SetError(nErr);
3316 }
3317 }
3318 break;
3319 case svMatrix :
3320 {
3321 ScMatrixRef pMat = PopMatrix();
3322 if (pMat)
3323 {
3324 nFuncFmtType = NUMBERFORMAT_NUMBER;
3325 SCSIZE nC, nR;
3326 pMat->GetDimensions(nC, nR);
3327 if (pMat->IsNumeric())
3328 {
3329 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3330 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3331 {
3332 nVal = pMat->GetDouble(nMatCol,nMatRow);
3333 if (nMax < nVal) nMax = nVal;
3334 }
3335 }
3336 else
3337 {
3338 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3339 {
3340 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3341 {
3342 if (!pMat->IsString(nMatCol,nMatRow))
3343 {
3344 nVal = pMat->GetDouble(nMatCol,nMatRow);
3345 if (nMax < nVal) nMax = nVal;
3346 }
3347 else if ( bTextAsZero )
3348 {
3349 if ( nMax < 0.0 )
3350 nMax = 0.0;
3351 }
3352 }
3353 }
3354 }
3355 }
3356 }
3357 break;
3358 case svString :
3359 {
3360 Pop();
3361 if ( bTextAsZero )
3362 {
3363 if ( nMax < 0.0 )
3364 nMax = 0.0;
3365 }
3366 else
3367 SetError(errIllegalParameter);
3368 }
3369 break;
3370 default :
3371 Pop();
3372 SetError(errIllegalParameter);
3373 }
3374 }
3375 if ( nVal > nMax )
3376 PushDouble(0.0);
3377 else
3378 PushDouble(nMax);
3379 }
3380
IterateParameters(ScIterFunc eFunc,sal_Bool bTextAsZero)3381 double ScInterpreter::IterateParameters( ScIterFunc eFunc, sal_Bool bTextAsZero )
3382 {
3383 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::IterateParameters" );
3384 short nParamCount = GetByte();
3385 double fRes = ( eFunc == ifPRODUCT ) ? 1.0 : 0.0;
3386 double fVal = 0.0;
3387 double fMem = 0.0;
3388 sal_Bool bNull = sal_True;
3389 sal_uLong nCount = 0;
3390 ScAddress aAdr;
3391 ScRange aRange;
3392 size_t nRefInList = 0;
3393 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3394 nGlobalError = 0;
3395 while (nParamCount-- > 0)
3396 {
3397 switch (GetStackType())
3398 {
3399
3400 case svString:
3401 {
3402 if( eFunc == ifCOUNT )
3403 {
3404 String aStr( PopString() );
3405 sal_uInt32 nFIndex = 0; // damit default Land/Spr.
3406 if ( bTextAsZero || pFormatter->IsNumberFormat(aStr, nFIndex, fVal))
3407 nCount++;
3408 }
3409 else
3410 {
3411 switch ( eFunc )
3412 {
3413 case ifAVERAGE:
3414 case ifSUM:
3415 case ifSUMSQ:
3416 case ifPRODUCT:
3417 {
3418 if ( bTextAsZero )
3419 {
3420 Pop();
3421 nCount++;
3422 if ( eFunc == ifPRODUCT )
3423 fRes = 0.0;
3424 }
3425 else
3426 {
3427 while (nParamCount-- > 0)
3428 Pop();
3429 SetError( errNoValue );
3430 }
3431 }
3432 break;
3433 default:
3434 Pop();
3435 nCount++;
3436 }
3437 }
3438 }
3439 break;
3440 case svDouble :
3441 fVal = GetDouble();
3442 nCount++;
3443 switch( eFunc )
3444 {
3445 case ifAVERAGE:
3446 case ifSUM:
3447 if ( bNull && fVal != 0.0 )
3448 {
3449 bNull = sal_False;
3450 fMem = fVal;
3451 }
3452 else
3453 fRes += fVal;
3454 break;
3455 case ifSUMSQ: fRes += fVal * fVal; break;
3456 case ifPRODUCT: fRes *= fVal; break;
3457 default: ; // nothing
3458 }
3459 nFuncFmtType = NUMBERFORMAT_NUMBER;
3460 break;
3461 case svSingleRef :
3462 {
3463 PopSingleRef( aAdr );
3464 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3465 {
3466 nGlobalError = 0;
3467 if ( eFunc == ifCOUNT2 )
3468 ++nCount;
3469 break;
3470 }
3471 ScBaseCell* pCell = GetCell( aAdr );
3472 if ( pCell )
3473 {
3474 if( eFunc == ifCOUNT2 )
3475 {
3476 CellType eCellType = pCell->GetCellType();
3477 if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
3478 nCount++;
3479 if ( nGlobalError )
3480 nGlobalError = 0;
3481 }
3482 else if ( pCell->HasValueData() )
3483 {
3484 nCount++;
3485 fVal = GetCellValue( aAdr, pCell );
3486 CurFmtToFuncFmt();
3487 switch( eFunc )
3488 {
3489 case ifAVERAGE:
3490 case ifSUM:
3491 if ( bNull && fVal != 0.0 )
3492 {
3493 bNull = sal_False;
3494 fMem = fVal;
3495 }
3496 else
3497 fRes += fVal;
3498 break;
3499 case ifSUMSQ: fRes += fVal * fVal; break;
3500 case ifPRODUCT: fRes *= fVal; break;
3501 case ifCOUNT:
3502 if ( nGlobalError )
3503 {
3504 nGlobalError = 0;
3505 nCount--;
3506 }
3507 break;
3508 default: ; // nothing
3509 }
3510 }
3511 else if ( bTextAsZero && pCell->HasStringData() )
3512 {
3513 nCount++;
3514 if ( eFunc == ifPRODUCT )
3515 fRes = 0.0;
3516 }
3517 }
3518 }
3519 break;
3520 case svDoubleRef :
3521 case svRefList :
3522 {
3523 sal_uInt16 nErr = 0;
3524 PopDoubleRef( aRange, nParamCount, nRefInList);
3525 if ( nGlobalError && ( eFunc == ifCOUNT2 || eFunc == ifCOUNT ) )
3526 {
3527 nGlobalError = 0;
3528 if ( eFunc == ifCOUNT2 )
3529 ++nCount;
3530 break;
3531 }
3532 if( eFunc == ifCOUNT2 )
3533 {
3534 ScBaseCell* pCell;
3535 ScCellIterator aIter( pDok, aRange, glSubTotal );
3536 if ( (pCell = aIter.GetFirst()) != NULL )
3537 {
3538 do
3539 {
3540 CellType eType = pCell->GetCellType();
3541 if( eType != CELLTYPE_NONE && eType != CELLTYPE_NOTE )
3542 nCount++;
3543 }
3544 while ( (pCell = aIter.GetNext()) != NULL );
3545 }
3546 if ( nGlobalError )
3547 nGlobalError = 0;
3548 }
3549 else
3550 {
3551 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3552 if (aValIter.GetFirst(fVal, nErr))
3553 {
3554 // Schleife aus Performance-Gruenden nach innen verlegt:
3555 aValIter.GetCurNumFmtInfo( nFuncFmtType, nFuncFmtIndex );
3556 switch( eFunc )
3557 {
3558 case ifAVERAGE:
3559 case ifSUM:
3560 do
3561 {
3562 SetError(nErr);
3563 if ( bNull && fVal != 0.0 )
3564 {
3565 bNull = sal_False;
3566 fMem = fVal;
3567 }
3568 else
3569 fRes += fVal;
3570 nCount++;
3571 }
3572 while (aValIter.GetNext(fVal, nErr));
3573 break;
3574 case ifSUMSQ:
3575 do
3576 {
3577 SetError(nErr);
3578 fRes += fVal * fVal;
3579 nCount++;
3580 }
3581 while (aValIter.GetNext(fVal, nErr));
3582 break;
3583 case ifPRODUCT:
3584 do
3585 {
3586 SetError(nErr);
3587 fRes *= fVal;
3588 nCount++;
3589 }
3590 while (aValIter.GetNext(fVal, nErr));
3591 break;
3592 case ifCOUNT:
3593 do
3594 {
3595 if ( !nErr )
3596 nCount++;
3597 }
3598 while (aValIter.GetNext(fVal, nErr));
3599 break;
3600 default: ; // nothing
3601 }
3602 SetError( nErr );
3603 }
3604 }
3605 }
3606 break;
3607 case svMatrix :
3608 {
3609 ScMatrixRef pMat = PopMatrix();
3610 if (pMat)
3611 {
3612 SCSIZE nC, nR;
3613 nFuncFmtType = NUMBERFORMAT_NUMBER;
3614 pMat->GetDimensions(nC, nR);
3615 if( eFunc == ifCOUNT2 )
3616 nCount += (sal_uLong) nC * nR;
3617 else
3618 {
3619 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3620 {
3621 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3622 {
3623 if (!pMat->IsString(nMatCol,nMatRow))
3624 {
3625 nCount++;
3626 fVal = pMat->GetDouble(nMatCol,nMatRow);
3627 switch( eFunc )
3628 {
3629 case ifAVERAGE:
3630 case ifSUM:
3631 if ( bNull && fVal != 0.0 )
3632 {
3633 bNull = sal_False;
3634 fMem = fVal;
3635 }
3636 else
3637 fRes += fVal;
3638 break;
3639 case ifSUMSQ: fRes += fVal * fVal; break;
3640 case ifPRODUCT: fRes *= fVal; break;
3641 default: ; // nothing
3642 }
3643 }
3644 else if ( bTextAsZero )
3645 {
3646 nCount++;
3647 if ( eFunc == ifPRODUCT )
3648 fRes = 0.0;
3649 }
3650 }
3651 }
3652 }
3653 }
3654 }
3655 break;
3656 case svError:
3657 {
3658 Pop();
3659 if ( eFunc == ifCOUNT )
3660 {
3661 nGlobalError = 0;
3662 }
3663 else if ( eFunc == ifCOUNT2 )
3664 {
3665 nCount++;
3666 nGlobalError = 0;
3667 }
3668 }
3669 break;
3670 default :
3671 while (nParamCount-- > 0)
3672 PopError();
3673 SetError(errIllegalParameter);
3674 }
3675 }
3676 switch( eFunc )
3677 {
3678 case ifSUM: fRes = ::rtl::math::approxAdd( fRes, fMem ); break;
3679 case ifAVERAGE: fRes = div(::rtl::math::approxAdd( fRes, fMem ), nCount); break;
3680 case ifCOUNT2:
3681 case ifCOUNT: fRes = nCount; break;
3682 case ifPRODUCT: if ( !nCount ) fRes = 0.0; break;
3683 default: ; // nothing
3684 }
3685 // Bei Summen etc. macht ein sal_Bool-Ergebnis keinen Sinn
3686 // und Anzahl ist immer Number (#38345#)
3687 if( eFunc == ifCOUNT || nFuncFmtType == NUMBERFORMAT_LOGICAL )
3688 nFuncFmtType = NUMBERFORMAT_NUMBER;
3689 return fRes;
3690 }
3691
3692
ScSumSQ()3693 void ScInterpreter::ScSumSQ()
3694 {
3695 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumSQ" );
3696 PushDouble( IterateParameters( ifSUMSQ ) );
3697 }
3698
3699
ScSum()3700 void ScInterpreter::ScSum()
3701 {
3702 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSum" );
3703 PushDouble( IterateParameters( ifSUM ) );
3704 }
3705
3706
ScProduct()3707 void ScInterpreter::ScProduct()
3708 {
3709 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScProduct" );
3710 PushDouble( IterateParameters( ifPRODUCT ) );
3711 }
3712
3713
ScAverage(sal_Bool bTextAsZero)3714 void ScInterpreter::ScAverage( sal_Bool bTextAsZero )
3715 {
3716 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAverage" );
3717 PushDouble( IterateParameters( ifAVERAGE, bTextAsZero ) );
3718 }
3719
3720
ScCount()3721 void ScInterpreter::ScCount()
3722 {
3723 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount" );
3724 PushDouble( IterateParameters( ifCOUNT ) );
3725 }
3726
3727
ScCount2()3728 void ScInterpreter::ScCount2()
3729 {
3730 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCount2" );
3731 PushDouble( IterateParameters( ifCOUNT2 ) );
3732 }
3733
3734
GetStVarParams(double & rVal,double & rValCount,sal_Bool bTextAsZero)3735 void ScInterpreter::GetStVarParams( double& rVal, double& rValCount,
3736 sal_Bool bTextAsZero )
3737 {
3738 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetStVarParams" );
3739 short nParamCount = GetByte();
3740
3741 std::vector<double> values;
3742 double fSum = 0.0;
3743 double vSum = 0.0;
3744 double vMean = 0.0;
3745 double fVal = 0.0;
3746 rValCount = 0.0;
3747 ScAddress aAdr;
3748 ScRange aRange;
3749 size_t nRefInList = 0;
3750 while (nParamCount-- > 0)
3751 {
3752 switch (GetStackType())
3753 {
3754 case svDouble :
3755 {
3756 fVal = GetDouble();
3757 values.push_back(fVal);
3758 fSum += fVal;
3759 rValCount++;
3760 }
3761 break;
3762 case svSingleRef :
3763 {
3764 PopSingleRef( aAdr );
3765 ScBaseCell* pCell = GetCell( aAdr );
3766 if (HasCellValueData(pCell))
3767 {
3768 fVal = GetCellValue( aAdr, pCell );
3769 values.push_back(fVal);
3770 fSum += fVal;
3771 rValCount++;
3772 }
3773 else if ( bTextAsZero && HasCellStringData( pCell ) )
3774 {
3775 values.push_back(0.0);
3776 rValCount++;
3777 }
3778 }
3779 break;
3780 case svDoubleRef :
3781 case svRefList :
3782 {
3783 sal_uInt16 nErr = 0;
3784 PopDoubleRef( aRange, nParamCount, nRefInList);
3785 ScValueIterator aValIter( pDok, aRange, glSubTotal, bTextAsZero );
3786 if (aValIter.GetFirst(fVal, nErr))
3787 {
3788 do
3789 {
3790 values.push_back(fVal);
3791 fSum += fVal;
3792 rValCount++;
3793 }
3794 while ((nErr == 0) && aValIter.GetNext(fVal, nErr));
3795 }
3796 }
3797 break;
3798 case svMatrix :
3799 {
3800 ScMatrixRef pMat = PopMatrix();
3801 if (pMat)
3802 {
3803 SCSIZE nC, nR;
3804 pMat->GetDimensions(nC, nR);
3805 for (SCSIZE nMatCol = 0; nMatCol < nC; nMatCol++)
3806 {
3807 for (SCSIZE nMatRow = 0; nMatRow < nR; nMatRow++)
3808 {
3809 if (!pMat->IsString(nMatCol,nMatRow))
3810 {
3811 fVal= pMat->GetDouble(nMatCol,nMatRow);
3812 values.push_back(fVal);
3813 fSum += fVal;
3814 rValCount++;
3815 }
3816 else if ( bTextAsZero )
3817 {
3818 values.push_back(0.0);
3819 rValCount++;
3820 }
3821 }
3822 }
3823 }
3824 }
3825 break;
3826 case svString :
3827 {
3828 Pop();
3829 if ( bTextAsZero )
3830 {
3831 values.push_back(0.0);
3832 rValCount++;
3833 }
3834 else
3835 SetError(errIllegalParameter);
3836 }
3837 break;
3838 default :
3839 Pop();
3840 SetError(errIllegalParameter);
3841 }
3842 }
3843
3844 ::std::vector<double>::size_type n = values.size();
3845 vMean = fSum / n;
3846 for (::std::vector<double>::size_type i = 0; i < n; i++)
3847 vSum += ::rtl::math::approxSub( values[i], vMean) * ::rtl::math::approxSub( values[i], vMean);
3848 rVal = vSum;
3849 }
3850
3851
ScVar(sal_Bool bTextAsZero)3852 void ScInterpreter::ScVar( sal_Bool bTextAsZero )
3853 {
3854 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVar" );
3855 double nVal;
3856 double nValCount;
3857 GetStVarParams( nVal, nValCount, bTextAsZero );
3858
3859 if (nValCount <= 1.0)
3860 PushError( errDivisionByZero );
3861 else
3862 PushDouble( nVal / (nValCount - 1.0));
3863 }
3864
3865
ScVarP(sal_Bool bTextAsZero)3866 void ScInterpreter::ScVarP( sal_Bool bTextAsZero )
3867 {
3868 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVarP" );
3869 double nVal;
3870 double nValCount;
3871 GetStVarParams( nVal, nValCount, bTextAsZero );
3872
3873 PushDouble( div( nVal, nValCount));
3874 }
3875
3876
ScStDev(sal_Bool bTextAsZero)3877 void ScInterpreter::ScStDev( sal_Bool bTextAsZero )
3878 {
3879 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStDev" );
3880 double nVal;
3881 double nValCount;
3882 GetStVarParams( nVal, nValCount, bTextAsZero );
3883 if (nValCount <= 1.0)
3884 PushError( errDivisionByZero );
3885 else
3886 PushDouble( sqrt( nVal / (nValCount - 1.0)));
3887 }
3888
3889
ScStDevP(sal_Bool bTextAsZero)3890 void ScInterpreter::ScStDevP( sal_Bool bTextAsZero )
3891 {
3892 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScStDevP" );
3893 double nVal;
3894 double nValCount;
3895 GetStVarParams( nVal, nValCount, bTextAsZero );
3896 if (nValCount == 0.0)
3897 PushError( errDivisionByZero );
3898 else
3899 PushDouble( sqrt( nVal / nValCount));
3900
3901 /* this was: PushDouble( sqrt( div( nVal, nValCount)));
3902 *
3903 * Besides that the special NAN gets lost in the call through sqrt(),
3904 * unxlngi6.pro then looped back and forth somewhere between div() and
3905 * ::rtl::math::setNan(). Tests showed that
3906 *
3907 * sqrt( div( 1, 0));
3908 *
3909 * produced a loop, but
3910 *
3911 * double f1 = div( 1, 0);
3912 * sqrt( f1 );
3913 *
3914 * was fine. There seems to be some compiler optimization problem. It does
3915 * not occur when compiled with debug=t.
3916 */
3917 }
3918
3919
ScColumns()3920 void ScInterpreter::ScColumns()
3921 {
3922 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColumns" );
3923 sal_uInt8 nParamCount = GetByte();
3924 sal_uLong nVal = 0;
3925 SCCOL nCol1;
3926 SCROW nRow1;
3927 SCTAB nTab1;
3928 SCCOL nCol2;
3929 SCROW nRow2;
3930 SCTAB nTab2;
3931 while (nParamCount-- > 0)
3932 {
3933 switch ( GetStackType() )
3934 {
3935 case svSingleRef:
3936 PopError();
3937 nVal++;
3938 break;
3939 case svDoubleRef:
3940 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3941 nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1) *
3942 static_cast<sal_uLong>(nCol2 - nCol1 + 1);
3943 break;
3944 case svMatrix:
3945 {
3946 ScMatrixRef pMat = PopMatrix();
3947 if (pMat)
3948 {
3949 SCSIZE nC, nR;
3950 pMat->GetDimensions(nC, nR);
3951 nVal += nC;
3952 }
3953 }
3954 break;
3955 default:
3956 PopError();
3957 SetError(errIllegalParameter);
3958 }
3959 }
3960 PushDouble((double)nVal);
3961 }
3962
3963
ScRows()3964 void ScInterpreter::ScRows()
3965 {
3966 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRows" );
3967 sal_uInt8 nParamCount = GetByte();
3968 sal_uLong nVal = 0;
3969 SCCOL nCol1;
3970 SCROW nRow1;
3971 SCTAB nTab1;
3972 SCCOL nCol2;
3973 SCROW nRow2;
3974 SCTAB nTab2;
3975 while (nParamCount-- > 0)
3976 {
3977 switch ( GetStackType() )
3978 {
3979 case svSingleRef:
3980 PopError();
3981 nVal++;
3982 break;
3983 case svDoubleRef:
3984 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
3985 nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1) *
3986 static_cast<sal_uLong>(nRow2 - nRow1 + 1);
3987 break;
3988 case svMatrix:
3989 {
3990 ScMatrixRef pMat = PopMatrix();
3991 if (pMat)
3992 {
3993 SCSIZE nC, nR;
3994 pMat->GetDimensions(nC, nR);
3995 nVal += nR;
3996 }
3997 }
3998 break;
3999 default:
4000 PopError();
4001 SetError(errIllegalParameter);
4002 }
4003 }
4004 PushDouble((double)nVal);
4005 }
4006
ScTables()4007 void ScInterpreter::ScTables()
4008 {
4009 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTables" );
4010 sal_uInt8 nParamCount = GetByte();
4011 sal_uLong nVal;
4012 if ( nParamCount == 0 )
4013 nVal = pDok->GetTableCount();
4014 else
4015 {
4016 nVal = 0;
4017 SCCOL nCol1;
4018 SCROW nRow1;
4019 SCTAB nTab1;
4020 SCCOL nCol2;
4021 SCROW nRow2;
4022 SCTAB nTab2;
4023 while (nParamCount-- > 0)
4024 {
4025 switch ( GetStackType() )
4026 {
4027 case svSingleRef:
4028 PopError();
4029 nVal++;
4030 break;
4031 case svDoubleRef:
4032 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4033 nVal += static_cast<sal_uLong>(nTab2 - nTab1 + 1);
4034 break;
4035 case svMatrix:
4036 PopError();
4037 nVal++;
4038 break;
4039 default:
4040 PopError();
4041 SetError( errIllegalParameter );
4042 }
4043 }
4044 }
4045 PushDouble( (double) nVal );
4046 }
4047
4048
ScColumn()4049 void ScInterpreter::ScColumn()
4050 {
4051 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScColumn" );
4052 sal_uInt8 nParamCount = GetByte();
4053 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
4054 {
4055 double nVal = 0;
4056 if (nParamCount == 0)
4057 {
4058 nVal = aPos.Col() + 1;
4059 if (bMatrixFormula)
4060 {
4061 SCCOL nCols;
4062 SCROW nRows;
4063 pMyFormulaCell->GetMatColsRows( nCols, nRows);
4064 ScMatrixRef pResMat = GetNewMat( static_cast<SCSIZE>(nCols), 1);
4065 if (pResMat)
4066 {
4067 for (SCCOL i=0; i < nCols; ++i)
4068 pResMat->PutDouble( nVal + i, static_cast<SCSIZE>(i), 0);
4069 PushMatrix( pResMat);
4070 return;
4071 }
4072 }
4073 }
4074 else
4075 {
4076 switch ( GetStackType() )
4077 {
4078 case svSingleRef :
4079 {
4080 SCCOL nCol1;
4081 SCROW nRow1;
4082 SCTAB nTab1;
4083 PopSingleRef( nCol1, nRow1, nTab1 );
4084 nVal = (double) (nCol1 + 1);
4085 }
4086 break;
4087 case svDoubleRef :
4088 {
4089 SCCOL nCol1;
4090 SCROW nRow1;
4091 SCTAB nTab1;
4092 SCCOL nCol2;
4093 SCROW nRow2;
4094 SCTAB nTab2;
4095 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
4096 if (nCol2 > nCol1)
4097 {
4098 ScMatrixRef pResMat = GetNewMat(
4099 static_cast<SCSIZE>(nCol2-nCol1+1), 1);
4100 if (pResMat)
4101 {
4102 for (SCCOL i = nCol1; i <= nCol2; i++)
4103 pResMat->PutDouble((double)(i+1),
4104 static_cast<SCSIZE>(i-nCol1), 0);
4105 PushMatrix(pResMat);
4106 return;
4107 }
4108 else
4109 nVal = 0.0;
4110 }
4111 else
4112 nVal = (double) (nCol1 + 1);
4113 }
4114 break;
4115 default:
4116 SetError( errIllegalParameter );
4117 nVal = 0.0;
4118 }
4119 }
4120 PushDouble( nVal );
4121 }
4122 }
4123
4124
ScRow()4125 void ScInterpreter::ScRow()
4126 {
4127 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRow" );
4128 sal_uInt8 nParamCount = GetByte();
4129 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
4130 {
4131 double nVal = 0;
4132 if (nParamCount == 0)
4133 {
4134 nVal = aPos.Row() + 1;
4135 if (bMatrixFormula)
4136 {
4137 SCCOL nCols;
4138 SCROW nRows;
4139 pMyFormulaCell->GetMatColsRows( nCols, nRows);
4140 ScMatrixRef pResMat = GetNewMat( 1, static_cast<SCSIZE>(nRows));
4141 if (pResMat)
4142 {
4143 for (SCROW i=0; i < nRows; i++)
4144 pResMat->PutDouble( nVal + i, 0, static_cast<SCSIZE>(i));
4145 PushMatrix( pResMat);
4146 return;
4147 }
4148 }
4149 }
4150 else
4151 {
4152 switch ( GetStackType() )
4153 {
4154 case svSingleRef :
4155 {
4156 SCCOL nCol1;
4157 SCROW nRow1;
4158 SCTAB nTab1;
4159 PopSingleRef( nCol1, nRow1, nTab1 );
4160 nVal = (double) (nRow1 + 1);
4161 }
4162 break;
4163 case svDoubleRef :
4164 {
4165 SCCOL nCol1;
4166 SCROW nRow1;
4167 SCTAB nTab1;
4168 SCCOL nCol2;
4169 SCROW nRow2;
4170 SCTAB nTab2;
4171 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
4172 if (nRow2 > nRow1)
4173 {
4174 ScMatrixRef pResMat = GetNewMat( 1,
4175 static_cast<SCSIZE>(nRow2-nRow1+1));
4176 if (pResMat)
4177 {
4178 for (SCROW i = nRow1; i <= nRow2; i++)
4179 pResMat->PutDouble((double)(i+1), 0,
4180 static_cast<SCSIZE>(i-nRow1));
4181 PushMatrix(pResMat);
4182 return;
4183 }
4184 else
4185 nVal = 0.0;
4186 }
4187 else
4188 nVal = (double) (nRow1 + 1);
4189 }
4190 break;
4191 default:
4192 SetError( errIllegalParameter );
4193 nVal = 0.0;
4194 }
4195 }
4196 PushDouble( nVal );
4197 }
4198 }
4199
ScTable()4200 void ScInterpreter::ScTable()
4201 {
4202 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScTable" );
4203 sal_uInt8 nParamCount = GetByte();
4204 if ( MustHaveParamCount( nParamCount, 0, 1 ) )
4205 {
4206 SCTAB nVal = 0;
4207 if ( nParamCount == 0 )
4208 nVal = aPos.Tab() + 1;
4209 else
4210 {
4211 switch ( GetStackType() )
4212 {
4213 case svString :
4214 {
4215 String aStr( PopString() );
4216 if ( pDok->GetTable( aStr, nVal ) )
4217 ++nVal;
4218 else
4219 SetError( errIllegalArgument );
4220 }
4221 break;
4222 case svSingleRef :
4223 {
4224 SCCOL nCol1;
4225 SCROW nRow1;
4226 SCTAB nTab1;
4227 PopSingleRef( nCol1, nRow1, nTab1 );
4228 nVal = nTab1 + 1;
4229 }
4230 break;
4231 case svDoubleRef :
4232 {
4233 SCCOL nCol1;
4234 SCROW nRow1;
4235 SCTAB nTab1;
4236 SCCOL nCol2;
4237 SCROW nRow2;
4238 SCTAB nTab2;
4239 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
4240 nVal = nTab1 + 1;
4241 }
4242 break;
4243 default:
4244 SetError( errIllegalParameter );
4245 }
4246 if ( nGlobalError )
4247 nVal = 0;
4248 }
4249 PushDouble( (double) nVal );
4250 }
4251 }
4252
4253 /** returns -1 when the matrix value is smaller than the query value, 0 when
4254 they are equal, and 1 when the matrix value is larger than the query
4255 value. */
lcl_CompareMatrix2Query(SCSIZE i,const ScMatrix & rMat,const ScQueryEntry & rEntry)4256 static sal_Int32 lcl_CompareMatrix2Query( SCSIZE i, const ScMatrix& rMat,
4257 const ScQueryEntry& rEntry)
4258 {
4259 if (rMat.IsEmpty(i))
4260 {
4261 /* TODO: in case we introduced query for real empty this would have to
4262 * be changed! */
4263 return -1; // empty always less than anything else
4264 }
4265
4266 /* FIXME: what is an empty path (result of IF(false;true_path) in
4267 * comparisons? */
4268
4269 if (rMat.IsValue(i))
4270 {
4271 if (rEntry.bQueryByString)
4272 return -1; // numeric always less than string
4273
4274 const double nVal1 = rMat.GetDouble(i);
4275 const double nVal2 = rEntry.nVal;
4276 if (nVal1 == nVal2)
4277 return 0;
4278
4279 return nVal1 < nVal2 ? -1 : 1;
4280 }
4281
4282 if (!rEntry.bQueryByString)
4283 return 1; // string always greater than numeric
4284
4285 if (!rEntry.pStr)
4286 // this should not happen!
4287 return 1;
4288
4289 const String& rStr1 = rMat.GetString(i);
4290 const String& rStr2 = *rEntry.pStr;
4291
4292 return ScGlobal::GetCollator()->compareString( rStr1, rStr2); // case-insensitive
4293 }
4294
4295 /** returns the last item with the identical value as the original item
4296 value. */
lcl_GetLastMatch(SCSIZE & rIndex,const ScMatrix & rMat,SCSIZE nMatCount,bool bReverse)4297 static void lcl_GetLastMatch( SCSIZE& rIndex, const ScMatrix& rMat,
4298 SCSIZE nMatCount, bool bReverse)
4299 {
4300 if (rMat.IsValue(rIndex))
4301 {
4302 double nVal = rMat.GetDouble(rIndex);
4303 if (bReverse)
4304 while (rIndex > 0 && rMat.IsValue(rIndex-1) &&
4305 nVal == rMat.GetDouble(rIndex-1))
4306 --rIndex;
4307 else
4308 while (rIndex < nMatCount-1 && rMat.IsValue(rIndex+1) &&
4309 nVal == rMat.GetDouble(rIndex+1))
4310 ++rIndex;
4311 }
4312 //! Order of IsEmptyPath, IsEmpty, IsString is significant!
4313 else if (rMat.IsEmptyPath(rIndex))
4314 {
4315 if (bReverse)
4316 while (rIndex > 0 && rMat.IsEmptyPath(rIndex-1))
4317 --rIndex;
4318 else
4319 while (rIndex < nMatCount-1 && rMat.IsEmptyPath(rIndex+1))
4320 ++rIndex;
4321 }
4322 else if (rMat.IsEmpty(rIndex))
4323 {
4324 if (bReverse)
4325 while (rIndex > 0 && rMat.IsEmpty(rIndex-1))
4326 --rIndex;
4327 else
4328 while (rIndex < nMatCount-1 && rMat.IsEmpty(rIndex+1))
4329 ++rIndex;
4330 }
4331 else if (rMat.IsString(rIndex))
4332 {
4333 String aStr( rMat.GetString(rIndex));
4334 if (bReverse)
4335 while (rIndex > 0 && rMat.IsString(rIndex-1) &&
4336 aStr == rMat.GetString(rIndex-1))
4337 --rIndex;
4338 else
4339 while (rIndex < nMatCount-1 && rMat.IsString(rIndex+1) &&
4340 aStr == rMat.GetString(rIndex+1))
4341 ++rIndex;
4342 }
4343 else
4344 {
4345 DBG_ERRORFILE("lcl_GetLastMatch: unhandled matrix type");
4346 }
4347 }
4348
ScMatch()4349 void ScInterpreter::ScMatch()
4350 {
4351 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMatch" );
4352 ScMatrixRef pMatSrc = NULL;
4353
4354 sal_uInt8 nParamCount = GetByte();
4355 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
4356 {
4357 double fTyp;
4358 if (nParamCount == 3)
4359 fTyp = GetDouble();
4360 else
4361 fTyp = 1.0;
4362 SCCOL nCol1 = 0;
4363 SCROW nRow1 = 0;
4364 SCTAB nTab1 = 0;
4365 SCCOL nCol2 = 0;
4366 SCROW nRow2 = 0;
4367 SCTAB nTab2 = 0;
4368 if (GetStackType() == svDoubleRef)
4369 {
4370 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4371 if (nTab1 != nTab2 || (nCol1 != nCol2 && nRow1 != nRow2))
4372 {
4373 PushIllegalParameter();
4374 return;
4375 }
4376 }
4377 else if (GetStackType() == svMatrix)
4378 {
4379 pMatSrc = PopMatrix();
4380 if (!pMatSrc)
4381 {
4382 PushIllegalParameter();
4383 return;
4384 }
4385 }
4386 else
4387 {
4388 PushIllegalParameter();
4389 return;
4390 }
4391 if (nGlobalError == 0)
4392 {
4393 double fVal;
4394 String sStr;
4395 ScQueryParam rParam;
4396 rParam.nCol1 = nCol1;
4397 rParam.nRow1 = nRow1;
4398 rParam.nCol2 = nCol2;
4399 rParam.nTab = nTab1;
4400 rParam.bMixedComparison = sal_True;
4401
4402 ScQueryEntry& rEntry = rParam.GetEntry(0);
4403 rEntry.bDoQuery = sal_True;
4404 if (fTyp < 0.0)
4405 rEntry.eOp = SC_GREATER_EQUAL;
4406 else if (fTyp > 0.0)
4407 rEntry.eOp = SC_LESS_EQUAL;
4408 switch ( GetStackType() )
4409 {
4410 case svDouble:
4411 {
4412 fVal = GetDouble();
4413 rEntry.bQueryByString = sal_False;
4414 rEntry.nVal = fVal;
4415 }
4416 break;
4417 case svString:
4418 {
4419 sStr = GetString();
4420 rEntry.bQueryByString = sal_True;
4421 *rEntry.pStr = sStr;
4422 }
4423 break;
4424 case svDoubleRef :
4425 case svSingleRef :
4426 {
4427 ScAddress aAdr;
4428 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4429 {
4430 PushInt(0);
4431 return ;
4432 }
4433 ScBaseCell* pCell = GetCell( aAdr );
4434 if (HasCellValueData(pCell))
4435 {
4436 fVal = GetCellValue( aAdr, pCell );
4437 rEntry.bQueryByString = sal_False;
4438 rEntry.nVal = fVal;
4439 }
4440 else
4441 {
4442 GetCellString(sStr, pCell);
4443 rEntry.bQueryByString = sal_True;
4444 *rEntry.pStr = sStr;
4445 }
4446 }
4447 break;
4448 case svMatrix :
4449 {
4450 ScMatValType nType = GetDoubleOrStringFromMatrix(
4451 rEntry.nVal, *rEntry.pStr);
4452 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
4453 }
4454 break;
4455 default:
4456 {
4457 PushIllegalParameter();
4458 return;
4459 }
4460 }
4461 if ( rEntry.bQueryByString )
4462 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4463
4464 if (pMatSrc) // The source data is matrix array.
4465 {
4466 SCSIZE nC, nR;
4467 pMatSrc->GetDimensions( nC, nR);
4468 if (nC > 1 && nR > 1)
4469 {
4470 // The source matrix must be a vector.
4471 PushIllegalParameter();
4472 return;
4473 }
4474 SCSIZE nMatCount = (nC == 1) ? nR : nC;
4475
4476 // simple serial search for equality mode (source data doesn't
4477 // need to be sorted).
4478
4479 if (rEntry.eOp == SC_EQUAL)
4480 {
4481 for (SCSIZE i = 0; i < nMatCount; ++i)
4482 {
4483 if (lcl_CompareMatrix2Query( i, *pMatSrc, rEntry) == 0)
4484 {
4485 PushDouble(i+1); // found !
4486 return;
4487 }
4488 }
4489 PushNA(); // not found
4490 return;
4491 }
4492
4493 // binary search for non-equality mode (the source data is
4494 // assumed to be sorted).
4495
4496 bool bAscOrder = (rEntry.eOp == SC_LESS_EQUAL);
4497 SCSIZE nFirst = 0, nLast = nMatCount-1, nHitIndex = 0;
4498 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
4499 {
4500 SCSIZE nMid = nFirst + nLen/2;
4501 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pMatSrc, rEntry);
4502 if (nCmp == 0)
4503 {
4504 // exact match. find the last item with the same value.
4505 lcl_GetLastMatch( nMid, *pMatSrc, nMatCount, !bAscOrder);
4506 PushDouble( nMid+1);
4507 return;
4508 }
4509
4510 if (nLen == 1) // first and last items are next to each other.
4511 {
4512 if (nCmp < 0)
4513 nHitIndex = bAscOrder ? nLast : nFirst;
4514 else
4515 nHitIndex = bAscOrder ? nFirst : nLast;
4516 break;
4517 }
4518
4519 if (nCmp < 0)
4520 {
4521 if (bAscOrder)
4522 nFirst = nMid;
4523 else
4524 nLast = nMid;
4525 }
4526 else
4527 {
4528 if (bAscOrder)
4529 nLast = nMid;
4530 else
4531 nFirst = nMid;
4532 }
4533 }
4534
4535 if (nHitIndex == nMatCount-1) // last item
4536 {
4537 sal_Int32 nCmp = lcl_CompareMatrix2Query( nHitIndex, *pMatSrc, rEntry);
4538 if ((bAscOrder && nCmp <= 0) || (!bAscOrder && nCmp >= 0))
4539 {
4540 // either the last item is an exact match or the real
4541 // hit is beyond the last item.
4542 PushDouble( nHitIndex+1);
4543 return;
4544 }
4545 }
4546
4547 if (nHitIndex > 0) // valid hit must be 2nd item or higher
4548 {
4549 PushDouble( nHitIndex); // non-exact match
4550 return;
4551 }
4552
4553 PushNA();
4554 return;
4555 }
4556
4557 SCCOLROW nDelta = 0;
4558 if (nCol1 == nCol2)
4559 { // search row in column
4560 rParam.nRow2 = nRow2;
4561 rEntry.nField = nCol1;
4562 ScAddress aResultPos( nCol1, nRow1, nTab1);
4563 if (!LookupQueryWithCache( aResultPos, rParam))
4564 {
4565 PushNA();
4566 return;
4567 }
4568 nDelta = aResultPos.Row() - nRow1;
4569 }
4570 else
4571 { // search column in row
4572 SCCOL nC;
4573 rParam.bByRow = sal_False;
4574 rParam.nRow2 = nRow1;
4575 rEntry.nField = nCol1;
4576 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
4577 // Advance Entry.nField in Iterator if column changed
4578 aCellIter.SetAdvanceQueryParamEntryField( sal_True );
4579 if (fTyp == 0.0)
4580 { // EQUAL
4581 if ( aCellIter.GetFirst() )
4582 nC = aCellIter.GetCol();
4583 else
4584 {
4585 PushNA();
4586 return;
4587 }
4588 }
4589 else
4590 { // <= or >=
4591 SCROW nR;
4592 if ( !aCellIter.FindEqualOrSortedLastInRange( nC, nR ) )
4593 {
4594 PushNA();
4595 return;
4596 }
4597 }
4598 nDelta = nC - nCol1;
4599 }
4600 PushDouble((double) (nDelta + 1));
4601 }
4602 else
4603 PushIllegalParameter();
4604 }
4605 }
4606
4607
ScCountEmptyCells()4608 void ScInterpreter::ScCountEmptyCells()
4609 {
4610 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountEmptyCells" );
4611 if ( MustHaveParamCount( GetByte(), 1 ) )
4612 {
4613 sal_uLong nMaxCount = 0, nCount = 0;
4614 CellType eCellType;
4615 switch (GetStackType())
4616 {
4617 case svSingleRef :
4618 {
4619 nMaxCount = 1;
4620 ScAddress aAdr;
4621 PopSingleRef( aAdr );
4622 eCellType = GetCellType( GetCell( aAdr ) );
4623 if (eCellType != CELLTYPE_NONE && eCellType != CELLTYPE_NOTE)
4624 nCount = 1;
4625 }
4626 break;
4627 case svDoubleRef :
4628 case svRefList :
4629 {
4630 ScRange aRange;
4631 short nParam = 1;
4632 size_t nRefInList = 0;
4633 while (nParam-- > 0)
4634 {
4635 PopDoubleRef( aRange, nParam, nRefInList);
4636 nMaxCount +=
4637 static_cast<sal_uLong>(aRange.aEnd.Row() - aRange.aStart.Row() + 1) *
4638 static_cast<sal_uLong>(aRange.aEnd.Col() - aRange.aStart.Col() + 1) *
4639 static_cast<sal_uLong>(aRange.aEnd.Tab() - aRange.aStart.Tab() + 1);
4640 ScBaseCell* pCell;
4641 ScCellIterator aDocIter( pDok, aRange, glSubTotal);
4642 if ( (pCell = aDocIter.GetFirst()) != NULL )
4643 {
4644 do
4645 {
4646 if ((eCellType = pCell->GetCellType()) != CELLTYPE_NONE
4647 && eCellType != CELLTYPE_NOTE)
4648 nCount++;
4649 } while ( (pCell = aDocIter.GetNext()) != NULL );
4650 }
4651 }
4652 }
4653 break;
4654 default : SetError(errIllegalParameter); break;
4655 }
4656 PushDouble(nMaxCount - nCount);
4657 }
4658 }
4659
4660
IterateParametersIf(ScIterFuncIf eFunc)4661 double ScInterpreter::IterateParametersIf( ScIterFuncIf eFunc )
4662 {
4663 sal_uInt8 nParamCount = GetByte();
4664 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
4665 {
4666 SCCOL nCol3 = 0;
4667 SCROW nRow3 = 0;
4668 SCTAB nTab3 = 0;
4669
4670 ScMatrixRef pSumExtraMatrix;
4671 bool bSumExtraRange = (nParamCount == 3);
4672 if (bSumExtraRange)
4673 {
4674 // Save only the upperleft cell in case of cell range. The geometry
4675 // of the 3rd parameter is taken from the 1st parameter.
4676
4677 switch ( GetStackType() )
4678 {
4679 case svDoubleRef :
4680 {
4681 SCCOL nColJunk = 0;
4682 SCROW nRowJunk = 0;
4683 SCTAB nTabJunk = 0;
4684 PopDoubleRef( nCol3, nRow3, nTab3, nColJunk, nRowJunk, nTabJunk );
4685 if ( nTabJunk != nTab3 )
4686 {
4687 SetError( errIllegalParameter);
4688 }
4689 }
4690 break;
4691 case svSingleRef :
4692 PopSingleRef( nCol3, nRow3, nTab3 );
4693 break;
4694 case svMatrix:
4695 pSumExtraMatrix = PopMatrix();
4696 //! nCol3, nRow3, nTab3 remain 0
4697 break;
4698 default:
4699 SetError( errIllegalParameter);
4700 }
4701 }
4702 String rString;
4703 double fVal = 0.0;
4704 bool bIsString = true;
4705 switch ( GetStackType() )
4706 {
4707 case svDoubleRef :
4708 case svSingleRef :
4709 {
4710 ScAddress aAdr;
4711 if ( !PopDoubleRefOrSingleRef( aAdr ) )
4712 return 0;
4713
4714 ScBaseCell* pCell = GetCell( aAdr );
4715 switch ( GetCellType( pCell ) )
4716 {
4717 case CELLTYPE_VALUE :
4718 fVal = GetCellValue( aAdr, pCell );
4719 bIsString = false;
4720 break;
4721 case CELLTYPE_FORMULA :
4722 if( ((ScFormulaCell*)pCell)->IsValue() )
4723 {
4724 fVal = GetCellValue( aAdr, pCell );
4725 bIsString = false;
4726 }
4727 else
4728 GetCellString(rString, pCell);
4729 break;
4730 case CELLTYPE_STRING :
4731 case CELLTYPE_EDIT :
4732 GetCellString(rString, pCell);
4733 break;
4734 default:
4735 fVal = 0.0;
4736 bIsString = false;
4737 }
4738 }
4739 break;
4740 case svString:
4741 rString = GetString();
4742 break;
4743 case svMatrix :
4744 {
4745 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
4746 bIsString = ScMatrix::IsNonValueType( nType);
4747 }
4748 break;
4749 default:
4750 {
4751 fVal = GetDouble();
4752 bIsString = false;
4753 }
4754 }
4755
4756 double fSum = 0.0;
4757 double fMem = 0.0;
4758 double fRes = 0.0;
4759 double fCount = 0.0;
4760 bool bNull = true;
4761 short nParam = 1;
4762 size_t nRefInList = 0;
4763 while (nParam-- > 0)
4764 {
4765 SCCOL nCol1 = 0;
4766 SCROW nRow1 = 0;
4767 SCTAB nTab1 = 0;
4768 SCCOL nCol2 = 0;
4769 SCROW nRow2 = 0;
4770 SCTAB nTab2 = 0;
4771 ScMatrixRef pQueryMatrix;
4772 switch ( GetStackType() )
4773 {
4774 case svRefList :
4775 if (bSumExtraRange)
4776 {
4777 SetError( errIllegalParameter);
4778 }
4779 else
4780 {
4781 ScRange aRange;
4782 PopDoubleRef( aRange, nParam, nRefInList);
4783 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
4784 }
4785 break;
4786 case svDoubleRef :
4787 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
4788 break;
4789 case svSingleRef :
4790 PopSingleRef( nCol1, nRow1, nTab1 );
4791 nCol2 = nCol1;
4792 nRow2 = nRow1;
4793 nTab2 = nTab1;
4794 break;
4795 case svMatrix:
4796 {
4797 pQueryMatrix = PopMatrix();
4798 if (!pQueryMatrix)
4799 {
4800 SetError( errIllegalParameter);
4801 }
4802 nCol1 = 0;
4803 nRow1 = 0;
4804 nTab1 = 0;
4805 SCSIZE nC, nR;
4806 pQueryMatrix->GetDimensions( nC, nR);
4807 nCol2 = static_cast<SCCOL>(nC - 1);
4808 nRow2 = static_cast<SCROW>(nR - 1);
4809 nTab2 = 0;
4810 }
4811 break;
4812 default:
4813 SetError( errIllegalParameter);
4814 }
4815 if ( nTab1 != nTab2 )
4816 {
4817 SetError( errIllegalParameter);
4818 }
4819
4820 if (bSumExtraRange)
4821 {
4822 // Take the range geometry of the 1st parameter and apply it to
4823 // the 3rd. If parts of the resulting range would point outside
4824 // the sheet, don't complain but silently ignore and simply cut
4825 // them away, this is what Xcl does :-/
4826
4827 // For the cut-away part we also don't need to determine the
4828 // criteria match, so shrink the source range accordingly,
4829 // instead of the result range.
4830 SCCOL nColDelta = nCol2 - nCol1;
4831 SCROW nRowDelta = nRow2 - nRow1;
4832 SCCOL nMaxCol;
4833 SCROW nMaxRow;
4834 if (pSumExtraMatrix)
4835 {
4836 SCSIZE nC, nR;
4837 pSumExtraMatrix->GetDimensions( nC, nR);
4838 nMaxCol = static_cast<SCCOL>(nC - 1);
4839 nMaxRow = static_cast<SCROW>(nR - 1);
4840 }
4841 else
4842 {
4843 nMaxCol = MAXCOL;
4844 nMaxRow = MAXROW;
4845 }
4846 if (nCol3 + nColDelta > nMaxCol)
4847 {
4848 SCCOL nNewDelta = nMaxCol - nCol3;
4849 nCol2 = nCol1 + nNewDelta;
4850 }
4851
4852 if (nRow3 + nRowDelta > nMaxRow)
4853 {
4854 SCROW nNewDelta = nMaxRow - nRow3;
4855 nRow2 = nRow1 + nNewDelta;
4856 }
4857 }
4858 else
4859 {
4860 nCol3 = nCol1;
4861 nRow3 = nRow1;
4862 nTab3 = nTab1;
4863 }
4864
4865 if (nGlobalError == 0)
4866 {
4867 ScQueryParam rParam;
4868 rParam.nRow1 = nRow1;
4869 rParam.nRow2 = nRow2;
4870
4871 ScQueryEntry& rEntry = rParam.GetEntry(0);
4872 rEntry.bDoQuery = true;
4873 if (!bIsString)
4874 {
4875 rEntry.bQueryByString = false;
4876 rEntry.nVal = fVal;
4877 rEntry.eOp = SC_EQUAL;
4878 }
4879 else
4880 {
4881 rParam.FillInExcelSyntax(rString, 0);
4882 sal_uInt32 nIndex = 0;
4883 rEntry.bQueryByString =
4884 !(pFormatter->IsNumberFormat(
4885 *rEntry.pStr, nIndex, rEntry.nVal));
4886 if ( rEntry.bQueryByString )
4887 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
4888 }
4889 ScAddress aAdr;
4890 aAdr.SetTab( nTab3 );
4891 rParam.nCol1 = nCol1;
4892 rParam.nCol2 = nCol2;
4893 rEntry.nField = nCol1;
4894 SCsCOL nColDiff = nCol3 - nCol1;
4895 SCsROW nRowDiff = nRow3 - nRow1;
4896 if (pQueryMatrix)
4897 {
4898 // Never case-sensitive.
4899 ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
4900 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
4901 if (nGlobalError || !pResultMatrix)
4902 {
4903 SetError( errIllegalParameter);
4904 }
4905
4906 if (pSumExtraMatrix)
4907 {
4908 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
4909 {
4910 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
4911 {
4912 if (pResultMatrix->IsValue( nCol, nRow) &&
4913 pResultMatrix->GetDouble( nCol, nRow))
4914 {
4915 SCSIZE nC = nCol + nColDiff;
4916 SCSIZE nR = nRow + nRowDiff;
4917 if (pSumExtraMatrix->IsValue( nC, nR))
4918 {
4919 fVal = pSumExtraMatrix->GetDouble( nC, nR);
4920 ++fCount;
4921 if ( bNull && fVal != 0.0 )
4922 {
4923 bNull = false;
4924 fMem = fVal;
4925 }
4926 else
4927 fSum += fVal;
4928 }
4929 }
4930 }
4931 }
4932 }
4933 else
4934 {
4935 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
4936 {
4937 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
4938 {
4939 if (pResultMatrix->GetDouble( nCol, nRow))
4940 {
4941 aAdr.SetCol( nCol + nColDiff);
4942 aAdr.SetRow( nRow + nRowDiff);
4943 ScBaseCell* pCell = GetCell( aAdr );
4944 if ( HasCellValueData(pCell) )
4945 {
4946 fVal = GetCellValue( aAdr, pCell );
4947 ++fCount;
4948 if ( bNull && fVal != 0.0 )
4949 {
4950 bNull = false;
4951 fMem = fVal;
4952 }
4953 else
4954 fSum += fVal;
4955 }
4956 }
4957 }
4958 }
4959 }
4960 }
4961 else
4962 {
4963 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
4964 // Increment Entry.nField in iterator when switching to next column.
4965 aCellIter.SetAdvanceQueryParamEntryField( true );
4966 if ( aCellIter.GetFirst() )
4967 {
4968 if (pSumExtraMatrix)
4969 {
4970 do
4971 {
4972 SCSIZE nC = aCellIter.GetCol() + nColDiff;
4973 SCSIZE nR = aCellIter.GetRow() + nRowDiff;
4974 if (pSumExtraMatrix->IsValue( nC, nR))
4975 {
4976 fVal = pSumExtraMatrix->GetDouble( nC, nR);
4977 ++fCount;
4978 if ( bNull && fVal != 0.0 )
4979 {
4980 bNull = false;
4981 fMem = fVal;
4982 }
4983 else
4984 fSum += fVal;
4985 }
4986 } while ( aCellIter.GetNext() );
4987 }
4988 else
4989 {
4990 do
4991 {
4992 aAdr.SetCol( aCellIter.GetCol() + nColDiff);
4993 aAdr.SetRow( aCellIter.GetRow() + nRowDiff);
4994 ScBaseCell* pCell = GetCell( aAdr );
4995 if ( HasCellValueData(pCell) )
4996 {
4997 fVal = GetCellValue( aAdr, pCell );
4998 ++fCount;
4999 if ( bNull && fVal != 0.0 )
5000 {
5001 bNull = false;
5002 fMem = fVal;
5003 }
5004 else
5005 fSum += fVal;
5006 }
5007 } while ( aCellIter.GetNext() );
5008 }
5009 }
5010 }
5011 }
5012 else
5013 {
5014 SetError( errIllegalParameter);
5015 }
5016 }
5017
5018 switch( eFunc )
5019 {
5020 case ifSUMIF: fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
5021 case ifAVERAGEIF: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
5022 }
5023 return fRes;
5024 }
5025 return 0;
5026 }
5027
ScSumIf()5028 void ScInterpreter::ScSumIf()
5029 {
5030 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSumIf" );
5031 PushDouble( IterateParametersIf( ifSUMIF));
5032 }
5033
ScAverageIf()5034 void ScInterpreter::ScAverageIf()
5035 {
5036 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScAverageIf" );
5037 PushDouble( IterateParametersIf( ifAVERAGEIF));
5038 }
5039
ScCountIf()5040 void ScInterpreter::ScCountIf()
5041 {
5042 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCountIf" );
5043 if ( MustHaveParamCount( GetByte(), 2 ) )
5044 {
5045 String rString;
5046 double fVal = 0.0;
5047 sal_Bool bIsString = sal_True;
5048 switch ( GetStackType() )
5049 {
5050 case svDoubleRef :
5051 case svSingleRef :
5052 {
5053 ScAddress aAdr;
5054 if ( !PopDoubleRefOrSingleRef( aAdr ) )
5055 {
5056 PushInt(0);
5057 return ;
5058 }
5059 ScBaseCell* pCell = GetCell( aAdr );
5060 switch ( GetCellType( pCell ) )
5061 {
5062 case CELLTYPE_VALUE :
5063 fVal = GetCellValue( aAdr, pCell );
5064 bIsString = sal_False;
5065 break;
5066 case CELLTYPE_FORMULA :
5067 if( ((ScFormulaCell*)pCell)->IsValue() )
5068 {
5069 fVal = GetCellValue( aAdr, pCell );
5070 bIsString = sal_False;
5071 }
5072 else
5073 GetCellString(rString, pCell);
5074 break;
5075 case CELLTYPE_STRING :
5076 case CELLTYPE_EDIT :
5077 GetCellString(rString, pCell);
5078 break;
5079 default:
5080 fVal = 0.0;
5081 bIsString = sal_False;
5082 }
5083 }
5084 break;
5085 case svMatrix :
5086 {
5087 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
5088 bIsString = ScMatrix::IsNonValueType( nType);
5089 }
5090 break;
5091 case svString:
5092 rString = GetString();
5093 break;
5094 default:
5095 {
5096 fVal = GetDouble();
5097 bIsString = sal_False;
5098 }
5099 }
5100 double fCount = 0.0;
5101 short nParam = 1;
5102 size_t nRefInList = 0;
5103 while (nParam-- > 0)
5104 {
5105 SCCOL nCol1;
5106 SCROW nRow1;
5107 SCTAB nTab1;
5108 SCCOL nCol2;
5109 SCROW nRow2;
5110 SCTAB nTab2;
5111 ScMatrixRef pQueryMatrix;
5112 switch ( GetStackType() )
5113 {
5114 case svDoubleRef :
5115 case svRefList :
5116 {
5117 ScRange aRange;
5118 PopDoubleRef( aRange, nParam, nRefInList);
5119 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
5120 }
5121 break;
5122 case svSingleRef :
5123 PopSingleRef( nCol1, nRow1, nTab1 );
5124 nCol2 = nCol1;
5125 nRow2 = nRow1;
5126 nTab2 = nTab1;
5127 break;
5128 case svMatrix:
5129 {
5130 pQueryMatrix = PopMatrix();
5131 if (!pQueryMatrix)
5132 {
5133 PushIllegalParameter();
5134 return;
5135 }
5136 nCol1 = 0;
5137 nRow1 = 0;
5138 nTab1 = 0;
5139 SCSIZE nC, nR;
5140 pQueryMatrix->GetDimensions( nC, nR);
5141 nCol2 = static_cast<SCCOL>(nC - 1);
5142 nRow2 = static_cast<SCROW>(nR - 1);
5143 nTab2 = 0;
5144 }
5145 break;
5146 default:
5147 PushIllegalParameter();
5148 return ;
5149 }
5150 if ( nTab1 != nTab2 )
5151 {
5152 PushIllegalParameter();
5153 return;
5154 }
5155 if (nCol1 > nCol2)
5156 {
5157 PushIllegalParameter();
5158 return;
5159 }
5160 if (nGlobalError == 0)
5161 {
5162 ScQueryParam rParam;
5163 rParam.nRow1 = nRow1;
5164 rParam.nRow2 = nRow2;
5165
5166 ScQueryEntry& rEntry = rParam.GetEntry(0);
5167 rEntry.bDoQuery = sal_True;
5168 if (!bIsString)
5169 {
5170 rEntry.bQueryByString = sal_False;
5171 rEntry.nVal = fVal;
5172 rEntry.eOp = SC_EQUAL;
5173 }
5174 else
5175 {
5176 rParam.FillInExcelSyntax(rString, 0);
5177 sal_uInt32 nIndex = 0;
5178 rEntry.bQueryByString =
5179 !(pFormatter->IsNumberFormat(
5180 *rEntry.pStr, nIndex, rEntry.nVal));
5181 if ( rEntry.bQueryByString )
5182 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5183 }
5184 rParam.nCol1 = nCol1;
5185 rParam.nCol2 = nCol2;
5186 rEntry.nField = nCol1;
5187 if (pQueryMatrix)
5188 {
5189 // Never case-sensitive.
5190 ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
5191 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
5192 if (nGlobalError || !pResultMatrix)
5193 {
5194 PushIllegalParameter();
5195 return;
5196 }
5197
5198 SCSIZE nSize = pResultMatrix->GetElementCount();
5199 for (SCSIZE nIndex = 0; nIndex < nSize; ++nIndex)
5200 {
5201 if (pResultMatrix->IsValue( nIndex) &&
5202 pResultMatrix->GetDouble( nIndex))
5203 ++fCount;
5204 }
5205 }
5206 else
5207 {
5208 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
5209 // Entry.nField im Iterator bei Spaltenwechsel weiterschalten
5210 aCellIter.SetAdvanceQueryParamEntryField( sal_True );
5211 if ( aCellIter.GetFirst() )
5212 {
5213 do
5214 {
5215 fCount++;
5216 } while ( aCellIter.GetNext() );
5217 }
5218 }
5219 }
5220 else
5221 {
5222 PushIllegalParameter();
5223 return;
5224 }
5225 }
5226 PushDouble(fCount);
5227 }
5228 }
5229
IterateParametersIfs(ScIterFuncIfs eFunc)5230 double ScInterpreter::IterateParametersIfs( ScIterFuncIfs eFunc )
5231 {
5232 sal_uInt8 nParamCount = GetByte();
5233 sal_uInt8 nQueryCount = nParamCount / 2;
5234
5235 bool bCheck;
5236 if ( eFunc == ifCOUNTIFS )
5237 bCheck = (nParamCount >= 2) && (nParamCount % 2 == 0);
5238 else
5239 bCheck = (nParamCount >= 3) && (nParamCount % 2 == 1);
5240
5241 if ( !bCheck )
5242 {
5243 SetError( errParameterExpected);
5244 }
5245 else
5246 {
5247 ScMatrixRef pResMat;
5248 double fVal = 0.0;
5249 double fSum = 0.0;
5250 double fMem = 0.0;
5251 double fRes = 0.0;
5252 double fCount = 0.0;
5253 short nParam = 1;
5254 size_t nRefInList = 0;
5255 SCCOL nDimensionCols = 0;
5256 SCROW nDimensionRows = 0;
5257
5258 while (nParamCount > 1 && !nGlobalError)
5259 {
5260 // take criteria
5261 String rString;
5262 fVal = 0.0;
5263 bool bIsString = true;
5264 switch ( GetStackType() )
5265 {
5266 case svDoubleRef :
5267 case svSingleRef :
5268 {
5269 ScAddress aAdr;
5270 if ( !PopDoubleRefOrSingleRef( aAdr ) )
5271 return 0;
5272
5273 ScBaseCell* pCell = GetCell( aAdr );
5274 switch ( GetCellType( pCell ) )
5275 {
5276 case CELLTYPE_VALUE :
5277 fVal = GetCellValue( aAdr, pCell );
5278 bIsString = false;
5279 break;
5280 case CELLTYPE_FORMULA :
5281 if( ((ScFormulaCell*)pCell)->IsValue() )
5282 {
5283 fVal = GetCellValue( aAdr, pCell );
5284 bIsString = false;
5285 }
5286 else
5287 GetCellString(rString, pCell);
5288 break;
5289 case CELLTYPE_STRING :
5290 case CELLTYPE_EDIT :
5291 GetCellString(rString, pCell);
5292 break;
5293 default:
5294 fVal = 0.0;
5295 bIsString = false;
5296 }
5297 }
5298 break;
5299 case svString:
5300 rString = GetString();
5301 break;
5302 case svMatrix :
5303 {
5304 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString);
5305 bIsString = ScMatrix::IsNonValueType( nType);
5306 }
5307 break;
5308 default:
5309 {
5310 fVal = GetDouble();
5311 bIsString = false;
5312 }
5313 }
5314
5315 if (nGlobalError)
5316 continue; // and bail out, no need to evaluate other arguments
5317
5318 // take range
5319 nParam = 1;
5320 nRefInList = 0;
5321 SCCOL nCol1 = 0;
5322 SCROW nRow1 = 0;
5323 SCTAB nTab1 = 0;
5324 SCCOL nCol2 = 0;
5325 SCROW nRow2 = 0;
5326 SCTAB nTab2 = 0;
5327 ScMatrixRef pQueryMatrix;
5328 switch ( GetStackType() )
5329 {
5330 case svRefList :
5331 {
5332 ScRange aRange;
5333 PopDoubleRef( aRange, nParam, nRefInList);
5334 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
5335 }
5336 break;
5337 case svDoubleRef :
5338 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 );
5339 break;
5340 case svSingleRef :
5341 PopSingleRef( nCol1, nRow1, nTab1 );
5342 nCol2 = nCol1;
5343 nRow2 = nRow1;
5344 nTab2 = nTab1;
5345 break;
5346 case svMatrix:
5347 {
5348 pQueryMatrix = PopMatrix();
5349 if (!pQueryMatrix)
5350 {
5351 SetError( errIllegalParameter);
5352 }
5353 nCol1 = 0;
5354 nRow1 = 0;
5355 nTab1 = 0;
5356 SCSIZE nC, nR;
5357 pQueryMatrix->GetDimensions( nC, nR);
5358 nCol2 = static_cast<SCCOL>(nC - 1);
5359 nRow2 = static_cast<SCROW>(nR - 1);
5360 nTab2 = 0;
5361 }
5362 break;
5363 default:
5364 SetError( errIllegalParameter);
5365 }
5366 if ( nTab1 != nTab2 )
5367 SetError( errIllegalArgument);
5368
5369 // All reference ranges must be of same dimension and size.
5370 if (!nDimensionCols)
5371 nDimensionCols = nCol2 - nCol1 + 1;
5372 if (!nDimensionRows)
5373 nDimensionRows = nRow2 - nRow1 + 1;
5374 if ((nDimensionCols != (nCol2 - nCol1 + 1)) || (nDimensionRows != (nRow2 - nRow1 + 1)))
5375 SetError ( errIllegalArgument);
5376
5377 // recalculate matrix values
5378 if (nGlobalError == 0)
5379 {
5380 // initialize temporary result matrix
5381 if (!pResMat)
5382 {
5383 SCSIZE nResC, nResR;
5384 nResC = nCol2 - nCol1 + 1;
5385 nResR = nRow2 - nRow1 + 1;
5386 pResMat = GetNewMat(nResC, nResR);
5387 if (!pResMat)
5388 SetError( errIllegalParameter);
5389 else
5390 pResMat->FillDouble( 0.0, 0, 0, nResC-1, nResR-1);
5391 }
5392
5393 ScQueryParam rParam;
5394 rParam.nRow1 = nRow1;
5395 rParam.nRow2 = nRow2;
5396
5397 ScQueryEntry& rEntry = rParam.GetEntry(0);
5398 rEntry.bDoQuery = true;
5399 if (!bIsString)
5400 {
5401 rEntry.bQueryByString = false;
5402 rEntry.nVal = fVal;
5403 rEntry.eOp = SC_EQUAL;
5404 }
5405 else
5406 {
5407 rParam.FillInExcelSyntax(rString, 0);
5408 sal_uInt32 nIndex = 0;
5409 rEntry.bQueryByString =
5410 !(pFormatter->IsNumberFormat(
5411 *rEntry.pStr, nIndex, rEntry.nVal));
5412 if ( rEntry.bQueryByString )
5413 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
5414 }
5415 ScAddress aAdr;
5416 aAdr.SetTab( nTab1 );
5417 rParam.nCol1 = nCol1;
5418 rParam.nCol2 = nCol2;
5419 rEntry.nField = nCol1;
5420 SCsCOL nColDiff = -nCol1;
5421 SCsROW nRowDiff = -nRow1;
5422 if (pQueryMatrix)
5423 {
5424 // Never case-sensitive.
5425 ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp);
5426 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions);
5427 if (nGlobalError || !pResultMatrix)
5428 {
5429 SetError( errIllegalParameter);
5430 }
5431
5432 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol)
5433 {
5434 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow)
5435 {
5436 if (pResultMatrix->IsValue( nCol, nRow) &&
5437 pResultMatrix->GetDouble( nCol, nRow))
5438 {
5439 SCSIZE nC = nCol + nColDiff;
5440 SCSIZE nR = nRow + nRowDiff;
5441 pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR);
5442 }
5443 }
5444 }
5445 }
5446 else
5447 {
5448 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false);
5449 // Increment Entry.nField in iterator when switching to next column.
5450 aCellIter.SetAdvanceQueryParamEntryField( true );
5451 if ( aCellIter.GetFirst() )
5452 {
5453 do
5454 {
5455 SCSIZE nC = aCellIter.GetCol() + nColDiff;
5456 SCSIZE nR = aCellIter.GetRow() + nRowDiff;
5457 pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR);
5458 } while ( aCellIter.GetNext() );
5459 }
5460 }
5461 }
5462 nParamCount -= 2;
5463 }
5464
5465 if (nGlobalError)
5466 return 0; // bail out
5467
5468 // main range - only for AVERAGEIFS and SUMIFS
5469 if (nParamCount == 1)
5470 {
5471 nParam = 1;
5472 nRefInList = 0;
5473 bool bNull = true;
5474 SCCOL nMainCol1 = 0;
5475 SCROW nMainRow1 = 0;
5476 SCTAB nMainTab1 = 0;
5477 SCCOL nMainCol2 = 0;
5478 SCROW nMainRow2 = 0;
5479 SCTAB nMainTab2 = 0;
5480 ScMatrixRef pMainMatrix;
5481 switch ( GetStackType() )
5482 {
5483 case svRefList :
5484 {
5485 ScRange aRange;
5486 PopDoubleRef( aRange, nParam, nRefInList);
5487 aRange.GetVars( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2);
5488 }
5489 break;
5490 case svDoubleRef :
5491 PopDoubleRef( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2 );
5492 break;
5493 case svSingleRef :
5494 PopSingleRef( nMainCol1, nMainRow1, nMainTab1 );
5495 nMainCol2 = nMainCol1;
5496 nMainRow2 = nMainRow1;
5497 nMainTab2 = nMainTab1;
5498 break;
5499 case svMatrix:
5500 {
5501 pMainMatrix = PopMatrix();
5502 if (!pMainMatrix)
5503 {
5504 SetError( errIllegalParameter);
5505 }
5506 nMainCol1 = 0;
5507 nMainRow1 = 0;
5508 nMainTab1 = 0;
5509 SCSIZE nC, nR;
5510 pMainMatrix->GetDimensions( nC, nR);
5511 nMainCol2 = static_cast<SCCOL>(nC - 1);
5512 nMainRow2 = static_cast<SCROW>(nR - 1);
5513 nMainTab2 = 0;
5514 }
5515 break;
5516 default:
5517 SetError( errIllegalParameter);
5518 }
5519 if ( nMainTab1 != nMainTab2 )
5520 SetError( errIllegalArgument);
5521
5522 // All reference ranges must be of same dimension and size.
5523 if ((nDimensionCols != (nMainCol2 - nMainCol1 + 1)) || (nDimensionRows != (nMainRow2 - nMainRow1 + 1)))
5524 SetError ( errIllegalArgument);
5525
5526 if (nGlobalError)
5527 return 0; // bail out
5528
5529 // end-result calculation
5530 ScAddress aAdr;
5531 aAdr.SetTab( nMainTab1 );
5532 if (pMainMatrix)
5533 {
5534 SCSIZE nC, nR;
5535 pResMat->GetDimensions(nC, nR);
5536 for (SCSIZE nCol = 0; nCol < nC; ++nCol)
5537 {
5538 for (SCSIZE nRow = 0; nRow < nR; ++nRow)
5539 {
5540 if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
5541 {
5542 if (pMainMatrix->IsValue( nCol, nRow))
5543 {
5544 fVal = pMainMatrix->GetDouble( nCol, nRow);
5545 ++fCount;
5546 if ( bNull && fVal != 0.0 )
5547 {
5548 bNull = false;
5549 fMem = fVal;
5550 }
5551 else
5552 fSum += fVal;
5553 }
5554 }
5555 }
5556 }
5557 }
5558 else
5559 {
5560 SCSIZE nC, nR;
5561 pResMat->GetDimensions(nC, nR);
5562 for (SCSIZE nCol = 0; nCol < nC; ++nCol)
5563 {
5564 for (SCSIZE nRow = 0; nRow < nR; ++nRow)
5565 {
5566 if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
5567 {
5568 aAdr.SetCol( static_cast<SCCOL>(nCol) + nMainCol1);
5569 aAdr.SetRow( static_cast<SCROW>(nRow) + nMainRow1);
5570 ScBaseCell* pCell = GetCell( aAdr );
5571 if ( HasCellValueData(pCell) )
5572 {
5573 fVal = GetCellValue( aAdr, pCell );
5574 ++fCount;
5575 if ( bNull && fVal != 0.0 )
5576 {
5577 bNull = false;
5578 fMem = fVal;
5579 }
5580 else
5581 fSum += fVal;
5582 }
5583 }
5584 }
5585 }
5586 }
5587 }
5588 else
5589 {
5590 SCSIZE nC, nR;
5591 pResMat->GetDimensions(nC, nR);
5592 for (SCSIZE nCol = 0; nCol < nC; ++nCol)
5593 {
5594 for (SCSIZE nRow = 0; nRow < nR; ++nRow)
5595 if (pResMat->GetDouble( nCol, nRow) == nQueryCount)
5596 ++fCount;
5597 }
5598 }
5599
5600 switch( eFunc )
5601 {
5602 case ifSUMIFS: fRes = ::rtl::math::approxAdd( fSum, fMem ); break;
5603 case ifAVERAGEIFS: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break;
5604 case ifCOUNTIFS: fRes = fCount; break;
5605 default: ; // nothing
5606 }
5607 return fRes;
5608 }
5609 return 0;
5610 }
5611
ScSumIfs()5612 void ScInterpreter::ScSumIfs()
5613 {
5614 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScSumIfs" );
5615 PushDouble( IterateParametersIfs( ifSUMIFS));
5616 }
5617
ScAverageIfs()5618 void ScInterpreter::ScAverageIfs()
5619 {
5620 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScAverageIfs" );
5621 PushDouble( IterateParametersIfs( ifAVERAGEIFS));
5622 }
5623
ScCountIfs()5624 void ScInterpreter::ScCountIfs()
5625 {
5626 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScCountIfs" );
5627 PushDouble( IterateParametersIfs( ifCOUNTIFS));
5628 }
5629
ScLookup()5630 void ScInterpreter::ScLookup()
5631 {
5632 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLookup" );
5633 sal_uInt8 nParamCount = GetByte();
5634 if ( !MustHaveParamCount( nParamCount, 2, 3 ) )
5635 return ;
5636
5637 ScMatrixRef pDataMat = NULL, pResMat = NULL;
5638 SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0;
5639 SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0;
5640 SCTAB nTab1 = 0, nResTab = 0;
5641 SCSIZE nLenMajor = 0; // length of major direction
5642 bool bVertical = true; // whether to lookup vertically or horizontally
5643
5644 // The third parameter, result array, for double, string and single reference.
5645 double fResVal = 0.0;
5646 String aResStr;
5647 ScAddress aResAdr;
5648 StackVar eResArrayType = svUnknown;
5649
5650 if (nParamCount == 3)
5651 {
5652 eResArrayType = GetStackType();
5653 switch (eResArrayType)
5654 {
5655 case svDoubleRef:
5656 {
5657 SCTAB nTabJunk;
5658 PopDoubleRef(nResCol1, nResRow1, nResTab,
5659 nResCol2, nResRow2, nTabJunk);
5660 if (nResTab != nTabJunk ||
5661 ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0))
5662 {
5663 // The result array must be a vector.
5664 PushIllegalParameter();
5665 return;
5666 }
5667 }
5668 break;
5669 case svMatrix:
5670 {
5671 pResMat = PopMatrix();
5672 if (!pResMat)
5673 {
5674 PushIllegalParameter();
5675 return;
5676 }
5677 SCSIZE nC, nR;
5678 pResMat->GetDimensions(nC, nR);
5679 if (nC != 1 && nR != 1)
5680 {
5681 // Result matrix must be a vector.
5682 PushIllegalParameter();
5683 return;
5684 }
5685 }
5686 break;
5687 case svDouble:
5688 fResVal = GetDouble();
5689 break;
5690 case svString:
5691 aResStr = GetString();
5692 break;
5693 case svSingleRef:
5694 PopSingleRef( aResAdr );
5695 break;
5696 default:
5697 PushIllegalParameter();
5698 return;
5699 }
5700 }
5701
5702 // For double, string and single reference.
5703 double fDataVal = 0.0;
5704 String aDataStr;
5705 ScAddress aDataAdr;
5706 bool bValueData = false;
5707
5708 // Get the data-result range and also determine whether this is vertical
5709 // lookup or horizontal lookup.
5710
5711 StackVar eDataArrayType = GetStackType();
5712 switch (eDataArrayType)
5713 {
5714 case svDoubleRef:
5715 {
5716 SCTAB nTabJunk;
5717 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk);
5718 if (nTab1 != nTabJunk)
5719 {
5720 PushIllegalParameter();
5721 return;
5722 }
5723 bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1);
5724 nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1;
5725 }
5726 break;
5727 case svMatrix:
5728 {
5729 pDataMat = PopMatrix();
5730 if (!pDataMat)
5731 {
5732 PushIllegalParameter();
5733 return;
5734 }
5735
5736 SCSIZE nC, nR;
5737 pDataMat->GetDimensions(nC, nR);
5738 bVertical = (nR >= nC);
5739 nLenMajor = bVertical ? nR : nC;
5740 }
5741 break;
5742 case svDouble:
5743 {
5744 fDataVal = GetDouble();
5745 bValueData = true;
5746 }
5747 break;
5748 case svString:
5749 {
5750 aDataStr = GetString();
5751 }
5752 break;
5753 case svSingleRef:
5754 {
5755 PopSingleRef( aDataAdr );
5756 const ScBaseCell* pDataCell = GetCell( aDataAdr );
5757 if (HasCellEmptyData( pDataCell))
5758 {
5759 // Empty cells aren't found anywhere, bail out early.
5760 SetError( NOTAVAILABLE);
5761 }
5762 else if (HasCellValueData( pDataCell))
5763 {
5764 fDataVal = GetCellValue( aDataAdr, pDataCell );
5765 bValueData = true;
5766 }
5767 else
5768 GetCellString( aDataStr, pDataCell );
5769 }
5770 break;
5771 default:
5772 SetError( errIllegalParameter);
5773 }
5774
5775
5776 if (nGlobalError)
5777 {
5778 PushError( nGlobalError);
5779 return;
5780 }
5781
5782 // Get the lookup value.
5783
5784 ScQueryParam aParam;
5785 ScQueryEntry& rEntry = aParam.GetEntry(0);
5786 if ( !FillEntry(rEntry) )
5787 return;
5788
5789 if ( eDataArrayType == svDouble || eDataArrayType == svString ||
5790 eDataArrayType == svSingleRef )
5791 {
5792 // Delta position for a single value is always 0.
5793
5794 // Found if data <= query, but not if query is string and found data is
5795 // numeric or vice versa. This is how Excel does it but doesn't
5796 // document it.
5797
5798 bool bFound = false;
5799 if ( bValueData )
5800 {
5801 if ( rEntry.bQueryByString )
5802 bFound = false;
5803 else
5804 bFound = (fDataVal <= rEntry.nVal);
5805 }
5806 else
5807 {
5808 if ( !rEntry.bQueryByString )
5809 bFound = false;
5810 else
5811 bFound = (ScGlobal::GetCollator()->compareString( aDataStr, *rEntry.pStr) <= 0);
5812 }
5813
5814 if (!bFound)
5815 {
5816 PushNA();
5817 return;
5818 }
5819
5820 if (pResMat)
5821 {
5822 if (pResMat->IsValue( 0 ))
5823 PushDouble(pResMat->GetDouble( 0 ));
5824 else
5825 PushString(pResMat->GetString( 0 ));
5826 }
5827 else if (nParamCount == 3)
5828 {
5829 switch (eResArrayType)
5830 {
5831 case svDouble:
5832 PushDouble( fResVal );
5833 break;
5834 case svString:
5835 PushString( aResStr );
5836 break;
5837 case svDoubleRef:
5838 aResAdr.Set( nResCol1, nResRow1, nResTab);
5839 // fallthru
5840 case svSingleRef:
5841 PushCellResultToken( true, aResAdr, NULL, NULL);
5842 break;
5843 default:
5844 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data");
5845 }
5846 }
5847 else
5848 {
5849 switch (eDataArrayType)
5850 {
5851 case svDouble:
5852 PushDouble( fDataVal );
5853 break;
5854 case svString:
5855 PushString( aDataStr );
5856 break;
5857 case svSingleRef:
5858 PushCellResultToken( true, aDataAdr, NULL, NULL);
5859 break;
5860 default:
5861 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data");
5862 }
5863 }
5864 return;
5865 }
5866
5867 // Now, perform the search to compute the delta position (nDelta).
5868
5869 if (pDataMat)
5870 {
5871 // Data array is given as a matrix.
5872 rEntry.bDoQuery = true;
5873 rEntry.eOp = SC_LESS_EQUAL;
5874 bool bFound = false;
5875
5876 SCSIZE nC, nR;
5877 pDataMat->GetDimensions(nC, nR);
5878
5879 // In case of non-vector matrix, only search the first row or column.
5880 ScMatrixRef pDataMat2;
5881 if (bVertical)
5882 {
5883 ScMatrixRef pTempMat(new ScMatrix(1, nR));
5884 for (SCSIZE i = 0; i < nR; ++i)
5885 if (pDataMat->IsValue(0, i))
5886 pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i);
5887 else
5888 pTempMat->PutString(pDataMat->GetString(0, i), 0, i);
5889 pDataMat2 = pTempMat;
5890 }
5891 else
5892 {
5893 ScMatrixRef pTempMat(new ScMatrix(nC, 1));
5894 for (SCSIZE i = 0; i < nC; ++i)
5895 if (pDataMat->IsValue(i, 0))
5896 pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0);
5897 else
5898 pTempMat->PutString(pDataMat->GetString(i, 0), i, 0);
5899 pDataMat2 = pTempMat;
5900 }
5901
5902 // binary search for non-equality mode (the source data is
5903 // assumed to be sorted in ascending order).
5904
5905 SCCOLROW nDelta = -1;
5906
5907 SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0;
5908 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst)
5909 {
5910 SCSIZE nMid = nFirst + nLen/2;
5911 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry);
5912 if (nCmp == 0)
5913 {
5914 // exact match. find the last item with the same value.
5915 lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false);
5916 nDelta = nMid;
5917 bFound = true;
5918 break;
5919 }
5920
5921 if (nLen == 1) // first and last items are next to each other.
5922 {
5923 nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1;
5924 // If already the 1st item is greater there's nothing found.
5925 bFound = (nDelta >= 0);
5926 break;
5927 }
5928
5929 if (nCmp < 0)
5930 nFirst = nMid;
5931 else
5932 nLast = nMid;
5933 }
5934
5935 if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item
5936 {
5937 sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry);
5938 if (nCmp <= 0)
5939 {
5940 // either the last item is an exact match or the real
5941 // hit is beyond the last item.
5942 nDelta += 1;
5943 bFound = true;
5944 }
5945 }
5946 else if (nDelta > 0) // valid hit must be 2nd item or higher
5947 {
5948 // non-exact match
5949 bFound = true;
5950 }
5951
5952 // With 0-9 < A-Z, if query is numeric and data found is string, or
5953 // vice versa, the (yet another undocumented) Excel behavior is to
5954 // return #N/A instead.
5955
5956 if (bFound)
5957 {
5958 SCCOLROW i = nDelta;
5959 SCSIZE n = pDataMat->GetElementCount();
5960 if (static_cast<SCSIZE>(i) >= n)
5961 i = static_cast<SCCOLROW>(n);
5962 if (bool(rEntry.bQueryByString) == bool(pDataMat->IsValue(i)))
5963 bFound = false;
5964 }
5965
5966 if (!bFound)
5967 {
5968 PushNA();
5969 return;
5970 }
5971
5972 // Now that we've found the delta, push the result back to the cell.
5973
5974 if (pResMat)
5975 {
5976 // result array is matrix.
5977 if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount())
5978 {
5979 PushNA();
5980 return;
5981 }
5982 if (pResMat->IsValue(nDelta))
5983 PushDouble(pResMat->GetDouble(nDelta));
5984 else
5985 PushString(pResMat->GetString(nDelta));
5986 }
5987 else if (nParamCount == 3)
5988 {
5989 // result array is cell range.
5990 ScAddress aAdr;
5991 aAdr.SetTab(nResTab);
5992 bool bResVertical = (nResRow2 - nResRow1) > 0;
5993 if (bResVertical)
5994 {
5995 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
5996 if (nTempRow > MAXROW)
5997 {
5998 PushDouble(0);
5999 return;
6000 }
6001 aAdr.SetCol(nResCol1);
6002 aAdr.SetRow(nTempRow);
6003 }
6004 else
6005 {
6006 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
6007 if (nTempCol > MAXCOL)
6008 {
6009 PushDouble(0);
6010 return;
6011 }
6012 aAdr.SetCol(nTempCol);
6013 aAdr.SetRow(nResRow1);
6014 }
6015 PushCellResultToken(true, aAdr, NULL, NULL);
6016 }
6017 else
6018 {
6019 // no result array. Use the data array to get the final value from.
6020 if (bVertical)
6021 {
6022 if (pDataMat->IsValue(nC-1, nDelta))
6023 PushDouble(pDataMat->GetDouble(nC-1, nDelta));
6024 else
6025 PushString(pDataMat->GetString(nC-1, nDelta));
6026 }
6027 else
6028 {
6029 if (pDataMat->IsValue(nDelta, nR-1))
6030 PushDouble(pDataMat->GetDouble(nDelta, nR-1));
6031 else
6032 PushString(pDataMat->GetString(nDelta, nR-1));
6033 }
6034 }
6035
6036 return;
6037 }
6038
6039 // Perform cell range search.
6040
6041 aParam.nCol1 = nCol1;
6042 aParam.nRow1 = nRow1;
6043 aParam.nCol2 = bVertical ? nCol1 : nCol2;
6044 aParam.nRow2 = bVertical ? nRow2 : nRow1;
6045 aParam.bByRow = bVertical;
6046 aParam.bMixedComparison = true;
6047
6048 rEntry.bDoQuery = sal_True;
6049 rEntry.eOp = SC_LESS_EQUAL;
6050 rEntry.nField = nCol1;
6051 if ( rEntry.bQueryByString )
6052 aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
6053
6054 ScQueryCellIterator aCellIter(pDok, nTab1, aParam, sal_False);
6055 SCCOL nC;
6056 SCROW nR;
6057 // Advance Entry.nField in iterator upon switching columns if
6058 // lookup in row.
6059 aCellIter.SetAdvanceQueryParamEntryField(!bVertical);
6060 if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) )
6061 {
6062 PushNA();
6063 return;
6064 }
6065
6066 SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1);
6067
6068 if (pResMat)
6069 {
6070 // Use the matrix result array.
6071 if (pResMat->IsValue(nDelta))
6072 PushDouble(pResMat->GetDouble(nDelta));
6073 else
6074 PushString(pResMat->GetString(nDelta));
6075 }
6076 else if (nParamCount == 3)
6077 {
6078 switch (eResArrayType)
6079 {
6080 case svDoubleRef:
6081 {
6082 // Use the result array vector. Note that the result array is assumed
6083 // to be a vector (i.e. 1-dimensinoal array).
6084
6085 ScAddress aAdr;
6086 aAdr.SetTab(nResTab);
6087 bool bResVertical = (nResRow2 - nResRow1) > 0;
6088 if (bResVertical)
6089 {
6090 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta);
6091 if (nTempRow > MAXROW)
6092 {
6093 PushDouble(0);
6094 return;
6095 }
6096 aAdr.SetCol(nResCol1);
6097 aAdr.SetRow(nTempRow);
6098 }
6099 else
6100 {
6101 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta);
6102 if (nTempCol > MAXCOL)
6103 {
6104 PushDouble(0);
6105 return;
6106 }
6107 aAdr.SetCol(nTempCol);
6108 aAdr.SetRow(nResRow1);
6109 }
6110 PushCellResultToken( true, aAdr, NULL, NULL);
6111 }
6112 break;
6113 case svDouble:
6114 case svString:
6115 case svSingleRef:
6116 {
6117 if (nDelta != 0)
6118 PushNA();
6119 else
6120 {
6121 switch (eResArrayType)
6122 {
6123 case svDouble:
6124 PushDouble( fResVal );
6125 break;
6126 case svString:
6127 PushString( aResStr );
6128 break;
6129 case svSingleRef:
6130 PushCellResultToken( true, aResAdr, NULL, NULL);
6131 break;
6132 default:
6133 ; // nothing
6134 }
6135 }
6136 }
6137 break;
6138 default:
6139 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, range search");
6140 }
6141 }
6142 else
6143 {
6144 // Regardless of whether or not the result array exists, the last
6145 // array is always used as the "result" array.
6146
6147 ScAddress aAdr;
6148 aAdr.SetTab(nTab1);
6149 if (bVertical)
6150 {
6151 SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta);
6152 if (nTempRow > MAXROW)
6153 {
6154 PushDouble(0);
6155 return;
6156 }
6157 aAdr.SetCol(nCol2);
6158 aAdr.SetRow(nTempRow);
6159 }
6160 else
6161 {
6162 SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta);
6163 if (nTempCol > MAXCOL)
6164 {
6165 PushDouble(0);
6166 return;
6167 }
6168 aAdr.SetCol(nTempCol);
6169 aAdr.SetRow(nRow2);
6170 }
6171 PushCellResultToken(true, aAdr, NULL, NULL);
6172 }
6173 }
6174
6175
ScHLookup()6176 void ScInterpreter::ScHLookup()
6177 {
6178 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHLookup" );
6179 CalculateLookup(sal_True);
6180 }
CalculateLookup(sal_Bool HLookup)6181 void ScInterpreter::CalculateLookup(sal_Bool HLookup)
6182 {
6183 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateLookup" );
6184 sal_uInt8 nParamCount = GetByte();
6185 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
6186 {
6187 sal_Bool bSorted;
6188 if (nParamCount == 4)
6189 bSorted = GetBool();
6190 else
6191 bSorted = sal_True;
6192 double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0;
6193 ScMatrixRef pMat = NULL;
6194 SCSIZE nC = 0, nR = 0;
6195 SCCOL nCol1 = 0;
6196 SCROW nRow1 = 0;
6197 SCTAB nTab1 = 0;
6198 SCCOL nCol2 = 0;
6199 SCROW nRow2 = 0;
6200 SCTAB nTab2;
6201 if (GetStackType() == svDoubleRef)
6202 {
6203 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
6204 if (nTab1 != nTab2)
6205 {
6206 PushIllegalParameter();
6207 return;
6208 }
6209 }
6210 else if (GetStackType() == svMatrix)
6211 {
6212 pMat = PopMatrix();
6213 if (pMat)
6214 pMat->GetDimensions(nC, nR);
6215 else
6216 {
6217 PushIllegalParameter();
6218 return;
6219 }
6220 }
6221 else
6222 {
6223 PushIllegalParameter();
6224 return;
6225 }
6226 if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) )
6227 {
6228 PushIllegalArgument();
6229 return;
6230 }
6231 SCROW nZIndex = static_cast<SCROW>(fIndex);
6232 SCCOL nSpIndex = static_cast<SCCOL>(fIndex);
6233
6234 if (!pMat)
6235 {
6236 nZIndex += nRow1; // Wertzeile
6237 nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 ); // value column
6238 }
6239
6240 if (nGlobalError == 0)
6241 {
6242 ScQueryParam rParam;
6243 rParam.nCol1 = nCol1;
6244 rParam.nRow1 = nRow1;
6245 if ( HLookup )
6246 {
6247 rParam.nCol2 = nCol2;
6248 rParam.nRow2 = nRow1; // nur in der ersten Zeile suchen
6249 rParam.bByRow = sal_False;
6250 } // if ( HLookup )
6251 else
6252 {
6253 rParam.nCol2 = nCol1; // nur in der ersten Spalte suchen
6254 rParam.nRow2 = nRow2;
6255 rParam.nTab = nTab1;
6256 }
6257 rParam.bMixedComparison = sal_True;
6258
6259 ScQueryEntry& rEntry = rParam.GetEntry(0);
6260 rEntry.bDoQuery = sal_True;
6261 if ( bSorted )
6262 rEntry.eOp = SC_LESS_EQUAL;
6263 if ( !FillEntry(rEntry) )
6264 return;
6265 if ( rEntry.bQueryByString )
6266 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
6267 if (pMat)
6268 {
6269 SCSIZE nMatCount = HLookup ? nC : nR;
6270 SCSIZE nDelta = SCSIZE_MAX;
6271 if (rEntry.bQueryByString)
6272 {
6273 //!!!!!!!
6274 //! TODO: enable regex on matrix strings
6275 //!!!!!!!
6276 String aParamStr = *rEntry.pStr;
6277 if ( bSorted )
6278 {
6279 static CollatorWrapper* pCollator = ScGlobal::GetCollator();
6280 for (SCSIZE i = 0; i < nMatCount; i++)
6281 {
6282 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
6283 {
6284 sal_Int32 nRes =
6285 pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr);
6286 if (nRes <= 0)
6287 nDelta = i;
6288 else if (i>0) // #i2168# ignore first mismatch
6289 i = nMatCount+1;
6290 }
6291 else
6292 nDelta = i;
6293 }
6294 }
6295 else
6296 {
6297 for (SCSIZE i = 0; i < nMatCount; i++)
6298 {
6299 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))
6300 {
6301 if ( ScGlobal::GetpTransliteration()->isEqual(
6302 HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr ) )
6303 {
6304 nDelta = i;
6305 i = nMatCount + 1;
6306 }
6307 }
6308 }
6309 }
6310 }
6311 else
6312 {
6313 if ( bSorted )
6314 {
6315 // #i2168# ignore strings
6316 for (SCSIZE i = 0; i < nMatCount; i++)
6317 {
6318 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
6319 {
6320 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rEntry.nVal)
6321 nDelta = i;
6322 else
6323 i = nMatCount+1;
6324 }
6325 }
6326 }
6327 else
6328 {
6329 for (SCSIZE i = 0; i < nMatCount; i++)
6330 {
6331 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)))
6332 {
6333 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) == rEntry.nVal)
6334 {
6335 nDelta = i;
6336 i = nMatCount + 1;
6337 }
6338 }
6339 }
6340 }
6341 }
6342 if ( nDelta != SCSIZE_MAX )
6343 {
6344 SCSIZE nX = static_cast<SCSIZE>(nSpIndex);
6345 SCSIZE nY = nDelta;
6346 if ( HLookup )
6347 {
6348 nX = nDelta;
6349 nY = static_cast<SCSIZE>(nZIndex);
6350 }
6351 if ( pMat->IsString( nX, nY) )
6352 PushString(pMat->GetString( nX,nY));
6353 else
6354 PushDouble(pMat->GetDouble( nX,nY));
6355 }
6356 else
6357 PushNA();
6358 }
6359 else
6360 {
6361 rEntry.nField = nCol1;
6362 sal_Bool bFound = sal_False;
6363 SCCOL nCol = 0;
6364 SCROW nRow = 0;
6365 if ( bSorted )
6366 rEntry.eOp = SC_LESS_EQUAL;
6367 if ( HLookup )
6368 {
6369 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False);
6370 // advance Entry.nField in Iterator upon switching columns
6371 aCellIter.SetAdvanceQueryParamEntryField( sal_True );
6372 if ( bSorted )
6373 {
6374 SCROW nRow1_temp;
6375 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp );
6376 }
6377 else if ( aCellIter.GetFirst() )
6378 {
6379 bFound = sal_True;
6380 nCol = aCellIter.GetCol();
6381 }
6382 nRow = nZIndex;
6383 } // if ( HLookup )
6384 else
6385 {
6386 ScAddress aResultPos( nCol1, nRow1, nTab1);
6387 bFound = LookupQueryWithCache( aResultPos, rParam);
6388 nRow = aResultPos.Row();
6389 nCol = nSpIndex;
6390 }
6391 if ( bFound )
6392 {
6393 ScAddress aAdr( nCol, nRow, nTab1 );
6394 PushCellResultToken( true, aAdr, NULL, NULL);
6395 }
6396 else
6397 PushNA();
6398 }
6399 }
6400 else
6401 PushIllegalParameter();
6402 }
6403 }
6404
FillEntry(ScQueryEntry & rEntry)6405 bool ScInterpreter::FillEntry(ScQueryEntry& rEntry)
6406 {
6407 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::FillEntry" );
6408 switch ( GetStackType() )
6409 {
6410 case svDouble:
6411 {
6412 rEntry.bQueryByString = sal_False;
6413 rEntry.nVal = GetDouble();
6414 }
6415 break;
6416 case svString:
6417 {
6418 const String sStr = GetString();
6419 rEntry.bQueryByString = sal_True;
6420 *rEntry.pStr = sStr;
6421 }
6422 break;
6423 case svDoubleRef :
6424 case svSingleRef :
6425 {
6426 ScAddress aAdr;
6427 if ( !PopDoubleRefOrSingleRef( aAdr ) )
6428 {
6429 PushInt(0);
6430 return false;
6431 }
6432 ScBaseCell* pCell = GetCell( aAdr );
6433 if (HasCellValueData(pCell))
6434 {
6435 rEntry.bQueryByString = sal_False;
6436 rEntry.nVal = GetCellValue( aAdr, pCell );
6437 }
6438 else
6439 {
6440 if ( GetCellType( pCell ) == CELLTYPE_NOTE )
6441 {
6442 rEntry.bQueryByString = sal_False;
6443 rEntry.nVal = 0.0;
6444 }
6445 else
6446 {
6447 String sStr;
6448 GetCellString(sStr, pCell);
6449 rEntry.bQueryByString = sal_True;
6450 *rEntry.pStr = sStr;
6451 }
6452 }
6453 }
6454 break;
6455 case svMatrix :
6456 {
6457 const ScMatValType nType = GetDoubleOrStringFromMatrix(rEntry.nVal, *rEntry.pStr);
6458 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType);
6459 }
6460 break;
6461 default:
6462 {
6463 PushIllegalParameter();
6464 return false;
6465 }
6466 } // switch ( GetStackType() )
6467 return true;
6468 }
ScVLookup()6469 void ScInterpreter::ScVLookup()
6470 {
6471 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVLookup" );
6472 CalculateLookup(sal_False);
6473 }
6474
ScSubTotal()6475 void ScInterpreter::ScSubTotal()
6476 {
6477 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubTotal" );
6478 sal_uInt8 nParamCount = GetByte();
6479 if ( MustHaveParamCountMin( nParamCount, 2 ) )
6480 {
6481 // We must fish the 1st parameter deep from the stack! And push it on top.
6482 const FormulaToken* p = pStack[ sp - nParamCount ];
6483 PushTempToken( *p );
6484 int nFunc = (int) ::rtl::math::approxFloor( GetDouble() );
6485 if( nFunc < 1 || nFunc > 11 )
6486 PushIllegalArgument(); // simulate return on stack, not SetError(...)
6487 else
6488 {
6489 cPar = nParamCount - 1;
6490 glSubTotal = sal_True;
6491 switch( nFunc )
6492 {
6493 case SUBTOTAL_FUNC_AVE : ScAverage(); break;
6494 case SUBTOTAL_FUNC_CNT : ScCount(); break;
6495 case SUBTOTAL_FUNC_CNT2 : ScCount2(); break;
6496 case SUBTOTAL_FUNC_MAX : ScMax(); break;
6497 case SUBTOTAL_FUNC_MIN : ScMin(); break;
6498 case SUBTOTAL_FUNC_PROD : ScProduct(); break;
6499 case SUBTOTAL_FUNC_STD : ScStDev(); break;
6500 case SUBTOTAL_FUNC_STDP : ScStDevP(); break;
6501 case SUBTOTAL_FUNC_SUM : ScSum(); break;
6502 case SUBTOTAL_FUNC_VAR : ScVar(); break;
6503 case SUBTOTAL_FUNC_VARP : ScVarP(); break;
6504 default : PushIllegalArgument(); break;
6505 }
6506 glSubTotal = sal_False;
6507 }
6508 // Get rid of the 1st (fished) parameter.
6509 double nVal = GetDouble();
6510 Pop();
6511 PushDouble( nVal );
6512 }
6513 }
6514
GetDBParams(sal_Bool & rMissingField)6515 ScDBQueryParamBase* ScInterpreter::GetDBParams( sal_Bool& rMissingField )
6516 {
6517 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" );
6518 sal_Bool bAllowMissingField = sal_False;
6519 if ( rMissingField )
6520 {
6521 bAllowMissingField = sal_True;
6522 rMissingField = sal_False;
6523 }
6524 if ( GetByte() == 3 )
6525 {
6526 // First, get the query criteria range.
6527 ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() );
6528 if (!pQueryRef.get())
6529 return NULL;
6530
6531 sal_Bool bByVal = sal_True;
6532 double nVal = 0.0;
6533 String aStr;
6534 ScRange aMissingRange;
6535 sal_Bool bRangeFake = sal_False;
6536 switch (GetStackType())
6537 {
6538 case svDouble :
6539 nVal = ::rtl::math::approxFloor( GetDouble() );
6540 if ( bAllowMissingField && nVal == 0.0 )
6541 rMissingField = sal_True; // fake missing parameter
6542 break;
6543 case svString :
6544 bByVal = sal_False;
6545 aStr = GetString();
6546 break;
6547 case svSingleRef :
6548 {
6549 ScAddress aAdr;
6550 PopSingleRef( aAdr );
6551 ScBaseCell* pCell = GetCell( aAdr );
6552 if (HasCellValueData(pCell))
6553 nVal = GetCellValue( aAdr, pCell );
6554 else
6555 {
6556 bByVal = sal_False;
6557 GetCellString(aStr, pCell);
6558 }
6559 }
6560 break;
6561 case svDoubleRef :
6562 if ( bAllowMissingField )
6563 { // fake missing parameter for old SO compatibility
6564 bRangeFake = sal_True;
6565 PopDoubleRef( aMissingRange );
6566 }
6567 else
6568 {
6569 PopError();
6570 SetError( errIllegalParameter );
6571 }
6572 break;
6573 case svMissing :
6574 PopError();
6575 if ( bAllowMissingField )
6576 rMissingField = sal_True;
6577 else
6578 SetError( errIllegalParameter );
6579 break;
6580 default:
6581 PopError();
6582 SetError( errIllegalParameter );
6583 }
6584
6585 auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() );
6586
6587 if (nGlobalError || !pDBRef.get())
6588 return NULL;
6589
6590 if ( bRangeFake )
6591 {
6592 // range parameter must match entire database range
6593 if (pDBRef->isRangeEqual(aMissingRange))
6594 rMissingField = sal_True;
6595 else
6596 SetError( errIllegalParameter );
6597 }
6598
6599 if (nGlobalError)
6600 return NULL;
6601
6602 SCCOL nField = pDBRef->getFirstFieldColumn();
6603 if (rMissingField)
6604 ; // special case
6605 else if (bByVal)
6606 nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal));
6607 else
6608 {
6609 sal_uInt16 nErr = 0;
6610 nField = pDBRef->findFieldColumn(aStr, &nErr);
6611 SetError(nErr);
6612 }
6613
6614 if (!ValidCol(nField))
6615 return NULL;
6616
6617 auto_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) );
6618
6619 if (pParam.get())
6620 {
6621 // An allowed missing field parameter sets the result field
6622 // to any of the query fields, just to be able to return
6623 // some cell from the iterator.
6624 if ( rMissingField )
6625 nField = static_cast<SCCOL>(pParam->GetEntry(0).nField);
6626 pParam->mnField = nField;
6627
6628 SCSIZE nCount = pParam->GetEntryCount();
6629 for ( SCSIZE i=0; i < nCount; i++ )
6630 {
6631 ScQueryEntry& rEntry = pParam->GetEntry(i);
6632 if ( rEntry.bDoQuery )
6633 {
6634 sal_uInt32 nIndex = 0;
6635 rEntry.bQueryByString = !pFormatter->IsNumberFormat(
6636 *rEntry.pStr, nIndex, rEntry.nVal );
6637 if ( rEntry.bQueryByString && !pParam->bRegExp )
6638 pParam->bRegExp = MayBeRegExp( *rEntry.pStr, pDok );
6639 }
6640 else
6641 break; // for
6642 }
6643 return pParam.release();
6644 }
6645 }
6646 return NULL;
6647 }
6648
6649
DBIterator(ScIterFunc eFunc)6650 void ScInterpreter::DBIterator( ScIterFunc eFunc )
6651 {
6652 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" );
6653 double nErg = 0.0;
6654 double fMem = 0.0;
6655 sal_Bool bNull = sal_True;
6656 sal_uLong nCount = 0;
6657 sal_Bool bMissingField = sal_False;
6658 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6659 if (pQueryParam.get())
6660 {
6661 ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
6662 ScDBQueryDataIterator::Value aValue;
6663 if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6664 {
6665 switch( eFunc )
6666 {
6667 case ifPRODUCT: nErg = 1; break;
6668 case ifMAX: nErg = -MAXDOUBLE; break;
6669 case ifMIN: nErg = MAXDOUBLE; break;
6670 default: ; // nothing
6671 }
6672 do
6673 {
6674 nCount++;
6675 switch( eFunc )
6676 {
6677 case ifAVERAGE:
6678 case ifSUM:
6679 if ( bNull && aValue.mfValue != 0.0 )
6680 {
6681 bNull = sal_False;
6682 fMem = aValue.mfValue;
6683 }
6684 else
6685 nErg += aValue.mfValue;
6686 break;
6687 case ifSUMSQ: nErg += aValue.mfValue * aValue.mfValue; break;
6688 case ifPRODUCT: nErg *= aValue.mfValue; break;
6689 case ifMAX: if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break;
6690 case ifMIN: if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break;
6691 default: ; // nothing
6692 }
6693 }
6694 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6695 }
6696 SetError(aValue.mnError);
6697 }
6698 else
6699 SetError( errIllegalParameter);
6700 switch( eFunc )
6701 {
6702 case ifCOUNT: nErg = nCount; break;
6703 case ifSUM: nErg = ::rtl::math::approxAdd( nErg, fMem ); break;
6704 case ifAVERAGE: nErg = ::rtl::math::approxAdd( nErg, fMem ) / nCount; break;
6705 default: ; // nothing
6706 }
6707 PushDouble( nErg );
6708 }
6709
6710
ScDBSum()6711 void ScInterpreter::ScDBSum()
6712 {
6713 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBSum" );
6714 DBIterator( ifSUM );
6715 }
6716
6717
ScDBCount()6718 void ScInterpreter::ScDBCount()
6719 {
6720 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount" );
6721 sal_Bool bMissingField = sal_True;
6722 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6723 if (pQueryParam.get())
6724 {
6725 sal_uLong nCount = 0;
6726 if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL )
6727 { // count all matching records
6728 // TODO: currently the QueryIterators only return cell pointers of
6729 // existing cells, so if a query matches an empty cell there's
6730 // nothing returned, and therefor not counted!
6731 // Since this has ever been the case and this code here only came
6732 // into existence to fix #i6899 and it never worked before we'll
6733 // have to live with it until we reimplement the iterators to also
6734 // return empty cells, which would mean to adapt all callers of
6735 // iterators.
6736 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get());
6737 SCTAB nTab = p->nTab;
6738 // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField,
6739 // so the source range has to be restricted, like before the introduction
6740 // of ScDBQueryParamBase.
6741 p->nCol1 = p->nCol2 = p->mnField;
6742 ScQueryCellIterator aCellIter( pDok, nTab, *p);
6743 if ( aCellIter.GetFirst() )
6744 {
6745 do
6746 {
6747 nCount++;
6748 } while ( aCellIter.GetNext() );
6749 }
6750 }
6751 else
6752 { // count only matching records with a value in the "result" field
6753 ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
6754 ScDBQueryDataIterator::Value aValue;
6755 if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6756 {
6757 do
6758 {
6759 nCount++;
6760 }
6761 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6762 }
6763 SetError(aValue.mnError);
6764 }
6765 PushDouble( nCount );
6766 }
6767 else
6768 PushIllegalParameter();
6769 }
6770
6771
ScDBCount2()6772 void ScInterpreter::ScDBCount2()
6773 {
6774 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount2" );
6775 sal_Bool bMissingField = sal_True;
6776 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6777 if (pQueryParam.get())
6778 {
6779 sal_uLong nCount = 0;
6780 pQueryParam->mbSkipString = false;
6781 ScDBQueryDataIterator aValIter( pDok, pQueryParam.release());
6782 ScDBQueryDataIterator::Value aValue;
6783 if ( aValIter.GetFirst(aValue) && !aValue.mnError )
6784 {
6785 do
6786 {
6787 nCount++;
6788 }
6789 while ( aValIter.GetNext(aValue) && !aValue.mnError );
6790 }
6791 SetError(aValue.mnError);
6792 PushDouble( nCount );
6793 }
6794 else
6795 PushIllegalParameter();
6796 }
6797
6798
ScDBAverage()6799 void ScInterpreter::ScDBAverage()
6800 {
6801 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBAverage" );
6802 DBIterator( ifAVERAGE );
6803 }
6804
6805
ScDBMax()6806 void ScInterpreter::ScDBMax()
6807 {
6808 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMax" );
6809 DBIterator( ifMAX );
6810 }
6811
6812
ScDBMin()6813 void ScInterpreter::ScDBMin()
6814 {
6815 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMin" );
6816 DBIterator( ifMIN );
6817 }
6818
6819
ScDBProduct()6820 void ScInterpreter::ScDBProduct()
6821 {
6822 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBProduct" );
6823 DBIterator( ifPRODUCT );
6824 }
6825
6826
GetDBStVarParams(double & rVal,double & rValCount)6827 void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount )
6828 {
6829 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBStVarParams" );
6830 std::vector<double> values;
6831 double vSum = 0.0;
6832 double vMean = 0.0;
6833
6834 rValCount = 0.0;
6835 double fSum = 0.0;
6836 sal_Bool bMissingField = sal_False;
6837 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) );
6838 if (pQueryParam.get())
6839 {
6840 ScDBQueryDataIterator aValIter(pDok, pQueryParam.release());
6841 ScDBQueryDataIterator::Value aValue;
6842 if (aValIter.GetFirst(aValue) && !aValue.mnError)
6843 {
6844 do
6845 {
6846 rValCount++;
6847 values.push_back(aValue.mfValue);
6848 fSum += aValue.mfValue;
6849 }
6850 while ((aValue.mnError == 0) && aValIter.GetNext(aValue));
6851 }
6852 SetError(aValue.mnError);
6853 }
6854 else
6855 SetError( errIllegalParameter);
6856
6857 vMean = fSum / values.size();
6858
6859 for (size_t i = 0; i < values.size(); i++)
6860 vSum += (values[i] - vMean) * (values[i] - vMean);
6861
6862 rVal = vSum;
6863 }
6864
6865
ScDBStdDev()6866 void ScInterpreter::ScDBStdDev()
6867 {
6868 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDev" );
6869 double fVal, fCount;
6870 GetDBStVarParams( fVal, fCount );
6871 PushDouble( sqrt(fVal/(fCount-1)));
6872 }
6873
6874
ScDBStdDevP()6875 void ScInterpreter::ScDBStdDevP()
6876 {
6877 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDevP" );
6878 double fVal, fCount;
6879 GetDBStVarParams( fVal, fCount );
6880 PushDouble( sqrt(fVal/fCount));
6881 }
6882
6883
ScDBVar()6884 void ScInterpreter::ScDBVar()
6885 {
6886 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVar" );
6887 double fVal, fCount;
6888 GetDBStVarParams( fVal, fCount );
6889 PushDouble(fVal/(fCount-1));
6890 }
6891
6892
ScDBVarP()6893 void ScInterpreter::ScDBVarP()
6894 {
6895 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVarP" );
6896 double fVal, fCount;
6897 GetDBStVarParams( fVal, fCount );
6898 PushDouble(fVal/fCount);
6899 }
6900
6901
lcl_CreateExternalRefSubroutine(const ScAddress & rPos,ScDocument * pDoc,const ScAddress::ExternalInfo & rExtInfo,const ScRefAddress & rRefAd1,const ScRefAddress * pRefAd2)6902 FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, ScDocument* pDoc,
6903 const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1,
6904 const ScRefAddress* pRefAd2 )
6905 {
6906 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
6907 size_t nSheets = 1;
6908 const String* pRealTab = pRefMgr->getRealTableName( rExtInfo.mnFileId, rExtInfo.maTabName);
6909 ScTokenArray* pTokenArray = new ScTokenArray;
6910 if (pRefAd2)
6911 {
6912 ScComplexRefData aRef;
6913 aRef.InitRangeRel( ScRange( rRefAd1.GetAddress(), pRefAd2->GetAddress()), rPos);
6914 aRef.Ref1.SetColRel( rRefAd1.IsRelCol());
6915 aRef.Ref1.SetRowRel( rRefAd1.IsRelRow());
6916 aRef.Ref1.SetTabRel( rRefAd1.IsRelTab());
6917 aRef.Ref1.SetFlag3D( true);
6918 aRef.Ref2.SetColRel( pRefAd2->IsRelCol());
6919 aRef.Ref2.SetRowRel( pRefAd2->IsRelRow());
6920 aRef.Ref2.SetTabRel( pRefAd2->IsRelTab());
6921 nSheets = aRef.Ref2.nTab - aRef.Ref1.nTab + 1;
6922 aRef.Ref2.SetFlag3D( nSheets > 1 );
6923 pTokenArray->AddExternalDoubleReference( rExtInfo.mnFileId,
6924 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
6925 }
6926 else
6927 {
6928 ScSingleRefData aRef;
6929 aRef.InitAddressRel( rRefAd1.GetAddress(), rPos);
6930 aRef.SetColRel( rRefAd1.IsRelCol());
6931 aRef.SetRowRel( rRefAd1.IsRelRow());
6932 aRef.SetTabRel( rRefAd1.IsRelTab());
6933 aRef.SetFlag3D( true);
6934 pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId,
6935 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef);
6936 }
6937 // The indirect usage of the external table can't be detected during the
6938 // store-to-file cycle, mark it as permanently referenced so it gets stored
6939 // even if not directly referenced anywhere.
6940 pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId,
6941 rExtInfo.maTabName, nSheets);
6942 ScCompiler aComp( pDoc, rPos, *pTokenArray);
6943 aComp.CompileTokenArray();
6944 return new FormulaSubroutineToken( pTokenArray);
6945 }
6946
6947
ScIndirect()6948 void ScInterpreter::ScIndirect()
6949 {
6950 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndirect" );
6951 sal_uInt8 nParamCount = GetByte();
6952 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
6953 {
6954 bool bTryXlA1 = true; // whether to try XL_A1 style as well.
6955 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO;
6956 if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble()))
6957 {
6958 eConv = FormulaGrammar::CONV_XL_R1C1;
6959 bTryXlA1 = false;
6960 }
6961 const ScAddress::Details aDetails( eConv, aPos );
6962 const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos );
6963 SCTAB nTab = aPos.Tab();
6964 String sRefStr( GetString() );
6965 ScRefAddress aRefAd, aRefAd2;
6966 ScAddress::ExternalInfo aExtInfo;
6967 if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) ||
6968 (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd,
6969 aRefAd2, aDetailsXlA1, &aExtInfo)))
6970 {
6971 if (aExtInfo.mbExternal)
6972 {
6973 // Push a subroutine that resolves the external reference as
6974 // the next instruction.
6975 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok,
6976 aExtInfo, aRefAd, &aRefAd2));
6977 }
6978 else
6979 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(),
6980 aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() );
6981 }
6982 else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) ||
6983 (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd,
6984 aDetailsXlA1, &aExtInfo)))
6985 {
6986 if (aExtInfo.mbExternal)
6987 {
6988 // Push a subroutine that resolves the external reference as
6989 // the next instruction.
6990 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok,
6991 aExtInfo, aRefAd, NULL));
6992 }
6993 else
6994 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() );
6995 }
6996 else
6997 {
6998 do
6999 {
7000 ScRangeName* pNames = pDok->GetRangeName();
7001 if (!pNames)
7002 break;
7003
7004 sal_uInt16 nPos = 0;
7005 if (!pNames->SearchName( sRefStr, nPos))
7006 break;
7007
7008 ScRangeData* rData = (*pNames)[nPos];
7009 if (!rData)
7010 break;
7011
7012 // We need this in order to obtain a good range.
7013 rData->ValidateTabRefs();
7014
7015 ScRange aRange;
7016 #if 0
7017 // This is some really odd Excel behavior and renders named
7018 // ranges containing relative references totally useless.
7019 if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0)))
7020 break;
7021 #else
7022 // This is the usual way to treat named ranges containing
7023 // relative references.
7024 if (!rData->IsReference( aRange, aPos))
7025 break;
7026 #endif
7027
7028 if (aRange.aStart == aRange.aEnd)
7029 PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(),
7030 aRange.aStart.Tab());
7031 else
7032 PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(),
7033 aRange.aStart.Tab(), aRange.aEnd.Col(),
7034 aRange.aEnd.Row(), aRange.aEnd.Tab());
7035
7036 // success!
7037 return;
7038 }
7039 while (false);
7040
7041 PushIllegalArgument();
7042 }
7043 }
7044 }
7045
7046
ScAddressFunc()7047 void ScInterpreter::ScAddressFunc()
7048 {
7049 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAddressFunc" );
7050 String sTabStr;
7051
7052 sal_uInt8 nParamCount = GetByte();
7053 if( !MustHaveParamCount( nParamCount, 2, 5 ) )
7054 return;
7055
7056 if( nParamCount >= 5 )
7057 sTabStr = GetString();
7058
7059 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO; // default
7060 if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)))
7061 eConv = FormulaGrammar::CONV_XL_R1C1;
7062
7063 sal_uInt16 nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE; // default
7064 if( nParamCount >= 3 )
7065 {
7066 sal_uInt16 n = (sal_uInt16) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0));
7067 switch ( n )
7068 {
7069 default :
7070 PushNoValue();
7071 return;
7072
7073 case 5:
7074 case 1 : break; // default
7075 case 6:
7076 case 2 : nFlags = SCA_ROW_ABSOLUTE; break;
7077 case 7:
7078 case 3 : nFlags = SCA_COL_ABSOLUTE; break;
7079 case 8:
7080 case 4 : nFlags = 0; break; // both relative
7081 }
7082 }
7083 nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL;
7084
7085 SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
7086 SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
7087 if( eConv == FormulaGrammar::CONV_XL_R1C1 )
7088 {
7089 // YUCK! The XL interface actually treats rel R1C1 refs differently
7090 // than A1
7091 if( !(nFlags & SCA_COL_ABSOLUTE) )
7092 nCol += aPos.Col() + 1;
7093 if( !(nFlags & SCA_ROW_ABSOLUTE) )
7094 nRow += aPos.Row() + 1;
7095 }
7096
7097 --nCol;
7098 --nRow;
7099 if(!ValidCol( nCol) || !ValidRow( nRow))
7100 {
7101 PushIllegalArgument();
7102 return;
7103 }
7104
7105 String aRefStr;
7106 const ScAddress::Details aDetails( eConv, aPos );
7107 const ScAddress aAdr( nCol, nRow, 0);
7108 aAdr.Format( aRefStr, nFlags, pDok, aDetails );
7109
7110 if( nParamCount >= 5 && sTabStr.Len() )
7111 {
7112 String aDoc;
7113 if (eConv == FormulaGrammar::CONV_OOO)
7114 {
7115 // Isolate Tab from 'Doc'#Tab
7116 xub_StrLen nPos = ScCompiler::GetDocTabPos( sTabStr);
7117 if (nPos != STRING_NOTFOUND)
7118 {
7119 if (sTabStr.GetChar(nPos+1) == '$')
7120 ++nPos; // also split 'Doc'#$Tab
7121 aDoc = sTabStr.Copy( 0, nPos+1);
7122 sTabStr.Erase( 0, nPos+1);
7123 }
7124 }
7125 /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may
7126 * need some extra handling to isolate Tab from Doc. */
7127 if (sTabStr.GetChar(0) != '\'' || sTabStr.GetChar(sTabStr.Len()-1) != '\'')
7128 ScCompiler::CheckTabQuotes( sTabStr, eConv);
7129 if (aDoc.Len())
7130 sTabStr.Insert( aDoc, 0);
7131 sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.');
7132 sTabStr += aRefStr;
7133 PushString( sTabStr );
7134 }
7135 else
7136 PushString( aRefStr );
7137 }
7138
7139
lcl_CreateExternalRefSubroutine(const ScAddress & rPos,ScDocument * pDoc,const FormulaTokenRef & xExtRef)7140 FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos,
7141 ScDocument* pDoc, const FormulaTokenRef& xExtRef )
7142 {
7143 // The exact usage (which cell range) of the external table can't be
7144 // detected during the store-to-file cycle, mark it as permanently
7145 // referenced so it gets stored even if not directly referenced anywhere.
7146 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager();
7147 pRefMgr->setCacheTableReferencedPermanently(
7148 static_cast<const ScToken*>(xExtRef.get())->GetIndex(),
7149 static_cast<const ScToken*>(xExtRef.get())->GetString(), 1);
7150 ScTokenArray* pTokenArray = new ScTokenArray;
7151 pTokenArray->AddToken( *xExtRef);
7152 ScCompiler aComp( pDoc, rPos, *pTokenArray);
7153 aComp.CompileTokenArray();
7154 return new FormulaSubroutineToken( pTokenArray);
7155 }
7156
7157
ScOffset()7158 void ScInterpreter::ScOffset()
7159 {
7160 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" );
7161 sal_uInt8 nParamCount = GetByte();
7162 if ( MustHaveParamCount( nParamCount, 3, 5 ) )
7163 {
7164 long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus;
7165 if (nParamCount == 5)
7166 nColNew = (long) ::rtl::math::approxFloor(GetDouble());
7167 if (nParamCount >= 4)
7168 nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 ));
7169 nColPlus = (long) ::rtl::math::approxFloor(GetDouble());
7170 nRowPlus = (long) ::rtl::math::approxFloor(GetDouble());
7171 SCCOL nCol1;
7172 SCROW nRow1;
7173 SCTAB nTab1;
7174 SCCOL nCol2;
7175 SCROW nRow2;
7176 SCTAB nTab2;
7177 if (nColNew == 0 || nRowNew == 0)
7178 {
7179 PushIllegalArgument();
7180 return;
7181 }
7182 FormulaTokenRef xExtRef;
7183 switch (GetStackType())
7184 {
7185 case svExternalSingleRef:
7186 xExtRef = PopToken()->Clone();
7187 // fallthru
7188 case svSingleRef:
7189 {
7190 if (xExtRef)
7191 {
7192 ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef();
7193 rData.CalcAbsIfRel( aPos);
7194 nCol1 = rData.nCol;
7195 nRow1 = rData.nRow;
7196 nTab1 = rData.nTab;
7197 }
7198 else
7199 PopSingleRef( nCol1, nRow1, nTab1);
7200 if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0))
7201 {
7202 nCol1 = (SCCOL)((long) nCol1 + nColPlus);
7203 nRow1 = (SCROW)((long) nRow1 + nRowPlus);
7204 if (!ValidCol(nCol1) || !ValidRow(nRow1))
7205 PushIllegalArgument();
7206 else if (xExtRef)
7207 {
7208 ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef();
7209 rData.nCol = nCol1;
7210 rData.nRow = nRow1;
7211 rData.nTab = nTab1;
7212 rData.CalcRelFromAbs( aPos);
7213 // Push a subroutine that resolves the external
7214 // reference as the next instruction.
7215 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef));
7216 }
7217 else
7218 PushSingleRef(nCol1, nRow1, nTab1);
7219 }
7220 else
7221 {
7222 if (nColNew < 0)
7223 nColNew = 1;
7224 if (nRowNew < 0)
7225 nRowNew = 1;
7226 nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 is modified
7227 nRow1 = (SCROW)((long)nRow1+nRowPlus);
7228 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
7229 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
7230 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
7231 !ValidCol(nCol2) || !ValidRow(nRow2))
7232 PushIllegalArgument();
7233 else if (xExtRef)
7234 {
7235 // Convert SingleRef to DoubleRef.
7236 xExtRef = new ScExternalDoubleRefToken(
7237 *static_cast<const ScExternalSingleRefToken*>(xExtRef.get()));
7238 ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef();
7239 rData.Ref1.nCol = nCol1;
7240 rData.Ref1.nRow = nRow1;
7241 rData.Ref1.nTab = nTab1;
7242 rData.Ref2.nCol = nCol2;
7243 rData.Ref2.nRow = nRow2;
7244 rData.Ref2.nTab = nTab1;
7245 rData.CalcRelFromAbs( aPos);
7246 // Push a subroutine that resolves the external
7247 // reference as the next instruction.
7248 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef));
7249 }
7250 else
7251 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
7252 }
7253 }
7254 break;
7255 case svExternalDoubleRef:
7256 xExtRef = PopToken()->Clone();
7257 // fallthru
7258 case svDoubleRef:
7259 {
7260 if (xExtRef)
7261 {
7262 ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef();
7263 rData.CalcAbsIfRel( aPos);
7264 nCol1 = rData.Ref1.nCol;
7265 nRow1 = rData.Ref1.nRow;
7266 nTab1 = rData.Ref1.nTab;
7267 nCol2 = rData.Ref2.nCol;
7268 nRow2 = rData.Ref2.nRow;
7269 nTab2 = rData.Ref2.nTab;
7270 }
7271 else
7272 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
7273 if (nColNew < 0)
7274 nColNew = nCol2 - nCol1 + 1;
7275 if (nRowNew < 0)
7276 nRowNew = nRow2 - nRow1 + 1;
7277 nCol1 = (SCCOL)((long)nCol1+nColPlus);
7278 nRow1 = (SCROW)((long)nRow1+nRowPlus);
7279 nCol2 = (SCCOL)((long)nCol1+nColNew-1);
7280 nRow2 = (SCROW)((long)nRow1+nRowNew-1);
7281 if (!ValidCol(nCol1) || !ValidRow(nRow1) ||
7282 !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2)
7283 PushIllegalArgument();
7284 else if (xExtRef)
7285 {
7286 ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef();
7287 rData.Ref1.nCol = nCol1;
7288 rData.Ref1.nRow = nRow1;
7289 rData.Ref1.nTab = nTab1;
7290 rData.Ref2.nCol = nCol2;
7291 rData.Ref2.nRow = nRow2;
7292 rData.Ref2.nTab = nTab1;
7293 rData.CalcRelFromAbs( aPos);
7294 // Push a subroutine that resolves the external
7295 // reference as the next instruction.
7296 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef));
7297 }
7298 else
7299 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1);
7300 }
7301 break;
7302 default:
7303 PushIllegalParameter();
7304 }
7305 }
7306 }
7307
7308
ScIndex()7309 void ScInterpreter::ScIndex()
7310 {
7311 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndex" );
7312 sal_uInt8 nParamCount = GetByte();
7313 if ( MustHaveParamCount( nParamCount, 1, 4 ) )
7314 {
7315 long nArea;
7316 size_t nAreaCount;
7317 SCCOL nCol;
7318 SCROW nRow;
7319 if (nParamCount == 4)
7320 nArea = (long) ::rtl::math::approxFloor(GetDouble());
7321 else
7322 nArea = 1;
7323 if (nParamCount >= 3)
7324 nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble());
7325 else
7326 nCol = 0;
7327 if (nParamCount >= 2)
7328 nRow = (SCROW) ::rtl::math::approxFloor(GetDouble());
7329 else
7330 nRow = 0;
7331 if (GetStackType() == svRefList)
7332 nAreaCount = (sp ? static_cast<ScToken*>(pStack[sp-1])->GetRefList()->size() : 0);
7333 else
7334 nAreaCount = 1; // one reference or array or whatever
7335 if (nAreaCount == 0 || (size_t)nArea > nAreaCount)
7336 {
7337 PushError( errNoRef);
7338 return;
7339 }
7340 else if (nArea < 1 || nCol < 0 || nRow < 0)
7341 {
7342 PushIllegalArgument();
7343 return;
7344 }
7345 switch (GetStackType())
7346 {
7347 case svMatrix:
7348 {
7349 if (nArea != 1)
7350 SetError(errIllegalArgument);
7351 sal_uInt16 nOldSp = sp;
7352 ScMatrixRef pMat = GetMatrix();
7353 if (pMat)
7354 {
7355 SCSIZE nC, nR;
7356 pMat->GetDimensions(nC, nR);
7357 // Access one element of a vector independent of col/row
7358 // orientation?
7359 bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1));
7360 SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol),
7361 static_cast<SCSIZE>(nRow));
7362 if (nC == 0 || nR == 0 ||
7363 (!bVector && (static_cast<SCSIZE>(nCol) > nC ||
7364 static_cast<SCSIZE>(nRow) > nR)) ||
7365 (bVector && nElement > nC * nR))
7366 PushIllegalArgument();
7367 else if (nCol == 0 && nRow == 0)
7368 sp = nOldSp;
7369 else if (bVector)
7370 {
7371 --nElement;
7372 if (pMat->IsString( nElement))
7373 PushString( pMat->GetString( nElement));
7374 else
7375 PushDouble( pMat->GetDouble( nElement));
7376 }
7377 else if (nCol == 0)
7378 {
7379 ScMatrixRef pResMat = GetNewMat(nC, 1);
7380 if (pResMat)
7381 {
7382 SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1);
7383 for (SCSIZE i = 0; i < nC; i++)
7384 if (!pMat->IsString(i, nRowMinus1))
7385 pResMat->PutDouble(pMat->GetDouble(i,
7386 nRowMinus1), i, 0);
7387 else
7388 pResMat->PutString(pMat->GetString(i,
7389 nRowMinus1), i, 0);
7390 PushMatrix(pResMat);
7391 }
7392 else
7393 PushIllegalArgument();
7394 }
7395 else if (nRow == 0)
7396 {
7397 ScMatrixRef pResMat = GetNewMat(1, nR);
7398 if (pResMat)
7399 {
7400 SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1);
7401 for (SCSIZE i = 0; i < nR; i++)
7402 if (!pMat->IsString(nColMinus1, i))
7403 pResMat->PutDouble(pMat->GetDouble(nColMinus1,
7404 i), i);
7405 else
7406 pResMat->PutString(pMat->GetString(nColMinus1,
7407 i), i);
7408 PushMatrix(pResMat);
7409 }
7410 else
7411 PushIllegalArgument();
7412 }
7413 else
7414 {
7415 if (!pMat->IsString( static_cast<SCSIZE>(nCol-1),
7416 static_cast<SCSIZE>(nRow-1)))
7417 PushDouble( pMat->GetDouble(
7418 static_cast<SCSIZE>(nCol-1),
7419 static_cast<SCSIZE>(nRow-1)));
7420 else
7421 PushString( pMat->GetString(
7422 static_cast<SCSIZE>(nCol-1),
7423 static_cast<SCSIZE>(nRow-1)));
7424 }
7425 }
7426 }
7427 break;
7428 case svSingleRef:
7429 {
7430 SCCOL nCol1 = 0;
7431 SCROW nRow1 = 0;
7432 SCTAB nTab1 = 0;
7433 PopSingleRef( nCol1, nRow1, nTab1);
7434 if (nCol > 1 || nRow > 1)
7435 PushIllegalArgument();
7436 else
7437 PushSingleRef( nCol1, nRow1, nTab1);
7438 }
7439 break;
7440 case svDoubleRef:
7441 case svRefList:
7442 {
7443 SCCOL nCol1 = 0;
7444 SCROW nRow1 = 0;
7445 SCTAB nTab1 = 0;
7446 SCCOL nCol2 = 0;
7447 SCROW nRow2 = 0;
7448 SCTAB nTab2 = 0;
7449 sal_Bool bRowArray = sal_False;
7450 if (GetStackType() == svRefList)
7451 {
7452 FormulaTokenRef xRef = PopToken();
7453 if (nGlobalError || !xRef)
7454 {
7455 PushIllegalParameter();
7456 return;
7457 }
7458 ScRange aRange( ScAddress::UNINITIALIZED);
7459 DoubleRefToRange( (*(static_cast<ScToken*>(xRef.get())->GetRefList()))[nArea-1], aRange);
7460 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
7461 if ( nParamCount == 2 && nRow1 == nRow2 )
7462 bRowArray = sal_True;
7463 }
7464 else
7465 {
7466 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2);
7467 if ( nParamCount == 2 && nRow1 == nRow2 )
7468 bRowArray = sal_True;
7469 }
7470 if ( nTab1 != nTab2 ||
7471 (nCol > 0 && nCol1+nCol-1 > nCol2) ||
7472 (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) ||
7473 ( nRow > nCol2 - nCol1 + 1 && bRowArray ))
7474 PushIllegalArgument();
7475 else if (nCol == 0 && nRow == 0)
7476 {
7477 if ( nCol1 == nCol2 && nRow1 == nRow2 )
7478 PushSingleRef( nCol1, nRow1, nTab1 );
7479 else
7480 PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 );
7481 }
7482 else if (nRow == 0)
7483 {
7484 if ( nRow1 == nRow2 )
7485 PushSingleRef( nCol1+nCol-1, nRow1, nTab1 );
7486 else
7487 PushDoubleRef( nCol1+nCol-1, nRow1, nTab1,
7488 nCol1+nCol-1, nRow2, nTab1 );
7489 }
7490 else if (nCol == 0)
7491 {
7492 if ( nCol1 == nCol2 )
7493 PushSingleRef( nCol1, nRow1+nRow-1, nTab1 );
7494 else if ( bRowArray )
7495 {
7496 nCol =(SCCOL) nRow;
7497 nRow = 1;
7498 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
7499 }
7500 else
7501 PushDoubleRef( nCol1, nRow1+nRow-1, nTab1,
7502 nCol2, nRow1+nRow-1, nTab1);
7503 }
7504 else
7505 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1);
7506 }
7507 break;
7508 default:
7509 PushIllegalParameter();
7510 }
7511 }
7512 }
7513
7514
ScMultiArea()7515 void ScInterpreter::ScMultiArea()
7516 {
7517 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMultiArea" );
7518 // Legacy support, convert to RefList
7519 sal_uInt8 nParamCount = GetByte();
7520 if (MustHaveParamCountMin( nParamCount, 1))
7521 {
7522 while (!nGlobalError && nParamCount-- > 1)
7523 {
7524 ScUnionFunc();
7525 }
7526 }
7527 }
7528
7529
ScAreas()7530 void ScInterpreter::ScAreas()
7531 {
7532 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAreas" );
7533 sal_uInt8 nParamCount = GetByte();
7534 if (MustHaveParamCount( nParamCount, 1))
7535 {
7536 size_t nCount = 0;
7537 switch (GetStackType())
7538 {
7539 case svSingleRef:
7540 {
7541 FormulaTokenRef xT = PopToken();
7542 ValidateRef( static_cast<ScToken*>(xT.get())->GetSingleRef());
7543 ++nCount;
7544 }
7545 break;
7546 case svDoubleRef:
7547 {
7548 FormulaTokenRef xT = PopToken();
7549 ValidateRef( static_cast<ScToken*>(xT.get())->GetDoubleRef());
7550 ++nCount;
7551 }
7552 break;
7553 case svRefList:
7554 {
7555 FormulaTokenRef xT = PopToken();
7556 ValidateRef( *(static_cast<ScToken*>(xT.get())->GetRefList()));
7557 nCount += static_cast<ScToken*>(xT.get())->GetRefList()->size();
7558 }
7559 break;
7560 default:
7561 SetError( errIllegalParameter);
7562 }
7563 PushDouble( double(nCount));
7564 }
7565 }
7566
7567
ScCurrency()7568 void ScInterpreter::ScCurrency()
7569 {
7570 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrency" );
7571 sal_uInt8 nParamCount = GetByte();
7572 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7573 {
7574 String aStr;
7575 double fDec;
7576 if (nParamCount == 2)
7577 {
7578 fDec = ::rtl::math::approxFloor(GetDouble());
7579 if (fDec < -15.0 || fDec > 15.0)
7580 {
7581 PushIllegalArgument();
7582 return;
7583 }
7584 }
7585 else
7586 fDec = 2.0;
7587 double fVal = GetDouble();
7588 double fFac;
7589 if ( fDec != 0.0 )
7590 fFac = pow( (double)10, fDec );
7591 else
7592 fFac = 1.0;
7593 if (fVal < 0.0)
7594 fVal = ceil(fVal*fFac-0.5)/fFac;
7595 else
7596 fVal = floor(fVal*fFac+0.5)/fFac;
7597 Color* pColor = NULL;
7598 if ( fDec < 0.0 )
7599 fDec = 0.0;
7600 sal_uLong nIndex = pFormatter->GetStandardFormat(
7601 NUMBERFORMAT_CURRENCY,
7602 ScGlobal::eLnge);
7603 if ( (sal_uInt16) fDec != pFormatter->GetFormatPrecision( nIndex ) )
7604 {
7605 String sFormatString;
7606 pFormatter->GenerateFormat(sFormatString,
7607 nIndex,
7608 ScGlobal::eLnge,
7609 sal_True, // mit Tausenderpunkt
7610 sal_False, // nicht rot
7611 (sal_uInt16) fDec,// Nachkommastellen
7612 1); // 1 Vorkommanull
7613 if (!pFormatter->GetPreviewString(sFormatString,
7614 fVal,
7615 aStr,
7616 &pColor,
7617 ScGlobal::eLnge))
7618 SetError(errIllegalArgument);
7619 }
7620 else
7621 {
7622 pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor);
7623 }
7624 PushString(aStr);
7625 }
7626 }
7627
7628
ScReplace()7629 void ScInterpreter::ScReplace()
7630 {
7631 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScReplace" );
7632 if ( MustHaveParamCount( GetByte(), 4 ) )
7633 {
7634 String aNewStr( GetString() );
7635 double fCount = ::rtl::math::approxFloor( GetDouble());
7636 double fPos = ::rtl::math::approxFloor( GetDouble());
7637 String aOldStr( GetString() );
7638 if (fPos < 1.0 || fPos > static_cast<double>(STRING_MAXLEN)
7639 || fCount < 0.0 || fCount > static_cast<double>(STRING_MAXLEN))
7640 PushIllegalArgument();
7641 else
7642 {
7643 xub_StrLen nCount = static_cast<xub_StrLen>(fCount);
7644 xub_StrLen nPos = static_cast<xub_StrLen>(fPos);
7645 xub_StrLen nLen = aOldStr.Len();
7646 if (nPos > nLen + 1)
7647 nPos = nLen + 1;
7648 if (nCount > nLen - nPos + 1)
7649 nCount = nLen - nPos + 1;
7650 aOldStr.Erase( nPos-1, nCount );
7651 if ( CheckStringResultLen( aOldStr, aNewStr ) )
7652 aOldStr.Insert( aNewStr, nPos-1 );
7653 PushString( aOldStr );
7654 }
7655 }
7656 }
7657
7658
ScFixed()7659 void ScInterpreter::ScFixed()
7660 {
7661 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFixed" );
7662 sal_uInt8 nParamCount = GetByte();
7663 if ( MustHaveParamCount( nParamCount, 1, 3 ) )
7664 {
7665 String aStr;
7666 double fDec;
7667 sal_Bool bThousand;
7668 if (nParamCount == 3)
7669 bThousand = !GetBool(); // Param TRUE: keine Tausenderpunkte
7670 else
7671 bThousand = sal_True;
7672 if (nParamCount >= 2)
7673 {
7674 fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 ));
7675 if (fDec < -15.0 || fDec > 15.0)
7676 {
7677 PushIllegalArgument();
7678 return;
7679 }
7680 }
7681 else
7682 fDec = 2.0;
7683 double fVal = GetDouble();
7684 double fFac;
7685 if ( fDec != 0.0 )
7686 fFac = pow( (double)10, fDec );
7687 else
7688 fFac = 1.0;
7689 if (fVal < 0.0)
7690 fVal = ceil(fVal*fFac-0.5)/fFac;
7691 else
7692 fVal = floor(fVal*fFac+0.5)/fFac;
7693 Color* pColor = NULL;
7694 String sFormatString;
7695 if (fDec < 0.0)
7696 fDec = 0.0;
7697 sal_uLong nIndex = pFormatter->GetStandardFormat(
7698 NUMBERFORMAT_NUMBER,
7699 ScGlobal::eLnge);
7700 pFormatter->GenerateFormat(sFormatString,
7701 nIndex,
7702 ScGlobal::eLnge,
7703 bThousand, // mit Tausenderpunkt
7704 sal_False, // nicht rot
7705 (sal_uInt16) fDec,// Nachkommastellen
7706 1); // 1 Vorkommanull
7707 if (!pFormatter->GetPreviewString(sFormatString,
7708 fVal,
7709 aStr,
7710 &pColor,
7711 ScGlobal::eLnge))
7712 PushIllegalArgument();
7713 else
7714 PushString(aStr);
7715 }
7716 }
7717
7718
ScFind()7719 void ScInterpreter::ScFind()
7720 {
7721 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFind" );
7722 sal_uInt8 nParamCount = GetByte();
7723 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
7724 {
7725 double fAnz;
7726 if (nParamCount == 3)
7727 fAnz = GetDouble();
7728 else
7729 fAnz = 1.0;
7730 String sStr = GetString();
7731 if( fAnz < 1.0 || fAnz > (double) sStr.Len() )
7732 PushNoValue();
7733 else
7734 {
7735 xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 );
7736 if (nPos == STRING_NOTFOUND)
7737 PushNoValue();
7738 else
7739 PushDouble((double)(nPos + 1));
7740 }
7741 }
7742 }
7743
7744
ScExact()7745 void ScInterpreter::ScExact()
7746 {
7747 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExact" );
7748 nFuncFmtType = NUMBERFORMAT_LOGICAL;
7749 if ( MustHaveParamCount( GetByte(), 2 ) )
7750 {
7751 String s1( GetString() );
7752 String s2( GetString() );
7753 PushInt( s1 == s2 );
7754 }
7755 }
7756
7757
ScLeft()7758 void ScInterpreter::ScLeft()
7759 {
7760 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLeft" );
7761 sal_uInt8 nParamCount = GetByte();
7762 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7763 {
7764 xub_StrLen n;
7765 if (nParamCount == 2)
7766 {
7767 double nVal = ::rtl::math::approxFloor(GetDouble());
7768 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7769 {
7770 PushIllegalArgument();
7771 return ;
7772 }
7773 else
7774 n = (xub_StrLen) nVal;
7775 }
7776 else
7777 n = 1;
7778 String aStr( GetString() );
7779 aStr.Erase( n );
7780 PushString( aStr );
7781 }
7782 }
7783
7784 typedef struct {
7785 UBlockCode from;
7786 UBlockCode to;
7787 } UBlockScript;
7788
7789 static UBlockScript scriptList[] = {
7790 {UBLOCK_HANGUL_JAMO, UBLOCK_HANGUL_JAMO},
7791 {UBLOCK_CJK_RADICALS_SUPPLEMENT, UBLOCK_HANGUL_SYLLABLES},
7792 {UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS,UBLOCK_CJK_RADICALS_SUPPLEMENT },
7793 {UBLOCK_IDEOGRAPHIC_DESCRIPTION_CHARACTERS,UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS},
7794 {UBLOCK_CJK_COMPATIBILITY_FORMS, UBLOCK_CJK_COMPATIBILITY_FORMS},
7795 {UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS, UBLOCK_HALFWIDTH_AND_FULLWIDTH_FORMS},
7796 {UBLOCK_CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B, UBLOCK_CJK_COMPATIBILITY_IDEOGRAPHS_SUPPLEMENT},
7797 {UBLOCK_CJK_STROKES, UBLOCK_CJK_STROKES}
7798 };
7799 #define scriptListCount sizeof (scriptList) / sizeof (UBlockScript)
lcl_getScriptClass(sal_uInt32 currentChar)7800 bool SAL_CALL lcl_getScriptClass(sal_uInt32 currentChar)
7801 {
7802 // for the locale of ja-JP, character U+0x005c and U+0x20ac should be ScriptType::Asian
7803 if( (currentChar == 0x005c || currentChar == 0x20ac) &&
7804 (MsLangId::getSystemLanguage() == LANGUAGE_JAPANESE) )
7805 return true;
7806 sal_uInt16 i;
7807 static sal_Int16 nRet = 0;
7808 UBlockCode block = (UBlockCode)ublock_getCode((sal_uInt32)currentChar);
7809 for ( i = 0; i < scriptListCount; i++) {
7810 if (block <= scriptList[i].to) break;
7811 }
7812 nRet = (i < scriptListCount && block >= scriptList[i].from);
7813 return nRet;
7814 }
IsDBCS(sal_Unicode ch)7815 bool IsDBCS(sal_Unicode ch)
7816 {
7817 return lcl_getScriptClass(ch);
7818 }
getLengthB(String & str)7819 sal_Int32 getLengthB(String &str)
7820 {
7821 xub_StrLen index = 0;
7822 sal_Int32 length = 0;
7823 if(0 == str.Len())
7824 return 0;
7825 while(index < str.Len()){
7826 if(IsDBCS(str.GetChar(index)))
7827 length += 2;
7828 else
7829 length++;
7830 index++;
7831 }
7832 return length;
7833 }
ScLenB()7834 void ScInterpreter::ScLenB()
7835 {
7836 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "luzhang", "ScInterpreter::ScLenB" );
7837 String aStr( GetString() );
7838 PushDouble( getLengthB(aStr) );
7839 }
lcl_RightB(String & aStr,sal_Int32 n)7840 void lcl_RightB(String &aStr, sal_Int32 n)
7841 {
7842 if( n < getLengthB(aStr) )
7843 {
7844 sal_Int32 index = aStr.Len();
7845 while(index-- >= 0)
7846 {
7847 if(0 == n)
7848 {
7849 aStr.Erase( 0, index + 1);
7850 break;
7851 }
7852 if(-1 == n)
7853 {
7854 aStr.Erase( 0, index + 2 );
7855 aStr.InsertAscii(" ", 0);
7856 break;
7857 }
7858 if(IsDBCS(aStr.GetChar(index)))
7859 n -= 2;
7860 else
7861 n--;
7862 }
7863 }
7864 }
ScRightB()7865 void ScInterpreter::ScRightB()
7866 {
7867 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "luzhang", "ScInterpreter::ScRightB" );
7868 sal_uInt8 nParamCount = GetByte();
7869 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7870 {
7871 sal_Int32 n;
7872 if (nParamCount == 2)
7873 {
7874 double nVal = ::rtl::math::approxFloor(GetDouble());
7875 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7876 {
7877 PushIllegalArgument();
7878 return ;
7879 }
7880 else
7881 n = (xub_StrLen) nVal;
7882 }
7883 else
7884 n = 1;
7885 String aStr( GetString() );
7886 lcl_RightB(aStr, n);
7887 PushString( aStr );
7888 }
7889 }
lcl_LeftB(String & aStr,sal_Int32 n)7890 void lcl_LeftB(String &aStr, sal_Int32 n)
7891 {
7892 if( n < getLengthB(aStr) )
7893 {
7894 sal_Int32 index = -1;
7895 while(index++ < aStr.Len())
7896 {
7897 if(0 == n)
7898 {
7899 aStr.Erase( index );
7900 break;
7901 }
7902 if(-1 == n)
7903 {
7904 aStr.Erase( index - 1 );
7905 aStr.InsertAscii(" ");
7906 break;
7907 }
7908 if(IsDBCS(aStr.GetChar(index)))
7909 n -= 2;
7910 else
7911 n--;
7912 }
7913 }
7914 }
ScLeftB()7915 void ScInterpreter::ScLeftB()
7916 {
7917 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "luzhang", "ScInterpreter::ScLeftB" );
7918 sal_uInt8 nParamCount = GetByte();
7919 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7920 {
7921 sal_Int32 n;
7922 if (nParamCount == 2)
7923 {
7924 double nVal = ::rtl::math::approxFloor(GetDouble());
7925 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7926 {
7927 PushIllegalArgument();
7928 return ;
7929 }
7930 else
7931 n = (xub_StrLen) nVal;
7932 }
7933 else
7934 n = 1;
7935 String aStr( GetString() );
7936 lcl_LeftB(aStr, n);
7937 PushString( aStr );
7938 }
7939 }
ScMidB()7940 void ScInterpreter::ScMidB()
7941 {
7942 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "luzhang", "ScInterpreter::ScMidB" );
7943 if ( MustHaveParamCount( GetByte(), 3 ) )
7944 {
7945 double fAnz = ::rtl::math::approxFloor(GetDouble());
7946 double fAnfang = ::rtl::math::approxFloor(GetDouble());
7947 String rStr( GetString() );
7948 if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
7949 PushIllegalArgument();
7950 else
7951 {
7952
7953 lcl_LeftB(rStr, (xub_StrLen)fAnfang + (xub_StrLen)fAnz - 1);
7954 sal_Int32 nCnt = getLengthB(rStr) - (xub_StrLen)fAnfang + 1;
7955 lcl_RightB(rStr, nCnt>0 ? nCnt:0);
7956 PushString(rStr);
7957 }
7958 }
7959 }
7960
ScRight()7961 void ScInterpreter::ScRight()
7962 {
7963 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRight" );
7964 sal_uInt8 nParamCount = GetByte();
7965 if ( MustHaveParamCount( nParamCount, 1, 2 ) )
7966 {
7967 xub_StrLen n;
7968 if (nParamCount == 2)
7969 {
7970 double nVal = ::rtl::math::approxFloor(GetDouble());
7971 if ( nVal < 0.0 || nVal > STRING_MAXLEN )
7972 {
7973 PushIllegalArgument();
7974 return ;
7975 }
7976 else
7977 n = (xub_StrLen) nVal;
7978 }
7979 else
7980 n = 1;
7981 String aStr( GetString() );
7982 if( n < aStr.Len() )
7983 aStr.Erase( 0, aStr.Len() - n );
7984 PushString( aStr );
7985 }
7986 }
7987
7988
ScSearch()7989 void ScInterpreter::ScSearch()
7990 {
7991 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSearch" );
7992 double fAnz;
7993 sal_uInt8 nParamCount = GetByte();
7994 if ( MustHaveParamCount( nParamCount, 2, 3 ) )
7995 {
7996 if (nParamCount == 3)
7997 {
7998 fAnz = ::rtl::math::approxFloor(GetDouble());
7999 if (fAnz > double(STRING_MAXLEN))
8000 {
8001 PushIllegalArgument();
8002 return;
8003 }
8004 }
8005 else
8006 fAnz = 1.0;
8007 String sStr = GetString();
8008 String SearchStr = GetString();
8009 xub_StrLen nPos = (xub_StrLen) fAnz - 1;
8010 xub_StrLen nEndPos = sStr.Len();
8011 if( nPos >= nEndPos )
8012 PushNoValue();
8013 else
8014 {
8015 utl::SearchParam::SearchType eSearchType =
8016 (MayBeRegExp( SearchStr, pDok ) ?
8017 utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL);
8018 utl::SearchParam sPar(SearchStr, eSearchType, sal_False, sal_False, sal_False);
8019 utl::TextSearch sT( sPar, *ScGlobal::pCharClass );
8020 int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos);
8021 if (!nBool)
8022 PushNoValue();
8023 else
8024 PushDouble((double)(nPos) + 1);
8025 }
8026 }
8027 }
8028
8029
ScMid()8030 void ScInterpreter::ScMid()
8031 {
8032 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMid" );
8033 if ( MustHaveParamCount( GetByte(), 3 ) )
8034 {
8035 double fAnz = ::rtl::math::approxFloor(GetDouble());
8036 double fAnfang = ::rtl::math::approxFloor(GetDouble());
8037 const String& rStr = GetString();
8038 if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN))
8039 PushIllegalArgument();
8040 else
8041 PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz ));
8042 }
8043 }
8044
8045
ScText()8046 void ScInterpreter::ScText()
8047 {
8048 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScText" );
8049 if ( MustHaveParamCount( GetByte(), 2 ) )
8050 {
8051 String sFormatString = GetString();
8052 String aStr;
8053 bool bString = false;
8054 double fVal = 0.0;
8055 switch (GetStackType())
8056 {
8057 case svError:
8058 PopError();
8059 break;
8060 case svDouble:
8061 fVal = PopDouble();
8062 break;
8063 default:
8064 {
8065 FormulaTokenRef xTok( PopToken());
8066 if (!nGlobalError)
8067 {
8068 PushTempToken( xTok);
8069 // Temporarily override the ConvertStringToValue()
8070 // error for GetCellValue() / GetCellValueOrZero()
8071 sal_uInt16 nSErr = mnStringNoValueError;
8072 mnStringNoValueError = errNotNumericString;
8073 fVal = GetDouble();
8074 mnStringNoValueError = nSErr;
8075 if (nGlobalError == errNotNumericString)
8076 {
8077 // Not numeric.
8078 nGlobalError = 0;
8079 PushTempToken( xTok);
8080 aStr = GetString();
8081 bString = true;
8082 }
8083 }
8084 }
8085 }
8086 if (nGlobalError)
8087 PushError( nGlobalError);
8088 else
8089 {
8090 String aResult;
8091 Color* pColor = NULL;
8092 LanguageType eCellLang;
8093 const ScPatternAttr* pPattern = pDok->GetPattern(
8094 aPos.Col(), aPos.Row(), aPos.Tab() );
8095 if ( pPattern )
8096 eCellLang = ((const SvxLanguageItem&)
8097 pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue();
8098 else
8099 eCellLang = ScGlobal::eLnge;
8100 if (bString)
8101 {
8102 if (!pFormatter->GetPreviewString( sFormatString, aStr,
8103 aResult, &pColor, eCellLang))
8104 PushIllegalArgument();
8105 else
8106 PushString( aResult);
8107 }
8108 else
8109 {
8110 if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal,
8111 aResult, &pColor, eCellLang))
8112 PushIllegalArgument();
8113 else
8114 PushString( aResult);
8115 }
8116 }
8117 }
8118 }
8119
8120
ScSubstitute()8121 void ScInterpreter::ScSubstitute()
8122 {
8123 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubstitute" );
8124 sal_uInt8 nParamCount = GetByte();
8125 if ( MustHaveParamCount( nParamCount, 3, 4 ) )
8126 {
8127 xub_StrLen nAnz;
8128 if (nParamCount == 4)
8129 {
8130 double fAnz = ::rtl::math::approxFloor(GetDouble());
8131 if( fAnz < 1 || fAnz > STRING_MAXLEN )
8132 {
8133 PushIllegalArgument();
8134 return;
8135 }
8136 else
8137 nAnz = (xub_StrLen) fAnz;
8138 }
8139 else
8140 nAnz = 0;
8141 String sNewStr = GetString();
8142 String sOldStr = GetString();
8143 String sStr = GetString();
8144 xub_StrLen nPos = 0;
8145 xub_StrLen nCount = 0;
8146 xub_StrLen nNewLen = sNewStr.Len();
8147 xub_StrLen nOldLen = sOldStr.Len();
8148 while( sal_True )
8149 {
8150 nPos = sStr.Search( sOldStr, nPos );
8151 if (nPos != STRING_NOTFOUND)
8152 {
8153 nCount++;
8154 if( !nAnz || nCount == nAnz )
8155 {
8156 sStr.Erase(nPos,nOldLen);
8157 if ( CheckStringResultLen( sStr, sNewStr ) )
8158 {
8159 sStr.Insert(sNewStr,nPos);
8160 nPos = sal::static_int_cast<xub_StrLen>( nPos + nNewLen );
8161 }
8162 else
8163 break;
8164 }
8165 else
8166 nPos++;
8167 }
8168 else
8169 break;
8170 }
8171 PushString( sStr );
8172 }
8173 }
8174
8175
ScRept()8176 void ScInterpreter::ScRept()
8177 {
8178 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRept" );
8179 if ( MustHaveParamCount( GetByte(), 2 ) )
8180 {
8181 double fAnz = ::rtl::math::approxFloor(GetDouble());
8182 String aStr( GetString() );
8183 if ( fAnz < 0.0 )
8184 PushIllegalArgument();
8185 else if ( fAnz * aStr.Len() > STRING_MAXLEN )
8186 {
8187 PushError( errStringOverflow );
8188 }
8189 else if ( fAnz == 0.0 )
8190 PushString( EMPTY_STRING );
8191 else
8192 {
8193 xub_StrLen n = (xub_StrLen) fAnz;
8194 const xub_StrLen nLen = aStr.Len();
8195 String aRes;
8196 const sal_Unicode* const pSrc = aStr.GetBuffer();
8197 sal_Unicode* pDst = aRes.AllocBuffer( n * nLen );
8198 while( n-- )
8199 {
8200 memcpy( pDst, pSrc, nLen * sizeof(sal_Unicode) );
8201 pDst += nLen;
8202 }
8203 PushString( aRes );
8204 }
8205 }
8206 }
8207
8208
ScConcat()8209 void ScInterpreter::ScConcat()
8210 {
8211 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConcat" );
8212 sal_uInt8 nParamCount = GetByte();
8213 String aRes;
8214 while( nParamCount-- > 0)
8215 {
8216 const String& rStr = GetString();
8217 aRes.Insert( rStr, 0 );
8218 }
8219 PushString( aRes );
8220 }
8221
8222
ScErrorType()8223 void ScInterpreter::ScErrorType()
8224 {
8225 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScErrorType" );
8226 sal_uInt16 nErr;
8227 sal_uInt16 nOldError = nGlobalError;
8228 nGlobalError = 0;
8229 switch ( GetStackType() )
8230 {
8231 case svRefList :
8232 {
8233 FormulaTokenRef x = PopToken();
8234 if (nGlobalError)
8235 nErr = nGlobalError;
8236 else
8237 {
8238 const ScRefList* pRefList = static_cast<ScToken*>(x.get())->GetRefList();
8239 size_t n = pRefList->size();
8240 if (!n)
8241 nErr = errNoRef;
8242 else if (n > 1)
8243 nErr = errNoValue;
8244 else
8245 {
8246 ScRange aRange;
8247 DoubleRefToRange( (*pRefList)[0], aRange);
8248 if (nGlobalError)
8249 nErr = nGlobalError;
8250 else
8251 {
8252 ScAddress aAdr;
8253 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
8254 nErr = pDok->GetErrCode( aAdr );
8255 else
8256 nErr = nGlobalError;
8257 }
8258 }
8259 }
8260 }
8261 break;
8262 case svDoubleRef :
8263 {
8264 ScRange aRange;
8265 PopDoubleRef( aRange );
8266 if ( nGlobalError )
8267 nErr = nGlobalError;
8268 else
8269 {
8270 ScAddress aAdr;
8271 if ( DoubleRefToPosSingleRef( aRange, aAdr ) )
8272 nErr = pDok->GetErrCode( aAdr );
8273 else
8274 nErr = nGlobalError;
8275 }
8276 }
8277 break;
8278 case svSingleRef :
8279 {
8280 ScAddress aAdr;
8281 PopSingleRef( aAdr );
8282 if ( nGlobalError )
8283 nErr = nGlobalError;
8284 else
8285 nErr = pDok->GetErrCode( aAdr );
8286 }
8287 break;
8288 default:
8289 PopError();
8290 nErr = nGlobalError;
8291 }
8292 if ( nErr )
8293 {
8294 nGlobalError = 0;
8295 PushDouble( nErr );
8296 }
8297 else
8298 {
8299 nGlobalError = nOldError;
8300 PushNA();
8301 }
8302 }
8303
8304
MayBeRegExp(const String & rStr,const ScDocument * pDoc)8305 sal_Bool ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc )
8306 {
8307 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MayBeRegExp" );
8308 if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() )
8309 return sal_False;
8310 if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') )
8311 return sal_False; // einzelnes Metazeichen kann keine RegExp sein
8312 static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 };
8313 const sal_Unicode* p1 = rStr.GetBuffer();
8314 sal_Unicode c1;
8315 while ( ( c1 = *p1++ ) != 0 )
8316 {
8317 const sal_Unicode* p2 = cre;
8318 while ( *p2 )
8319 {
8320 if ( c1 == *p2++ )
8321 return sal_True;
8322 }
8323 }
8324 return sal_False;
8325 }
8326
lcl_LookupQuery(ScAddress & o_rResultPos,ScDocument * pDoc,const ScQueryParam & rParam,const ScQueryEntry & rEntry)8327 static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc,
8328 const ScQueryParam & rParam, const ScQueryEntry & rEntry )
8329 {
8330 bool bFound = false;
8331 ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, sal_False);
8332 if (rEntry.eOp != SC_EQUAL)
8333 {
8334 // range lookup <= or >=
8335 SCCOL nCol;
8336 SCROW nRow;
8337 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow);
8338 if (bFound)
8339 {
8340 o_rResultPos.SetCol( nCol);
8341 o_rResultPos.SetRow( nRow);
8342 }
8343 }
8344 else if (aCellIter.GetFirst())
8345 {
8346 // EQUAL
8347 bFound = true;
8348 o_rResultPos.SetCol( aCellIter.GetCol());
8349 o_rResultPos.SetRow( aCellIter.GetRow());
8350 }
8351 return bFound;
8352 }
8353
8354 #define erDEBUG_LOOKUPCACHE 0
8355 #if erDEBUG_LOOKUPCACHE
8356 #include <cstdio>
8357 using ::std::fprintf;
8358 using ::std::fflush;
8359 static struct LookupCacheDebugCounter
8360 {
8361 unsigned long nMiss;
8362 unsigned long nHit;
LookupCacheDebugCounterLookupCacheDebugCounter8363 LookupCacheDebugCounter() : nMiss(0), nHit(0) {}
~LookupCacheDebugCounterLookupCacheDebugCounter8364 ~LookupCacheDebugCounter()
8365 {
8366 fprintf( stderr, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n",
8367 nMiss, nHit, nHit+nMiss, (nMiss>0 ? nHit/nMiss : 0),
8368 ((nHit+nMiss)>0 ? (100*nHit)/(nHit+nMiss) : 0));
8369 fflush( stderr);
8370 }
8371 } aLookupCacheDebugCounter;
8372 #endif
8373
LookupQueryWithCache(ScAddress & o_rResultPos,const ScQueryParam & rParam) const8374 bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos,
8375 const ScQueryParam & rParam ) const
8376 {
8377 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::LookupQueryWithCache" );
8378 bool bFound = false;
8379 const ScQueryEntry& rEntry = rParam.GetEntry(0);
8380 bool bColumnsMatch = (rParam.nCol1 == rEntry.nField);
8381 DBG_ASSERT( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match");
8382 if (!bColumnsMatch)
8383 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
8384 else
8385 {
8386 ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab,
8387 rParam.nCol2, rParam.nRow2, rParam.nTab);
8388 ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange);
8389 ScLookupCache::QueryCriteria aCriteria( rEntry);
8390 ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos,
8391 aCriteria, aPos);
8392 switch (eCacheResult)
8393 {
8394 case ScLookupCache::NOT_CACHED :
8395 case ScLookupCache::CRITERIA_DIFFERENT :
8396 #if erDEBUG_LOOKUPCACHE
8397 ++aLookupCacheDebugCounter.nMiss;
8398 #if erDEBUG_LOOKUPCACHE > 1
8399 fprintf( stderr, "miss %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
8400 #endif
8401 #endif
8402 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry);
8403 if (eCacheResult == ScLookupCache::NOT_CACHED)
8404 rCache.insert( o_rResultPos, aCriteria, aPos, bFound);
8405 break;
8406 case ScLookupCache::FOUND :
8407 #if erDEBUG_LOOKUPCACHE
8408 ++aLookupCacheDebugCounter.nHit;
8409 #if erDEBUG_LOOKUPCACHE > 1
8410 fprintf( stderr, "hit %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab());
8411 #endif
8412 #endif
8413 bFound = true;
8414 break;
8415 case ScLookupCache::NOT_AVAILABLE :
8416 ; // nothing, bFound remains FALSE
8417 break;
8418 }
8419 }
8420 return bFound;
8421 }
8422