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