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