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