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