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