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