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