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