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