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