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