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