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