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