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