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