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