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