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