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; 4617 SCROW nRow1; 4618 SCTAB nTab1; 4619 SCCOL nCol2; 4620 SCROW nRow2; 4621 SCTAB nTab2; 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 5107 while (nParamCount > 1 && !nGlobalError) 5108 { 5109 // take criteria 5110 String rString; 5111 fVal = 0.0; 5112 bool bIsString = true; 5113 switch ( GetStackType() ) 5114 { 5115 case svDoubleRef : 5116 case svSingleRef : 5117 { 5118 ScAddress aAdr; 5119 if ( !PopDoubleRefOrSingleRef( aAdr ) ) 5120 return 0; 5121 5122 ScBaseCell* pCell = GetCell( aAdr ); 5123 switch ( GetCellType( pCell ) ) 5124 { 5125 case CELLTYPE_VALUE : 5126 fVal = GetCellValue( aAdr, pCell ); 5127 bIsString = false; 5128 break; 5129 case CELLTYPE_FORMULA : 5130 if( ((ScFormulaCell*)pCell)->IsValue() ) 5131 { 5132 fVal = GetCellValue( aAdr, pCell ); 5133 bIsString = false; 5134 } 5135 else 5136 GetCellString(rString, pCell); 5137 break; 5138 case CELLTYPE_STRING : 5139 case CELLTYPE_EDIT : 5140 GetCellString(rString, pCell); 5141 break; 5142 default: 5143 fVal = 0.0; 5144 bIsString = false; 5145 } 5146 } 5147 break; 5148 case svString: 5149 rString = GetString(); 5150 break; 5151 case svMatrix : 5152 { 5153 ScMatValType nType = GetDoubleOrStringFromMatrix( fVal, rString); 5154 bIsString = ScMatrix::IsNonValueType( nType); 5155 } 5156 break; 5157 default: 5158 { 5159 fVal = GetDouble(); 5160 bIsString = false; 5161 } 5162 } 5163 5164 // take range 5165 nParam = 1; 5166 nRefInList = 0; 5167 SCCOL nCol1; 5168 SCROW nRow1; 5169 SCTAB nTab1; 5170 SCCOL nCol2; 5171 SCROW nRow2; 5172 SCTAB nTab2; 5173 ScMatrixRef pQueryMatrix; 5174 switch ( GetStackType() ) 5175 { 5176 case svRefList : 5177 { 5178 ScRange aRange; 5179 PopDoubleRef( aRange, nParam, nRefInList); 5180 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 5181 } 5182 break; 5183 case svDoubleRef : 5184 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2 ); 5185 break; 5186 case svSingleRef : 5187 PopSingleRef( nCol1, nRow1, nTab1 ); 5188 nCol2 = nCol1; 5189 nRow2 = nRow1; 5190 nTab2 = nTab1; 5191 break; 5192 case svMatrix: 5193 { 5194 pQueryMatrix = PopMatrix(); 5195 if (!pQueryMatrix) 5196 { 5197 SetError( errIllegalParameter); 5198 } 5199 nCol1 = 0; 5200 nRow1 = 0; 5201 nTab1 = 0; 5202 SCSIZE nC, nR; 5203 pQueryMatrix->GetDimensions( nC, nR); 5204 nCol2 = static_cast<SCCOL>(nC - 1); 5205 nRow2 = static_cast<SCROW>(nR - 1); 5206 nTab2 = 0; 5207 } 5208 break; 5209 default: 5210 SetError( errIllegalParameter); 5211 } 5212 if ( nTab1 != nTab2 ) 5213 { 5214 SetError( errIllegalParameter); 5215 } 5216 // initialize temporary result matrix 5217 if (!pResMat) 5218 { 5219 SCSIZE nResC, nResR; 5220 nResC = nCol2 - nCol1 + 1; 5221 nResR = nRow2 - nRow1 + 1; 5222 pResMat = GetNewMat(nResC, nResR); 5223 if (!pResMat) 5224 { 5225 SetError( errIllegalParameter); 5226 } 5227 else 5228 { 5229 pResMat->FillDouble( 0.0, 0, 0, nResC-1, nResR-1); 5230 } 5231 } 5232 // recalculate matrix values 5233 if (nGlobalError == 0) 5234 { 5235 ScQueryParam rParam; 5236 rParam.nRow1 = nRow1; 5237 rParam.nRow2 = nRow2; 5238 5239 ScQueryEntry& rEntry = rParam.GetEntry(0); 5240 rEntry.bDoQuery = true; 5241 if (!bIsString) 5242 { 5243 rEntry.bQueryByString = false; 5244 rEntry.nVal = fVal; 5245 rEntry.eOp = SC_EQUAL; 5246 } 5247 else 5248 { 5249 rParam.FillInExcelSyntax(rString, 0); 5250 sal_uInt32 nIndex = 0; 5251 rEntry.bQueryByString = 5252 !(pFormatter->IsNumberFormat( 5253 *rEntry.pStr, nIndex, rEntry.nVal)); 5254 if ( rEntry.bQueryByString ) 5255 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); 5256 } 5257 ScAddress aAdr; 5258 aAdr.SetTab( nTab1 ); 5259 rParam.nCol1 = nCol1; 5260 rParam.nCol2 = nCol2; 5261 rEntry.nField = nCol1; 5262 SCsCOL nColDiff = -nCol1; 5263 SCsROW nRowDiff = -nRow1; 5264 if (pQueryMatrix) 5265 { 5266 // Never case-sensitive. 5267 ScCompareOptions aOptions( pDok, rEntry, rParam.bRegExp); 5268 ScMatrixRef pResultMatrix = QueryMat( pQueryMatrix, aOptions); 5269 if (nGlobalError || !pResultMatrix) 5270 { 5271 SetError( errIllegalParameter); 5272 } 5273 5274 for (SCCOL nCol = nCol1; nCol <= nCol2; ++nCol) 5275 { 5276 for (SCROW nRow = nRow1; nRow <= nRow2; ++nRow) 5277 { 5278 if (pResultMatrix->IsValue( nCol, nRow) && 5279 pResultMatrix->GetDouble( nCol, nRow)) 5280 { 5281 SCSIZE nC = nCol + nColDiff; 5282 SCSIZE nR = nRow + nRowDiff; 5283 pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR); 5284 } 5285 } 5286 } 5287 } 5288 else 5289 { 5290 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, false); 5291 // Increment Entry.nField in iterator when switching to next column. 5292 aCellIter.SetAdvanceQueryParamEntryField( true ); 5293 if ( aCellIter.GetFirst() ) 5294 { 5295 do 5296 { 5297 SCSIZE nC = aCellIter.GetCol() + nColDiff; 5298 SCSIZE nR = aCellIter.GetRow() + nRowDiff; 5299 pResMat->PutDouble(pResMat->GetDouble(nC, nR)+1.0, nC, nR); 5300 } while ( aCellIter.GetNext() ); 5301 } 5302 } 5303 } 5304 else 5305 { 5306 SetError( errIllegalParameter); 5307 } 5308 nParamCount -= 2; 5309 } 5310 5311 // main range - only for AVERAGEIFS and SUMIFS 5312 if (nParamCount == 1) 5313 { 5314 nParam = 1; 5315 nRefInList = 0; 5316 bool bNull = true; 5317 SCCOL nMainCol1; 5318 SCROW nMainRow1; 5319 SCTAB nMainTab1; 5320 SCCOL nMainCol2; 5321 SCROW nMainRow2; 5322 SCTAB nMainTab2; 5323 ScMatrixRef pMainMatrix; 5324 switch ( GetStackType() ) 5325 { 5326 case svRefList : 5327 { 5328 ScRange aRange; 5329 PopDoubleRef( aRange, nParam, nRefInList); 5330 aRange.GetVars( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2); 5331 } 5332 break; 5333 case svDoubleRef : 5334 PopDoubleRef( nMainCol1, nMainRow1, nMainTab1, nMainCol2, nMainRow2, nMainTab2 ); 5335 break; 5336 case svSingleRef : 5337 PopSingleRef( nMainCol1, nMainRow1, nMainTab1 ); 5338 nMainCol2 = nMainCol1; 5339 nMainRow2 = nMainRow1; 5340 nMainTab2 = nMainTab1; 5341 break; 5342 case svMatrix: 5343 { 5344 pMainMatrix = PopMatrix(); 5345 if (!pMainMatrix) 5346 { 5347 SetError( errIllegalParameter); 5348 } 5349 nMainCol1 = 0; 5350 nMainRow1 = 0; 5351 nMainTab1 = 0; 5352 SCSIZE nC, nR; 5353 pMainMatrix->GetDimensions( nC, nR); 5354 nMainCol2 = static_cast<SCCOL>(nC - 1); 5355 nMainRow2 = static_cast<SCROW>(nR - 1); 5356 nMainTab2 = 0; 5357 } 5358 break; 5359 default: 5360 SetError( errIllegalParameter); 5361 } 5362 if ( nMainTab1 != nMainTab2 ) 5363 { 5364 SetError( errIllegalParameter); 5365 } 5366 // end-result calculation 5367 ScAddress aAdr; 5368 aAdr.SetTab( nMainTab1 ); 5369 if (pMainMatrix) 5370 { 5371 SCSIZE nC, nR; 5372 pResMat->GetDimensions(nC, nR); 5373 for (SCSIZE nCol = 0; nCol < nC; ++nCol) 5374 { 5375 for (SCSIZE nRow = 0; nRow < nR; ++nRow) 5376 { 5377 if (pResMat->GetDouble( nCol, nRow) == nQueryCount) 5378 { 5379 if (pMainMatrix->IsValue( nCol, nRow)) 5380 { 5381 fVal = pMainMatrix->GetDouble( nCol, nRow); 5382 ++fCount; 5383 if ( bNull && fVal != 0.0 ) 5384 { 5385 bNull = false; 5386 fMem = fVal; 5387 } 5388 else 5389 fSum += fVal; 5390 } 5391 } 5392 } 5393 } 5394 } 5395 else 5396 { 5397 SCSIZE nC, nR; 5398 pResMat->GetDimensions(nC, nR); 5399 for (SCSIZE nCol = 0; nCol < nC; ++nCol) 5400 { 5401 for (SCSIZE nRow = 0; nRow < nR; ++nRow) 5402 { 5403 if (pResMat->GetDouble( nCol, nRow) == nQueryCount) 5404 { 5405 aAdr.SetCol( nCol + nMainCol1); 5406 aAdr.SetRow( nRow + nMainRow1); 5407 ScBaseCell* pCell = GetCell( aAdr ); 5408 if ( HasCellValueData(pCell) ) 5409 { 5410 fVal = GetCellValue( aAdr, pCell ); 5411 ++fCount; 5412 if ( bNull && fVal != 0.0 ) 5413 { 5414 bNull = false; 5415 fMem = fVal; 5416 } 5417 else 5418 fSum += fVal; 5419 } 5420 } 5421 } 5422 } 5423 } 5424 } 5425 else 5426 { 5427 SCSIZE nC, nR; 5428 pResMat->GetDimensions(nC, nR); 5429 for (SCSIZE nCol = 0; nCol < nC; ++nCol) 5430 { 5431 for (SCSIZE nRow = 0; nRow < nR; ++nRow) 5432 if (pResMat->GetDouble( nCol, nRow) == nQueryCount) 5433 ++fCount; 5434 } 5435 } 5436 // 5437 switch( eFunc ) 5438 { 5439 case ifSUMIFS: fRes = ::rtl::math::approxAdd( fSum, fMem ); break; 5440 case ifAVERAGEIFS: fRes = div( ::rtl::math::approxAdd( fSum, fMem ), fCount); break; 5441 case ifCOUNTIFS: fRes = fCount; break; 5442 default: ; // nothing 5443 } 5444 return fRes; 5445 } 5446 return 0; 5447 } 5448 5449 void ScInterpreter::ScSumIfs() 5450 { 5451 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScSumIfs" ); 5452 PushDouble( IterateParametersIfs( ifSUMIFS)); 5453 } 5454 5455 void ScInterpreter::ScAverageIfs() 5456 { 5457 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScAverageIfs" ); 5458 PushDouble( IterateParametersIfs( ifAVERAGEIFS)); 5459 } 5460 5461 void ScInterpreter::ScCountIfs() 5462 { 5463 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "makkica", "ScInterpreter::ScCountIfs" ); 5464 PushDouble( IterateParametersIfs( ifCOUNTIFS)); 5465 } 5466 5467 void ScInterpreter::ScLookup() 5468 { 5469 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLookup" ); 5470 sal_uInt8 nParamCount = GetByte(); 5471 if ( !MustHaveParamCount( nParamCount, 2, 3 ) ) 5472 return ; 5473 5474 ScMatrixRef pDataMat = NULL, pResMat = NULL; 5475 SCCOL nCol1 = 0, nCol2 = 0, nResCol1 = 0, nResCol2 = 0; 5476 SCROW nRow1 = 0, nRow2 = 0, nResRow1 = 0, nResRow2 = 0; 5477 SCTAB nTab1 = 0, nResTab = 0; 5478 SCSIZE nLenMajor = 0; // length of major direction 5479 bool bVertical = true; // whether to lookup vertically or horizontally 5480 5481 // The third parameter, result array, for double, string and single reference. 5482 double fResVal = 0.0; 5483 String aResStr; 5484 ScAddress aResAdr; 5485 StackVar eResArrayType = svUnknown; 5486 5487 if (nParamCount == 3) 5488 { 5489 eResArrayType = GetStackType(); 5490 switch (eResArrayType) 5491 { 5492 case svDoubleRef: 5493 { 5494 SCTAB nTabJunk; 5495 PopDoubleRef(nResCol1, nResRow1, nResTab, 5496 nResCol2, nResRow2, nTabJunk); 5497 if (nResTab != nTabJunk || 5498 ((nResRow2 - nResRow1) > 0 && (nResCol2 - nResCol1) > 0)) 5499 { 5500 // The result array must be a vector. 5501 PushIllegalParameter(); 5502 return; 5503 } 5504 } 5505 break; 5506 case svMatrix: 5507 { 5508 pResMat = PopMatrix(); 5509 if (!pResMat) 5510 { 5511 PushIllegalParameter(); 5512 return; 5513 } 5514 SCSIZE nC, nR; 5515 pResMat->GetDimensions(nC, nR); 5516 if (nC != 1 && nR != 1) 5517 { 5518 // Result matrix must be a vector. 5519 PushIllegalParameter(); 5520 return; 5521 } 5522 } 5523 break; 5524 case svDouble: 5525 fResVal = GetDouble(); 5526 break; 5527 case svString: 5528 aResStr = GetString(); 5529 break; 5530 case svSingleRef: 5531 PopSingleRef( aResAdr ); 5532 break; 5533 default: 5534 PushIllegalParameter(); 5535 return; 5536 } 5537 } 5538 5539 // For double, string and single reference. 5540 double fDataVal = 0.0; 5541 String aDataStr; 5542 ScAddress aDataAdr; 5543 bool bValueData = false; 5544 5545 // Get the data-result range and also determine whether this is vertical 5546 // lookup or horizontal lookup. 5547 5548 StackVar eDataArrayType = GetStackType(); 5549 switch (eDataArrayType) 5550 { 5551 case svDoubleRef: 5552 { 5553 SCTAB nTabJunk; 5554 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTabJunk); 5555 if (nTab1 != nTabJunk) 5556 { 5557 PushIllegalParameter(); 5558 return; 5559 } 5560 bVertical = (nRow2 - nRow1) >= (nCol2 - nCol1); 5561 nLenMajor = bVertical ? nRow2 - nRow1 + 1 : nCol2 - nCol1 + 1; 5562 } 5563 break; 5564 case svMatrix: 5565 { 5566 pDataMat = PopMatrix(); 5567 if (!pDataMat) 5568 { 5569 PushIllegalParameter(); 5570 return; 5571 } 5572 5573 SCSIZE nC, nR; 5574 pDataMat->GetDimensions(nC, nR); 5575 bVertical = (nR >= nC); 5576 nLenMajor = bVertical ? nR : nC; 5577 } 5578 break; 5579 case svDouble: 5580 { 5581 fDataVal = GetDouble(); 5582 bValueData = true; 5583 } 5584 break; 5585 case svString: 5586 { 5587 aDataStr = GetString(); 5588 } 5589 break; 5590 case svSingleRef: 5591 { 5592 PopSingleRef( aDataAdr ); 5593 const ScBaseCell* pDataCell = GetCell( aDataAdr ); 5594 if (HasCellEmptyData( pDataCell)) 5595 { 5596 // Empty cells aren't found anywhere, bail out early. 5597 SetError( NOTAVAILABLE); 5598 } 5599 else if (HasCellValueData( pDataCell)) 5600 { 5601 fDataVal = GetCellValue( aDataAdr, pDataCell ); 5602 bValueData = true; 5603 } 5604 else 5605 GetCellString( aDataStr, pDataCell ); 5606 } 5607 break; 5608 default: 5609 SetError( errIllegalParameter); 5610 } 5611 5612 5613 if (nGlobalError) 5614 { 5615 PushError( nGlobalError); 5616 return; 5617 } 5618 5619 // Get the lookup value. 5620 5621 ScQueryParam aParam; 5622 ScQueryEntry& rEntry = aParam.GetEntry(0); 5623 if ( !FillEntry(rEntry) ) 5624 return; 5625 5626 if ( eDataArrayType == svDouble || eDataArrayType == svString || 5627 eDataArrayType == svSingleRef ) 5628 { 5629 // Delta position for a single value is always 0. 5630 5631 // Found if data <= query, but not if query is string and found data is 5632 // numeric or vice versa. This is how Excel does it but doesn't 5633 // document it. 5634 5635 bool bFound = false; 5636 if ( bValueData ) 5637 { 5638 if ( rEntry.bQueryByString ) 5639 bFound = false; 5640 else 5641 bFound = (fDataVal <= rEntry.nVal); 5642 } 5643 else 5644 { 5645 if ( !rEntry.bQueryByString ) 5646 bFound = false; 5647 else 5648 bFound = (ScGlobal::GetCollator()->compareString( aDataStr, *rEntry.pStr) <= 0); 5649 } 5650 5651 if (!bFound) 5652 { 5653 PushNA(); 5654 return; 5655 } 5656 5657 if (pResMat) 5658 { 5659 if (pResMat->IsValue( 0 )) 5660 PushDouble(pResMat->GetDouble( 0 )); 5661 else 5662 PushString(pResMat->GetString( 0 )); 5663 } 5664 else if (nParamCount == 3) 5665 { 5666 switch (eResArrayType) 5667 { 5668 case svDouble: 5669 PushDouble( fResVal ); 5670 break; 5671 case svString: 5672 PushString( aResStr ); 5673 break; 5674 case svDoubleRef: 5675 aResAdr.Set( nResCol1, nResRow1, nResTab); 5676 // fallthru 5677 case svSingleRef: 5678 PushCellResultToken( true, aResAdr, NULL, NULL); 5679 break; 5680 default: 5681 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, single value data"); 5682 } 5683 } 5684 else 5685 { 5686 switch (eDataArrayType) 5687 { 5688 case svDouble: 5689 PushDouble( fDataVal ); 5690 break; 5691 case svString: 5692 PushString( aDataStr ); 5693 break; 5694 case svSingleRef: 5695 PushCellResultToken( true, aDataAdr, NULL, NULL); 5696 break; 5697 default: 5698 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eDataArrayType, single value data"); 5699 } 5700 } 5701 return; 5702 } 5703 5704 // Now, perform the search to compute the delta position (nDelta). 5705 5706 if (pDataMat) 5707 { 5708 // Data array is given as a matrix. 5709 rEntry.bDoQuery = true; 5710 rEntry.eOp = SC_LESS_EQUAL; 5711 bool bFound = false; 5712 5713 SCSIZE nC, nR; 5714 pDataMat->GetDimensions(nC, nR); 5715 5716 // In case of non-vector matrix, only search the first row or column. 5717 ScMatrixRef pDataMat2; 5718 if (bVertical) 5719 { 5720 ScMatrixRef pTempMat(new ScMatrix(1, nR)); 5721 for (SCSIZE i = 0; i < nR; ++i) 5722 if (pDataMat->IsValue(0, i)) 5723 pTempMat->PutDouble(pDataMat->GetDouble(0, i), 0, i); 5724 else 5725 pTempMat->PutString(pDataMat->GetString(0, i), 0, i); 5726 pDataMat2 = pTempMat; 5727 } 5728 else 5729 { 5730 ScMatrixRef pTempMat(new ScMatrix(nC, 1)); 5731 for (SCSIZE i = 0; i < nC; ++i) 5732 if (pDataMat->IsValue(i, 0)) 5733 pTempMat->PutDouble(pDataMat->GetDouble(i, 0), i, 0); 5734 else 5735 pTempMat->PutString(pDataMat->GetString(i, 0), i, 0); 5736 pDataMat2 = pTempMat; 5737 } 5738 5739 // binary search for non-equality mode (the source data is 5740 // assumed to be sorted in ascending order). 5741 5742 SCCOLROW nDelta = -1; 5743 5744 SCSIZE nFirst = 0, nLast = nLenMajor-1; //, nHitIndex = 0; 5745 for (SCSIZE nLen = nLast-nFirst; nLen > 0; nLen = nLast-nFirst) 5746 { 5747 SCSIZE nMid = nFirst + nLen/2; 5748 sal_Int32 nCmp = lcl_CompareMatrix2Query( nMid, *pDataMat2, rEntry); 5749 if (nCmp == 0) 5750 { 5751 // exact match. find the last item with the same value. 5752 lcl_GetLastMatch( nMid, *pDataMat2, nLenMajor, false); 5753 nDelta = nMid; 5754 bFound = true; 5755 break; 5756 } 5757 5758 if (nLen == 1) // first and last items are next to each other. 5759 { 5760 nDelta = nCmp < 0 ? nLast - 1 : nFirst - 1; 5761 // If already the 1st item is greater there's nothing found. 5762 bFound = (nDelta >= 0); 5763 break; 5764 } 5765 5766 if (nCmp < 0) 5767 nFirst = nMid; 5768 else 5769 nLast = nMid; 5770 } 5771 5772 if (nDelta == static_cast<SCCOLROW>(nLenMajor-2)) // last item 5773 { 5774 sal_Int32 nCmp = lcl_CompareMatrix2Query(nDelta+1, *pDataMat2, rEntry); 5775 if (nCmp <= 0) 5776 { 5777 // either the last item is an exact match or the real 5778 // hit is beyond the last item. 5779 nDelta += 1; 5780 bFound = true; 5781 } 5782 } 5783 else if (nDelta > 0) // valid hit must be 2nd item or higher 5784 { 5785 // non-exact match 5786 bFound = true; 5787 } 5788 5789 // With 0-9 < A-Z, if query is numeric and data found is string, or 5790 // vice versa, the (yet another undocumented) Excel behavior is to 5791 // return #N/A instead. 5792 5793 if (bFound) 5794 { 5795 SCCOLROW i = nDelta; 5796 SCSIZE n = pDataMat->GetElementCount(); 5797 if (static_cast<SCSIZE>(i) >= n) 5798 i = static_cast<SCCOLROW>(n); 5799 if (bool(rEntry.bQueryByString) == bool(pDataMat->IsValue(i))) 5800 bFound = false; 5801 } 5802 5803 if (!bFound) 5804 { 5805 PushNA(); 5806 return; 5807 } 5808 5809 // Now that we've found the delta, push the result back to the cell. 5810 5811 if (pResMat) 5812 { 5813 // result array is matrix. 5814 if (static_cast<SCSIZE>(nDelta) >= pResMat->GetElementCount()) 5815 { 5816 PushNA(); 5817 return; 5818 } 5819 if (pResMat->IsValue(nDelta)) 5820 PushDouble(pResMat->GetDouble(nDelta)); 5821 else 5822 PushString(pResMat->GetString(nDelta)); 5823 } 5824 else if (nParamCount == 3) 5825 { 5826 // result array is cell range. 5827 ScAddress aAdr; 5828 aAdr.SetTab(nResTab); 5829 bool bResVertical = (nResRow2 - nResRow1) > 0; 5830 if (bResVertical) 5831 { 5832 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta); 5833 if (nTempRow > MAXROW) 5834 { 5835 PushDouble(0); 5836 return; 5837 } 5838 aAdr.SetCol(nResCol1); 5839 aAdr.SetRow(nTempRow); 5840 } 5841 else 5842 { 5843 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta); 5844 if (nTempCol > MAXCOL) 5845 { 5846 PushDouble(0); 5847 return; 5848 } 5849 aAdr.SetCol(nTempCol); 5850 aAdr.SetRow(nResRow1); 5851 } 5852 PushCellResultToken(true, aAdr, NULL, NULL); 5853 } 5854 else 5855 { 5856 // no result array. Use the data array to get the final value from. 5857 if (bVertical) 5858 { 5859 if (pDataMat->IsValue(nC-1, nDelta)) 5860 PushDouble(pDataMat->GetDouble(nC-1, nDelta)); 5861 else 5862 PushString(pDataMat->GetString(nC-1, nDelta)); 5863 } 5864 else 5865 { 5866 if (pDataMat->IsValue(nDelta, nR-1)) 5867 PushDouble(pDataMat->GetDouble(nDelta, nR-1)); 5868 else 5869 PushString(pDataMat->GetString(nDelta, nR-1)); 5870 } 5871 } 5872 5873 return; 5874 } 5875 5876 // Perform cell range search. 5877 5878 aParam.nCol1 = nCol1; 5879 aParam.nRow1 = nRow1; 5880 aParam.nCol2 = bVertical ? nCol1 : nCol2; 5881 aParam.nRow2 = bVertical ? nRow2 : nRow1; 5882 aParam.bByRow = bVertical; 5883 aParam.bMixedComparison = true; 5884 5885 rEntry.bDoQuery = sal_True; 5886 rEntry.eOp = SC_LESS_EQUAL; 5887 rEntry.nField = nCol1; 5888 if ( rEntry.bQueryByString ) 5889 aParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); 5890 5891 ScQueryCellIterator aCellIter(pDok, nTab1, aParam, sal_False); 5892 SCCOL nC; 5893 SCROW nR; 5894 // Advance Entry.nField in iterator upon switching columns if 5895 // lookup in row. 5896 aCellIter.SetAdvanceQueryParamEntryField(!bVertical); 5897 if ( !aCellIter.FindEqualOrSortedLastInRange(nC, nR) ) 5898 { 5899 PushNA(); 5900 return; 5901 } 5902 5903 SCCOLROW nDelta = bVertical ? static_cast<SCSIZE>(nR-nRow1) : static_cast<SCSIZE>(nC-nCol1); 5904 5905 if (pResMat) 5906 { 5907 // Use the matrix result array. 5908 if (pResMat->IsValue(nDelta)) 5909 PushDouble(pResMat->GetDouble(nDelta)); 5910 else 5911 PushString(pResMat->GetString(nDelta)); 5912 } 5913 else if (nParamCount == 3) 5914 { 5915 switch (eResArrayType) 5916 { 5917 case svDoubleRef: 5918 { 5919 // Use the result array vector. Note that the result array is assumed 5920 // to be a vector (i.e. 1-dimensinoal array). 5921 5922 ScAddress aAdr; 5923 aAdr.SetTab(nResTab); 5924 bool bResVertical = (nResRow2 - nResRow1) > 0; 5925 if (bResVertical) 5926 { 5927 SCROW nTempRow = static_cast<SCROW>(nResRow1 + nDelta); 5928 if (nTempRow > MAXROW) 5929 { 5930 PushDouble(0); 5931 return; 5932 } 5933 aAdr.SetCol(nResCol1); 5934 aAdr.SetRow(nTempRow); 5935 } 5936 else 5937 { 5938 SCCOL nTempCol = static_cast<SCCOL>(nResCol1 + nDelta); 5939 if (nTempCol > MAXCOL) 5940 { 5941 PushDouble(0); 5942 return; 5943 } 5944 aAdr.SetCol(nTempCol); 5945 aAdr.SetRow(nResRow1); 5946 } 5947 PushCellResultToken( true, aAdr, NULL, NULL); 5948 } 5949 break; 5950 case svDouble: 5951 case svString: 5952 case svSingleRef: 5953 { 5954 if (nDelta != 0) 5955 PushNA(); 5956 else 5957 { 5958 switch (eResArrayType) 5959 { 5960 case svDouble: 5961 PushDouble( fResVal ); 5962 break; 5963 case svString: 5964 PushString( aResStr ); 5965 break; 5966 case svSingleRef: 5967 PushCellResultToken( true, aResAdr, NULL, NULL); 5968 break; 5969 default: 5970 ; // nothing 5971 } 5972 } 5973 } 5974 break; 5975 default: 5976 DBG_ERRORFILE( "ScInterpreter::ScLookup: unhandled eResArrayType, range search"); 5977 } 5978 } 5979 else 5980 { 5981 // Regardless of whether or not the result array exists, the last 5982 // array is always used as the "result" array. 5983 5984 ScAddress aAdr; 5985 aAdr.SetTab(nTab1); 5986 if (bVertical) 5987 { 5988 SCROW nTempRow = static_cast<SCROW>(nRow1 + nDelta); 5989 if (nTempRow > MAXROW) 5990 { 5991 PushDouble(0); 5992 return; 5993 } 5994 aAdr.SetCol(nCol2); 5995 aAdr.SetRow(nTempRow); 5996 } 5997 else 5998 { 5999 SCCOL nTempCol = static_cast<SCCOL>(nCol1 + nDelta); 6000 if (nTempCol > MAXCOL) 6001 { 6002 PushDouble(0); 6003 return; 6004 } 6005 aAdr.SetCol(nTempCol); 6006 aAdr.SetRow(nRow2); 6007 } 6008 PushCellResultToken(true, aAdr, NULL, NULL); 6009 } 6010 } 6011 6012 6013 void ScInterpreter::ScHLookup() 6014 { 6015 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScHLookup" ); 6016 CalculateLookup(sal_True); 6017 } 6018 void ScInterpreter::CalculateLookup(sal_Bool HLookup) 6019 { 6020 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::CalculateLookup" ); 6021 sal_uInt8 nParamCount = GetByte(); 6022 if ( MustHaveParamCount( nParamCount, 3, 4 ) ) 6023 { 6024 sal_Bool bSorted; 6025 if (nParamCount == 4) 6026 bSorted = GetBool(); 6027 else 6028 bSorted = sal_True; 6029 double fIndex = ::rtl::math::approxFloor( GetDouble() ) - 1.0; 6030 ScMatrixRef pMat = NULL; 6031 SCSIZE nC = 0, nR = 0; 6032 SCCOL nCol1 = 0; 6033 SCROW nRow1 = 0; 6034 SCTAB nTab1 = 0; 6035 SCCOL nCol2 = 0; 6036 SCROW nRow2 = 0; 6037 SCTAB nTab2; 6038 if (GetStackType() == svDoubleRef) 6039 { 6040 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 6041 if (nTab1 != nTab2) 6042 { 6043 PushIllegalParameter(); 6044 return; 6045 } 6046 } 6047 else if (GetStackType() == svMatrix) 6048 { 6049 pMat = PopMatrix(); 6050 if (pMat) 6051 pMat->GetDimensions(nC, nR); 6052 else 6053 { 6054 PushIllegalParameter(); 6055 return; 6056 } 6057 } 6058 else 6059 { 6060 PushIllegalParameter(); 6061 return; 6062 } 6063 if ( fIndex < 0.0 || (HLookup ? (pMat ? (fIndex >= nR) : (fIndex+nRow1 > nRow2)) : (pMat ? (fIndex >= nC) : (fIndex+nCol1 > nCol2)) ) ) 6064 { 6065 PushIllegalArgument(); 6066 return; 6067 } 6068 SCROW nZIndex = static_cast<SCROW>(fIndex); 6069 SCCOL nSpIndex = static_cast<SCCOL>(fIndex); 6070 6071 if (!pMat) 6072 { 6073 nZIndex += nRow1; // Wertzeile 6074 nSpIndex = sal::static_int_cast<SCCOL>( nSpIndex + nCol1 ); // value column 6075 } 6076 6077 if (nGlobalError == 0) 6078 { 6079 ScQueryParam rParam; 6080 rParam.nCol1 = nCol1; 6081 rParam.nRow1 = nRow1; 6082 if ( HLookup ) 6083 { 6084 rParam.nCol2 = nCol2; 6085 rParam.nRow2 = nRow1; // nur in der ersten Zeile suchen 6086 rParam.bByRow = sal_False; 6087 } // if ( HLookup ) 6088 else 6089 { 6090 rParam.nCol2 = nCol1; // nur in der ersten Spalte suchen 6091 rParam.nRow2 = nRow2; 6092 rParam.nTab = nTab1; 6093 } 6094 rParam.bMixedComparison = sal_True; 6095 6096 ScQueryEntry& rEntry = rParam.GetEntry(0); 6097 rEntry.bDoQuery = sal_True; 6098 if ( bSorted ) 6099 rEntry.eOp = SC_LESS_EQUAL; 6100 if ( !FillEntry(rEntry) ) 6101 return; 6102 if ( rEntry.bQueryByString ) 6103 rParam.bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); 6104 if (pMat) 6105 { 6106 SCSIZE nMatCount = HLookup ? nC : nR; 6107 SCSIZE nDelta = SCSIZE_MAX; 6108 if (rEntry.bQueryByString) 6109 { 6110 //!!!!!!! 6111 //! TODO: enable regex on matrix strings 6112 //!!!!!!! 6113 String aParamStr = *rEntry.pStr; 6114 if ( bSorted ) 6115 { 6116 static CollatorWrapper* pCollator = ScGlobal::GetCollator(); 6117 for (SCSIZE i = 0; i < nMatCount; i++) 6118 { 6119 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)) 6120 { 6121 sal_Int32 nRes = 6122 pCollator->compareString( HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr); 6123 if (nRes <= 0) 6124 nDelta = i; 6125 else if (i>0) // #i2168# ignore first mismatch 6126 i = nMatCount+1; 6127 } 6128 else 6129 nDelta = i; 6130 } 6131 } 6132 else 6133 { 6134 for (SCSIZE i = 0; i < nMatCount; i++) 6135 { 6136 if (HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i)) 6137 { 6138 if ( ScGlobal::GetpTransliteration()->isEqual( 6139 HLookup ? pMat->GetString(i,0) : pMat->GetString(0,i), aParamStr ) ) 6140 { 6141 nDelta = i; 6142 i = nMatCount + 1; 6143 } 6144 } 6145 } 6146 } 6147 } 6148 else 6149 { 6150 if ( bSorted ) 6151 { 6152 // #i2168# ignore strings 6153 for (SCSIZE i = 0; i < nMatCount; i++) 6154 { 6155 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))) 6156 { 6157 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) <= rEntry.nVal) 6158 nDelta = i; 6159 else 6160 i = nMatCount+1; 6161 } 6162 } 6163 } 6164 else 6165 { 6166 for (SCSIZE i = 0; i < nMatCount; i++) 6167 { 6168 if (!(HLookup ? pMat->IsString(i, 0) : pMat->IsString(0, i))) 6169 { 6170 if ((HLookup ? pMat->GetDouble(i,0) : pMat->GetDouble(0,i)) == rEntry.nVal) 6171 { 6172 nDelta = i; 6173 i = nMatCount + 1; 6174 } 6175 } 6176 } 6177 } 6178 } 6179 if ( nDelta != SCSIZE_MAX ) 6180 { 6181 SCSIZE nX = static_cast<SCSIZE>(nSpIndex); 6182 SCSIZE nY = nDelta; 6183 if ( HLookup ) 6184 { 6185 nX = nDelta; 6186 nY = static_cast<SCSIZE>(nZIndex); 6187 } 6188 if ( pMat->IsString( nX, nY) ) 6189 PushString(pMat->GetString( nX,nY)); 6190 else 6191 PushDouble(pMat->GetDouble( nX,nY)); 6192 } 6193 else 6194 PushNA(); 6195 } 6196 else 6197 { 6198 rEntry.nField = nCol1; 6199 sal_Bool bFound = sal_False; 6200 SCCOL nCol = 0; 6201 SCROW nRow = 0; 6202 if ( bSorted ) 6203 rEntry.eOp = SC_LESS_EQUAL; 6204 if ( HLookup ) 6205 { 6206 ScQueryCellIterator aCellIter(pDok, nTab1, rParam, sal_False); 6207 // advance Entry.nField in Iterator upon switching columns 6208 aCellIter.SetAdvanceQueryParamEntryField( sal_True ); 6209 if ( bSorted ) 6210 { 6211 SCROW nRow1_temp; 6212 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow1_temp ); 6213 } 6214 else if ( aCellIter.GetFirst() ) 6215 { 6216 bFound = sal_True; 6217 nCol = aCellIter.GetCol(); 6218 } 6219 nRow = nZIndex; 6220 } // if ( HLookup ) 6221 else 6222 { 6223 ScAddress aResultPos( nCol1, nRow1, nTab1); 6224 bFound = LookupQueryWithCache( aResultPos, rParam); 6225 nRow = aResultPos.Row(); 6226 nCol = nSpIndex; 6227 } 6228 if ( bFound ) 6229 { 6230 ScAddress aAdr( nCol, nRow, nTab1 ); 6231 PushCellResultToken( true, aAdr, NULL, NULL); 6232 } 6233 else 6234 PushNA(); 6235 } 6236 } 6237 else 6238 PushIllegalParameter(); 6239 } 6240 } 6241 6242 bool ScInterpreter::FillEntry(ScQueryEntry& rEntry) 6243 { 6244 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::FillEntry" ); 6245 switch ( GetStackType() ) 6246 { 6247 case svDouble: 6248 { 6249 rEntry.bQueryByString = sal_False; 6250 rEntry.nVal = GetDouble(); 6251 } 6252 break; 6253 case svString: 6254 { 6255 const String sStr = GetString(); 6256 rEntry.bQueryByString = sal_True; 6257 *rEntry.pStr = sStr; 6258 } 6259 break; 6260 case svDoubleRef : 6261 case svSingleRef : 6262 { 6263 ScAddress aAdr; 6264 if ( !PopDoubleRefOrSingleRef( aAdr ) ) 6265 { 6266 PushInt(0); 6267 return false; 6268 } 6269 ScBaseCell* pCell = GetCell( aAdr ); 6270 if (HasCellValueData(pCell)) 6271 { 6272 rEntry.bQueryByString = sal_False; 6273 rEntry.nVal = GetCellValue( aAdr, pCell ); 6274 } 6275 else 6276 { 6277 if ( GetCellType( pCell ) == CELLTYPE_NOTE ) 6278 { 6279 rEntry.bQueryByString = sal_False; 6280 rEntry.nVal = 0.0; 6281 } 6282 else 6283 { 6284 String sStr; 6285 GetCellString(sStr, pCell); 6286 rEntry.bQueryByString = sal_True; 6287 *rEntry.pStr = sStr; 6288 } 6289 } 6290 } 6291 break; 6292 case svMatrix : 6293 { 6294 const ScMatValType nType = GetDoubleOrStringFromMatrix(rEntry.nVal, *rEntry.pStr); 6295 rEntry.bQueryByString = ScMatrix::IsNonValueType( nType); 6296 } 6297 break; 6298 default: 6299 { 6300 PushIllegalParameter(); 6301 return false; 6302 } 6303 } // switch ( GetStackType() ) 6304 return true; 6305 } 6306 void ScInterpreter::ScVLookup() 6307 { 6308 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScVLookup" ); 6309 CalculateLookup(sal_False); 6310 } 6311 6312 void ScInterpreter::ScSubTotal() 6313 { 6314 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubTotal" ); 6315 sal_uInt8 nParamCount = GetByte(); 6316 if ( MustHaveParamCountMin( nParamCount, 2 ) ) 6317 { 6318 // We must fish the 1st parameter deep from the stack! And push it on top. 6319 const FormulaToken* p = pStack[ sp - nParamCount ]; 6320 PushTempToken( *p ); 6321 int nFunc = (int) ::rtl::math::approxFloor( GetDouble() ); 6322 if( nFunc < 1 || nFunc > 11 ) 6323 PushIllegalArgument(); // simulate return on stack, not SetError(...) 6324 else 6325 { 6326 cPar = nParamCount - 1; 6327 glSubTotal = sal_True; 6328 switch( nFunc ) 6329 { 6330 case SUBTOTAL_FUNC_AVE : ScAverage(); break; 6331 case SUBTOTAL_FUNC_CNT : ScCount(); break; 6332 case SUBTOTAL_FUNC_CNT2 : ScCount2(); break; 6333 case SUBTOTAL_FUNC_MAX : ScMax(); break; 6334 case SUBTOTAL_FUNC_MIN : ScMin(); break; 6335 case SUBTOTAL_FUNC_PROD : ScProduct(); break; 6336 case SUBTOTAL_FUNC_STD : ScStDev(); break; 6337 case SUBTOTAL_FUNC_STDP : ScStDevP(); break; 6338 case SUBTOTAL_FUNC_SUM : ScSum(); break; 6339 case SUBTOTAL_FUNC_VAR : ScVar(); break; 6340 case SUBTOTAL_FUNC_VARP : ScVarP(); break; 6341 default : PushIllegalArgument(); break; 6342 } 6343 glSubTotal = sal_False; 6344 } 6345 // Get rid of the 1st (fished) parameter. 6346 double nVal = GetDouble(); 6347 Pop(); 6348 PushDouble( nVal ); 6349 } 6350 } 6351 6352 ScDBQueryParamBase* ScInterpreter::GetDBParams( sal_Bool& rMissingField ) 6353 { 6354 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBParams" ); 6355 sal_Bool bAllowMissingField = sal_False; 6356 if ( rMissingField ) 6357 { 6358 bAllowMissingField = sal_True; 6359 rMissingField = sal_False; 6360 } 6361 if ( GetByte() == 3 ) 6362 { 6363 // First, get the query criteria range. 6364 ::std::auto_ptr<ScDBRangeBase> pQueryRef( PopDoubleRef() ); 6365 if (!pQueryRef.get()) 6366 return NULL; 6367 6368 sal_Bool bByVal = sal_True; 6369 double nVal = 0.0; 6370 String aStr; 6371 ScRange aMissingRange; 6372 sal_Bool bRangeFake = sal_False; 6373 switch (GetStackType()) 6374 { 6375 case svDouble : 6376 nVal = ::rtl::math::approxFloor( GetDouble() ); 6377 if ( bAllowMissingField && nVal == 0.0 ) 6378 rMissingField = sal_True; // fake missing parameter 6379 break; 6380 case svString : 6381 bByVal = sal_False; 6382 aStr = GetString(); 6383 break; 6384 case svSingleRef : 6385 { 6386 ScAddress aAdr; 6387 PopSingleRef( aAdr ); 6388 ScBaseCell* pCell = GetCell( aAdr ); 6389 if (HasCellValueData(pCell)) 6390 nVal = GetCellValue( aAdr, pCell ); 6391 else 6392 { 6393 bByVal = sal_False; 6394 GetCellString(aStr, pCell); 6395 } 6396 } 6397 break; 6398 case svDoubleRef : 6399 if ( bAllowMissingField ) 6400 { // fake missing parameter for old SO compatibility 6401 bRangeFake = sal_True; 6402 PopDoubleRef( aMissingRange ); 6403 } 6404 else 6405 { 6406 PopError(); 6407 SetError( errIllegalParameter ); 6408 } 6409 break; 6410 case svMissing : 6411 PopError(); 6412 if ( bAllowMissingField ) 6413 rMissingField = sal_True; 6414 else 6415 SetError( errIllegalParameter ); 6416 break; 6417 default: 6418 PopError(); 6419 SetError( errIllegalParameter ); 6420 } 6421 6422 auto_ptr<ScDBRangeBase> pDBRef( PopDoubleRef() ); 6423 6424 if (nGlobalError || !pDBRef.get()) 6425 return NULL; 6426 6427 if ( bRangeFake ) 6428 { 6429 // range parameter must match entire database range 6430 if (pDBRef->isRangeEqual(aMissingRange)) 6431 rMissingField = sal_True; 6432 else 6433 SetError( errIllegalParameter ); 6434 } 6435 6436 if (nGlobalError) 6437 return NULL; 6438 6439 SCCOL nField = pDBRef->getFirstFieldColumn(); 6440 if (rMissingField) 6441 ; // special case 6442 else if (bByVal) 6443 nField = pDBRef->findFieldColumn(static_cast<SCCOL>(nVal)); 6444 else 6445 { 6446 sal_uInt16 nErr = 0; 6447 nField = pDBRef->findFieldColumn(aStr, &nErr); 6448 SetError(nErr); 6449 } 6450 6451 if (!ValidCol(nField)) 6452 return NULL; 6453 6454 auto_ptr<ScDBQueryParamBase> pParam( pDBRef->createQueryParam(pQueryRef.get()) ); 6455 6456 if (pParam.get()) 6457 { 6458 // An allowed missing field parameter sets the result field 6459 // to any of the query fields, just to be able to return 6460 // some cell from the iterator. 6461 if ( rMissingField ) 6462 nField = static_cast<SCCOL>(pParam->GetEntry(0).nField); 6463 pParam->mnField = nField; 6464 6465 SCSIZE nCount = pParam->GetEntryCount(); 6466 for ( SCSIZE i=0; i < nCount; i++ ) 6467 { 6468 ScQueryEntry& rEntry = pParam->GetEntry(i); 6469 if ( rEntry.bDoQuery ) 6470 { 6471 sal_uInt32 nIndex = 0; 6472 rEntry.bQueryByString = !pFormatter->IsNumberFormat( 6473 *rEntry.pStr, nIndex, rEntry.nVal ); 6474 if ( rEntry.bQueryByString && !pParam->bRegExp ) 6475 pParam->bRegExp = MayBeRegExp( *rEntry.pStr, pDok ); 6476 } 6477 else 6478 break; // for 6479 } 6480 return pParam.release(); 6481 } 6482 } 6483 return false; 6484 } 6485 6486 6487 void ScInterpreter::DBIterator( ScIterFunc eFunc ) 6488 { 6489 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::DBIterator" ); 6490 double nErg = 0.0; 6491 double fMem = 0.0; 6492 sal_Bool bNull = sal_True; 6493 sal_uLong nCount = 0; 6494 sal_Bool bMissingField = sal_False; 6495 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); 6496 if (pQueryParam.get()) 6497 { 6498 ScDBQueryDataIterator aValIter(pDok, pQueryParam.release()); 6499 ScDBQueryDataIterator::Value aValue; 6500 if ( aValIter.GetFirst(aValue) && !aValue.mnError ) 6501 { 6502 switch( eFunc ) 6503 { 6504 case ifPRODUCT: nErg = 1; break; 6505 case ifMAX: nErg = -MAXDOUBLE; break; 6506 case ifMIN: nErg = MAXDOUBLE; break; 6507 default: ; // nothing 6508 } 6509 do 6510 { 6511 nCount++; 6512 switch( eFunc ) 6513 { 6514 case ifAVERAGE: 6515 case ifSUM: 6516 if ( bNull && aValue.mfValue != 0.0 ) 6517 { 6518 bNull = sal_False; 6519 fMem = aValue.mfValue; 6520 } 6521 else 6522 nErg += aValue.mfValue; 6523 break; 6524 case ifSUMSQ: nErg += aValue.mfValue * aValue.mfValue; break; 6525 case ifPRODUCT: nErg *= aValue.mfValue; break; 6526 case ifMAX: if( aValue.mfValue > nErg ) nErg = aValue.mfValue; break; 6527 case ifMIN: if( aValue.mfValue < nErg ) nErg = aValue.mfValue; break; 6528 default: ; // nothing 6529 } 6530 } 6531 while ( aValIter.GetNext(aValue) && !aValue.mnError ); 6532 } 6533 SetError(aValue.mnError); 6534 } 6535 else 6536 SetError( errIllegalParameter); 6537 switch( eFunc ) 6538 { 6539 case ifCOUNT: nErg = nCount; break; 6540 case ifSUM: nErg = ::rtl::math::approxAdd( nErg, fMem ); break; 6541 case ifAVERAGE: nErg = ::rtl::math::approxAdd( nErg, fMem ) / nCount; break; 6542 default: ; // nothing 6543 } 6544 PushDouble( nErg ); 6545 } 6546 6547 6548 void ScInterpreter::ScDBSum() 6549 { 6550 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBSum" ); 6551 DBIterator( ifSUM ); 6552 } 6553 6554 6555 void ScInterpreter::ScDBCount() 6556 { 6557 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount" ); 6558 sal_Bool bMissingField = sal_True; 6559 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); 6560 if (pQueryParam.get()) 6561 { 6562 sal_uLong nCount = 0; 6563 if ( bMissingField && pQueryParam->GetType() == ScDBQueryParamBase::INTERNAL ) 6564 { // count all matching records 6565 // TODO: currently the QueryIterators only return cell pointers of 6566 // existing cells, so if a query matches an empty cell there's 6567 // nothing returned, and therefor not counted! 6568 // Since this has ever been the case and this code here only came 6569 // into existance to fix #i6899 and it never worked before we'll 6570 // have to live with it until we reimplement the iterators to also 6571 // return empty cells, which would mean to adapt all callers of 6572 // iterators. 6573 ScDBQueryParamInternal* p = static_cast<ScDBQueryParamInternal*>(pQueryParam.get()); 6574 SCTAB nTab = p->nTab; 6575 // ScQueryCellIterator doesn't make use of ScDBQueryParamBase::mnField, 6576 // so the source range has to be restricted, like before the introduction 6577 // of ScDBQueryParamBase. 6578 p->nCol1 = p->nCol2 = p->mnField; 6579 ScQueryCellIterator aCellIter( pDok, nTab, *p); 6580 if ( aCellIter.GetFirst() ) 6581 { 6582 do 6583 { 6584 nCount++; 6585 } while ( aCellIter.GetNext() ); 6586 } 6587 } 6588 else 6589 { // count only matching records with a value in the "result" field 6590 ScDBQueryDataIterator aValIter( pDok, pQueryParam.release()); 6591 ScDBQueryDataIterator::Value aValue; 6592 if ( aValIter.GetFirst(aValue) && !aValue.mnError ) 6593 { 6594 do 6595 { 6596 nCount++; 6597 } 6598 while ( aValIter.GetNext(aValue) && !aValue.mnError ); 6599 } 6600 SetError(aValue.mnError); 6601 } 6602 PushDouble( nCount ); 6603 } 6604 else 6605 PushIllegalParameter(); 6606 } 6607 6608 6609 void ScInterpreter::ScDBCount2() 6610 { 6611 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBCount2" ); 6612 sal_Bool bMissingField = sal_True; 6613 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); 6614 if (pQueryParam.get()) 6615 { 6616 sal_uLong nCount = 0; 6617 pQueryParam->mbSkipString = false; 6618 ScDBQueryDataIterator aValIter( pDok, pQueryParam.release()); 6619 ScDBQueryDataIterator::Value aValue; 6620 if ( aValIter.GetFirst(aValue) && !aValue.mnError ) 6621 { 6622 do 6623 { 6624 nCount++; 6625 } 6626 while ( aValIter.GetNext(aValue) && !aValue.mnError ); 6627 } 6628 SetError(aValue.mnError); 6629 PushDouble( nCount ); 6630 } 6631 else 6632 PushIllegalParameter(); 6633 } 6634 6635 6636 void ScInterpreter::ScDBAverage() 6637 { 6638 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBAverage" ); 6639 DBIterator( ifAVERAGE ); 6640 } 6641 6642 6643 void ScInterpreter::ScDBMax() 6644 { 6645 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMax" ); 6646 DBIterator( ifMAX ); 6647 } 6648 6649 6650 void ScInterpreter::ScDBMin() 6651 { 6652 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBMin" ); 6653 DBIterator( ifMIN ); 6654 } 6655 6656 6657 void ScInterpreter::ScDBProduct() 6658 { 6659 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBProduct" ); 6660 DBIterator( ifPRODUCT ); 6661 } 6662 6663 6664 void ScInterpreter::GetDBStVarParams( double& rVal, double& rValCount ) 6665 { 6666 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::GetDBStVarParams" ); 6667 std::vector<double> values; 6668 double vSum = 0.0; 6669 double vMean = 0.0; 6670 6671 rValCount = 0.0; 6672 double fSum = 0.0; 6673 sal_Bool bMissingField = sal_False; 6674 auto_ptr<ScDBQueryParamBase> pQueryParam( GetDBParams(bMissingField) ); 6675 if (pQueryParam.get()) 6676 { 6677 ScDBQueryDataIterator aValIter(pDok, pQueryParam.release()); 6678 ScDBQueryDataIterator::Value aValue; 6679 if (aValIter.GetFirst(aValue) && !aValue.mnError) 6680 { 6681 do 6682 { 6683 rValCount++; 6684 values.push_back(aValue.mfValue); 6685 fSum += aValue.mfValue; 6686 } 6687 while ((aValue.mnError == 0) && aValIter.GetNext(aValue)); 6688 } 6689 SetError(aValue.mnError); 6690 } 6691 else 6692 SetError( errIllegalParameter); 6693 6694 vMean = fSum / values.size(); 6695 6696 for (size_t i = 0; i < values.size(); i++) 6697 vSum += (values[i] - vMean) * (values[i] - vMean); 6698 6699 rVal = vSum; 6700 } 6701 6702 6703 void ScInterpreter::ScDBStdDev() 6704 { 6705 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDev" ); 6706 double fVal, fCount; 6707 GetDBStVarParams( fVal, fCount ); 6708 PushDouble( sqrt(fVal/(fCount-1))); 6709 } 6710 6711 6712 void ScInterpreter::ScDBStdDevP() 6713 { 6714 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBStdDevP" ); 6715 double fVal, fCount; 6716 GetDBStVarParams( fVal, fCount ); 6717 PushDouble( sqrt(fVal/fCount)); 6718 } 6719 6720 6721 void ScInterpreter::ScDBVar() 6722 { 6723 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVar" ); 6724 double fVal, fCount; 6725 GetDBStVarParams( fVal, fCount ); 6726 PushDouble(fVal/(fCount-1)); 6727 } 6728 6729 6730 void ScInterpreter::ScDBVarP() 6731 { 6732 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScDBVarP" ); 6733 double fVal, fCount; 6734 GetDBStVarParams( fVal, fCount ); 6735 PushDouble(fVal/fCount); 6736 } 6737 6738 6739 FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, ScDocument* pDoc, 6740 const ScAddress::ExternalInfo& rExtInfo, const ScRefAddress& rRefAd1, 6741 const ScRefAddress* pRefAd2 ) 6742 { 6743 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 6744 size_t nSheets = 1; 6745 const String* pRealTab = pRefMgr->getRealTableName( rExtInfo.mnFileId, rExtInfo.maTabName); 6746 ScTokenArray* pTokenArray = new ScTokenArray; 6747 if (pRefAd2) 6748 { 6749 ScComplexRefData aRef; 6750 aRef.InitRangeRel( ScRange( rRefAd1.GetAddress(), pRefAd2->GetAddress()), rPos); 6751 aRef.Ref1.SetColRel( rRefAd1.IsRelCol()); 6752 aRef.Ref1.SetRowRel( rRefAd1.IsRelRow()); 6753 aRef.Ref1.SetTabRel( rRefAd1.IsRelTab()); 6754 aRef.Ref1.SetFlag3D( true); 6755 aRef.Ref2.SetColRel( pRefAd2->IsRelCol()); 6756 aRef.Ref2.SetRowRel( pRefAd2->IsRelRow()); 6757 aRef.Ref2.SetTabRel( pRefAd2->IsRelTab()); 6758 nSheets = aRef.Ref2.nTab - aRef.Ref1.nTab + 1; 6759 aRef.Ref2.SetFlag3D( nSheets > 1 ); 6760 pTokenArray->AddExternalDoubleReference( rExtInfo.mnFileId, 6761 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef); 6762 } 6763 else 6764 { 6765 ScSingleRefData aRef; 6766 aRef.InitAddressRel( rRefAd1.GetAddress(), rPos); 6767 aRef.SetColRel( rRefAd1.IsRelCol()); 6768 aRef.SetRowRel( rRefAd1.IsRelRow()); 6769 aRef.SetTabRel( rRefAd1.IsRelTab()); 6770 aRef.SetFlag3D( true); 6771 pTokenArray->AddExternalSingleReference( rExtInfo.mnFileId, 6772 (pRealTab ? *pRealTab : rExtInfo.maTabName), aRef); 6773 } 6774 // The indirect usage of the external table can't be detected during the 6775 // store-to-file cycle, mark it as permanently referenced so it gets stored 6776 // even if not directly referenced anywhere. 6777 pRefMgr->setCacheTableReferencedPermanently( rExtInfo.mnFileId, 6778 rExtInfo.maTabName, nSheets); 6779 ScCompiler aComp( pDoc, rPos, *pTokenArray); 6780 aComp.CompileTokenArray(); 6781 return new FormulaSubroutineToken( pTokenArray); 6782 } 6783 6784 6785 void ScInterpreter::ScIndirect() 6786 { 6787 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndirect" ); 6788 sal_uInt8 nParamCount = GetByte(); 6789 if ( MustHaveParamCount( nParamCount, 1, 2 ) ) 6790 { 6791 bool bTryXlA1 = true; // whether to try XL_A1 style as well. 6792 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO; 6793 if (nParamCount == 2 && 0.0 == ::rtl::math::approxFloor( GetDouble())) 6794 { 6795 eConv = FormulaGrammar::CONV_XL_R1C1; 6796 bTryXlA1 = false; 6797 } 6798 const ScAddress::Details aDetails( eConv, aPos ); 6799 const ScAddress::Details aDetailsXlA1( FormulaGrammar::CONV_XL_A1, aPos ); 6800 SCTAB nTab = aPos.Tab(); 6801 String sRefStr( GetString() ); 6802 ScRefAddress aRefAd, aRefAd2; 6803 ScAddress::ExternalInfo aExtInfo; 6804 if ( ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, aRefAd2, aDetails, &aExtInfo) || 6805 (bTryXlA1 && ConvertDoubleRef( pDok, sRefStr, nTab, aRefAd, 6806 aRefAd2, aDetailsXlA1, &aExtInfo))) 6807 { 6808 if (aExtInfo.mbExternal) 6809 { 6810 // Push a subroutine that resolves the external reference as 6811 // the next instruction. 6812 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, 6813 aExtInfo, aRefAd, &aRefAd2)); 6814 } 6815 else 6816 PushDoubleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab(), 6817 aRefAd2.Col(), aRefAd2.Row(), aRefAd2.Tab() ); 6818 } 6819 else if ( ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, aDetails, &aExtInfo) || 6820 (bTryXlA1 && ConvertSingleRef ( pDok, sRefStr, nTab, aRefAd, 6821 aDetailsXlA1, &aExtInfo))) 6822 { 6823 if (aExtInfo.mbExternal) 6824 { 6825 // Push a subroutine that resolves the external reference as 6826 // the next instruction. 6827 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, 6828 aExtInfo, aRefAd, NULL)); 6829 } 6830 else 6831 PushSingleRef( aRefAd.Col(), aRefAd.Row(), aRefAd.Tab() ); 6832 } 6833 else 6834 { 6835 do 6836 { 6837 ScRangeName* pNames = pDok->GetRangeName(); 6838 if (!pNames) 6839 break; 6840 6841 sal_uInt16 nPos = 0; 6842 if (!pNames->SearchName( sRefStr, nPos)) 6843 break; 6844 6845 ScRangeData* rData = (*pNames)[nPos]; 6846 if (!rData) 6847 break; 6848 6849 // We need this in order to obtain a good range. 6850 rData->ValidateTabRefs(); 6851 6852 ScRange aRange; 6853 #if 0 6854 // This is some really odd Excel behavior and renders named 6855 // ranges containing relative references totally useless. 6856 if (!rData->IsReference(aRange, ScAddress( aPos.Tab(), 0, 0))) 6857 break; 6858 #else 6859 // This is the usual way to treat named ranges containing 6860 // relative references. 6861 if (!rData->IsReference( aRange, aPos)) 6862 break; 6863 #endif 6864 6865 if (aRange.aStart == aRange.aEnd) 6866 PushSingleRef( aRange.aStart.Col(), aRange.aStart.Row(), 6867 aRange.aStart.Tab()); 6868 else 6869 PushDoubleRef( aRange.aStart.Col(), aRange.aStart.Row(), 6870 aRange.aStart.Tab(), aRange.aEnd.Col(), 6871 aRange.aEnd.Row(), aRange.aEnd.Tab()); 6872 6873 // success! 6874 return; 6875 } 6876 while (false); 6877 6878 PushIllegalArgument(); 6879 } 6880 } 6881 } 6882 6883 6884 void ScInterpreter::ScAddressFunc() 6885 { 6886 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAddressFunc" ); 6887 String sTabStr; 6888 6889 sal_uInt8 nParamCount = GetByte(); 6890 if( !MustHaveParamCount( nParamCount, 2, 5 ) ) 6891 return; 6892 6893 if( nParamCount >= 5 ) 6894 sTabStr = GetString(); 6895 6896 FormulaGrammar::AddressConvention eConv = FormulaGrammar::CONV_OOO; // default 6897 if( nParamCount >= 4 && 0.0 == ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0))) 6898 eConv = FormulaGrammar::CONV_XL_R1C1; 6899 6900 sal_uInt16 nFlags = SCA_COL_ABSOLUTE | SCA_ROW_ABSOLUTE; // default 6901 if( nParamCount >= 3 ) 6902 { 6903 sal_uInt16 n = (sal_uInt16) ::rtl::math::approxFloor( GetDoubleWithDefault( 1.0)); 6904 switch ( n ) 6905 { 6906 default : 6907 PushNoValue(); 6908 return; 6909 6910 case 5: 6911 case 1 : break; // default 6912 case 6: 6913 case 2 : nFlags = SCA_ROW_ABSOLUTE; break; 6914 case 7: 6915 case 3 : nFlags = SCA_COL_ABSOLUTE; break; 6916 case 8: 6917 case 4 : nFlags = 0; break; // both relative 6918 } 6919 } 6920 nFlags |= SCA_VALID | SCA_VALID_ROW | SCA_VALID_COL; 6921 6922 SCCOL nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble()); 6923 SCROW nRow = (SCROW) ::rtl::math::approxFloor(GetDouble()); 6924 if( eConv == FormulaGrammar::CONV_XL_R1C1 ) 6925 { 6926 // YUCK! The XL interface actually treats rel R1C1 refs differently 6927 // than A1 6928 if( !(nFlags & SCA_COL_ABSOLUTE) ) 6929 nCol += aPos.Col() + 1; 6930 if( !(nFlags & SCA_ROW_ABSOLUTE) ) 6931 nRow += aPos.Row() + 1; 6932 } 6933 6934 --nCol; 6935 --nRow; 6936 if(!ValidCol( nCol) || !ValidRow( nRow)) 6937 { 6938 PushIllegalArgument(); 6939 return; 6940 } 6941 6942 String aRefStr; 6943 const ScAddress::Details aDetails( eConv, aPos ); 6944 const ScAddress aAdr( nCol, nRow, 0); 6945 aAdr.Format( aRefStr, nFlags, pDok, aDetails ); 6946 6947 if( nParamCount >= 5 && sTabStr.Len() ) 6948 { 6949 String aDoc; 6950 if (eConv == FormulaGrammar::CONV_OOO) 6951 { 6952 // Isolate Tab from 'Doc'#Tab 6953 xub_StrLen nPos = ScCompiler::GetDocTabPos( sTabStr); 6954 if (nPos != STRING_NOTFOUND) 6955 { 6956 if (sTabStr.GetChar(nPos+1) == '$') 6957 ++nPos; // also split 'Doc'#$Tab 6958 aDoc = sTabStr.Copy( 0, nPos+1); 6959 sTabStr.Erase( 0, nPos+1); 6960 } 6961 } 6962 /* TODO: yet unsupported external reference in CONV_XL_R1C1 syntax may 6963 * need some extra handling to isolate Tab from Doc. */ 6964 if (sTabStr.GetChar(0) != '\'' || sTabStr.GetChar(sTabStr.Len()-1) != '\'') 6965 ScCompiler::CheckTabQuotes( sTabStr, eConv); 6966 if (aDoc.Len()) 6967 sTabStr.Insert( aDoc, 0); 6968 sTabStr += static_cast<sal_Unicode>(eConv == FormulaGrammar::CONV_XL_R1C1 ? '!' : '.'); 6969 sTabStr += aRefStr; 6970 PushString( sTabStr ); 6971 } 6972 else 6973 PushString( aRefStr ); 6974 } 6975 6976 6977 FormulaSubroutineToken* lcl_CreateExternalRefSubroutine( const ScAddress& rPos, 6978 ScDocument* pDoc, const FormulaTokenRef& xExtRef ) 6979 { 6980 // The exact usage (which cell range) of the external table can't be 6981 // detected during the store-to-file cycle, mark it as permanently 6982 // referenced so it gets stored even if not directly referenced anywhere. 6983 ScExternalRefManager* pRefMgr = pDoc->GetExternalRefManager(); 6984 pRefMgr->setCacheTableReferencedPermanently( 6985 static_cast<const ScToken*>(xExtRef.get())->GetIndex(), 6986 static_cast<const ScToken*>(xExtRef.get())->GetString(), 1); 6987 ScTokenArray* pTokenArray = new ScTokenArray; 6988 pTokenArray->AddToken( *xExtRef); 6989 ScCompiler aComp( pDoc, rPos, *pTokenArray); 6990 aComp.CompileTokenArray(); 6991 return new FormulaSubroutineToken( pTokenArray); 6992 } 6993 6994 6995 void ScInterpreter::ScOffset() 6996 { 6997 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScOffset" ); 6998 sal_uInt8 nParamCount = GetByte(); 6999 if ( MustHaveParamCount( nParamCount, 3, 5 ) ) 7000 { 7001 long nColNew = -1, nRowNew = -1, nColPlus, nRowPlus; 7002 if (nParamCount == 5) 7003 nColNew = (long) ::rtl::math::approxFloor(GetDouble()); 7004 if (nParamCount >= 4) 7005 nRowNew = (long) ::rtl::math::approxFloor(GetDoubleWithDefault( -1.0 )); 7006 nColPlus = (long) ::rtl::math::approxFloor(GetDouble()); 7007 nRowPlus = (long) ::rtl::math::approxFloor(GetDouble()); 7008 SCCOL nCol1; 7009 SCROW nRow1; 7010 SCTAB nTab1; 7011 SCCOL nCol2; 7012 SCROW nRow2; 7013 SCTAB nTab2; 7014 if (nColNew == 0 || nRowNew == 0) 7015 { 7016 PushIllegalArgument(); 7017 return; 7018 } 7019 FormulaTokenRef xExtRef; 7020 switch (GetStackType()) 7021 { 7022 case svExternalSingleRef: 7023 xExtRef = PopToken()->Clone(); 7024 // fallthru 7025 case svSingleRef: 7026 { 7027 if (xExtRef) 7028 { 7029 ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef(); 7030 rData.CalcAbsIfRel( aPos); 7031 nCol1 = rData.nCol; 7032 nRow1 = rData.nRow; 7033 nTab1 = rData.nTab; 7034 } 7035 else 7036 PopSingleRef( nCol1, nRow1, nTab1); 7037 if (nParamCount == 3 || (nColNew < 0 && nRowNew < 0)) 7038 { 7039 nCol1 = (SCCOL)((long) nCol1 + nColPlus); 7040 nRow1 = (SCROW)((long) nRow1 + nRowPlus); 7041 if (!ValidCol(nCol1) || !ValidRow(nRow1)) 7042 PushIllegalArgument(); 7043 else if (xExtRef) 7044 { 7045 ScSingleRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetSingleRef(); 7046 rData.nCol = nCol1; 7047 rData.nRow = nRow1; 7048 rData.nTab = nTab1; 7049 rData.CalcRelFromAbs( aPos); 7050 // Push a subroutine that resolves the external 7051 // reference as the next instruction. 7052 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); 7053 } 7054 else 7055 PushSingleRef(nCol1, nRow1, nTab1); 7056 } 7057 else 7058 { 7059 if (nColNew < 0) 7060 nColNew = 1; 7061 if (nRowNew < 0) 7062 nRowNew = 1; 7063 nCol1 = (SCCOL)((long)nCol1+nColPlus); // ! nCol1 is modified 7064 nRow1 = (SCROW)((long)nRow1+nRowPlus); 7065 nCol2 = (SCCOL)((long)nCol1+nColNew-1); 7066 nRow2 = (SCROW)((long)nRow1+nRowNew-1); 7067 if (!ValidCol(nCol1) || !ValidRow(nRow1) || 7068 !ValidCol(nCol2) || !ValidRow(nRow2)) 7069 PushIllegalArgument(); 7070 else if (xExtRef) 7071 { 7072 // Convert SingleRef to DoubleRef. 7073 xExtRef = new ScExternalDoubleRefToken( 7074 *static_cast<const ScExternalSingleRefToken*>(xExtRef.get())); 7075 ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); 7076 rData.Ref1.nCol = nCol1; 7077 rData.Ref1.nRow = nRow1; 7078 rData.Ref1.nTab = nTab1; 7079 rData.Ref2.nCol = nCol2; 7080 rData.Ref2.nRow = nRow2; 7081 rData.Ref2.nTab = nTab1; 7082 rData.CalcRelFromAbs( aPos); 7083 // Push a subroutine that resolves the external 7084 // reference as the next instruction. 7085 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); 7086 } 7087 else 7088 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); 7089 } 7090 } 7091 break; 7092 case svExternalDoubleRef: 7093 xExtRef = PopToken()->Clone(); 7094 // fallthru 7095 case svDoubleRef: 7096 { 7097 if (xExtRef) 7098 { 7099 ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); 7100 rData.CalcAbsIfRel( aPos); 7101 nCol1 = rData.Ref1.nCol; 7102 nRow1 = rData.Ref1.nRow; 7103 nTab1 = rData.Ref1.nTab; 7104 nCol2 = rData.Ref2.nCol; 7105 nRow2 = rData.Ref2.nRow; 7106 nTab2 = rData.Ref2.nTab; 7107 } 7108 else 7109 PopDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 7110 if (nColNew < 0) 7111 nColNew = nCol2 - nCol1 + 1; 7112 if (nRowNew < 0) 7113 nRowNew = nRow2 - nRow1 + 1; 7114 nCol1 = (SCCOL)((long)nCol1+nColPlus); 7115 nRow1 = (SCROW)((long)nRow1+nRowPlus); 7116 nCol2 = (SCCOL)((long)nCol1+nColNew-1); 7117 nRow2 = (SCROW)((long)nRow1+nRowNew-1); 7118 if (!ValidCol(nCol1) || !ValidRow(nRow1) || 7119 !ValidCol(nCol2) || !ValidRow(nRow2) || nTab1 != nTab2) 7120 PushIllegalArgument(); 7121 else if (xExtRef) 7122 { 7123 ScComplexRefData& rData = static_cast<ScToken*>(xExtRef.get())->GetDoubleRef(); 7124 rData.Ref1.nCol = nCol1; 7125 rData.Ref1.nRow = nRow1; 7126 rData.Ref1.nTab = nTab1; 7127 rData.Ref2.nCol = nCol2; 7128 rData.Ref2.nRow = nRow2; 7129 rData.Ref2.nTab = nTab1; 7130 rData.CalcRelFromAbs( aPos); 7131 // Push a subroutine that resolves the external 7132 // reference as the next instruction. 7133 PushTempToken( lcl_CreateExternalRefSubroutine( aPos, pDok, xExtRef)); 7134 } 7135 else 7136 PushDoubleRef(nCol1, nRow1, nTab1, nCol2, nRow2, nTab1); 7137 } 7138 break; 7139 default: 7140 PushIllegalParameter(); 7141 } 7142 } 7143 } 7144 7145 7146 void ScInterpreter::ScIndex() 7147 { 7148 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScIndex" ); 7149 sal_uInt8 nParamCount = GetByte(); 7150 if ( MustHaveParamCount( nParamCount, 1, 4 ) ) 7151 { 7152 long nArea; 7153 size_t nAreaCount; 7154 SCCOL nCol; 7155 SCROW nRow; 7156 if (nParamCount == 4) 7157 nArea = (long) ::rtl::math::approxFloor(GetDouble()); 7158 else 7159 nArea = 1; 7160 if (nParamCount >= 3) 7161 nCol = (SCCOL) ::rtl::math::approxFloor(GetDouble()); 7162 else 7163 nCol = 0; 7164 if (nParamCount >= 2) 7165 nRow = (SCROW) ::rtl::math::approxFloor(GetDouble()); 7166 else 7167 nRow = 0; 7168 if (GetStackType() == svRefList) 7169 nAreaCount = (sp ? static_cast<ScToken*>(pStack[sp-1])->GetRefList()->size() : 0); 7170 else 7171 nAreaCount = 1; // one reference or array or whatever 7172 if (nAreaCount == 0 || (size_t)nArea > nAreaCount) 7173 { 7174 PushError( errNoRef); 7175 return; 7176 } 7177 else if (nArea < 1 || nCol < 0 || nRow < 0) 7178 { 7179 PushIllegalArgument(); 7180 return; 7181 } 7182 switch (GetStackType()) 7183 { 7184 case svMatrix: 7185 { 7186 if (nArea != 1) 7187 SetError(errIllegalArgument); 7188 sal_uInt16 nOldSp = sp; 7189 ScMatrixRef pMat = GetMatrix(); 7190 if (pMat) 7191 { 7192 SCSIZE nC, nR; 7193 pMat->GetDimensions(nC, nR); 7194 // Access one element of a vector independent of col/row 7195 // orientation? 7196 bool bVector = ((nCol == 0 || nRow == 0) && (nC == 1 || nR == 1)); 7197 SCSIZE nElement = ::std::max( static_cast<SCSIZE>(nCol), 7198 static_cast<SCSIZE>(nRow)); 7199 if (nC == 0 || nR == 0 || 7200 (!bVector && (static_cast<SCSIZE>(nCol) > nC || 7201 static_cast<SCSIZE>(nRow) > nR)) || 7202 (bVector && nElement > nC * nR)) 7203 PushIllegalArgument(); 7204 else if (nCol == 0 && nRow == 0) 7205 sp = nOldSp; 7206 else if (bVector) 7207 { 7208 --nElement; 7209 if (pMat->IsString( nElement)) 7210 PushString( pMat->GetString( nElement)); 7211 else 7212 PushDouble( pMat->GetDouble( nElement)); 7213 } 7214 else if (nCol == 0) 7215 { 7216 ScMatrixRef pResMat = GetNewMat(nC, 1); 7217 if (pResMat) 7218 { 7219 SCSIZE nRowMinus1 = static_cast<SCSIZE>(nRow - 1); 7220 for (SCSIZE i = 0; i < nC; i++) 7221 if (!pMat->IsString(i, nRowMinus1)) 7222 pResMat->PutDouble(pMat->GetDouble(i, 7223 nRowMinus1), i, 0); 7224 else 7225 pResMat->PutString(pMat->GetString(i, 7226 nRowMinus1), i, 0); 7227 PushMatrix(pResMat); 7228 } 7229 else 7230 PushIllegalArgument(); 7231 } 7232 else if (nRow == 0) 7233 { 7234 ScMatrixRef pResMat = GetNewMat(1, nR); 7235 if (pResMat) 7236 { 7237 SCSIZE nColMinus1 = static_cast<SCSIZE>(nCol - 1); 7238 for (SCSIZE i = 0; i < nR; i++) 7239 if (!pMat->IsString(nColMinus1, i)) 7240 pResMat->PutDouble(pMat->GetDouble(nColMinus1, 7241 i), i); 7242 else 7243 pResMat->PutString(pMat->GetString(nColMinus1, 7244 i), i); 7245 PushMatrix(pResMat); 7246 } 7247 else 7248 PushIllegalArgument(); 7249 } 7250 else 7251 { 7252 if (!pMat->IsString( static_cast<SCSIZE>(nCol-1), 7253 static_cast<SCSIZE>(nRow-1))) 7254 PushDouble( pMat->GetDouble( 7255 static_cast<SCSIZE>(nCol-1), 7256 static_cast<SCSIZE>(nRow-1))); 7257 else 7258 PushString( pMat->GetString( 7259 static_cast<SCSIZE>(nCol-1), 7260 static_cast<SCSIZE>(nRow-1))); 7261 } 7262 } 7263 } 7264 break; 7265 case svSingleRef: 7266 { 7267 SCCOL nCol1 = 0; 7268 SCROW nRow1 = 0; 7269 SCTAB nTab1 = 0; 7270 PopSingleRef( nCol1, nRow1, nTab1); 7271 if (nCol > 1 || nRow > 1) 7272 PushIllegalArgument(); 7273 else 7274 PushSingleRef( nCol1, nRow1, nTab1); 7275 } 7276 break; 7277 case svDoubleRef: 7278 case svRefList: 7279 { 7280 SCCOL nCol1 = 0; 7281 SCROW nRow1 = 0; 7282 SCTAB nTab1 = 0; 7283 SCCOL nCol2 = 0; 7284 SCROW nRow2 = 0; 7285 SCTAB nTab2 = 0; 7286 sal_Bool bRowArray = sal_False; 7287 if (GetStackType() == svRefList) 7288 { 7289 FormulaTokenRef xRef = PopToken(); 7290 if (nGlobalError || !xRef) 7291 { 7292 PushIllegalParameter(); 7293 return; 7294 } 7295 ScRange aRange( ScAddress::UNINITIALIZED); 7296 DoubleRefToRange( (*(static_cast<ScToken*>(xRef.get())->GetRefList()))[nArea-1], aRange); 7297 aRange.GetVars( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 7298 if ( nParamCount == 2 && nRow1 == nRow2 ) 7299 bRowArray = sal_True; 7300 } 7301 else 7302 { 7303 PopDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab2); 7304 if ( nParamCount == 2 && nRow1 == nRow2 ) 7305 bRowArray = sal_True; 7306 } 7307 if ( nTab1 != nTab2 || 7308 (nCol > 0 && nCol1+nCol-1 > nCol2) || 7309 (nRow > 0 && nRow1+nRow-1 > nRow2 && !bRowArray ) || 7310 ( nRow > nCol2 - nCol1 + 1 && bRowArray )) 7311 PushIllegalArgument(); 7312 else if (nCol == 0 && nRow == 0) 7313 { 7314 if ( nCol1 == nCol2 && nRow1 == nRow2 ) 7315 PushSingleRef( nCol1, nRow1, nTab1 ); 7316 else 7317 PushDoubleRef( nCol1, nRow1, nTab1, nCol2, nRow2, nTab1 ); 7318 } 7319 else if (nRow == 0) 7320 { 7321 if ( nRow1 == nRow2 ) 7322 PushSingleRef( nCol1+nCol-1, nRow1, nTab1 ); 7323 else 7324 PushDoubleRef( nCol1+nCol-1, nRow1, nTab1, 7325 nCol1+nCol-1, nRow2, nTab1 ); 7326 } 7327 else if (nCol == 0) 7328 { 7329 if ( nCol1 == nCol2 ) 7330 PushSingleRef( nCol1, nRow1+nRow-1, nTab1 ); 7331 else if ( bRowArray ) 7332 { 7333 nCol =(SCCOL) nRow; 7334 nRow = 1; 7335 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1); 7336 } 7337 else 7338 PushDoubleRef( nCol1, nRow1+nRow-1, nTab1, 7339 nCol2, nRow1+nRow-1, nTab1); 7340 } 7341 else 7342 PushSingleRef( nCol1+nCol-1, nRow1+nRow-1, nTab1); 7343 } 7344 break; 7345 default: 7346 PushIllegalParameter(); 7347 } 7348 } 7349 } 7350 7351 7352 void ScInterpreter::ScMultiArea() 7353 { 7354 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMultiArea" ); 7355 // Legacy support, convert to RefList 7356 sal_uInt8 nParamCount = GetByte(); 7357 if (MustHaveParamCountMin( nParamCount, 1)) 7358 { 7359 while (!nGlobalError && nParamCount-- > 1) 7360 { 7361 ScUnionFunc(); 7362 } 7363 } 7364 } 7365 7366 7367 void ScInterpreter::ScAreas() 7368 { 7369 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScAreas" ); 7370 sal_uInt8 nParamCount = GetByte(); 7371 if (MustHaveParamCount( nParamCount, 1)) 7372 { 7373 size_t nCount = 0; 7374 switch (GetStackType()) 7375 { 7376 case svSingleRef: 7377 { 7378 FormulaTokenRef xT = PopToken(); 7379 ValidateRef( static_cast<ScToken*>(xT.get())->GetSingleRef()); 7380 ++nCount; 7381 } 7382 break; 7383 case svDoubleRef: 7384 { 7385 FormulaTokenRef xT = PopToken(); 7386 ValidateRef( static_cast<ScToken*>(xT.get())->GetDoubleRef()); 7387 ++nCount; 7388 } 7389 break; 7390 case svRefList: 7391 { 7392 FormulaTokenRef xT = PopToken(); 7393 ValidateRef( *(static_cast<ScToken*>(xT.get())->GetRefList())); 7394 nCount += static_cast<ScToken*>(xT.get())->GetRefList()->size(); 7395 } 7396 break; 7397 default: 7398 SetError( errIllegalParameter); 7399 } 7400 PushDouble( double(nCount)); 7401 } 7402 } 7403 7404 7405 void ScInterpreter::ScCurrency() 7406 { 7407 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScCurrency" ); 7408 sal_uInt8 nParamCount = GetByte(); 7409 if ( MustHaveParamCount( nParamCount, 1, 2 ) ) 7410 { 7411 String aStr; 7412 double fDec; 7413 if (nParamCount == 2) 7414 { 7415 fDec = ::rtl::math::approxFloor(GetDouble()); 7416 if (fDec < -15.0 || fDec > 15.0) 7417 { 7418 PushIllegalArgument(); 7419 return; 7420 } 7421 } 7422 else 7423 fDec = 2.0; 7424 double fVal = GetDouble(); 7425 double fFac; 7426 if ( fDec != 0.0 ) 7427 fFac = pow( (double)10, fDec ); 7428 else 7429 fFac = 1.0; 7430 if (fVal < 0.0) 7431 fVal = ceil(fVal*fFac-0.5)/fFac; 7432 else 7433 fVal = floor(fVal*fFac+0.5)/fFac; 7434 Color* pColor = NULL; 7435 if ( fDec < 0.0 ) 7436 fDec = 0.0; 7437 sal_uLong nIndex = pFormatter->GetStandardFormat( 7438 NUMBERFORMAT_CURRENCY, 7439 ScGlobal::eLnge); 7440 if ( (sal_uInt16) fDec != pFormatter->GetFormatPrecision( nIndex ) ) 7441 { 7442 String sFormatString; 7443 pFormatter->GenerateFormat(sFormatString, 7444 nIndex, 7445 ScGlobal::eLnge, 7446 sal_True, // mit Tausenderpunkt 7447 sal_False, // nicht rot 7448 (sal_uInt16) fDec,// Nachkommastellen 7449 1); // 1 Vorkommanull 7450 if (!pFormatter->GetPreviewString(sFormatString, 7451 fVal, 7452 aStr, 7453 &pColor, 7454 ScGlobal::eLnge)) 7455 SetError(errIllegalArgument); 7456 } 7457 else 7458 { 7459 pFormatter->GetOutputString(fVal, nIndex, aStr, &pColor); 7460 } 7461 PushString(aStr); 7462 } 7463 } 7464 7465 7466 void ScInterpreter::ScReplace() 7467 { 7468 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScReplace" ); 7469 if ( MustHaveParamCount( GetByte(), 4 ) ) 7470 { 7471 String aNewStr( GetString() ); 7472 double fCount = ::rtl::math::approxFloor( GetDouble()); 7473 double fPos = ::rtl::math::approxFloor( GetDouble()); 7474 String aOldStr( GetString() ); 7475 if (fPos < 1.0 || fPos > static_cast<double>(STRING_MAXLEN) 7476 || fCount < 0.0 || fCount > static_cast<double>(STRING_MAXLEN)) 7477 PushIllegalArgument(); 7478 else 7479 { 7480 xub_StrLen nCount = static_cast<xub_StrLen>(fCount); 7481 xub_StrLen nPos = static_cast<xub_StrLen>(fPos); 7482 xub_StrLen nLen = aOldStr.Len(); 7483 if (nPos > nLen + 1) 7484 nPos = nLen + 1; 7485 if (nCount > nLen - nPos + 1) 7486 nCount = nLen - nPos + 1; 7487 aOldStr.Erase( nPos-1, nCount ); 7488 if ( CheckStringResultLen( aOldStr, aNewStr ) ) 7489 aOldStr.Insert( aNewStr, nPos-1 ); 7490 PushString( aOldStr ); 7491 } 7492 } 7493 } 7494 7495 7496 void ScInterpreter::ScFixed() 7497 { 7498 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFixed" ); 7499 sal_uInt8 nParamCount = GetByte(); 7500 if ( MustHaveParamCount( nParamCount, 1, 3 ) ) 7501 { 7502 String aStr; 7503 double fDec; 7504 sal_Bool bThousand; 7505 if (nParamCount == 3) 7506 bThousand = !GetBool(); // Param TRUE: keine Tausenderpunkte 7507 else 7508 bThousand = sal_True; 7509 if (nParamCount >= 2) 7510 { 7511 fDec = ::rtl::math::approxFloor(GetDoubleWithDefault( 2.0 )); 7512 if (fDec < -15.0 || fDec > 15.0) 7513 { 7514 PushIllegalArgument(); 7515 return; 7516 } 7517 } 7518 else 7519 fDec = 2.0; 7520 double fVal = GetDouble(); 7521 double fFac; 7522 if ( fDec != 0.0 ) 7523 fFac = pow( (double)10, fDec ); 7524 else 7525 fFac = 1.0; 7526 if (fVal < 0.0) 7527 fVal = ceil(fVal*fFac-0.5)/fFac; 7528 else 7529 fVal = floor(fVal*fFac+0.5)/fFac; 7530 Color* pColor = NULL; 7531 String sFormatString; 7532 if (fDec < 0.0) 7533 fDec = 0.0; 7534 sal_uLong nIndex = pFormatter->GetStandardFormat( 7535 NUMBERFORMAT_NUMBER, 7536 ScGlobal::eLnge); 7537 pFormatter->GenerateFormat(sFormatString, 7538 nIndex, 7539 ScGlobal::eLnge, 7540 bThousand, // mit Tausenderpunkt 7541 sal_False, // nicht rot 7542 (sal_uInt16) fDec,// Nachkommastellen 7543 1); // 1 Vorkommanull 7544 if (!pFormatter->GetPreviewString(sFormatString, 7545 fVal, 7546 aStr, 7547 &pColor, 7548 ScGlobal::eLnge)) 7549 PushIllegalArgument(); 7550 else 7551 PushString(aStr); 7552 } 7553 } 7554 7555 7556 void ScInterpreter::ScFind() 7557 { 7558 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScFind" ); 7559 sal_uInt8 nParamCount = GetByte(); 7560 if ( MustHaveParamCount( nParamCount, 2, 3 ) ) 7561 { 7562 double fAnz; 7563 if (nParamCount == 3) 7564 fAnz = GetDouble(); 7565 else 7566 fAnz = 1.0; 7567 String sStr = GetString(); 7568 if( fAnz < 1.0 || fAnz > (double) sStr.Len() ) 7569 PushNoValue(); 7570 else 7571 { 7572 xub_StrLen nPos = sStr.Search( GetString(), (xub_StrLen) fAnz - 1 ); 7573 if (nPos == STRING_NOTFOUND) 7574 PushNoValue(); 7575 else 7576 PushDouble((double)(nPos + 1)); 7577 } 7578 } 7579 } 7580 7581 7582 void ScInterpreter::ScExact() 7583 { 7584 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScExact" ); 7585 nFuncFmtType = NUMBERFORMAT_LOGICAL; 7586 if ( MustHaveParamCount( GetByte(), 2 ) ) 7587 { 7588 String s1( GetString() ); 7589 String s2( GetString() ); 7590 PushInt( s1 == s2 ); 7591 } 7592 } 7593 7594 7595 void ScInterpreter::ScLeft() 7596 { 7597 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScLeft" ); 7598 sal_uInt8 nParamCount = GetByte(); 7599 if ( MustHaveParamCount( nParamCount, 1, 2 ) ) 7600 { 7601 xub_StrLen n; 7602 if (nParamCount == 2) 7603 { 7604 double nVal = ::rtl::math::approxFloor(GetDouble()); 7605 if ( nVal < 0.0 || nVal > STRING_MAXLEN ) 7606 { 7607 PushIllegalArgument(); 7608 return ; 7609 } 7610 else 7611 n = (xub_StrLen) nVal; 7612 } 7613 else 7614 n = 1; 7615 String aStr( GetString() ); 7616 aStr.Erase( n ); 7617 PushString( aStr ); 7618 } 7619 } 7620 7621 7622 void ScInterpreter::ScRight() 7623 { 7624 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRight" ); 7625 sal_uInt8 nParamCount = GetByte(); 7626 if ( MustHaveParamCount( nParamCount, 1, 2 ) ) 7627 { 7628 xub_StrLen n; 7629 if (nParamCount == 2) 7630 { 7631 double nVal = ::rtl::math::approxFloor(GetDouble()); 7632 if ( nVal < 0.0 || nVal > STRING_MAXLEN ) 7633 { 7634 PushIllegalArgument(); 7635 return ; 7636 } 7637 else 7638 n = (xub_StrLen) nVal; 7639 } 7640 else 7641 n = 1; 7642 String aStr( GetString() ); 7643 if( n < aStr.Len() ) 7644 aStr.Erase( 0, aStr.Len() - n ); 7645 PushString( aStr ); 7646 } 7647 } 7648 7649 7650 void ScInterpreter::ScSearch() 7651 { 7652 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSearch" ); 7653 double fAnz; 7654 sal_uInt8 nParamCount = GetByte(); 7655 if ( MustHaveParamCount( nParamCount, 2, 3 ) ) 7656 { 7657 if (nParamCount == 3) 7658 { 7659 fAnz = ::rtl::math::approxFloor(GetDouble()); 7660 if (fAnz > double(STRING_MAXLEN)) 7661 { 7662 PushIllegalArgument(); 7663 return; 7664 } 7665 } 7666 else 7667 fAnz = 1.0; 7668 String sStr = GetString(); 7669 String SearchStr = GetString(); 7670 xub_StrLen nPos = (xub_StrLen) fAnz - 1; 7671 xub_StrLen nEndPos = sStr.Len(); 7672 if( nPos >= nEndPos ) 7673 PushNoValue(); 7674 else 7675 { 7676 utl::SearchParam::SearchType eSearchType = 7677 (MayBeRegExp( SearchStr, pDok ) ? 7678 utl::SearchParam::SRCH_REGEXP : utl::SearchParam::SRCH_NORMAL); 7679 utl::SearchParam sPar(SearchStr, eSearchType, sal_False, sal_False, sal_False); 7680 utl::TextSearch sT( sPar, *ScGlobal::pCharClass ); 7681 int nBool = sT.SearchFrwrd(sStr, &nPos, &nEndPos); 7682 if (!nBool) 7683 PushNoValue(); 7684 else 7685 PushDouble((double)(nPos) + 1); 7686 } 7687 } 7688 } 7689 7690 7691 void ScInterpreter::ScMid() 7692 { 7693 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScMid" ); 7694 if ( MustHaveParamCount( GetByte(), 3 ) ) 7695 { 7696 double fAnz = ::rtl::math::approxFloor(GetDouble()); 7697 double fAnfang = ::rtl::math::approxFloor(GetDouble()); 7698 const String& rStr = GetString(); 7699 if (fAnfang < 1.0 || fAnz < 0.0 || fAnfang > double(STRING_MAXLEN) || fAnz > double(STRING_MAXLEN)) 7700 PushIllegalArgument(); 7701 else 7702 PushString(rStr.Copy( (xub_StrLen) fAnfang - 1, (xub_StrLen) fAnz )); 7703 } 7704 } 7705 7706 7707 void ScInterpreter::ScText() 7708 { 7709 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScText" ); 7710 if ( MustHaveParamCount( GetByte(), 2 ) ) 7711 { 7712 String sFormatString = GetString(); 7713 String aStr; 7714 bool bString = false; 7715 double fVal = 0.0; 7716 switch (GetStackType()) 7717 { 7718 case svError: 7719 PopError(); 7720 break; 7721 case svDouble: 7722 fVal = PopDouble(); 7723 break; 7724 default: 7725 { 7726 FormulaTokenRef xTok( PopToken()); 7727 if (!nGlobalError) 7728 { 7729 PushTempToken( xTok); 7730 // Temporarily override the ConvertStringToValue() 7731 // error for GetCellValue() / GetCellValueOrZero() 7732 sal_uInt16 nSErr = mnStringNoValueError; 7733 mnStringNoValueError = errNotNumericString; 7734 fVal = GetDouble(); 7735 mnStringNoValueError = nSErr; 7736 if (nGlobalError == errNotNumericString) 7737 { 7738 // Not numeric. 7739 nGlobalError = 0; 7740 PushTempToken( xTok); 7741 aStr = GetString(); 7742 bString = true; 7743 } 7744 } 7745 } 7746 } 7747 if (nGlobalError) 7748 PushError( nGlobalError); 7749 else 7750 { 7751 String aResult; 7752 Color* pColor = NULL; 7753 LanguageType eCellLang; 7754 const ScPatternAttr* pPattern = pDok->GetPattern( 7755 aPos.Col(), aPos.Row(), aPos.Tab() ); 7756 if ( pPattern ) 7757 eCellLang = ((const SvxLanguageItem&) 7758 pPattern->GetItem( ATTR_LANGUAGE_FORMAT )).GetValue(); 7759 else 7760 eCellLang = ScGlobal::eLnge; 7761 if (bString) 7762 { 7763 if (!pFormatter->GetPreviewString( sFormatString, aStr, 7764 aResult, &pColor, eCellLang)) 7765 PushIllegalArgument(); 7766 else 7767 PushString( aResult); 7768 } 7769 else 7770 { 7771 if (!pFormatter->GetPreviewStringGuess( sFormatString, fVal, 7772 aResult, &pColor, eCellLang)) 7773 PushIllegalArgument(); 7774 else 7775 PushString( aResult); 7776 } 7777 } 7778 } 7779 } 7780 7781 7782 void ScInterpreter::ScSubstitute() 7783 { 7784 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScSubstitute" ); 7785 sal_uInt8 nParamCount = GetByte(); 7786 if ( MustHaveParamCount( nParamCount, 3, 4 ) ) 7787 { 7788 xub_StrLen nAnz; 7789 if (nParamCount == 4) 7790 { 7791 double fAnz = ::rtl::math::approxFloor(GetDouble()); 7792 if( fAnz < 1 || fAnz > STRING_MAXLEN ) 7793 { 7794 PushIllegalArgument(); 7795 return; 7796 } 7797 else 7798 nAnz = (xub_StrLen) fAnz; 7799 } 7800 else 7801 nAnz = 0; 7802 String sNewStr = GetString(); 7803 String sOldStr = GetString(); 7804 String sStr = GetString(); 7805 xub_StrLen nPos = 0; 7806 xub_StrLen nCount = 0; 7807 xub_StrLen nNewLen = sNewStr.Len(); 7808 xub_StrLen nOldLen = sOldStr.Len(); 7809 while( sal_True ) 7810 { 7811 nPos = sStr.Search( sOldStr, nPos ); 7812 if (nPos != STRING_NOTFOUND) 7813 { 7814 nCount++; 7815 if( !nAnz || nCount == nAnz ) 7816 { 7817 sStr.Erase(nPos,nOldLen); 7818 if ( CheckStringResultLen( sStr, sNewStr ) ) 7819 { 7820 sStr.Insert(sNewStr,nPos); 7821 nPos = sal::static_int_cast<xub_StrLen>( nPos + nNewLen ); 7822 } 7823 else 7824 break; 7825 } 7826 else 7827 nPos++; 7828 } 7829 else 7830 break; 7831 } 7832 PushString( sStr ); 7833 } 7834 } 7835 7836 7837 void ScInterpreter::ScRept() 7838 { 7839 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScRept" ); 7840 if ( MustHaveParamCount( GetByte(), 2 ) ) 7841 { 7842 double fAnz = ::rtl::math::approxFloor(GetDouble()); 7843 String aStr( GetString() ); 7844 if ( fAnz < 0.0 ) 7845 PushIllegalArgument(); 7846 else if ( fAnz * aStr.Len() > STRING_MAXLEN ) 7847 { 7848 PushError( errStringOverflow ); 7849 } 7850 else if ( fAnz == 0.0 ) 7851 PushString( EMPTY_STRING ); 7852 else 7853 { 7854 xub_StrLen n = (xub_StrLen) fAnz; 7855 const xub_StrLen nLen = aStr.Len(); 7856 String aRes; 7857 const sal_Unicode* const pSrc = aStr.GetBuffer(); 7858 sal_Unicode* pDst = aRes.AllocBuffer( n * nLen ); 7859 while( n-- ) 7860 { 7861 memcpy( pDst, pSrc, nLen * sizeof(sal_Unicode) ); 7862 pDst += nLen; 7863 } 7864 PushString( aRes ); 7865 } 7866 } 7867 } 7868 7869 7870 void ScInterpreter::ScConcat() 7871 { 7872 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScConcat" ); 7873 sal_uInt8 nParamCount = GetByte(); 7874 String aRes; 7875 while( nParamCount-- > 0) 7876 { 7877 const String& rStr = GetString(); 7878 aRes.Insert( rStr, 0 ); 7879 } 7880 PushString( aRes ); 7881 } 7882 7883 7884 void ScInterpreter::ScErrorType() 7885 { 7886 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::ScErrorType" ); 7887 sal_uInt16 nErr; 7888 sal_uInt16 nOldError = nGlobalError; 7889 nGlobalError = 0; 7890 switch ( GetStackType() ) 7891 { 7892 case svRefList : 7893 { 7894 FormulaTokenRef x = PopToken(); 7895 if (nGlobalError) 7896 nErr = nGlobalError; 7897 else 7898 { 7899 const ScRefList* pRefList = static_cast<ScToken*>(x.get())->GetRefList(); 7900 size_t n = pRefList->size(); 7901 if (!n) 7902 nErr = errNoRef; 7903 else if (n > 1) 7904 nErr = errNoValue; 7905 else 7906 { 7907 ScRange aRange; 7908 DoubleRefToRange( (*pRefList)[0], aRange); 7909 if (nGlobalError) 7910 nErr = nGlobalError; 7911 else 7912 { 7913 ScAddress aAdr; 7914 if ( DoubleRefToPosSingleRef( aRange, aAdr ) ) 7915 nErr = pDok->GetErrCode( aAdr ); 7916 else 7917 nErr = nGlobalError; 7918 } 7919 } 7920 } 7921 } 7922 break; 7923 case svDoubleRef : 7924 { 7925 ScRange aRange; 7926 PopDoubleRef( aRange ); 7927 if ( nGlobalError ) 7928 nErr = nGlobalError; 7929 else 7930 { 7931 ScAddress aAdr; 7932 if ( DoubleRefToPosSingleRef( aRange, aAdr ) ) 7933 nErr = pDok->GetErrCode( aAdr ); 7934 else 7935 nErr = nGlobalError; 7936 } 7937 } 7938 break; 7939 case svSingleRef : 7940 { 7941 ScAddress aAdr; 7942 PopSingleRef( aAdr ); 7943 if ( nGlobalError ) 7944 nErr = nGlobalError; 7945 else 7946 nErr = pDok->GetErrCode( aAdr ); 7947 } 7948 break; 7949 default: 7950 PopError(); 7951 nErr = nGlobalError; 7952 } 7953 if ( nErr ) 7954 { 7955 nGlobalError = 0; 7956 PushDouble( nErr ); 7957 } 7958 else 7959 { 7960 nGlobalError = nOldError; 7961 PushNA(); 7962 } 7963 } 7964 7965 7966 sal_Bool ScInterpreter::MayBeRegExp( const String& rStr, const ScDocument* pDoc ) 7967 { 7968 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::MayBeRegExp" ); 7969 if ( pDoc && !pDoc->GetDocOptions().IsFormulaRegexEnabled() ) 7970 return sal_False; 7971 if ( !rStr.Len() || (rStr.Len() == 1 && rStr.GetChar(0) != '.') ) 7972 return sal_False; // einzelnes Metazeichen kann keine RegExp sein 7973 static const sal_Unicode cre[] = { '.','*','+','?','[',']','^','$','\\','<','>','(',')','|', 0 }; 7974 const sal_Unicode* p1 = rStr.GetBuffer(); 7975 sal_Unicode c1; 7976 while ( ( c1 = *p1++ ) != 0 ) 7977 { 7978 const sal_Unicode* p2 = cre; 7979 while ( *p2 ) 7980 { 7981 if ( c1 == *p2++ ) 7982 return sal_True; 7983 } 7984 } 7985 return sal_False; 7986 } 7987 7988 static bool lcl_LookupQuery( ScAddress & o_rResultPos, ScDocument * pDoc, 7989 const ScQueryParam & rParam, const ScQueryEntry & rEntry ) 7990 { 7991 bool bFound = false; 7992 ScQueryCellIterator aCellIter( pDoc, rParam.nTab, rParam, sal_False); 7993 if (rEntry.eOp != SC_EQUAL) 7994 { 7995 // range lookup <= or >= 7996 SCCOL nCol; 7997 SCROW nRow; 7998 bFound = aCellIter.FindEqualOrSortedLastInRange( nCol, nRow); 7999 if (bFound) 8000 { 8001 o_rResultPos.SetCol( nCol); 8002 o_rResultPos.SetRow( nRow); 8003 } 8004 } 8005 else if (aCellIter.GetFirst()) 8006 { 8007 // EQUAL 8008 bFound = true; 8009 o_rResultPos.SetCol( aCellIter.GetCol()); 8010 o_rResultPos.SetRow( aCellIter.GetRow()); 8011 } 8012 return bFound; 8013 } 8014 8015 #define erDEBUG_LOOKUPCACHE 0 8016 #if erDEBUG_LOOKUPCACHE 8017 #include <cstdio> 8018 using ::std::fprintf; 8019 using ::std::fflush; 8020 static struct LookupCacheDebugCounter 8021 { 8022 unsigned long nMiss; 8023 unsigned long nHit; 8024 LookupCacheDebugCounter() : nMiss(0), nHit(0) {} 8025 ~LookupCacheDebugCounter() 8026 { 8027 fprintf( stderr, "\nmiss: %lu, hit: %lu, total: %lu, hit/miss: %lu, hit/total %lu%\n", 8028 nMiss, nHit, nHit+nMiss, (nMiss>0 ? nHit/nMiss : 0), 8029 ((nHit+nMiss)>0 ? (100*nHit)/(nHit+nMiss) : 0)); 8030 fflush( stderr); 8031 } 8032 } aLookupCacheDebugCounter; 8033 #endif 8034 8035 bool ScInterpreter::LookupQueryWithCache( ScAddress & o_rResultPos, 8036 const ScQueryParam & rParam ) const 8037 { 8038 RTL_LOGFILE_CONTEXT_AUTHOR( aLogger, "sc", "er", "ScInterpreter::LookupQueryWithCache" ); 8039 bool bFound = false; 8040 const ScQueryEntry& rEntry = rParam.GetEntry(0); 8041 bool bColumnsMatch = (rParam.nCol1 == rEntry.nField); 8042 DBG_ASSERT( bColumnsMatch, "ScInterpreter::LookupQueryWithCache: columns don't match"); 8043 if (!bColumnsMatch) 8044 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry); 8045 else 8046 { 8047 ScRange aLookupRange( rParam.nCol1, rParam.nRow1, rParam.nTab, 8048 rParam.nCol2, rParam.nRow2, rParam.nTab); 8049 ScLookupCache& rCache = pDok->GetLookupCache( aLookupRange); 8050 ScLookupCache::QueryCriteria aCriteria( rEntry); 8051 ScLookupCache::Result eCacheResult = rCache.lookup( o_rResultPos, 8052 aCriteria, aPos); 8053 switch (eCacheResult) 8054 { 8055 case ScLookupCache::NOT_CACHED : 8056 case ScLookupCache::CRITERIA_DIFFERENT : 8057 #if erDEBUG_LOOKUPCACHE 8058 ++aLookupCacheDebugCounter.nMiss; 8059 #if erDEBUG_LOOKUPCACHE > 1 8060 fprintf( stderr, "miss %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab()); 8061 #endif 8062 #endif 8063 bFound = lcl_LookupQuery( o_rResultPos, pDok, rParam, rEntry); 8064 if (eCacheResult == ScLookupCache::NOT_CACHED) 8065 rCache.insert( o_rResultPos, aCriteria, aPos, bFound); 8066 break; 8067 case ScLookupCache::FOUND : 8068 #if erDEBUG_LOOKUPCACHE 8069 ++aLookupCacheDebugCounter.nHit; 8070 #if erDEBUG_LOOKUPCACHE > 1 8071 fprintf( stderr, "hit %d,%d,%d\n", (int)aPos.Col(), (int)aPos.Row(), (int)aPos.Tab()); 8072 #endif 8073 #endif 8074 bFound = true; 8075 break; 8076 case ScLookupCache::NOT_AVAILABLE : 8077 ; // nothing, bFound remains FALSE 8078 break; 8079 } 8080 } 8081 return bFound; 8082 } 8083