1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */ 2 /* 3 * This file is part of the LibreOffice project. 4 * 5 * This Source Code Form is subject to the terms of the Mozilla Public 6 * License, v. 2.0. If a copy of the MPL was not distributed with this 7 * file, You can obtain one at http://mozilla.org/MPL/2.0/. 8 * 9 * This file incorporates work covered by the following license notice: 10 * 11 * Licensed to the Apache Software Foundation (ASF) under one or more 12 * contributor license agreements. See the NOTICE file distributed 13 * with this work for additional information regarding copyright 14 * ownership. The ASF licenses this file to you under the Apache 15 * License, Version 2.0 (the "License"); you may not use this file 16 * except in compliance with the License. You may obtain a copy of 17 * the License at http://www.apache.org/licenses/LICENSE-2.0 . 18 */ 19 20 #include <stdlib.h> 21 22 #include <algorithm> 23 #include <string_view> 24 #include <unordered_map> 25 26 #include <com/sun/star/beans/XPropertySet.hpp> 27 #include <com/sun/star/container/XEnumerationAccess.hpp> 28 #include <com/sun/star/container/XIndexAccess.hpp> 29 #include <com/sun/star/script/XDefaultMethod.hpp> 30 #include <com/sun/star/uno/Any.hxx> 31 #include <com/sun/star/util/SearchAlgorithms2.hpp> 32 33 #include <comphelper/processfactory.hxx> 34 #include <comphelper/string.hxx> 35 36 #include <sal/log.hxx> 37 38 #include <tools/wldcrd.hxx> 39 #include <tools/diagnose_ex.h> 40 41 #include <vcl/svapp.hxx> 42 #include <vcl/settings.hxx> 43 44 #include <rtl/instance.hxx> 45 #include <rtl/math.hxx> 46 #include <rtl/ustrbuf.hxx> 47 #include <rtl/character.hxx> 48 49 #include <svl/zforlist.hxx> 50 51 #include <i18nutil/searchopt.hxx> 52 #include <unotools/syslocale.hxx> 53 #include <unotools/textsearch.hxx> 54 55 #include <basic/sbuno.hxx> 56 57 #include <codegen.hxx> 58 #include "comenumwrapper.hxx" 59 #include "ddectrl.hxx" 60 #include "dllmgr.hxx" 61 #include <errobject.hxx> 62 #include <image.hxx> 63 #include <iosys.hxx> 64 #include <opcodes.hxx> 65 #include <runtime.hxx> 66 #include <sb.hxx> 67 #include <sbintern.hxx> 68 #include <sbprop.hxx> 69 #include <sbunoobj.hxx> 70 #include <basic/codecompletecache.hxx> 71 #include <memory> 72 73 using com::sun::star::uno::Reference; 74 75 using namespace com::sun::star::uno; 76 using namespace com::sun::star::container; 77 using namespace com::sun::star::lang; 78 using namespace com::sun::star::beans; 79 using namespace com::sun::star::script; 80 81 using namespace ::com::sun::star; 82 83 static void lcl_clearImpl( SbxVariableRef const & refVar, SbxDataType const & eType ); 84 static void lcl_eraseImpl( SbxVariableRef const & refVar, bool bVBAEnabled ); 85 86 bool SbiRuntime::isVBAEnabled() 87 { 88 bool bResult = false; 89 SbiInstance* pInst = GetSbData()->pInst; 90 if ( pInst && GetSbData()->pInst->pRun ) 91 bResult = pInst->pRun->bVBAEnabled; 92 return bResult; 93 } 94 95 void StarBASIC::SetVBAEnabled( bool bEnabled ) 96 { 97 if ( bDocBasic ) 98 { 99 bVBAEnabled = bEnabled; 100 } 101 } 102 103 bool StarBASIC::isVBAEnabled() const 104 { 105 if ( bDocBasic ) 106 { 107 if( SbiRuntime::isVBAEnabled() ) 108 return true; 109 return bVBAEnabled; 110 } 111 return false; 112 } 113 114 struct SbiArgv { // Argv stack: 115 SbxArrayRef refArgv; // Argv 116 short nArgc; // Argc 117 118 SbiArgv(SbxArrayRef const & refArgv_, short nArgc_) : 119 refArgv(refArgv_), 120 nArgc(nArgc_) {} 121 }; 122 123 struct SbiGosub { // GOSUB-Stack: 124 const sal_uInt8* pCode; // Return-Pointer 125 sal_uInt16 nStartForLvl; // #118235: For Level in moment of gosub 126 127 SbiGosub(const sal_uInt8* pCode_, sal_uInt16 nStartForLvl_) : 128 pCode(pCode_), 129 nStartForLvl(nStartForLvl_) {} 130 }; 131 132 SbiRuntime::pStep0 SbiRuntime::aStep0[] = { // all opcodes without operands 133 &SbiRuntime::StepNOP, 134 &SbiRuntime::StepEXP, 135 &SbiRuntime::StepMUL, 136 &SbiRuntime::StepDIV, 137 &SbiRuntime::StepMOD, 138 &SbiRuntime::StepPLUS, 139 &SbiRuntime::StepMINUS, 140 &SbiRuntime::StepNEG, 141 &SbiRuntime::StepEQ, 142 &SbiRuntime::StepNE, 143 &SbiRuntime::StepLT, 144 &SbiRuntime::StepGT, 145 &SbiRuntime::StepLE, 146 &SbiRuntime::StepGE, 147 &SbiRuntime::StepIDIV, 148 &SbiRuntime::StepAND, 149 &SbiRuntime::StepOR, 150 &SbiRuntime::StepXOR, 151 &SbiRuntime::StepEQV, 152 &SbiRuntime::StepIMP, 153 &SbiRuntime::StepNOT, 154 &SbiRuntime::StepCAT, 155 156 &SbiRuntime::StepLIKE, 157 &SbiRuntime::StepIS, 158 // load/save 159 &SbiRuntime::StepARGC, // establish new Argv 160 &SbiRuntime::StepARGV, // TOS ==> current Argv 161 &SbiRuntime::StepINPUT, // Input ==> TOS 162 &SbiRuntime::StepLINPUT, // Line Input ==> TOS 163 &SbiRuntime::StepGET, // touch TOS 164 &SbiRuntime::StepSET, // save object TOS ==> TOS-1 165 &SbiRuntime::StepPUT, // TOS ==> TOS-1 166 &SbiRuntime::StepPUTC, // TOS ==> TOS-1, then ReadOnly 167 &SbiRuntime::StepDIM, // DIM 168 &SbiRuntime::StepREDIM, // REDIM 169 &SbiRuntime::StepREDIMP, // REDIM PRESERVE 170 &SbiRuntime::StepERASE, // delete TOS 171 // branch 172 &SbiRuntime::StepSTOP, // program end 173 &SbiRuntime::StepINITFOR, // initialize FOR-Variable 174 &SbiRuntime::StepNEXT, // increment FOR-Variable 175 &SbiRuntime::StepCASE, // beginning CASE 176 &SbiRuntime::StepENDCASE, // end CASE 177 &SbiRuntime::StepSTDERROR, // standard error handling 178 &SbiRuntime::StepNOERROR, // no error handling 179 &SbiRuntime::StepLEAVE, // leave UP 180 // E/A 181 &SbiRuntime::StepCHANNEL, // TOS = channel number 182 &SbiRuntime::StepPRINT, // print TOS 183 &SbiRuntime::StepPRINTF, // print TOS in field 184 &SbiRuntime::StepWRITE, // write TOS 185 &SbiRuntime::StepRENAME, // Rename Tos+1 to Tos 186 &SbiRuntime::StepPROMPT, // define Input Prompt from TOS 187 &SbiRuntime::StepRESTART, // Set restart point 188 &SbiRuntime::StepCHANNEL0, // set E/A-channel 0 189 &SbiRuntime::StepEMPTY, // empty expression on stack 190 &SbiRuntime::StepERROR, // TOS = error code 191 &SbiRuntime::StepLSET, // save object TOS ==> TOS-1 192 &SbiRuntime::StepRSET, // save object TOS ==> TOS-1 193 &SbiRuntime::StepREDIMP_ERASE,// Copy array object for REDIMP 194 &SbiRuntime::StepINITFOREACH,// Init for each loop 195 &SbiRuntime::StepVBASET,// vba-like set statement 196 &SbiRuntime::StepERASE_CLEAR,// vba-like set statement 197 &SbiRuntime::StepARRAYACCESS,// access TOS as array 198 &SbiRuntime::StepBYVAL, // access TOS as array 199 }; 200 201 SbiRuntime::pStep1 SbiRuntime::aStep1[] = { // all opcodes with one operand 202 &SbiRuntime::StepLOADNC, // loading a numeric constant (+ID) 203 &SbiRuntime::StepLOADSC, // loading a string constant (+ID) 204 &SbiRuntime::StepLOADI, // Immediate Load (+value) 205 &SbiRuntime::StepARGN, // save a named Args in Argv (+StringID) 206 &SbiRuntime::StepPAD, // bring string to a definite length (+length) 207 // branches 208 &SbiRuntime::StepJUMP, // jump (+Target) 209 &SbiRuntime::StepJUMPT, // evaluate TOS, conditional jump (+Target) 210 &SbiRuntime::StepJUMPF, // evaluate TOS, conditional jump (+Target) 211 &SbiRuntime::StepONJUMP, // evaluate TOS, jump into JUMP-table (+MaxVal) 212 &SbiRuntime::StepGOSUB, // UP-call (+Target) 213 &SbiRuntime::StepRETURN, // UP-return (+0 or Target) 214 &SbiRuntime::StepTESTFOR, // check FOR-variable, increment (+Endlabel) 215 &SbiRuntime::StepCASETO, // Tos+1 <= Case <= Tos), 2xremove (+Target) 216 &SbiRuntime::StepERRHDL, // error handler (+Offset) 217 &SbiRuntime::StepRESUME, // resume after errors (+0 or 1 or Label) 218 // E/A 219 &SbiRuntime::StepCLOSE, // (+channel/0) 220 &SbiRuntime::StepPRCHAR, // (+char) 221 // management 222 &SbiRuntime::StepSETCLASS, // check set + class names (+StringId) 223 &SbiRuntime::StepTESTCLASS, // Check TOS class (+StringId) 224 &SbiRuntime::StepLIB, // lib for declare-call (+StringId) 225 &SbiRuntime::StepBASED, // TOS is incremented by BASE, BASE is pushed before 226 &SbiRuntime::StepARGTYP, // convert last parameter in Argv (+Type) 227 &SbiRuntime::StepVBASETCLASS,// vba-like set statement 228 }; 229 230 SbiRuntime::pStep2 SbiRuntime::aStep2[] = {// all opcodes with two operands 231 &SbiRuntime::StepRTL, // load from RTL (+StringID+Typ) 232 &SbiRuntime::StepFIND, // load (+StringID+Typ) 233 &SbiRuntime::StepELEM, // load element (+StringID+Typ) 234 &SbiRuntime::StepPARAM, // Parameter (+Offset+Typ) 235 // branches 236 &SbiRuntime::StepCALL, // Declare-Call (+StringID+Typ) 237 &SbiRuntime::StepCALLC, // CDecl-Declare-Call (+StringID+Typ) 238 &SbiRuntime::StepCASEIS, // Case-Test (+Test-Opcode+False-Target) 239 // management 240 &SbiRuntime::StepSTMNT, // beginning of a statement (+Line+Col) 241 // E/A 242 &SbiRuntime::StepOPEN, // (+StreamMode+Flags) 243 // Objects 244 &SbiRuntime::StepLOCAL, // define local variable (+StringId+Typ) 245 &SbiRuntime::StepPUBLIC, // module global variable (+StringID+Typ) 246 &SbiRuntime::StepGLOBAL, // define global variable (+StringID+Typ) 247 &SbiRuntime::StepCREATE, // create object (+StringId+StringId) 248 &SbiRuntime::StepSTATIC, // static variable (+StringId+StringId) 249 &SbiRuntime::StepTCREATE, // user-defined objects (+StringId+StringId) 250 &SbiRuntime::StepDCREATE, // create object-array (+StringID+StringID) 251 &SbiRuntime::StepGLOBAL_P, // define global variable which is not overwritten 252 // by the Basic on a restart (+StringID+Typ) 253 &SbiRuntime::StepFIND_G, // finds global variable with special treatment because of _GLOBAL_P 254 &SbiRuntime::StepDCREATE_REDIMP, // redimension object array (+StringID+StringID) 255 &SbiRuntime::StepFIND_CM, // Search inside a class module (CM) to enable global search in time 256 &SbiRuntime::StepPUBLIC_P, // Search inside a class module (CM) to enable global search in time 257 &SbiRuntime::StepFIND_STATIC, // Search inside a class module (CM) to enable global search in time 258 }; 259 260 261 // SbiRTLData 262 263 SbiRTLData::SbiRTLData() 264 { 265 nDirFlags = SbAttributes::NONE; 266 nCurDirPos = 0; 267 } 268 269 SbiRTLData::~SbiRTLData() 270 { 271 } 272 273 // SbiInstance 274 275 // 16.10.96: #31460 new concept for StepInto/Over/Out 276 // The decision whether StepPoint shall be called is done with the help of 277 // the CallLevel. It's stopped when the current CallLevel is <= nBreakCallLvl. 278 // The current CallLevel can never be smaller than 1, as it's also incremented 279 // during the call of a method (also main). Therefore a BreakCallLvl from 0 280 // means that the program isn't stopped at all. 281 // (also have a look at: step2.cxx, SbiRuntime::StepSTMNT() ) 282 283 284 void SbiInstance::CalcBreakCallLevel( BasicDebugFlags nFlags ) 285 { 286 287 nFlags &= ~BasicDebugFlags::Break; 288 289 sal_uInt16 nRet; 290 if (nFlags == BasicDebugFlags::StepInto) { 291 nRet = nCallLvl + 1; // CallLevel+1 is also stopped 292 } else if (nFlags == (BasicDebugFlags::StepOver | BasicDebugFlags::StepInto)) { 293 nRet = nCallLvl; // current CallLevel is stopped 294 } else if (nFlags == BasicDebugFlags::StepOut) { 295 nRet = nCallLvl - 1; // smaller CallLevel is stopped 296 } else { 297 // Basic-IDE returns 0 instead of BasicDebugFlags::Continue, so also default=continue 298 nRet = 0; // CallLevel is always > 0 -> no StepPoint 299 } 300 nBreakCallLvl = nRet; // take result 301 } 302 303 SbiInstance::SbiInstance( StarBASIC* p ) 304 : pIosys(new SbiIoSystem) 305 , pDdeCtrl(new SbiDdeControl) 306 , pBasic(p) 307 , meFormatterLangType(LANGUAGE_DONTKNOW) 308 , meFormatterDateOrder(DateOrder::YMD) 309 , nStdDateIdx(0) 310 , nStdTimeIdx(0) 311 , nStdDateTimeIdx(0) 312 , nErr(0) 313 , nErl(0) 314 , bReschedule(true) 315 , bCompatibility(false) 316 , pRun(nullptr) 317 , nCallLvl(0) 318 , nBreakCallLvl(0) 319 { 320 } 321 322 SbiInstance::~SbiInstance() 323 { 324 while( pRun ) 325 { 326 SbiRuntime* p = pRun->pNext; 327 delete pRun; 328 pRun = p; 329 } 330 331 try 332 { 333 int nSize = ComponentVector.size(); 334 if( nSize ) 335 { 336 for( int i = nSize - 1 ; i >= 0 ; --i ) 337 { 338 Reference< XComponent > xDlgComponent = ComponentVector[i]; 339 if( xDlgComponent.is() ) 340 xDlgComponent->dispose(); 341 } 342 } 343 } 344 catch( const Exception& ) 345 { 346 TOOLS_WARN_EXCEPTION("basic", "SbiInstance::~SbiInstance: caught an exception while disposing the components" ); 347 } 348 } 349 350 SbiDllMgr* SbiInstance::GetDllMgr() 351 { 352 if( !pDllMgr ) 353 { 354 pDllMgr.reset(new SbiDllMgr); 355 } 356 return pDllMgr.get(); 357 } 358 359 // #39629 create NumberFormatter with the help of a static method now 360 std::shared_ptr<SvNumberFormatter> const & SbiInstance::GetNumberFormatter() 361 { 362 LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType(); 363 SvtSysLocale aSysLocale; 364 DateOrder eDate = aSysLocale.GetLocaleData().getDateOrder(); 365 if( pNumberFormatter ) 366 { 367 if( eLangType != meFormatterLangType || 368 eDate != meFormatterDateOrder ) 369 { 370 pNumberFormatter.reset(); 371 } 372 } 373 meFormatterLangType = eLangType; 374 meFormatterDateOrder = eDate; 375 if( !pNumberFormatter ) 376 { 377 pNumberFormatter = PrepareNumberFormatter( nStdDateIdx, nStdTimeIdx, nStdDateTimeIdx, 378 &meFormatterLangType, &meFormatterDateOrder); 379 } 380 return pNumberFormatter; 381 } 382 383 // #39629 offer NumberFormatter static too 384 std::shared_ptr<SvNumberFormatter> SbiInstance::PrepareNumberFormatter( sal_uInt32 &rnStdDateIdx, 385 sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx, 386 LanguageType const * peFormatterLangType, DateOrder const * peFormatterDateOrder ) 387 { 388 LanguageType eLangType; 389 if( peFormatterLangType ) 390 { 391 eLangType = *peFormatterLangType; 392 } 393 else 394 { 395 eLangType = Application::GetSettings().GetLanguageTag().getLanguageType(); 396 } 397 DateOrder eDate; 398 if( peFormatterDateOrder ) 399 { 400 eDate = *peFormatterDateOrder; 401 } 402 else 403 { 404 SvtSysLocale aSysLocale; 405 eDate = aSysLocale.GetLocaleData().getDateOrder(); 406 } 407 408 std::shared_ptr<SvNumberFormatter> pNumberFormatter( 409 new SvNumberFormatter( comphelper::getProcessComponentContext(), eLangType )); 410 411 // Several parser methods pass SvNumberFormatter::IsNumberFormat() a number 412 // format index to parse against. Tell the formatter the proper date 413 // evaluation order, which also determines the date acceptance patterns to 414 // use if a format was passed. NF_EVALDATEFORMAT_FORMAT restricts to the 415 // format's locale's date patterns/order (no init/system locale match 416 // tried) and falls back to NF_EVALDATEFORMAT_INTL if no specific (i.e. 0) 417 // (or an unknown) format index was passed. 418 pNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT); 419 420 sal_Int32 nCheckPos = 0; 421 SvNumFormatType nType; 422 rnStdTimeIdx = pNumberFormatter->GetStandardFormat( SvNumFormatType::TIME, eLangType ); 423 424 // the formatter's standard templates have only got a two-digit date 425 // -> registering an own format 426 427 // HACK, because the numberformatter doesn't swap the place holders 428 // for month, day and year according to the system setting. 429 // Problem: Print Year(Date) under engl. BS 430 // also have a look at: basic/source/sbx/sbxdate.cxx 431 432 OUString aDateStr; 433 switch( eDate ) 434 { 435 default: 436 case DateOrder::MDY: aDateStr = "MM/DD/YYYY"; break; 437 case DateOrder::DMY: aDateStr = "DD/MM/YYYY"; break; 438 case DateOrder::YMD: aDateStr = "YYYY/MM/DD"; break; 439 } 440 OUString aStr( aDateStr ); // PutandConvertEntry() modifies string! 441 pNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, 442 rnStdDateIdx, LANGUAGE_ENGLISH_US, eLangType, true); 443 nCheckPos = 0; 444 aDateStr += " HH:MM:SS"; 445 aStr = aDateStr; 446 pNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, 447 rnStdDateTimeIdx, LANGUAGE_ENGLISH_US, eLangType, true); 448 return pNumberFormatter; 449 } 450 451 452 // Let engine run. If Flags == BasicDebugFlags::Continue, take Flags over 453 454 void SbiInstance::Stop() 455 { 456 for( SbiRuntime* p = pRun; p; p = p->pNext ) 457 { 458 p->Stop(); 459 } 460 } 461 462 // Allows Basic IDE to set watch mode to suppress errors 463 static bool bWatchMode = false; 464 465 void setBasicWatchMode( bool bOn ) 466 { 467 bWatchMode = bOn; 468 } 469 470 void SbiInstance::Error( ErrCode n ) 471 { 472 Error( n, OUString() ); 473 } 474 475 void SbiInstance::Error( ErrCode n, const OUString& rMsg ) 476 { 477 if( !bWatchMode ) 478 { 479 aErrorMsg = rMsg; 480 pRun->Error( n ); 481 } 482 } 483 484 void SbiInstance::ErrorVB( sal_Int32 nVBNumber, const OUString& rMsg ) 485 { 486 if( !bWatchMode ) 487 { 488 ErrCode n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) ); 489 if ( !n ) 490 { 491 n = ErrCode(nVBNumber); // force orig number, probably should have a specific table of vb ( localized ) errors 492 } 493 aErrorMsg = rMsg; 494 SbiRuntime::translateErrorToVba( n, aErrorMsg ); 495 496 pRun->Error( ERRCODE_BASIC_COMPAT, true/*bVBATranslationAlreadyDone*/ ); 497 } 498 } 499 500 void SbiInstance::setErrorVB( sal_Int32 nVBNumber ) 501 { 502 ErrCode n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) ); 503 if( !n ) 504 { 505 n = ErrCode(nVBNumber); // force orig number, probably should have a specific table of vb ( localized ) errors 506 } 507 aErrorMsg = OUString(); 508 SbiRuntime::translateErrorToVba( n, aErrorMsg ); 509 510 nErr = n; 511 } 512 513 514 void SbiInstance::FatalError( ErrCode n ) 515 { 516 pRun->FatalError( n ); 517 } 518 519 void SbiInstance::FatalError( ErrCode _errCode, const OUString& _details ) 520 { 521 pRun->FatalError( _errCode, _details ); 522 } 523 524 void SbiInstance::Abort() 525 { 526 StarBASIC* pErrBasic = GetCurrentBasic( pBasic ); 527 pErrBasic->RTError( nErr, aErrorMsg, pRun->nLine, pRun->nCol1, pRun->nCol2 ); 528 StarBASIC::Stop(); 529 } 530 531 // can be unequal to pRTBasic 532 StarBASIC* GetCurrentBasic( StarBASIC* pRTBasic ) 533 { 534 StarBASIC* pCurBasic = pRTBasic; 535 SbModule* pActiveModule = StarBASIC::GetActiveModule(); 536 if( pActiveModule ) 537 { 538 SbxObject* pParent = pActiveModule->GetParent(); 539 if (StarBASIC *pBasic = dynamic_cast<StarBASIC*>(pParent)) 540 pCurBasic = pBasic; 541 } 542 return pCurBasic; 543 } 544 545 SbModule* SbiInstance::GetActiveModule() 546 { 547 if( pRun ) 548 { 549 return pRun->GetModule(); 550 } 551 else 552 { 553 return nullptr; 554 } 555 } 556 557 SbMethod* SbiInstance::GetCaller( sal_uInt16 nLevel ) 558 { 559 SbiRuntime* p = pRun; 560 while( nLevel-- && p ) 561 { 562 p = p->pNext; 563 } 564 return p ? p->GetCaller() : nullptr; 565 } 566 567 // SbiInstance 568 569 // Attention: pMeth can also be NULL (on a call of the init-code) 570 571 SbiRuntime::SbiRuntime( SbModule* pm, SbMethod* pe, sal_uInt32 nStart ) 572 : rBasic( *static_cast<StarBASIC*>(pm->pParent) ), pInst( GetSbData()->pInst ), 573 pMod( pm ), pMeth( pe ), pImg( pMod->pImage.get() ), mpExtCaller(nullptr), m_nLastTime(0) 574 { 575 nFlags = pe ? pe->GetDebugFlags() : BasicDebugFlags::NONE; 576 pIosys = pInst->GetIoSystem(); 577 pForStk = nullptr; 578 pError = nullptr; 579 pErrCode = 580 pErrStmnt = 581 pRestart = nullptr; 582 pNext = nullptr; 583 pCode = 584 pStmnt = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nStart; 585 bRun = 586 bError = true; 587 bInError = false; 588 bBlocked = false; 589 nLine = 0; 590 nCol1 = 0; 591 nCol2 = 0; 592 nExprLvl = 0; 593 nArgc = 0; 594 nError = ERRCODE_NONE; 595 nForLvl = 0; 596 nOps = 0; 597 refExprStk = new SbxArray; 598 SetVBAEnabled( pMod->IsVBACompat() ); 599 SetParameters( pe ? pe->GetParameters() : nullptr ); 600 } 601 602 SbiRuntime::~SbiRuntime() 603 { 604 ClearArgvStack(); 605 ClearForStack(); 606 } 607 608 void SbiRuntime::SetVBAEnabled(bool bEnabled ) 609 { 610 bVBAEnabled = bEnabled; 611 if ( bVBAEnabled ) 612 { 613 if ( pMeth ) 614 { 615 mpExtCaller = pMeth->mCaller; 616 } 617 } 618 else 619 { 620 mpExtCaller = nullptr; 621 } 622 } 623 624 // Construction of the parameter list. All ByRef-parameters are directly 625 // taken over; copies of ByVal-parameters are created. If a particular 626 // data type is requested, it is converted. 627 628 void SbiRuntime::SetParameters( SbxArray* pParams ) 629 { 630 refParams = new SbxArray; 631 // for the return value 632 refParams->Put( pMeth, 0 ); 633 634 SbxInfo* pInfo = pMeth ? pMeth->GetInfo() : nullptr; 635 sal_uInt16 nParamCount = pParams ? pParams->Count() : 1; 636 if( nParamCount > 1 ) 637 { 638 for( sal_uInt16 i = 1 ; i < nParamCount ; i++ ) 639 { 640 const SbxParamInfo* p = pInfo ? pInfo->GetParam( i ) : nullptr; 641 642 // #111897 ParamArray 643 if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) 644 { 645 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); 646 sal_uInt16 nParamArrayParamCount = nParamCount - i; 647 pArray->unoAddDim( 0, nParamArrayParamCount - 1 ); 648 for (sal_uInt16 j = i; j < nParamCount ; ++j) 649 { 650 SbxVariable* v = pParams->Get( j ); 651 short aDimIndex[1]; 652 aDimIndex[0] = j - i; 653 pArray->Put(v, aDimIndex); 654 } 655 SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); 656 pArrayVar->SetFlag( SbxFlagBits::ReadWrite ); 657 pArrayVar->PutObject( pArray ); 658 refParams->Put( pArrayVar, i ); 659 660 // Block ParamArray for missing parameter 661 pInfo = nullptr; 662 break; 663 } 664 665 SbxVariable* v = pParams->Get( i ); 666 // methods are always byval! 667 bool bByVal = dynamic_cast<const SbxMethod *>(v) != nullptr; 668 SbxDataType t = v->GetType(); 669 bool bTargetTypeIsArray = false; 670 if( p ) 671 { 672 bByVal |= ( p->eType & SbxBYREF ) == 0; 673 t = static_cast<SbxDataType>( p->eType & 0x0FFF ); 674 675 if( !bByVal && t != SbxVARIANT && 676 (!v->IsFixed() || static_cast<SbxDataType>(v->GetType() & 0x0FFF ) != t) ) 677 { 678 bByVal = true; 679 } 680 681 bTargetTypeIsArray = (p->nUserData & PARAM_INFO_WITHBRACKETS) != 0; 682 } 683 if( bByVal ) 684 { 685 if( bTargetTypeIsArray ) 686 { 687 t = SbxOBJECT; 688 } 689 SbxVariable* v2 = new SbxVariable( t ); 690 v2->SetFlag( SbxFlagBits::ReadWrite ); 691 *v2 = *v; 692 refParams->Put( v2, i ); 693 } 694 else 695 { 696 if( t != SbxVARIANT && t != ( v->GetType() & 0x0FFF ) ) 697 { 698 if( p && (p->eType & SbxARRAY) ) 699 { 700 Error( ERRCODE_BASIC_CONVERSION ); 701 } 702 else 703 { 704 v->Convert( t ); 705 } 706 } 707 refParams->Put( v, i ); 708 } 709 if( p ) 710 { 711 refParams->PutAlias( p->aName, i ); 712 } 713 } 714 } 715 716 // ParamArray for missing parameter 717 if( pInfo ) 718 { 719 // #111897 Check first missing parameter for ParamArray 720 const SbxParamInfo* p = pInfo->GetParam( nParamCount ); 721 if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) 722 { 723 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); 724 pArray->unoAddDim( 0, -1 ); 725 SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); 726 pArrayVar->SetFlag( SbxFlagBits::ReadWrite ); 727 pArrayVar->PutObject( pArray ); 728 refParams->Put( pArrayVar, nParamCount ); 729 } 730 } 731 } 732 733 734 // execute a P-Code 735 736 bool SbiRuntime::Step() 737 { 738 if( bRun ) 739 { 740 // in any case check casually! 741 if( !( ++nOps & 0xF ) && pInst->IsReschedule() ) 742 { 743 sal_uInt32 nTime = osl_getGlobalTimer(); 744 if (nTime - m_nLastTime > 5 ) // 20 ms 745 { 746 Application::Reschedule(); 747 m_nLastTime = nTime; 748 } 749 } 750 751 // #i48868 blocked by next call level? 752 while( bBlocked ) 753 { 754 if( pInst->IsReschedule() ) 755 { 756 Application::Reschedule(); 757 } 758 } 759 760 SbiOpcode eOp = static_cast<SbiOpcode>( *pCode++ ); 761 sal_uInt32 nOp1, nOp2; 762 if (eOp <= SbiOpcode::SbOP0_END) 763 { 764 (this->*( aStep0[ int(eOp) ] ) )(); 765 } 766 else if (eOp >= SbiOpcode::SbOP1_START && eOp <= SbiOpcode::SbOP1_END) 767 { 768 nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; 769 770 (this->*( aStep1[ int(eOp) - int(SbiOpcode::SbOP1_START) ] ) )( nOp1 ); 771 } 772 else if (eOp >= SbiOpcode::SbOP2_START && eOp <= SbiOpcode::SbOP2_END) 773 { 774 nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; 775 nOp2 = *pCode++; nOp2 |= *pCode++ << 8; nOp2 |= *pCode++ << 16; nOp2 |= *pCode++ << 24; 776 (this->*( aStep2[ int(eOp) - int(SbiOpcode::SbOP2_START) ] ) )( nOp1, nOp2 ); 777 } 778 else 779 { 780 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 781 } 782 783 ErrCode nErrCode = SbxBase::GetError(); 784 Error( nErrCode.IgnoreWarning() ); 785 786 // from 13.2.1997, new error handling: 787 // ATTENTION: nError can be set already even if !nErrCode 788 // since nError can now also be set from other RT-instances 789 790 if( nError ) 791 { 792 SbxBase::ResetError(); 793 } 794 795 // from 15.3.96: display errors only if BASIC is still active 796 // (especially not after compiler errors at the runtime) 797 if( nError && bRun ) 798 { 799 ErrCode err = nError; 800 ClearExprStack(); 801 nError = ERRCODE_NONE; 802 pInst->nErr = err; 803 pInst->nErl = nLine; 804 pErrCode = pCode; 805 pErrStmnt = pStmnt; 806 // An error occurred in an error handler 807 // force parent handler ( if there is one ) 808 // to handle the error 809 bool bLetParentHandleThis = false; 810 811 // in the error handler? so std-error 812 if ( !bInError ) 813 { 814 bInError = true; 815 816 if( !bError ) // On Error Resume Next 817 { 818 StepRESUME( 1 ); 819 } 820 else if( pError ) // On Error Goto ... 821 { 822 pCode = pError; 823 } 824 else 825 { 826 bLetParentHandleThis = true; 827 } 828 } 829 else 830 { 831 bLetParentHandleThis = true; 832 pError = nullptr; //terminate the handler 833 } 834 if ( bLetParentHandleThis ) 835 { 836 // from 13.2.1997, new error handling: 837 // consider superior error handlers 838 839 // there's no error handler -> find one farther above 840 SbiRuntime* pRtErrHdl = nullptr; 841 SbiRuntime* pRt = this; 842 while( (pRt = pRt->pNext) != nullptr ) 843 { 844 if( !pRt->bError || pRt->pError != nullptr ) 845 { 846 pRtErrHdl = pRt; 847 break; 848 } 849 } 850 851 852 if( pRtErrHdl ) 853 { 854 // manipulate all the RTs that are below in the call-stack 855 pRt = this; 856 do 857 { 858 pRt->nError = err; 859 if( pRt != pRtErrHdl ) 860 { 861 pRt->bRun = false; 862 } 863 else 864 { 865 break; 866 } 867 pRt = pRt->pNext; 868 } 869 while( pRt ); 870 } 871 // no error-hdl found -> old behaviour 872 else 873 { 874 pInst->Abort(); 875 } 876 } 877 } 878 } 879 return bRun; 880 } 881 882 void SbiRuntime::Error( ErrCode n, bool bVBATranslationAlreadyDone ) 883 { 884 if( n ) 885 { 886 nError = n; 887 if( isVBAEnabled() && !bVBATranslationAlreadyDone ) 888 { 889 OUString aMsg = pInst->GetErrorMsg(); 890 sal_Int32 nVBAErrorNumber = translateErrorToVba( nError, aMsg ); 891 SbxVariable* pSbxErrObjVar = SbxErrObject::getErrObject().get(); 892 SbxErrObject* pGlobErr = static_cast< SbxErrObject* >( pSbxErrObjVar ); 893 if( pGlobErr != nullptr ) 894 { 895 pGlobErr->setNumberAndDescription( nVBAErrorNumber, aMsg ); 896 } 897 pInst->aErrorMsg = aMsg; 898 nError = ERRCODE_BASIC_COMPAT; 899 } 900 } 901 } 902 903 void SbiRuntime::Error( ErrCode _errCode, const OUString& _details ) 904 { 905 if ( _errCode ) 906 { 907 // Not correct for class module usage, remove for now 908 //OSL_WARN_IF( pInst->pRun != this, "basic", "SbiRuntime::Error: can't propagate the error message details!" ); 909 if ( pInst->pRun == this ) 910 { 911 pInst->Error( _errCode, _details ); 912 //OSL_WARN_IF( nError != _errCode, "basic", "SbiRuntime::Error: the instance is expected to propagate the error code back to me!" ); 913 } 914 else 915 { 916 nError = _errCode; 917 } 918 } 919 } 920 921 void SbiRuntime::FatalError( ErrCode n ) 922 { 923 StepSTDERROR(); 924 Error( n ); 925 } 926 927 void SbiRuntime::FatalError( ErrCode _errCode, const OUString& _details ) 928 { 929 StepSTDERROR(); 930 Error( _errCode, _details ); 931 } 932 933 sal_Int32 SbiRuntime::translateErrorToVba( ErrCode nError, OUString& rMsg ) 934 { 935 // If a message is defined use that ( in preference to 936 // the defined one for the error ) NB #TODO 937 // if there is an error defined it more than likely 938 // is not the one you want ( some are the same though ) 939 // we really need a new vba compatible error list 940 if ( rMsg.isEmpty() ) 941 { 942 StarBASIC::MakeErrorText( nError, rMsg ); 943 rMsg = StarBASIC::GetErrorText(); 944 if ( rMsg.isEmpty() ) // no message for err no, need localized resource here 945 { 946 rMsg = "Internal Object Error:"; 947 } 948 } 949 // no num? most likely then it *is* really a vba err 950 sal_uInt16 nVBErrorCode = StarBASIC::GetVBErrorCode( nError ); 951 sal_Int32 nVBAErrorNumber = ( nVBErrorCode == 0 ) ? sal_uInt32(nError) : nVBErrorCode; 952 return nVBAErrorNumber; 953 } 954 955 // Stacks 956 957 // The expression-stack is available for the continuous evaluation 958 // of expressions. 959 960 void SbiRuntime::PushVar( SbxVariable* pVar ) 961 { 962 if( pVar ) 963 { 964 refExprStk->Put( pVar, nExprLvl++ ); 965 } 966 } 967 968 SbxVariableRef SbiRuntime::PopVar() 969 { 970 #ifdef DBG_UTIL 971 if( !nExprLvl ) 972 { 973 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 974 return new SbxVariable; 975 } 976 #endif 977 SbxVariableRef xVar = refExprStk->Get( --nExprLvl ); 978 SAL_INFO_IF( xVar->GetName() == "Cells", "basic", "PopVar: Name equals 'Cells'" ); 979 // methods hold themselves in parameter 0 980 if( dynamic_cast<const SbxMethod *>(xVar.get()) != nullptr ) 981 { 982 xVar->SetParameters(nullptr); 983 } 984 return xVar; 985 } 986 987 void SbiRuntime::ClearExprStack() 988 { 989 // Attention: Clear() doesn't suffice as methods must be deleted 990 while ( nExprLvl ) 991 { 992 PopVar(); 993 } 994 refExprStk->Clear(); 995 } 996 997 // Take variable from the expression-stack without removing it 998 // n counts from 0 999 1000 SbxVariable* SbiRuntime::GetTOS() 1001 { 1002 short n = nExprLvl - 1; 1003 #ifdef DBG_UTIL 1004 if( n < 0 ) 1005 { 1006 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 1007 return new SbxVariable; 1008 } 1009 #endif 1010 return refExprStk->Get( static_cast<sal_uInt16>(n) ); 1011 } 1012 1013 1014 void SbiRuntime::TOSMakeTemp() 1015 { 1016 SbxVariable* p = refExprStk->Get( nExprLvl - 1 ); 1017 if ( p->GetType() == SbxEMPTY ) 1018 { 1019 p->Broadcast( SfxHintId::BasicDataWanted ); 1020 } 1021 1022 SbxVariable* pDflt = nullptr; 1023 if ( bVBAEnabled && ( p->GetType() == SbxOBJECT || p->GetType() == SbxVARIANT ) && ((pDflt = getDefaultProp(p)) != nullptr) ) 1024 { 1025 pDflt->Broadcast( SfxHintId::BasicDataWanted ); 1026 // replacing new p on stack causes object pointed by 1027 // pDft->pParent to be deleted, when p2->Compute() is 1028 // called below pParent is accessed (but it's deleted) 1029 // so set it to NULL now 1030 pDflt->SetParent( nullptr ); 1031 p = new SbxVariable( *pDflt ); 1032 p->SetFlag( SbxFlagBits::ReadWrite ); 1033 refExprStk->Put( p, nExprLvl - 1 ); 1034 } 1035 else if( p->GetRefCount() != 1 ) 1036 { 1037 SbxVariable* pNew = new SbxVariable( *p ); 1038 pNew->SetFlag( SbxFlagBits::ReadWrite ); 1039 refExprStk->Put( pNew, nExprLvl - 1 ); 1040 } 1041 } 1042 1043 // the GOSUB-stack collects return-addresses for GOSUBs 1044 void SbiRuntime::PushGosub( const sal_uInt8* pc ) 1045 { 1046 if( pGosubStk.size() >= MAXRECURSION ) 1047 { 1048 StarBASIC::FatalError( ERRCODE_BASIC_STACK_OVERFLOW ); 1049 } 1050 pGosubStk.emplace_back(pc, nForLvl); 1051 } 1052 1053 void SbiRuntime::PopGosub() 1054 { 1055 if( pGosubStk.empty() ) 1056 { 1057 Error( ERRCODE_BASIC_NO_GOSUB ); 1058 } 1059 else 1060 { 1061 pCode = pGosubStk.back().pCode; 1062 pGosubStk.pop_back(); 1063 } 1064 } 1065 1066 // the Argv-stack collects current argument-vectors 1067 1068 void SbiRuntime::PushArgv() 1069 { 1070 pArgvStk.emplace_back(refArgv, nArgc); 1071 nArgc = 1; 1072 refArgv.clear(); 1073 } 1074 1075 void SbiRuntime::PopArgv() 1076 { 1077 if( !pArgvStk.empty() ) 1078 { 1079 refArgv = pArgvStk.back().refArgv; 1080 nArgc = pArgvStk.back().nArgc; 1081 pArgvStk.pop_back(); 1082 } 1083 } 1084 1085 1086 void SbiRuntime::ClearArgvStack() 1087 { 1088 while( !pArgvStk.empty() ) 1089 { 1090 PopArgv(); 1091 } 1092 } 1093 1094 // Push of the for-stack. The stack has increment, end, begin and variable. 1095 // After the creation of the stack-element the stack's empty. 1096 1097 void SbiRuntime::PushFor() 1098 { 1099 SbiForStack* p = new SbiForStack; 1100 p->eForType = ForType::To; 1101 p->pNext = pForStk; 1102 pForStk = p; 1103 1104 p->refInc = PopVar(); 1105 p->refEnd = PopVar(); 1106 SbxVariableRef xBgn = PopVar(); 1107 p->refVar = PopVar(); 1108 *(p->refVar) = *xBgn; 1109 nForLvl++; 1110 } 1111 1112 void SbiRuntime::PushForEach() 1113 { 1114 SbiForStack* p = new SbiForStack; 1115 p->pNext = pForStk; 1116 pForStk = p; 1117 1118 SbxVariableRef xObjVar = PopVar(); 1119 SbxBase* pObj = xObjVar.is() ? xObjVar->GetObject() : nullptr; 1120 if( pObj == nullptr ) 1121 { 1122 Error( ERRCODE_BASIC_NO_OBJECT ); 1123 return; 1124 } 1125 1126 bool bError_ = false; 1127 if (SbxDimArray* pArray = dynamic_cast<SbxDimArray*>(pObj)) 1128 { 1129 p->eForType = ForType::EachArray; 1130 p->refEnd = reinterpret_cast<SbxVariable*>(pArray); 1131 1132 short nDims = pArray->GetDims(); 1133 p->pArrayLowerBounds.reset( new sal_Int32[nDims] ); 1134 p->pArrayUpperBounds.reset( new sal_Int32[nDims] ); 1135 p->pArrayCurIndices.reset( new sal_Int32[nDims] ); 1136 sal_Int32 lBound, uBound; 1137 for( short i = 0 ; i < nDims ; i++ ) 1138 { 1139 pArray->GetDim32( i+1, lBound, uBound ); 1140 p->pArrayCurIndices[i] = p->pArrayLowerBounds[i] = lBound; 1141 p->pArrayUpperBounds[i] = uBound; 1142 } 1143 } 1144 else if (BasicCollection* pCollection = dynamic_cast<BasicCollection*>(pObj)) 1145 { 1146 p->eForType = ForType::EachCollection; 1147 p->refEnd = pCollection; 1148 p->nCurCollectionIndex = 0; 1149 } 1150 else if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>(pObj)) 1151 { 1152 // XEnumerationAccess? 1153 Any aAny = pUnoObj->getUnoAny(); 1154 Reference< XEnumerationAccess > xEnumerationAccess; 1155 if( aAny >>= xEnumerationAccess ) 1156 { 1157 p->xEnumeration = xEnumerationAccess->createEnumeration(); 1158 p->eForType = ForType::EachXEnumeration; 1159 } 1160 else if ( isVBAEnabled() && pUnoObj->isNativeCOMObject() ) 1161 { 1162 uno::Reference< script::XInvocation > xInvocation; 1163 if ( ( aAny >>= xInvocation ) && xInvocation.is() ) 1164 { 1165 try 1166 { 1167 p->xEnumeration = new ComEnumerationWrapper( xInvocation ); 1168 p->eForType = ForType::EachXEnumeration; 1169 } 1170 catch(const uno::Exception& ) 1171 {} 1172 } 1173 if ( !p->xEnumeration.is() ) 1174 { 1175 bError_ = true; 1176 } 1177 } 1178 else 1179 { 1180 bError_ = true; 1181 } 1182 } 1183 else 1184 { 1185 bError_ = true; 1186 } 1187 1188 if( bError_ ) 1189 { 1190 Error( ERRCODE_BASIC_CONVERSION ); 1191 return; 1192 } 1193 1194 // Container variable 1195 p->refVar = PopVar(); 1196 nForLvl++; 1197 } 1198 1199 1200 void SbiRuntime::PopFor() 1201 { 1202 if( pForStk ) 1203 { 1204 SbiForStack* p = pForStk; 1205 pForStk = p->pNext; 1206 delete p; 1207 nForLvl--; 1208 } 1209 } 1210 1211 1212 void SbiRuntime::ClearForStack() 1213 { 1214 while( pForStk ) 1215 { 1216 PopFor(); 1217 } 1218 } 1219 1220 SbiForStack* SbiRuntime::FindForStackItemForCollection( class BasicCollection const * pCollection ) 1221 { 1222 for (SbiForStack *p = pForStk; p; p = p->pNext) 1223 { 1224 SbxVariable* pVar = p->refEnd.is() ? p->refEnd.get() : nullptr; 1225 if( p->eForType == ForType::EachCollection 1226 && pVar != nullptr 1227 && dynamic_cast<BasicCollection*>( pVar) == pCollection ) 1228 { 1229 return p; 1230 } 1231 } 1232 1233 return nullptr; 1234 } 1235 1236 1237 // DLL-calls 1238 1239 void SbiRuntime::DllCall 1240 ( const OUString& aFuncName, 1241 const OUString& aDLLName, 1242 SbxArray* pArgs, // parameter (from index 1, can be NULL) 1243 SbxDataType eResType, // return value 1244 bool bCDecl ) // true: according to C-conventions 1245 { 1246 // NOT YET IMPLEMENTED 1247 1248 SbxVariable* pRes = new SbxVariable( eResType ); 1249 SbiDllMgr* pDllMgr = pInst->GetDllMgr(); 1250 ErrCode nErr = pDllMgr->Call( aFuncName, aDLLName, pArgs, *pRes, bCDecl ); 1251 if( nErr ) 1252 { 1253 Error( nErr ); 1254 } 1255 PushVar( pRes ); 1256 } 1257 1258 bool SbiRuntime::IsImageFlag( SbiImageFlags n ) const 1259 { 1260 return pImg->IsFlag( n ); 1261 } 1262 1263 sal_uInt16 SbiRuntime::GetBase() const 1264 { 1265 return pImg->GetBase(); 1266 } 1267 1268 void SbiRuntime::StepNOP() 1269 {} 1270 1271 void SbiRuntime::StepArith( SbxOperator eOp ) 1272 { 1273 SbxVariableRef p1 = PopVar(); 1274 TOSMakeTemp(); 1275 SbxVariable* p2 = GetTOS(); 1276 1277 p2->ResetFlag( SbxFlagBits::Fixed ); 1278 p2->Compute( eOp, *p1 ); 1279 1280 checkArithmeticOverflow( p2 ); 1281 } 1282 1283 void SbiRuntime::StepUnary( SbxOperator eOp ) 1284 { 1285 TOSMakeTemp(); 1286 SbxVariable* p = GetTOS(); 1287 p->Compute( eOp, *p ); 1288 } 1289 1290 void SbiRuntime::StepCompare( SbxOperator eOp ) 1291 { 1292 SbxVariableRef p1 = PopVar(); 1293 SbxVariableRef p2 = PopVar(); 1294 1295 // Make sure objects with default params have 1296 // values ( and type ) set as appropriate 1297 SbxDataType p1Type = p1->GetType(); 1298 SbxDataType p2Type = p2->GetType(); 1299 if ( p1Type == SbxEMPTY ) 1300 { 1301 p1->Broadcast( SfxHintId::BasicDataWanted ); 1302 p1Type = p1->GetType(); 1303 } 1304 if ( p2Type == SbxEMPTY ) 1305 { 1306 p2->Broadcast( SfxHintId::BasicDataWanted ); 1307 p2Type = p2->GetType(); 1308 } 1309 if ( p1Type == p2Type ) 1310 { 1311 // if both sides are an object and have default props 1312 // then we need to use the default props 1313 // we don't need to worry if only one side ( lhs, rhs ) is an 1314 // object ( object side will get coerced to correct type in 1315 // Compare ) 1316 if ( p1Type == SbxOBJECT ) 1317 { 1318 SbxVariable* pDflt = getDefaultProp( p1.get() ); 1319 if ( pDflt ) 1320 { 1321 p1 = pDflt; 1322 p1->Broadcast( SfxHintId::BasicDataWanted ); 1323 } 1324 pDflt = getDefaultProp( p2.get() ); 1325 if ( pDflt ) 1326 { 1327 p2 = pDflt; 1328 p2->Broadcast( SfxHintId::BasicDataWanted ); 1329 } 1330 } 1331 1332 } 1333 static SbxVariable* pTRUE = nullptr; 1334 static SbxVariable* pFALSE = nullptr; 1335 // why do this on non-windows ? 1336 // why do this at all ? 1337 // I dumbly follow the pattern :-/ 1338 if ( bVBAEnabled && ( p1->IsNull() || p2->IsNull() ) ) 1339 { 1340 static SbxVariable* pNULL = [&]() { 1341 SbxVariable* p = new SbxVariable; 1342 p->PutNull(); 1343 p->AddFirstRef(); 1344 return p; 1345 }(); 1346 PushVar( pNULL ); 1347 } 1348 else if( p2->Compare( eOp, *p1 ) ) 1349 { 1350 if( !pTRUE ) 1351 { 1352 pTRUE = new SbxVariable; 1353 pTRUE->PutBool( true ); 1354 pTRUE->AddFirstRef(); 1355 } 1356 PushVar( pTRUE ); 1357 } 1358 else 1359 { 1360 if( !pFALSE ) 1361 { 1362 pFALSE = new SbxVariable; 1363 pFALSE->PutBool( false ); 1364 pFALSE->AddFirstRef(); 1365 } 1366 PushVar( pFALSE ); 1367 } 1368 } 1369 1370 void SbiRuntime::StepEXP() { StepArith( SbxEXP ); } 1371 void SbiRuntime::StepMUL() { StepArith( SbxMUL ); } 1372 void SbiRuntime::StepDIV() { StepArith( SbxDIV ); } 1373 void SbiRuntime::StepIDIV() { StepArith( SbxIDIV ); } 1374 void SbiRuntime::StepMOD() { StepArith( SbxMOD ); } 1375 void SbiRuntime::StepPLUS() { StepArith( SbxPLUS ); } 1376 void SbiRuntime::StepMINUS() { StepArith( SbxMINUS ); } 1377 void SbiRuntime::StepCAT() { StepArith( SbxCAT ); } 1378 void SbiRuntime::StepAND() { StepArith( SbxAND ); } 1379 void SbiRuntime::StepOR() { StepArith( SbxOR ); } 1380 void SbiRuntime::StepXOR() { StepArith( SbxXOR ); } 1381 void SbiRuntime::StepEQV() { StepArith( SbxEQV ); } 1382 void SbiRuntime::StepIMP() { StepArith( SbxIMP ); } 1383 1384 void SbiRuntime::StepNEG() { StepUnary( SbxNEG ); } 1385 void SbiRuntime::StepNOT() { StepUnary( SbxNOT ); } 1386 1387 void SbiRuntime::StepEQ() { StepCompare( SbxEQ ); } 1388 void SbiRuntime::StepNE() { StepCompare( SbxNE ); } 1389 void SbiRuntime::StepLT() { StepCompare( SbxLT ); } 1390 void SbiRuntime::StepGT() { StepCompare( SbxGT ); } 1391 void SbiRuntime::StepLE() { StepCompare( SbxLE ); } 1392 void SbiRuntime::StepGE() { StepCompare( SbxGE ); } 1393 1394 namespace 1395 { 1396 bool NeedEsc(sal_Unicode cCode) 1397 { 1398 if(!rtl::isAscii(cCode)) 1399 { 1400 return false; 1401 } 1402 switch(cCode) 1403 { 1404 case '.': 1405 case '^': 1406 case '$': 1407 case '+': 1408 case '\\': 1409 case '|': 1410 case '{': 1411 case '}': 1412 case '(': 1413 case ')': 1414 return true; 1415 default: 1416 return false; 1417 } 1418 } 1419 1420 OUString VBALikeToRegexp(const OUString &rIn) 1421 { 1422 OUStringBuffer sResult; 1423 const sal_Unicode *start = rIn.getStr(); 1424 const sal_Unicode *end = start + rIn.getLength(); 1425 1426 int seenright = 0; 1427 1428 sResult.append('^'); 1429 1430 while (start < end) 1431 { 1432 switch (*start) 1433 { 1434 case '?': 1435 sResult.append('.'); 1436 start++; 1437 break; 1438 case '*': 1439 sResult.append(".*"); 1440 start++; 1441 break; 1442 case '#': 1443 sResult.append("[0-9]"); 1444 start++; 1445 break; 1446 case ']': 1447 sResult.append('\\'); 1448 sResult.append(*start++); 1449 break; 1450 case '[': 1451 sResult.append(*start++); 1452 seenright = 0; 1453 while (start < end && !seenright) 1454 { 1455 switch (*start) 1456 { 1457 case '[': 1458 case '?': 1459 case '*': 1460 sResult.append('\\'); 1461 sResult.append(*start); 1462 break; 1463 case ']': 1464 sResult.append(*start); 1465 seenright = 1; 1466 break; 1467 case '!': 1468 sResult.append('^'); 1469 break; 1470 default: 1471 if (NeedEsc(*start)) 1472 { 1473 sResult.append('\\'); 1474 } 1475 sResult.append(*start); 1476 break; 1477 } 1478 start++; 1479 } 1480 break; 1481 default: 1482 if (NeedEsc(*start)) 1483 { 1484 sResult.append('\\'); 1485 } 1486 sResult.append(*start++); 1487 } 1488 } 1489 1490 sResult.append('$'); 1491 1492 return sResult.makeStringAndClear(); 1493 } 1494 } 1495 1496 void SbiRuntime::StepLIKE() 1497 { 1498 SbxVariableRef refVar1 = PopVar(); 1499 SbxVariableRef refVar2 = PopVar(); 1500 1501 OUString pattern = VBALikeToRegexp(refVar1->GetOUString()); 1502 OUString value = refVar2->GetOUString(); 1503 1504 i18nutil::SearchOptions2 aSearchOpt; 1505 1506 aSearchOpt.AlgorithmType2 = css::util::SearchAlgorithms2::REGEXP; 1507 1508 aSearchOpt.Locale = Application::GetSettings().GetLanguageTag().getLocale(); 1509 aSearchOpt.searchString = pattern; 1510 1511 bool bTextMode(true); 1512 bool bCompatibility = ( GetSbData()->pInst && GetSbData()->pInst->IsCompatibility() ); 1513 if( bCompatibility ) 1514 { 1515 bTextMode = IsImageFlag( SbiImageFlags::COMPARETEXT ); 1516 } 1517 if( bTextMode ) 1518 { 1519 aSearchOpt.transliterateFlags |= TransliterationFlags::IGNORE_CASE; 1520 } 1521 SbxVariable* pRes = new SbxVariable; 1522 utl::TextSearch aSearch( aSearchOpt); 1523 sal_Int32 nStart=0, nEnd=value.getLength(); 1524 bool bRes = aSearch.SearchForward(value, &nStart, &nEnd); 1525 pRes->PutBool( bRes ); 1526 1527 PushVar( pRes ); 1528 } 1529 1530 // TOS and TOS-1 are both object variables and contain the same pointer 1531 1532 void SbiRuntime::StepIS() 1533 { 1534 SbxVariableRef refVar1 = PopVar(); 1535 SbxVariableRef refVar2 = PopVar(); 1536 1537 SbxDataType eType1 = refVar1->GetType(); 1538 SbxDataType eType2 = refVar2->GetType(); 1539 if ( eType1 == SbxEMPTY ) 1540 { 1541 refVar1->Broadcast( SfxHintId::BasicDataWanted ); 1542 eType1 = refVar1->GetType(); 1543 } 1544 if ( eType2 == SbxEMPTY ) 1545 { 1546 refVar2->Broadcast( SfxHintId::BasicDataWanted ); 1547 eType2 = refVar2->GetType(); 1548 } 1549 1550 bool bRes = ( eType1 == SbxOBJECT && eType2 == SbxOBJECT ); 1551 if ( bVBAEnabled && !bRes ) 1552 { 1553 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1554 } 1555 bRes = ( bRes && refVar1->GetObject() == refVar2->GetObject() ); 1556 SbxVariable* pRes = new SbxVariable; 1557 pRes->PutBool( bRes ); 1558 PushVar( pRes ); 1559 } 1560 1561 // update the value of TOS 1562 1563 void SbiRuntime::StepGET() 1564 { 1565 SbxVariable* p = GetTOS(); 1566 p->Broadcast( SfxHintId::BasicDataWanted ); 1567 } 1568 1569 // #67607 copy Uno-Structs 1570 static bool checkUnoStructCopy( bool bVBA, SbxVariableRef const & refVal, SbxVariableRef const & refVar ) 1571 { 1572 SbxDataType eVarType = refVar->GetType(); 1573 SbxDataType eValType = refVal->GetType(); 1574 1575 if ( ( bVBA && ( eVarType == SbxEMPTY ) ) || !refVar->CanWrite() ) 1576 return false; 1577 1578 if ( eValType != SbxOBJECT ) 1579 return false; 1580 // we seem to be duplicating parts of SbxValue=operator, maybe we should just move this to 1581 // there :-/ not sure if for every '=' we would want struct handling 1582 if( eVarType != SbxOBJECT ) 1583 { 1584 if ( refVar->IsFixed() ) 1585 return false; 1586 } 1587 // #115826: Exclude ProcedureProperties to avoid call to Property Get procedure 1588 else if( dynamic_cast<const SbProcedureProperty*>( refVar.get() ) != nullptr ) 1589 return false; 1590 1591 SbxObjectRef xValObj = static_cast<SbxObject*>(refVal->GetObject()); 1592 if( !xValObj.is() || dynamic_cast<const SbUnoAnyObject*>( xValObj.get() ) != nullptr ) 1593 return false; 1594 1595 SbUnoObject* pUnoVal = dynamic_cast<SbUnoObject*>( xValObj.get() ); 1596 SbUnoStructRefObject* pUnoStructVal = dynamic_cast<SbUnoStructRefObject*>( xValObj.get() ); 1597 Any aAny; 1598 // make doubly sure value is either a Uno object or 1599 // a uno struct 1600 if ( pUnoVal || pUnoStructVal ) 1601 aAny = pUnoVal ? pUnoVal->getUnoAny() : pUnoStructVal->getUnoAny(); 1602 else 1603 return false; 1604 if ( aAny.getValueType().getTypeClass() == TypeClass_STRUCT ) 1605 { 1606 refVar->SetType( SbxOBJECT ); 1607 ErrCode eOldErr = SbxBase::GetError(); 1608 // There are some circumstances when calling GetObject 1609 // will trigger an error, we need to squash those here. 1610 // Alternatively it is possible that the same scenario 1611 // could overwrite and existing error. Lets prevent that 1612 SbxObjectRef xVarObj = static_cast<SbxObject*>(refVar->GetObject()); 1613 if ( eOldErr != ERRCODE_NONE ) 1614 SbxBase::SetError( eOldErr ); 1615 else 1616 SbxBase::ResetError(); 1617 1618 SbUnoStructRefObject* pUnoStructObj = dynamic_cast<SbUnoStructRefObject*>( xVarObj.get() ); 1619 1620 OUString sClassName = pUnoVal ? pUnoVal->GetClassName() : pUnoStructVal->GetClassName(); 1621 OUString sName = pUnoVal ? pUnoVal->GetName() : pUnoStructVal->GetName(); 1622 1623 if ( pUnoStructObj ) 1624 { 1625 StructRefInfo aInfo = pUnoStructObj->getStructInfo(); 1626 aInfo.setValue( aAny ); 1627 } 1628 else 1629 { 1630 SbUnoObject* pNewUnoObj = new SbUnoObject( sName, aAny ); 1631 // #70324: adopt ClassName 1632 pNewUnoObj->SetClassName( sClassName ); 1633 refVar->PutObject( pNewUnoObj ); 1634 } 1635 return true; 1636 } 1637 return false; 1638 } 1639 1640 1641 // laying down TOS in TOS-1 1642 1643 void SbiRuntime::StepPUT() 1644 { 1645 SbxVariableRef refVal = PopVar(); 1646 SbxVariableRef refVar = PopVar(); 1647 // store on its own method (inside a function)? 1648 bool bFlagsChanged = false; 1649 SbxFlagBits n = SbxFlagBits::NONE; 1650 if( refVar.get() == pMeth ) 1651 { 1652 bFlagsChanged = true; 1653 n = refVar->GetFlags(); 1654 refVar->SetFlag( SbxFlagBits::Write ); 1655 } 1656 1657 // if left side arg is an object or variant and right handside isn't 1658 // either an object or a variant then try and see if a default 1659 // property exists. 1660 // to use e.g. Range{"A1") = 34 1661 // could equate to Range("A1").Value = 34 1662 if ( bVBAEnabled ) 1663 { 1664 // yet more hacking at this, I feel we don't quite have the correct 1665 // heuristics for dealing with obj1 = obj2 ( where obj2 ( and maybe 1666 // obj1 ) has default member/property ) ) It seems that default props 1667 // aren't dealt with if the object is a member of some parent object 1668 bool bObjAssign = false; 1669 if ( refVar->GetType() == SbxEMPTY ) 1670 refVar->Broadcast( SfxHintId::BasicDataWanted ); 1671 if ( refVar->GetType() == SbxOBJECT ) 1672 { 1673 if ( dynamic_cast<const SbxMethod *>(refVar.get()) != nullptr || ! refVar->GetParent() ) 1674 { 1675 SbxVariable* pDflt = getDefaultProp( refVar.get() ); 1676 1677 if ( pDflt ) 1678 refVar = pDflt; 1679 } 1680 else 1681 bObjAssign = true; 1682 } 1683 if ( refVal->GetType() == SbxOBJECT && !bObjAssign && ( dynamic_cast<const SbxMethod *>(refVal.get()) != nullptr || ! refVal->GetParent() ) ) 1684 { 1685 SbxVariable* pDflt = getDefaultProp( refVal.get() ); 1686 if ( pDflt ) 1687 refVal = pDflt; 1688 } 1689 } 1690 1691 if ( !checkUnoStructCopy( bVBAEnabled, refVal, refVar ) ) 1692 *refVar = *refVal; 1693 1694 if( bFlagsChanged ) 1695 refVar->SetFlags( n ); 1696 } 1697 1698 namespace { 1699 1700 // VBA Dim As New behavior handling, save init object information 1701 struct DimAsNewRecoverItem 1702 { 1703 OUString m_aObjClass; 1704 OUString m_aObjName; 1705 SbxObject* m_pObjParent; 1706 SbModule* m_pClassModule; 1707 1708 DimAsNewRecoverItem() 1709 : m_pObjParent( nullptr ) 1710 , m_pClassModule( nullptr ) 1711 {} 1712 1713 DimAsNewRecoverItem( const OUString& rObjClass, const OUString& rObjName, 1714 SbxObject* pObjParent, SbModule* pClassModule ) 1715 : m_aObjClass( rObjClass ) 1716 , m_aObjName( rObjName ) 1717 , m_pObjParent( pObjParent ) 1718 , m_pClassModule( pClassModule ) 1719 {} 1720 1721 }; 1722 1723 1724 struct SbxVariablePtrHash 1725 { 1726 size_t operator()( SbxVariable* pVar ) const 1727 { return reinterpret_cast<size_t>(pVar); } 1728 }; 1729 1730 } 1731 1732 typedef std::unordered_map< SbxVariable*, DimAsNewRecoverItem, 1733 SbxVariablePtrHash > DimAsNewRecoverHash; 1734 1735 namespace { 1736 1737 class GaDimAsNewRecoverHash : public rtl::Static<DimAsNewRecoverHash, GaDimAsNewRecoverHash> {}; 1738 1739 } 1740 1741 void removeDimAsNewRecoverItem( SbxVariable* pVar ) 1742 { 1743 DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get(); 1744 DimAsNewRecoverHash::iterator it = rDimAsNewRecoverHash.find( pVar ); 1745 if( it != rDimAsNewRecoverHash.end() ) 1746 { 1747 rDimAsNewRecoverHash.erase( it ); 1748 } 1749 } 1750 1751 1752 // saving object variable 1753 // not-object variables will cause errors 1754 1755 static const char pCollectionStr[] = "Collection"; 1756 1757 void SbiRuntime::StepSET_Impl( SbxVariableRef& refVal, SbxVariableRef& refVar, bool bHandleDefaultProp ) 1758 { 1759 // #67733 types with array-flag are OK too 1760 1761 // Check var, !object is no error for sure if, only if type is fixed 1762 SbxDataType eVarType = refVar->GetType(); 1763 if( !bHandleDefaultProp && eVarType != SbxOBJECT && !(eVarType & SbxARRAY) && refVar->IsFixed() ) 1764 { 1765 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1766 return; 1767 } 1768 1769 // Check value, !object is no error for sure if, only if type is fixed 1770 SbxDataType eValType = refVal->GetType(); 1771 if( !bHandleDefaultProp && eValType != SbxOBJECT && !(eValType & SbxARRAY) && refVal->IsFixed() ) 1772 { 1773 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1774 return; 1775 } 1776 1777 // Getting in here causes problems with objects with default properties 1778 // if they are SbxEMPTY I guess 1779 if ( !bHandleDefaultProp || eValType == SbxOBJECT ) 1780 { 1781 // activate GetObject for collections on refVal 1782 SbxBase* pObjVarObj = refVal->GetObject(); 1783 if( pObjVarObj ) 1784 { 1785 SbxVariableRef refObjVal = dynamic_cast<SbxObject*>( pObjVarObj ); 1786 1787 if( refObjVal.is() ) 1788 { 1789 refVal = refObjVal; 1790 } 1791 else if( !(eValType & SbxARRAY) ) 1792 { 1793 refVal = nullptr; 1794 } 1795 } 1796 } 1797 1798 // #52896 refVal can be invalid here, if uno-sequences - or more 1799 // general arrays - are assigned to variables that are declared 1800 // as an object! 1801 if( !refVal.is() ) 1802 { 1803 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 1804 } 1805 else 1806 { 1807 bool bFlagsChanged = false; 1808 SbxFlagBits n = SbxFlagBits::NONE; 1809 if( refVar.get() == pMeth ) 1810 { 1811 bFlagsChanged = true; 1812 n = refVar->GetFlags(); 1813 refVar->SetFlag( SbxFlagBits::Write ); 1814 } 1815 SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( refVar.get() ); 1816 if( pProcProperty ) 1817 { 1818 pProcProperty->setSet( true ); 1819 } 1820 if ( bHandleDefaultProp ) 1821 { 1822 // get default properties for lhs & rhs where necessary 1823 // SbxVariable* defaultProp = NULL; unused variable 1824 // LHS try determine if a default prop exists 1825 // again like in StepPUT (see there too ) we are tweaking the 1826 // heuristics again for when to assign an object reference or 1827 // use default members if they exist 1828 // #FIXME we really need to get to the bottom of this mess 1829 bool bObjAssign = false; 1830 if ( refVar->GetType() == SbxOBJECT ) 1831 { 1832 if ( dynamic_cast<const SbxMethod *>(refVar.get()) != nullptr || ! refVar->GetParent() ) 1833 { 1834 SbxVariable* pDflt = getDefaultProp( refVar.get() ); 1835 if ( pDflt ) 1836 { 1837 refVar = pDflt; 1838 } 1839 } 1840 else 1841 bObjAssign = true; 1842 } 1843 // RHS only get a default prop is the rhs has one 1844 if ( refVal->GetType() == SbxOBJECT ) 1845 { 1846 // check if lhs is a null object 1847 // if it is then use the object not the default property 1848 SbxObject* pObj = dynamic_cast<SbxObject*>( refVar.get() ); 1849 1850 // calling GetObject on a SbxEMPTY variable raises 1851 // object not set errors, make sure it's an Object 1852 if ( !pObj && refVar->GetType() == SbxOBJECT ) 1853 { 1854 SbxBase* pObjVarObj = refVar->GetObject(); 1855 pObj = dynamic_cast<SbxObject*>( pObjVarObj ); 1856 } 1857 SbxVariable* pDflt = nullptr; 1858 if ( pObj && !bObjAssign ) 1859 { 1860 // lhs is either a valid object || or has a defaultProp 1861 pDflt = getDefaultProp( refVal.get() ); 1862 } 1863 if ( pDflt ) 1864 { 1865 refVal = pDflt; 1866 } 1867 } 1868 } 1869 1870 // Handle Dim As New 1871 bool bDimAsNew = bVBAEnabled && refVar->IsSet( SbxFlagBits::DimAsNew ); 1872 SbxBaseRef xPrevVarObj; 1873 if( bDimAsNew ) 1874 { 1875 xPrevVarObj = refVar->GetObject(); 1876 } 1877 // Handle withevents 1878 bool bWithEvents = refVar->IsSet( SbxFlagBits::WithEvents ); 1879 if ( bWithEvents ) 1880 { 1881 Reference< XInterface > xComListener; 1882 1883 SbxBase* pObj = refVal->GetObject(); 1884 SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj ); 1885 if( pUnoObj != nullptr ) 1886 { 1887 Any aControlAny = pUnoObj->getUnoAny(); 1888 OUString aDeclareClassName = refVar->GetDeclareClassName(); 1889 OUString aPrefix = refVar->GetName(); 1890 SbxObjectRef xScopeObj = refVar->GetParent(); 1891 xComListener = createComListener( aControlAny, aDeclareClassName, aPrefix, xScopeObj ); 1892 1893 refVal->SetDeclareClassName( aDeclareClassName ); 1894 refVal->SetComListener( xComListener, &rBasic ); // Hold reference 1895 } 1896 1897 } 1898 1899 // lhs is a property who's value is currently (Empty e.g. no broadcast yet) 1900 // in this case if there is a default prop involved the value of the 1901 // default property may in fact be void so the type will also be SbxEMPTY 1902 // in this case we do not want to call checkUnoStructCopy 'cause that will 1903 // cause an error also 1904 if ( !checkUnoStructCopy( bHandleDefaultProp, refVal, refVar ) ) 1905 { 1906 *refVar = *refVal; 1907 } 1908 if ( bDimAsNew ) 1909 { 1910 if( dynamic_cast<const SbxObject*>( refVar.get() ) == nullptr ) 1911 { 1912 SbxBase* pValObjBase = refVal->GetObject(); 1913 if( pValObjBase == nullptr ) 1914 { 1915 if( xPrevVarObj.is() ) 1916 { 1917 // Object is overwritten with NULL, instantiate init object 1918 DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get(); 1919 DimAsNewRecoverHash::iterator it = rDimAsNewRecoverHash.find( refVar.get() ); 1920 if( it != rDimAsNewRecoverHash.end() ) 1921 { 1922 const DimAsNewRecoverItem& rItem = it->second; 1923 if( rItem.m_pClassModule != nullptr ) 1924 { 1925 SbClassModuleObject* pNewObj = new SbClassModuleObject( rItem.m_pClassModule ); 1926 pNewObj->SetName( rItem.m_aObjName ); 1927 pNewObj->SetParent( rItem.m_pObjParent ); 1928 refVar->PutObject( pNewObj ); 1929 } 1930 else if( rItem.m_aObjClass.equalsIgnoreAsciiCase( pCollectionStr ) ) 1931 { 1932 BasicCollection* pNewCollection = new BasicCollection( pCollectionStr ); 1933 pNewCollection->SetName( rItem.m_aObjName ); 1934 pNewCollection->SetParent( rItem.m_pObjParent ); 1935 refVar->PutObject( pNewCollection ); 1936 } 1937 } 1938 } 1939 } 1940 else 1941 { 1942 // Does old value exist? 1943 bool bFirstInit = !xPrevVarObj.is(); 1944 if( bFirstInit ) 1945 { 1946 // Store information to instantiate object later 1947 SbxObject* pValObj = dynamic_cast<SbxObject*>( pValObjBase ); 1948 if( pValObj != nullptr ) 1949 { 1950 OUString aObjClass = pValObj->GetClassName(); 1951 1952 SbClassModuleObject* pClassModuleObj = dynamic_cast<SbClassModuleObject*>( pValObjBase ); 1953 DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get(); 1954 if( pClassModuleObj != nullptr ) 1955 { 1956 SbModule* pClassModule = pClassModuleObj->getClassModule(); 1957 rDimAsNewRecoverHash[refVar.get()] = 1958 DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), pClassModule ); 1959 } 1960 else if( aObjClass.equalsIgnoreAsciiCase( "Collection" ) ) 1961 { 1962 rDimAsNewRecoverHash[refVar.get()] = 1963 DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), nullptr ); 1964 } 1965 } 1966 } 1967 } 1968 } 1969 } 1970 1971 if( bFlagsChanged ) 1972 { 1973 refVar->SetFlags( n ); 1974 } 1975 } 1976 } 1977 1978 void SbiRuntime::StepSET() 1979 { 1980 SbxVariableRef refVal = PopVar(); 1981 SbxVariableRef refVar = PopVar(); 1982 StepSET_Impl( refVal, refVar, bVBAEnabled ); // this is really assignment 1983 } 1984 1985 void SbiRuntime::StepVBASET() 1986 { 1987 SbxVariableRef refVal = PopVar(); 1988 SbxVariableRef refVar = PopVar(); 1989 // don't handle default property 1990 StepSET_Impl( refVal, refVar ); // set obj = something 1991 } 1992 1993 1994 void SbiRuntime::StepLSET() 1995 { 1996 SbxVariableRef refVal = PopVar(); 1997 SbxVariableRef refVar = PopVar(); 1998 if( refVar->GetType() != SbxSTRING || 1999 refVal->GetType() != SbxSTRING ) 2000 { 2001 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 2002 } 2003 else 2004 { 2005 SbxFlagBits n = refVar->GetFlags(); 2006 if( refVar.get() == pMeth ) 2007 { 2008 refVar->SetFlag( SbxFlagBits::Write ); 2009 } 2010 OUString aRefVarString = refVar->GetOUString(); 2011 OUString aRefValString = refVal->GetOUString(); 2012 2013 sal_Int32 nVarStrLen = aRefVarString.getLength(); 2014 sal_Int32 nValStrLen = aRefValString.getLength(); 2015 OUString aNewStr; 2016 if( nVarStrLen > nValStrLen ) 2017 { 2018 OUStringBuffer buf(aRefValString); 2019 comphelper::string::padToLength(buf, nVarStrLen, ' '); 2020 aNewStr = buf.makeStringAndClear(); 2021 } 2022 else 2023 { 2024 aNewStr = aRefValString.copy( 0, nVarStrLen ); 2025 } 2026 2027 refVar->PutString(aNewStr); 2028 refVar->SetFlags( n ); 2029 } 2030 } 2031 2032 void SbiRuntime::StepRSET() 2033 { 2034 SbxVariableRef refVal = PopVar(); 2035 SbxVariableRef refVar = PopVar(); 2036 if( refVar->GetType() != SbxSTRING || refVal->GetType() != SbxSTRING ) 2037 { 2038 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 2039 } 2040 else 2041 { 2042 SbxFlagBits n = refVar->GetFlags(); 2043 if( refVar.get() == pMeth ) 2044 { 2045 refVar->SetFlag( SbxFlagBits::Write ); 2046 } 2047 OUString aRefVarString = refVar->GetOUString(); 2048 OUString aRefValString = refVal->GetOUString(); 2049 sal_Int32 nVarStrLen = aRefVarString.getLength(); 2050 sal_Int32 nValStrLen = aRefValString.getLength(); 2051 2052 OUStringBuffer aNewStr(nVarStrLen); 2053 if (nVarStrLen > nValStrLen) 2054 { 2055 comphelper::string::padToLength(aNewStr, nVarStrLen - nValStrLen, ' '); 2056 aNewStr.append(aRefValString); 2057 } 2058 else 2059 { 2060 aNewStr.append(std::u16string_view(aRefValString).substr(0, nVarStrLen)); 2061 } 2062 refVar->PutString(aNewStr.makeStringAndClear()); 2063 2064 refVar->SetFlags( n ); 2065 } 2066 } 2067 2068 // laying down TOS in TOS-1, then set ReadOnly-Bit 2069 2070 void SbiRuntime::StepPUTC() 2071 { 2072 SbxVariableRef refVal = PopVar(); 2073 SbxVariableRef refVar = PopVar(); 2074 refVar->SetFlag( SbxFlagBits::Write ); 2075 *refVar = *refVal; 2076 refVar->ResetFlag( SbxFlagBits::Write ); 2077 refVar->SetFlag( SbxFlagBits::Const ); 2078 } 2079 2080 // DIM 2081 // TOS = variable for the array with dimension information as parameter 2082 2083 void SbiRuntime::StepDIM() 2084 { 2085 SbxVariableRef refVar = PopVar(); 2086 DimImpl( refVar ); 2087 } 2088 2089 // #56204 swap out DIM-functionality into a help method (step0.cxx) 2090 void SbiRuntime::DimImpl(const SbxVariableRef& refVar) 2091 { 2092 // If refDim then this DIM statement is terminating a ReDIM and 2093 // previous StepERASE_CLEAR for an array, the following actions have 2094 // been delayed from ( StepERASE_CLEAR ) 'till here 2095 if ( refRedim.is() ) 2096 { 2097 if ( !refRedimpArray.is() ) // only erase the array not ReDim Preserve 2098 { 2099 lcl_eraseImpl( refVar, bVBAEnabled ); 2100 } 2101 SbxDataType eType = refVar->GetType(); 2102 lcl_clearImpl( refVar, eType ); 2103 refRedim = nullptr; 2104 } 2105 SbxArray* pDims = refVar->GetParameters(); 2106 // must have an even number of arguments 2107 // have in mind that Arg[0] does not count! 2108 if( pDims && !( pDims->Count() & 1 ) ) 2109 { 2110 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2111 } 2112 else 2113 { 2114 SbxDataType eType = refVar->IsFixed() ? refVar->GetType() : SbxVARIANT; 2115 SbxDimArray* pArray = new SbxDimArray( eType ); 2116 // allow arrays without dimension information, too (VB-compatible) 2117 if( pDims ) 2118 { 2119 refVar->ResetFlag( SbxFlagBits::VarToDim ); 2120 2121 for( sal_uInt16 i = 1; i < pDims->Count(); ) 2122 { 2123 sal_Int32 lb = pDims->Get( i++ )->GetLong(); 2124 sal_Int32 ub = pDims->Get( i++ )->GetLong(); 2125 if( ub < lb ) 2126 { 2127 Error( ERRCODE_BASIC_OUT_OF_RANGE ); 2128 ub = lb; 2129 } 2130 pArray->AddDim32( lb, ub ); 2131 if ( lb != ub ) 2132 { 2133 pArray->setHasFixedSize( true ); 2134 } 2135 } 2136 } 2137 else 2138 { 2139 // #62867 On creating an array of the length 0, create 2140 // a dimension (like for Uno-Sequences of the length 0) 2141 pArray->unoAddDim( 0, -1 ); 2142 } 2143 SbxFlagBits nSavFlags = refVar->GetFlags(); 2144 refVar->ResetFlag( SbxFlagBits::Fixed ); 2145 refVar->PutObject( pArray ); 2146 refVar->SetFlags( nSavFlags ); 2147 refVar->SetParameters( nullptr ); 2148 } 2149 } 2150 2151 // REDIM 2152 // TOS = variable for the array 2153 // argv = dimension information 2154 2155 void SbiRuntime::StepREDIM() 2156 { 2157 // Nothing different than dim at the moment because 2158 // a double dim is already recognized by the compiler. 2159 StepDIM(); 2160 } 2161 2162 2163 // Helper function for StepREDIMP 2164 static void implCopyDimArray( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex, 2165 short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds ) 2166 { 2167 sal_Int32& ri = pActualIndices[nActualDim]; 2168 for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ ) 2169 { 2170 if( nActualDim < nMaxDimIndex ) 2171 { 2172 implCopyDimArray( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1, 2173 pActualIndices, pLowerBounds, pUpperBounds ); 2174 } 2175 else 2176 { 2177 SbxVariable* pSource = pOldArray->Get32( pActualIndices ); 2178 SbxVariable* pDest = pNewArray->Get32( pActualIndices ); 2179 if( pSource && pDest ) 2180 { 2181 *pDest = *pSource; 2182 } 2183 } 2184 } 2185 } 2186 2187 // REDIM PRESERVE 2188 // TOS = variable for the array 2189 // argv = dimension information 2190 2191 void SbiRuntime::StepREDIMP() 2192 { 2193 SbxVariableRef refVar = PopVar(); 2194 DimImpl( refVar ); 2195 2196 // Now check, if we can copy from the old array 2197 if( refRedimpArray.is() ) 2198 { 2199 SbxBase* pElemObj = refVar->GetObject(); 2200 SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>( pElemObj ); 2201 SbxDimArray* pOldArray = static_cast<SbxDimArray*>(refRedimpArray.get()); 2202 if( pNewArray ) 2203 { 2204 short nDimsNew = pNewArray->GetDims(); 2205 short nDimsOld = pOldArray->GetDims(); 2206 short nDims = nDimsNew; 2207 2208 if( nDimsOld != nDimsNew ) 2209 { 2210 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE ); 2211 } 2212 else if (nDims > 0) 2213 { 2214 // Store dims to use them for copying later 2215 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]); 2216 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]); 2217 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]); 2218 2219 // Compare bounds 2220 for( short i = 1 ; i <= nDims ; i++ ) 2221 { 2222 sal_Int32 lBoundNew, uBoundNew; 2223 sal_Int32 lBoundOld, uBoundOld; 2224 pNewArray->GetDim32( i, lBoundNew, uBoundNew ); 2225 pOldArray->GetDim32( i, lBoundOld, uBoundOld ); 2226 lBoundNew = std::max( lBoundNew, lBoundOld ); 2227 uBoundNew = std::min( uBoundNew, uBoundOld ); 2228 short j = i - 1; 2229 pActualIndices[j] = pLowerBounds[j] = lBoundNew; 2230 pUpperBounds[j] = uBoundNew; 2231 } 2232 // Copy data from old array by going recursively through all dimensions 2233 // (It would be faster to work on the flat internal data array of an 2234 // SbyArray but this solution is clearer and easier) 2235 implCopyDimArray( pNewArray, pOldArray, nDims - 1, 2236 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() ); 2237 } 2238 2239 refRedimpArray = nullptr; 2240 } 2241 } 2242 2243 } 2244 2245 // REDIM_COPY 2246 // TOS = Array-Variable, Reference to array is copied 2247 // Variable is cleared as in ERASE 2248 2249 void SbiRuntime::StepREDIMP_ERASE() 2250 { 2251 SbxVariableRef refVar = PopVar(); 2252 refRedim = refVar; 2253 SbxDataType eType = refVar->GetType(); 2254 if( eType & SbxARRAY ) 2255 { 2256 SbxBase* pElemObj = refVar->GetObject(); 2257 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj ); 2258 if( pDimArray ) 2259 { 2260 refRedimpArray = pDimArray; 2261 } 2262 2263 } 2264 else if( refVar->IsFixed() ) 2265 { 2266 refVar->Clear(); 2267 } 2268 else 2269 { 2270 refVar->SetType( SbxEMPTY ); 2271 } 2272 } 2273 2274 static void lcl_clearImpl( SbxVariableRef const & refVar, SbxDataType const & eType ) 2275 { 2276 SbxFlagBits nSavFlags = refVar->GetFlags(); 2277 refVar->ResetFlag( SbxFlagBits::Fixed ); 2278 refVar->SetType( SbxDataType(eType & 0x0FFF) ); 2279 refVar->SetFlags( nSavFlags ); 2280 refVar->Clear(); 2281 } 2282 2283 static void lcl_eraseImpl( SbxVariableRef const & refVar, bool bVBAEnabled ) 2284 { 2285 SbxDataType eType = refVar->GetType(); 2286 if( eType & SbxARRAY ) 2287 { 2288 if ( bVBAEnabled ) 2289 { 2290 SbxBase* pElemObj = refVar->GetObject(); 2291 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj ); 2292 if( pDimArray ) 2293 { 2294 if ( pDimArray->hasFixedSize() ) 2295 { 2296 // Clear all Value(s) 2297 pDimArray->SbxArray::Clear(); 2298 } 2299 else 2300 { 2301 pDimArray->Clear(); // clear dims and values 2302 } 2303 } 2304 else 2305 { 2306 SbxArray* pArray = dynamic_cast<SbxArray*>( pElemObj ); 2307 if ( pArray ) 2308 { 2309 pArray->Clear(); 2310 } 2311 } 2312 } 2313 else 2314 { 2315 // Arrays have on an erase to VB quite a complex behaviour. Here are 2316 // only the type problems at REDIM (#26295) removed at first: 2317 // Set type hard onto the array-type, because a variable with array is 2318 // SbxOBJECT. At REDIM there's an SbxOBJECT-array generated then and 2319 // the original type is lost -> runtime error 2320 lcl_clearImpl( refVar, eType ); 2321 } 2322 } 2323 else if( refVar->IsFixed() ) 2324 { 2325 refVar->Clear(); 2326 } 2327 else 2328 { 2329 refVar->SetType( SbxEMPTY ); 2330 } 2331 } 2332 2333 // delete variable 2334 // TOS = variable 2335 2336 void SbiRuntime::StepERASE() 2337 { 2338 SbxVariableRef refVar = PopVar(); 2339 lcl_eraseImpl( refVar, bVBAEnabled ); 2340 } 2341 2342 void SbiRuntime::StepERASE_CLEAR() 2343 { 2344 refRedim = PopVar(); 2345 } 2346 2347 void SbiRuntime::StepARRAYACCESS() 2348 { 2349 if( !refArgv.is() ) 2350 { 2351 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2352 } 2353 SbxVariableRef refVar = PopVar(); 2354 refVar->SetParameters( refArgv.get() ); 2355 PopArgv(); 2356 PushVar( CheckArray( refVar.get() ) ); 2357 } 2358 2359 void SbiRuntime::StepBYVAL() 2360 { 2361 // Copy variable on stack to break call by reference 2362 SbxVariableRef pVar = PopVar(); 2363 SbxDataType t = pVar->GetType(); 2364 2365 SbxVariable* pCopyVar = new SbxVariable( t ); 2366 pCopyVar->SetFlag( SbxFlagBits::ReadWrite ); 2367 *pCopyVar = *pVar; 2368 2369 PushVar( pCopyVar ); 2370 } 2371 2372 // establishing an argv 2373 // nOp1 stays as it is -> 1st element is the return value 2374 2375 void SbiRuntime::StepARGC() 2376 { 2377 PushArgv(); 2378 refArgv = new SbxArray; 2379 nArgc = 1; 2380 } 2381 2382 // storing an argument in Argv 2383 2384 void SbiRuntime::StepARGV() 2385 { 2386 if( !refArgv.is() ) 2387 { 2388 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2389 } 2390 else 2391 { 2392 SbxVariableRef pVal = PopVar(); 2393 2394 // Before fix of #94916: 2395 if( dynamic_cast<const SbxMethod*>( pVal.get() ) != nullptr 2396 || dynamic_cast<const SbUnoProperty*>( pVal.get() ) != nullptr 2397 || dynamic_cast<const SbProcedureProperty*>( pVal.get() ) != nullptr ) 2398 { 2399 // evaluate methods and properties! 2400 SbxVariable* pRes = new SbxVariable( *pVal ); 2401 pVal = pRes; 2402 } 2403 refArgv->Put( pVal.get(), nArgc++ ); 2404 } 2405 } 2406 2407 // Input to Variable. The variable is on TOS and is 2408 // is removed afterwards. 2409 void SbiRuntime::StepINPUT() 2410 { 2411 OUStringBuffer sin; 2412 OUString s; 2413 char ch = 0; 2414 ErrCode err; 2415 // Skip whitespace 2416 while( ( err = pIosys->GetError() ) == ERRCODE_NONE ) 2417 { 2418 ch = pIosys->Read(); 2419 if( ch != ' ' && ch != '\t' && ch != '\n' ) 2420 { 2421 break; 2422 } 2423 } 2424 if( !err ) 2425 { 2426 // Scan until comma or whitespace 2427 char sep = ( ch == '"' ) ? ch : 0; 2428 if( sep ) 2429 { 2430 ch = pIosys->Read(); 2431 } 2432 while( ( err = pIosys->GetError() ) == ERRCODE_NONE ) 2433 { 2434 if( ch == sep ) 2435 { 2436 ch = pIosys->Read(); 2437 if( ch != sep ) 2438 { 2439 break; 2440 } 2441 } 2442 else if( !sep && (ch == ',' || ch == '\n') ) 2443 { 2444 break; 2445 } 2446 sin.append( ch ); 2447 ch = pIosys->Read(); 2448 } 2449 // skip whitespace 2450 if( ch == ' ' || ch == '\t' ) 2451 { 2452 while( ( err = pIosys->GetError() ) == ERRCODE_NONE ) 2453 { 2454 if( ch != ' ' && ch != '\t' && ch != '\n' ) 2455 { 2456 break; 2457 } 2458 ch = pIosys->Read(); 2459 } 2460 } 2461 } 2462 if( !err ) 2463 { 2464 s = sin.makeStringAndClear(); 2465 SbxVariableRef pVar = GetTOS(); 2466 // try to fill the variable with a numeric value first, 2467 // then with a string value 2468 if( !pVar->IsFixed() || pVar->IsNumeric() ) 2469 { 2470 sal_uInt16 nLen = 0; 2471 if( !pVar->Scan( s, &nLen ) ) 2472 { 2473 err = SbxBase::GetError(); 2474 SbxBase::ResetError(); 2475 } 2476 // the value has to be scanned in completely 2477 else if( nLen != s.getLength() && !pVar->PutString( s ) ) 2478 { 2479 err = SbxBase::GetError(); 2480 SbxBase::ResetError(); 2481 } 2482 else if( nLen != s.getLength() && pVar->IsNumeric() ) 2483 { 2484 err = SbxBase::GetError(); 2485 SbxBase::ResetError(); 2486 if( !err ) 2487 { 2488 err = ERRCODE_BASIC_CONVERSION; 2489 } 2490 } 2491 } 2492 else 2493 { 2494 pVar->PutString( s ); 2495 err = SbxBase::GetError(); 2496 SbxBase::ResetError(); 2497 } 2498 } 2499 if( err == ERRCODE_BASIC_USER_ABORT ) 2500 { 2501 Error( err ); 2502 } 2503 else if( err ) 2504 { 2505 if( pRestart && !pIosys->GetChannel() ) 2506 { 2507 pCode = pRestart; 2508 } 2509 else 2510 { 2511 Error( err ); 2512 } 2513 } 2514 else 2515 { 2516 PopVar(); 2517 } 2518 } 2519 2520 // Line Input to Variable. The variable is on TOS and is 2521 // deleted afterwards. 2522 2523 void SbiRuntime::StepLINPUT() 2524 { 2525 OString aInput; 2526 pIosys->Read( aInput ); 2527 Error( pIosys->GetError() ); 2528 SbxVariableRef p = PopVar(); 2529 p->PutString(OStringToOUString(aInput, osl_getThreadTextEncoding())); 2530 } 2531 2532 // end of program 2533 2534 void SbiRuntime::StepSTOP() 2535 { 2536 pInst->Stop(); 2537 } 2538 2539 2540 void SbiRuntime::StepINITFOR() 2541 { 2542 PushFor(); 2543 } 2544 2545 void SbiRuntime::StepINITFOREACH() 2546 { 2547 PushForEach(); 2548 } 2549 2550 // increment FOR-variable 2551 2552 void SbiRuntime::StepNEXT() 2553 { 2554 if( !pForStk ) 2555 { 2556 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2557 return; 2558 } 2559 if( pForStk->eForType == ForType::To ) 2560 { 2561 pForStk->refVar->Compute( SbxPLUS, *pForStk->refInc ); 2562 } 2563 } 2564 2565 // beginning CASE: TOS in CASE-stack 2566 2567 void SbiRuntime::StepCASE() 2568 { 2569 if( !refCaseStk.is() ) 2570 { 2571 refCaseStk = new SbxArray; 2572 } 2573 SbxVariableRef xVar = PopVar(); 2574 refCaseStk->Put( xVar.get(), refCaseStk->Count() ); 2575 } 2576 2577 // end CASE: free variable 2578 2579 void SbiRuntime::StepENDCASE() 2580 { 2581 if( !refCaseStk.is() || !refCaseStk->Count() ) 2582 { 2583 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2584 } 2585 else 2586 { 2587 refCaseStk->Remove( refCaseStk->Count() - 1 ); 2588 } 2589 } 2590 2591 2592 void SbiRuntime::StepSTDERROR() 2593 { 2594 pError = nullptr; bError = true; 2595 pInst->aErrorMsg.clear(); 2596 pInst->nErr = ERRCODE_NONE; 2597 pInst->nErl = 0; 2598 nError = ERRCODE_NONE; 2599 SbxErrObject::getUnoErrObject()->Clear(); 2600 } 2601 2602 void SbiRuntime::StepNOERROR() 2603 { 2604 pInst->aErrorMsg.clear(); 2605 pInst->nErr = ERRCODE_NONE; 2606 pInst->nErl = 0; 2607 nError = ERRCODE_NONE; 2608 SbxErrObject::getUnoErrObject()->Clear(); 2609 bError = false; 2610 } 2611 2612 // leave UP 2613 2614 void SbiRuntime::StepLEAVE() 2615 { 2616 bRun = false; 2617 // If VBA and we are leaving an ErrorHandler then clear the error ( it's been processed ) 2618 if ( bInError && pError ) 2619 { 2620 SbxErrObject::getUnoErrObject()->Clear(); 2621 } 2622 } 2623 2624 void SbiRuntime::StepCHANNEL() // TOS = channel number 2625 { 2626 SbxVariableRef pChan = PopVar(); 2627 short nChan = pChan->GetInteger(); 2628 pIosys->SetChannel( nChan ); 2629 Error( pIosys->GetError() ); 2630 } 2631 2632 void SbiRuntime::StepCHANNEL0() 2633 { 2634 pIosys->ResetChannel(); 2635 } 2636 2637 void SbiRuntime::StepPRINT() // print TOS 2638 { 2639 SbxVariableRef p = PopVar(); 2640 OUString s1 = p->GetOUString(); 2641 OUString s; 2642 if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE ) 2643 { 2644 s = " "; // one blank before 2645 } 2646 s += s1; 2647 pIosys->Write( s ); 2648 Error( pIosys->GetError() ); 2649 } 2650 2651 void SbiRuntime::StepPRINTF() // print TOS in field 2652 { 2653 SbxVariableRef p = PopVar(); 2654 OUString s1 = p->GetOUString(); 2655 OUStringBuffer s; 2656 if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE ) 2657 { 2658 s.append(' '); 2659 } 2660 s.append(s1); 2661 comphelper::string::padToLength(s, 14, ' '); 2662 pIosys->Write( s.makeStringAndClear() ); 2663 Error( pIosys->GetError() ); 2664 } 2665 2666 void SbiRuntime::StepWRITE() // write TOS 2667 { 2668 SbxVariableRef p = PopVar(); 2669 // Does the string have to be encapsulated? 2670 char ch = 0; 2671 switch (p->GetType() ) 2672 { 2673 case SbxSTRING: ch = '"'; break; 2674 case SbxCURRENCY: 2675 case SbxBOOL: 2676 case SbxDATE: ch = '#'; break; 2677 default: break; 2678 } 2679 OUString s; 2680 if( ch ) 2681 { 2682 s += OUString(ch); 2683 } 2684 s += p->GetOUString(); 2685 if( ch ) 2686 { 2687 s += OUString(ch); 2688 } 2689 pIosys->Write( s ); 2690 Error( pIosys->GetError() ); 2691 } 2692 2693 void SbiRuntime::StepRENAME() // Rename Tos+1 to Tos 2694 { 2695 SbxVariableRef pTos1 = PopVar(); 2696 SbxVariableRef pTos = PopVar(); 2697 OUString aDest = pTos1->GetOUString(); 2698 OUString aSource = pTos->GetOUString(); 2699 2700 if( hasUno() ) 2701 { 2702 implStepRenameUCB( aSource, aDest ); 2703 } 2704 else 2705 { 2706 implStepRenameOSL( aSource, aDest ); 2707 } 2708 } 2709 2710 // TOS = Prompt 2711 2712 void SbiRuntime::StepPROMPT() 2713 { 2714 SbxVariableRef p = PopVar(); 2715 OString aStr(OUStringToOString(p->GetOUString(), osl_getThreadTextEncoding())); 2716 pIosys->SetPrompt( aStr ); 2717 } 2718 2719 // Set Restart point 2720 2721 void SbiRuntime::StepRESTART() 2722 { 2723 pRestart = pCode; 2724 } 2725 2726 // empty expression on stack for missing parameter 2727 2728 void SbiRuntime::StepEMPTY() 2729 { 2730 // #57915 The semantics of StepEMPTY() is the representation of a missing argument. 2731 // This is represented by the value 448 (ERRCODE_BASIC_NAMED_NOT_FOUND) of the type error 2732 // in VB. StepEmpty should now rather be named StepMISSING() but the name is kept 2733 // to simplify matters. 2734 SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); 2735 xVar->PutErr( 448 ); 2736 PushVar( xVar.get() ); 2737 } 2738 2739 // TOS = error code 2740 2741 void SbiRuntime::StepERROR() 2742 { 2743 SbxVariableRef refCode = PopVar(); 2744 sal_uInt16 n = refCode->GetUShort(); 2745 ErrCode error = StarBASIC::GetSfxFromVBError( n ); 2746 if ( bVBAEnabled ) 2747 { 2748 pInst->Error( error ); 2749 } 2750 else 2751 { 2752 Error( error ); 2753 } 2754 } 2755 2756 // loading a numeric constant (+ID) 2757 2758 void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 ) 2759 { 2760 SbxVariable* p = new SbxVariable( SbxDOUBLE ); 2761 2762 // #57844 use localized function 2763 OUString aStr = pImg->GetString( static_cast<short>( nOp1 ) ); 2764 // also allow , !!! 2765 sal_Int32 iComma = aStr.indexOf(','); 2766 if( iComma >= 0 ) 2767 { 2768 aStr = aStr.replaceAt(iComma, 1, "."); 2769 } 2770 double n = ::rtl::math::stringToDouble( aStr, '.', ',' ); 2771 2772 p->PutDouble( n ); 2773 PushVar( p ); 2774 } 2775 2776 // loading a string constant (+ID) 2777 2778 void SbiRuntime::StepLOADSC( sal_uInt32 nOp1 ) 2779 { 2780 SbxVariable* p = new SbxVariable; 2781 p->PutString( pImg->GetString( static_cast<short>( nOp1 ) ) ); 2782 PushVar( p ); 2783 } 2784 2785 // Immediate Load (+value) 2786 2787 void SbiRuntime::StepLOADI( sal_uInt32 nOp1 ) 2788 { 2789 SbxVariable* p = new SbxVariable; 2790 p->PutInteger( static_cast<sal_Int16>( nOp1 ) ); 2791 PushVar( p ); 2792 } 2793 2794 // store a named argument in Argv (+Arg-no. from 1!) 2795 2796 void SbiRuntime::StepARGN( sal_uInt32 nOp1 ) 2797 { 2798 if( !refArgv.is() ) 2799 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2800 else 2801 { 2802 OUString aAlias( pImg->GetString( static_cast<short>( nOp1 ) ) ); 2803 SbxVariableRef pVal = PopVar(); 2804 if( bVBAEnabled && 2805 ( dynamic_cast<const SbxMethod*>( pVal.get()) != nullptr 2806 || dynamic_cast<const SbUnoProperty*>( pVal.get()) != nullptr 2807 || dynamic_cast<const SbProcedureProperty*>( pVal.get()) != nullptr ) ) 2808 { 2809 // named variables ( that are Any especially properties ) can be empty at this point and need a broadcast 2810 if ( pVal->GetType() == SbxEMPTY ) 2811 pVal->Broadcast( SfxHintId::BasicDataWanted ); 2812 // evaluate methods and properties! 2813 SbxVariable* pRes = new SbxVariable( *pVal ); 2814 pVal = pRes; 2815 } 2816 refArgv->Put( pVal.get(), nArgc ); 2817 refArgv->PutAlias( aAlias, nArgc++ ); 2818 } 2819 } 2820 2821 // converting the type of an argument in Argv for DECLARE-Fkt. (+type) 2822 2823 void SbiRuntime::StepARGTYP( sal_uInt32 nOp1 ) 2824 { 2825 if( !refArgv.is() ) 2826 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2827 else 2828 { 2829 bool bByVal = (nOp1 & 0x8000) != 0; // Is BYVAL requested? 2830 SbxDataType t = static_cast<SbxDataType>(nOp1 & 0x7FFF); 2831 SbxVariable* pVar = refArgv->Get( refArgv->Count() - 1 ); // last Arg 2832 2833 // check BYVAL 2834 if( pVar->GetRefCount() > 2 ) // 2 is normal for BYVAL 2835 { 2836 // parameter is a reference 2837 if( bByVal ) 2838 { 2839 // Call by Value is requested -> create a copy 2840 pVar = new SbxVariable( *pVar ); 2841 pVar->SetFlag( SbxFlagBits::ReadWrite ); 2842 refExprStk->Put( pVar, refArgv->Count() - 1 ); 2843 } 2844 else 2845 pVar->SetFlag( SbxFlagBits::Reference ); // Ref-Flag for DllMgr 2846 } 2847 else 2848 { 2849 // parameter is NO reference 2850 if( bByVal ) 2851 pVar->ResetFlag( SbxFlagBits::Reference ); // no reference -> OK 2852 else 2853 Error( ERRCODE_BASIC_BAD_PARAMETERS ); // reference needed 2854 } 2855 2856 if( pVar->GetType() != t ) 2857 { 2858 // variant for correct conversion 2859 // besides error, if SbxBYREF 2860 pVar->Convert( SbxVARIANT ); 2861 pVar->Convert( t ); 2862 } 2863 } 2864 } 2865 2866 // bring string to a definite length (+length) 2867 2868 void SbiRuntime::StepPAD( sal_uInt32 nOp1 ) 2869 { 2870 SbxVariable* p = GetTOS(); 2871 OUString s = p->GetOUString(); 2872 sal_Int32 nLen(nOp1); 2873 if( s.getLength() != nLen ) 2874 { 2875 OUStringBuffer aBuf(s); 2876 if (aBuf.getLength() > nLen) 2877 { 2878 comphelper::string::truncateToLength(aBuf, nLen); 2879 } 2880 else 2881 { 2882 comphelper::string::padToLength(aBuf, nLen, ' '); 2883 } 2884 s = aBuf.makeStringAndClear(); 2885 } 2886 } 2887 2888 // jump (+target) 2889 2890 void SbiRuntime::StepJUMP( sal_uInt32 nOp1 ) 2891 { 2892 #ifdef DBG_UTIL 2893 // #QUESTION shouldn't this be 2894 // if( (sal_uInt8*)( nOp1+pImagGetCode() ) >= pImg->GetCodeSize() ) 2895 if( nOp1 >= pImg->GetCodeSize() ) 2896 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2897 #endif 2898 pCode = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nOp1; 2899 } 2900 2901 // evaluate TOS, conditional jump (+target) 2902 2903 void SbiRuntime::StepJUMPT( sal_uInt32 nOp1 ) 2904 { 2905 SbxVariableRef p = PopVar(); 2906 if( p->GetBool() ) 2907 StepJUMP( nOp1 ); 2908 } 2909 2910 // evaluate TOS, conditional jump (+target) 2911 2912 void SbiRuntime::StepJUMPF( sal_uInt32 nOp1 ) 2913 { 2914 SbxVariableRef p = PopVar(); 2915 // In a test e.g. If Null then 2916 // will evaluate Null will act as if False 2917 if( ( bVBAEnabled && p->IsNull() ) || !p->GetBool() ) 2918 StepJUMP( nOp1 ); 2919 } 2920 2921 // evaluate TOS, jump into JUMP-table (+MaxVal) 2922 // looks like this: 2923 // ONJUMP 2 2924 // JUMP target1 2925 // JUMP target2 2926 2927 // if 0x8000 is set in the operand, push the return address (ON..GOSUB) 2928 2929 void SbiRuntime::StepONJUMP( sal_uInt32 nOp1 ) 2930 { 2931 SbxVariableRef p = PopVar(); 2932 sal_Int16 n = p->GetInteger(); 2933 if( nOp1 & 0x8000 ) 2934 { 2935 nOp1 &= 0x7FFF; 2936 PushGosub( pCode + 5 * nOp1 ); 2937 } 2938 if( n < 1 || static_cast<sal_uInt32>(n) > nOp1 ) 2939 n = static_cast<sal_Int16>( nOp1 + 1 ); 2940 nOp1 = static_cast<sal_uInt32>( reinterpret_cast<const char*>(pCode) - pImg->GetCode() ) + 5 * --n; 2941 StepJUMP( nOp1 ); 2942 } 2943 2944 // UP-call (+target) 2945 2946 void SbiRuntime::StepGOSUB( sal_uInt32 nOp1 ) 2947 { 2948 PushGosub( pCode ); 2949 if( nOp1 >= pImg->GetCodeSize() ) 2950 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2951 pCode = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nOp1; 2952 } 2953 2954 // UP-return (+0 or target) 2955 2956 void SbiRuntime::StepRETURN( sal_uInt32 nOp1 ) 2957 { 2958 PopGosub(); 2959 if( nOp1 ) 2960 StepJUMP( nOp1 ); 2961 } 2962 2963 // check FOR-variable (+Endlabel) 2964 2965 void SbiRuntime::StepTESTFOR( sal_uInt32 nOp1 ) 2966 { 2967 if( !pForStk ) 2968 { 2969 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 2970 return; 2971 } 2972 2973 bool bEndLoop = false; 2974 switch( pForStk->eForType ) 2975 { 2976 case ForType::To: 2977 { 2978 SbxOperator eOp = ( pForStk->refInc->GetDouble() < 0 ) ? SbxLT : SbxGT; 2979 if( pForStk->refVar->Compare( eOp, *pForStk->refEnd ) ) 2980 bEndLoop = true; 2981 break; 2982 } 2983 case ForType::EachArray: 2984 { 2985 SbiForStack* p = pForStk; 2986 if( p->pArrayCurIndices == nullptr ) 2987 { 2988 bEndLoop = true; 2989 } 2990 else 2991 { 2992 SbxDimArray* pArray = reinterpret_cast<SbxDimArray*>(p->refEnd.get()); 2993 short nDims = pArray->GetDims(); 2994 2995 // Empty array? 2996 if( nDims == 1 && p->pArrayLowerBounds[0] > p->pArrayUpperBounds[0] ) 2997 { 2998 bEndLoop = true; 2999 break; 3000 } 3001 SbxVariable* pVal = pArray->Get32( p->pArrayCurIndices.get() ); 3002 *(p->refVar) = *pVal; 3003 3004 bool bFoundNext = false; 3005 for( short i = 0 ; i < nDims ; i++ ) 3006 { 3007 if( p->pArrayCurIndices[i] < p->pArrayUpperBounds[i] ) 3008 { 3009 bFoundNext = true; 3010 p->pArrayCurIndices[i]++; 3011 for( short j = i - 1 ; j >= 0 ; j-- ) 3012 p->pArrayCurIndices[j] = p->pArrayLowerBounds[j]; 3013 break; 3014 } 3015 } 3016 if( !bFoundNext ) 3017 { 3018 p->pArrayCurIndices.reset(); 3019 } 3020 } 3021 break; 3022 } 3023 case ForType::EachCollection: 3024 { 3025 BasicCollection* pCollection = static_cast<BasicCollection*>(pForStk->refEnd.get()); 3026 SbxArrayRef xItemArray = pCollection->xItemArray; 3027 sal_Int32 nCount = xItemArray->Count32(); 3028 if( pForStk->nCurCollectionIndex < nCount ) 3029 { 3030 SbxVariable* pRes = xItemArray->Get32( pForStk->nCurCollectionIndex ); 3031 pForStk->nCurCollectionIndex++; 3032 (*pForStk->refVar) = *pRes; 3033 } 3034 else 3035 { 3036 bEndLoop = true; 3037 } 3038 break; 3039 } 3040 case ForType::EachXEnumeration: 3041 { 3042 SbiForStack* p = pForStk; 3043 if( p->xEnumeration->hasMoreElements() ) 3044 { 3045 Any aElem = p->xEnumeration->nextElement(); 3046 SbxVariableRef xVar = new SbxVariable( SbxVARIANT ); 3047 unoToSbxValue( xVar.get(), aElem ); 3048 (*pForStk->refVar) = *xVar; 3049 } 3050 else 3051 { 3052 bEndLoop = true; 3053 } 3054 break; 3055 } 3056 } 3057 if( bEndLoop ) 3058 { 3059 PopFor(); 3060 StepJUMP( nOp1 ); 3061 } 3062 } 3063 3064 // Tos+1 <= Tos+2 <= Tos, 2xremove (+Target) 3065 3066 void SbiRuntime::StepCASETO( sal_uInt32 nOp1 ) 3067 { 3068 if( !refCaseStk.is() || !refCaseStk->Count() ) 3069 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 3070 else 3071 { 3072 SbxVariableRef xTo = PopVar(); 3073 SbxVariableRef xFrom = PopVar(); 3074 SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 ); 3075 if( *xCase >= *xFrom && *xCase <= *xTo ) 3076 StepJUMP( nOp1 ); 3077 } 3078 } 3079 3080 3081 void SbiRuntime::StepERRHDL( sal_uInt32 nOp1 ) 3082 { 3083 const sal_uInt8* p = pCode; 3084 StepJUMP( nOp1 ); 3085 pError = pCode; 3086 pCode = p; 3087 pInst->aErrorMsg.clear(); 3088 pInst->nErr = ERRCODE_NONE; 3089 pInst->nErl = 0; 3090 nError = ERRCODE_NONE; 3091 SbxErrObject::getUnoErrObject()->Clear(); 3092 } 3093 3094 // Resume after errors (+0=statement, 1=next or Label) 3095 3096 void SbiRuntime::StepRESUME( sal_uInt32 nOp1 ) 3097 { 3098 // #32714 Resume without error? -> error 3099 if( !bInError ) 3100 { 3101 Error( ERRCODE_BASIC_BAD_RESUME ); 3102 return; 3103 } 3104 if( nOp1 ) 3105 { 3106 // set Code-pointer to the next statement 3107 sal_uInt16 n1, n2; 3108 pCode = pMod->FindNextStmnt( pErrCode, n1, n2, true, pImg ); 3109 } 3110 else 3111 pCode = pErrStmnt; 3112 if ( pError ) // current in error handler ( and got a Resume Next statement ) 3113 SbxErrObject::getUnoErrObject()->Clear(); 3114 3115 if( nOp1 > 1 ) 3116 StepJUMP( nOp1 ); 3117 pInst->aErrorMsg.clear(); 3118 pInst->nErr = ERRCODE_NONE; 3119 pInst->nErl = 0; 3120 nError = ERRCODE_NONE; 3121 bInError = false; 3122 } 3123 3124 // close channel (+channel, 0=all) 3125 void SbiRuntime::StepCLOSE( sal_uInt32 nOp1 ) 3126 { 3127 ErrCode err; 3128 if( !nOp1 ) 3129 pIosys->Shutdown(); 3130 else 3131 { 3132 err = pIosys->GetError(); 3133 if( !err ) 3134 { 3135 pIosys->Close(); 3136 } 3137 } 3138 err = pIosys->GetError(); 3139 Error( err ); 3140 } 3141 3142 // output character (+char) 3143 3144 void SbiRuntime::StepPRCHAR( sal_uInt32 nOp1 ) 3145 { 3146 OUString s(static_cast<sal_Unicode>(nOp1)); 3147 pIosys->Write( s ); 3148 Error( pIosys->GetError() ); 3149 } 3150 3151 // check whether TOS is a certain object class (+StringID) 3152 3153 bool SbiRuntime::implIsClass( SbxObject const * pObj, const OUString& aClass ) 3154 { 3155 bool bRet = true; 3156 3157 if( !aClass.isEmpty() ) 3158 { 3159 bRet = pObj->IsClass( aClass ); 3160 if( !bRet ) 3161 bRet = aClass.equalsIgnoreAsciiCase( "object" ); 3162 if( !bRet ) 3163 { 3164 const OUString& aObjClass = pObj->GetClassName(); 3165 SbModule* pClassMod = GetSbData()->pClassFac->FindClass( aObjClass ); 3166 if( pClassMod && pClassMod->pClassData ) 3167 { 3168 SbxVariable* pClassVar = pClassMod->pClassData->mxIfaces->Find( aClass, SbxClassType::DontCare ); 3169 bRet = (pClassVar != nullptr); 3170 } 3171 } 3172 } 3173 return bRet; 3174 } 3175 3176 bool SbiRuntime::checkClass_Impl( const SbxVariableRef& refVal, 3177 const OUString& aClass, bool bRaiseErrors, bool bDefault ) 3178 { 3179 bool bOk = bDefault; 3180 3181 SbxDataType t = refVal->GetType(); 3182 SbxVariable* pVal = refVal.get(); 3183 // we don't know the type of uno properties that are (maybevoid) 3184 if ( t == SbxEMPTY ) 3185 { 3186 if ( auto pProp = dynamic_cast<SbUnoProperty*>( refVal.get() ) ) 3187 { 3188 t = pProp->getRealType(); 3189 } 3190 } 3191 if( t == SbxOBJECT || bVBAEnabled ) 3192 { 3193 SbxObject* pObj = dynamic_cast<SbxObject*>(pVal); 3194 if (!pObj) 3195 { 3196 pObj = dynamic_cast<SbxObject*>(refVal->GetObject()); 3197 } 3198 if( pObj ) 3199 { 3200 if( !implIsClass( pObj, aClass ) ) 3201 { 3202 SbUnoObject* pUnoObj(nullptr); 3203 if (bVBAEnabled || CodeCompleteOptions::IsExtendedTypeDeclaration()) 3204 { 3205 pUnoObj = dynamic_cast<SbUnoObject*>(pObj); 3206 } 3207 3208 if (pUnoObj) 3209 bOk = checkUnoObjectType(*pUnoObj, aClass); 3210 else 3211 bOk = false; 3212 if ( !bOk && bRaiseErrors ) 3213 Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT ); 3214 } 3215 else 3216 { 3217 bOk = true; 3218 3219 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pObj ); 3220 if( pClassModuleObject != nullptr ) 3221 pClassModuleObject->triggerInitializeEvent(); 3222 } 3223 } 3224 } 3225 else 3226 { 3227 if( bRaiseErrors ) 3228 Error( ERRCODE_BASIC_NEEDS_OBJECT ); 3229 bOk = false; 3230 } 3231 return bOk; 3232 } 3233 3234 void SbiRuntime::StepSETCLASS_impl( sal_uInt32 nOp1, bool bHandleDflt ) 3235 { 3236 SbxVariableRef refVal = PopVar(); 3237 SbxVariableRef refVar = PopVar(); 3238 OUString aClass( pImg->GetString( static_cast<short>( nOp1 ) ) ); 3239 3240 bool bOk = checkClass_Impl( refVal, aClass, true, true ); 3241 if( bOk ) 3242 { 3243 StepSET_Impl( refVal, refVar, bHandleDflt ); // don't do handle default prop for a "proper" set 3244 } 3245 } 3246 3247 void SbiRuntime::StepVBASETCLASS( sal_uInt32 nOp1 ) 3248 { 3249 StepSETCLASS_impl( nOp1, false ); 3250 } 3251 3252 void SbiRuntime::StepSETCLASS( sal_uInt32 nOp1 ) 3253 { 3254 StepSETCLASS_impl( nOp1, true ); 3255 } 3256 3257 void SbiRuntime::StepTESTCLASS( sal_uInt32 nOp1 ) 3258 { 3259 SbxVariableRef xObjVal = PopVar(); 3260 OUString aClass( pImg->GetString( static_cast<short>( nOp1 ) ) ); 3261 bool bDefault = !bVBAEnabled; 3262 bool bOk = checkClass_Impl( xObjVal, aClass, false, bDefault ); 3263 3264 SbxVariable* pRet = new SbxVariable; 3265 pRet->PutBool( bOk ); 3266 PushVar( pRet ); 3267 } 3268 3269 // define library for following declare-call 3270 3271 void SbiRuntime::StepLIB( sal_uInt32 nOp1 ) 3272 { 3273 aLibName = pImg->GetString( static_cast<short>( nOp1 ) ); 3274 } 3275 3276 // TOS is incremented by BASE, BASE is pushed before (+BASE) 3277 // This opcode is pushed before DIM/REDIM-commands, 3278 // if there's been only one index named. 3279 3280 void SbiRuntime::StepBASED( sal_uInt32 nOp1 ) 3281 { 3282 SbxVariable* p1 = new SbxVariable; 3283 SbxVariableRef x2 = PopVar(); 3284 3285 // #109275 Check compatibility mode 3286 bool bCompatible = ((nOp1 & 0x8000) != 0); 3287 sal_uInt16 uBase = static_cast<sal_uInt16>(nOp1 & 1); // Can only be 0 or 1 3288 p1->PutInteger( uBase ); 3289 if( !bCompatible ) 3290 x2->Compute( SbxPLUS, *p1 ); 3291 PushVar( x2.get() ); // first the Expr 3292 PushVar( p1 ); // then the Base 3293 } 3294 3295 // the bits in the String-ID: 3296 // 0x8000 - Argv is reserved 3297 3298 SbxVariable* SbiRuntime::FindElement( SbxObject* pObj, sal_uInt32 nOp1, sal_uInt32 nOp2, 3299 ErrCode nNotFound, bool bLocal, bool bStatic ) 3300 { 3301 bool bIsVBAInterOp = SbiRuntime::isVBAEnabled(); 3302 if( bIsVBAInterOp ) 3303 { 3304 StarBASIC* pMSOMacroRuntimeLib = GetSbData()->pMSOMacroRuntimLib; 3305 if( pMSOMacroRuntimeLib != nullptr ) 3306 { 3307 pMSOMacroRuntimeLib->ResetFlag( SbxFlagBits::ExtSearch ); 3308 } 3309 } 3310 3311 SbxVariable* pElem = nullptr; 3312 if( !pObj ) 3313 { 3314 Error( ERRCODE_BASIC_NO_OBJECT ); 3315 pElem = new SbxVariable; 3316 } 3317 else 3318 { 3319 bool bFatalError = false; 3320 SbxDataType t = static_cast<SbxDataType>(nOp2); 3321 OUString aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) ); 3322 // Hacky capture of Evaluate [] syntax 3323 // this should be tackled I feel at the pcode level 3324 if ( bIsVBAInterOp && aName.startsWith("[") ) 3325 { 3326 // emulate pcode here 3327 StepARGC(); 3328 // pseudo StepLOADSC 3329 OUString sArg = aName.copy( 1, aName.getLength() - 2 ); 3330 SbxVariable* p = new SbxVariable; 3331 p->PutString( sArg ); 3332 PushVar( p ); 3333 StepARGV(); 3334 nOp1 = nOp1 | 0x8000; // indicate params are present 3335 aName = "Evaluate"; 3336 } 3337 if( bLocal ) 3338 { 3339 if ( bStatic && pMeth ) 3340 { 3341 pElem = pMeth->GetStatics()->Find( aName, SbxClassType::DontCare ); 3342 } 3343 3344 if ( !pElem ) 3345 { 3346 pElem = refLocals->Find( aName, SbxClassType::DontCare ); 3347 } 3348 } 3349 if( !pElem ) 3350 { 3351 bool bSave = rBasic.bNoRtl; 3352 rBasic.bNoRtl = true; 3353 pElem = pObj->Find( aName, SbxClassType::DontCare ); 3354 3355 // #110004, #112015: Make private really private 3356 if( bLocal && pElem ) // Local as flag for global search 3357 { 3358 if( pElem->IsSet( SbxFlagBits::Private ) ) 3359 { 3360 SbiInstance* pInst_ = GetSbData()->pInst; 3361 if( pInst_ && pInst_->IsCompatibility() && pObj != pElem->GetParent() ) 3362 { 3363 pElem = nullptr; // Found but in wrong module! 3364 } 3365 // Interfaces: Use SbxFlagBits::ExtFound 3366 } 3367 } 3368 rBasic.bNoRtl = bSave; 3369 3370 // is it a global uno-identifier? 3371 if( bLocal && !pElem ) 3372 { 3373 bool bSetName = true; // preserve normal behaviour 3374 3375 // i#i68894# if VBAInterOp favour searching vba globals 3376 // over searching for uno classes 3377 if ( bVBAEnabled ) 3378 { 3379 // Try Find in VBA symbols space 3380 pElem = rBasic.VBAFind( aName, SbxClassType::DontCare ); 3381 if ( pElem ) 3382 { 3383 bSetName = false; // don't overwrite uno name 3384 } 3385 else 3386 { 3387 pElem = VBAConstantHelper::instance().getVBAConstant( aName ); 3388 } 3389 } 3390 3391 if( !pElem ) 3392 { 3393 // #72382 ATTENTION! ALWAYS returns a result now 3394 // because of unknown modules! 3395 SbUnoClass* pUnoClass = findUnoClass( aName ); 3396 if( pUnoClass ) 3397 { 3398 pElem = new SbxVariable( t ); 3399 SbxValues aRes( SbxOBJECT ); 3400 aRes.pObj = pUnoClass; 3401 pElem->SbxVariable::Put( aRes ); 3402 } 3403 } 3404 3405 // #62939 If a uno-class has been found, the wrapper 3406 // object has to be held, because the uno-class, e. g. 3407 // "stardiv", has to be read out of the registry 3408 // every time again otherwise 3409 if( pElem ) 3410 { 3411 // #63774 May not be saved too!!! 3412 pElem->SetFlag( SbxFlagBits::DontStore ); 3413 pElem->SetFlag( SbxFlagBits::NoModify); 3414 3415 // #72382 save locally, all variables that have been declared 3416 // implicit would become global automatically otherwise! 3417 if ( bSetName ) 3418 { 3419 pElem->SetName( aName ); 3420 } 3421 refLocals->Put( pElem, refLocals->Count() ); 3422 } 3423 } 3424 3425 if( !pElem ) 3426 { 3427 // not there and not in the object? 3428 // don't establish if that thing has parameters! 3429 if( nOp1 & 0x8000 ) 3430 { 3431 bFatalError = true; 3432 } 3433 3434 // else, if there are parameters, use different error code 3435 if( !bLocal || pImg->IsFlag( SbiImageFlags::EXPLICIT ) ) 3436 { 3437 // #39108 if explicit and as ELEM always a fatal error 3438 bFatalError = true; 3439 3440 3441 if( !( nOp1 & 0x8000 ) && nNotFound == ERRCODE_BASIC_PROC_UNDEFINED ) 3442 { 3443 nNotFound = ERRCODE_BASIC_VAR_UNDEFINED; 3444 } 3445 } 3446 if( bFatalError ) 3447 { 3448 // #39108 use dummy variable instead of fatal error 3449 if( !xDummyVar.is() ) 3450 { 3451 xDummyVar = new SbxVariable( SbxVARIANT ); 3452 } 3453 pElem = xDummyVar.get(); 3454 3455 ClearArgvStack(); 3456 3457 Error( nNotFound, aName ); 3458 } 3459 else 3460 { 3461 if ( bStatic ) 3462 { 3463 pElem = StepSTATIC_Impl( aName, t, 0 ); 3464 } 3465 if ( !pElem ) 3466 { 3467 pElem = new SbxVariable( t ); 3468 if( t != SbxVARIANT ) 3469 { 3470 pElem->SetFlag( SbxFlagBits::Fixed ); 3471 } 3472 pElem->SetName( aName ); 3473 refLocals->Put( pElem, refLocals->Count() ); 3474 } 3475 } 3476 } 3477 } 3478 // #39108 Args can already be deleted! 3479 if( !bFatalError ) 3480 { 3481 SetupArgs( pElem, nOp1 ); 3482 } 3483 // because a particular call-type is requested 3484 if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pElem)) 3485 { 3486 // shall the type be converted? 3487 SbxDataType t2 = pElem->GetType(); 3488 bool bSet = false; 3489 if( (pElem->GetFlags() & SbxFlagBits::Fixed) == SbxFlagBits::NONE ) 3490 { 3491 if( t != SbxVARIANT && t != t2 && 3492 t >= SbxINTEGER && t <= SbxSTRING ) 3493 { 3494 pElem->SetType( t ); 3495 bSet = true; 3496 } 3497 } 3498 // assign pElem to a Ref, to delete a temp-var if applicable 3499 SbxVariableRef refTemp = pElem; 3500 3501 // remove potential rests of the last call of the SbxMethod 3502 // free Write before, so that there's no error 3503 SbxFlagBits nSavFlags = pElem->GetFlags(); 3504 pElem->SetFlag( SbxFlagBits::ReadWrite | SbxFlagBits::NoBroadcast ); 3505 pElem->SbxValue::Clear(); 3506 pElem->SetFlags( nSavFlags ); 3507 3508 // don't touch before setting, as e. g. LEFT() 3509 // has to know the difference between Left$() and Left() 3510 3511 // because the methods' parameters are cut away in PopVar() 3512 SbxVariable* pNew = new SbxMethod(*pMethod); 3513 //OLD: SbxVariable* pNew = new SbxVariable( *pElem ); 3514 3515 pElem->SetParameters(nullptr); 3516 pNew->SetFlag( SbxFlagBits::ReadWrite ); 3517 3518 if( bSet ) 3519 { 3520 pElem->SetType( t2 ); 3521 } 3522 pElem = pNew; 3523 } 3524 // consider index-access for UnoObjects 3525 // definitely we want this for VBA where properties are often 3526 // collections ( which need index access ), but lets only do 3527 // this if we actually have params following 3528 else if( bVBAEnabled && dynamic_cast<const SbUnoProperty*>( pElem) != nullptr && pElem->GetParameters() ) 3529 { 3530 SbxVariableRef refTemp = pElem; 3531 3532 // dissolve the notify while copying variable 3533 SbxVariable* pNew = new SbxVariable( *pElem ); 3534 pElem->SetParameters( nullptr ); 3535 pElem = pNew; 3536 } 3537 } 3538 return CheckArray( pElem ); 3539 } 3540 3541 // for current scope (e. g. query from BASIC-IDE) 3542 SbxBase* SbiRuntime::FindElementExtern( const OUString& rName ) 3543 { 3544 // don't expect pMeth to be != 0, as there are none set 3545 // in the RunInit yet 3546 3547 SbxVariable* pElem = nullptr; 3548 if( !pMod || rName.isEmpty() ) 3549 { 3550 return nullptr; 3551 } 3552 if( refLocals.is() ) 3553 { 3554 pElem = refLocals->Find( rName, SbxClassType::DontCare ); 3555 } 3556 if ( !pElem && pMeth ) 3557 { 3558 // for statics, set the method's name in front 3559 OUString aMethName = pMeth->GetName() + ":" + rName; 3560 pElem = pMod->Find(aMethName, SbxClassType::DontCare); 3561 } 3562 3563 // search in parameter list 3564 if( !pElem && pMeth ) 3565 { 3566 SbxInfo* pInfo = pMeth->GetInfo(); 3567 if( pInfo && refParams.is() ) 3568 { 3569 sal_uInt16 nParamCount = refParams->Count(); 3570 sal_uInt16 j = 1; 3571 const SbxParamInfo* pParam = pInfo->GetParam( j ); 3572 while( pParam ) 3573 { 3574 if( pParam->aName.equalsIgnoreAsciiCase( rName ) ) 3575 { 3576 if( j >= nParamCount ) 3577 { 3578 // Parameter is missing 3579 pElem = new SbxVariable( SbxSTRING ); 3580 pElem->PutString( "<missing parameter>"); 3581 } 3582 else 3583 { 3584 pElem = refParams->Get( j ); 3585 } 3586 break; 3587 } 3588 pParam = pInfo->GetParam( ++j ); 3589 } 3590 } 3591 } 3592 3593 // search in module 3594 if( !pElem ) 3595 { 3596 bool bSave = rBasic.bNoRtl; 3597 rBasic.bNoRtl = true; 3598 pElem = pMod->Find( rName, SbxClassType::DontCare ); 3599 rBasic.bNoRtl = bSave; 3600 } 3601 return pElem; 3602 } 3603 3604 3605 void SbiRuntime::SetupArgs( SbxVariable* p, sal_uInt32 nOp1 ) 3606 { 3607 if( nOp1 & 0x8000 ) 3608 { 3609 if( !refArgv.is() ) 3610 { 3611 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 3612 } 3613 bool bHasNamed = false; 3614 sal_uInt16 i; 3615 sal_uInt16 nArgCount = refArgv->Count(); 3616 for( i = 1 ; i < nArgCount ; i++ ) 3617 { 3618 if( !refArgv->GetAlias(i).isEmpty() ) 3619 { 3620 bHasNamed = true; break; 3621 } 3622 } 3623 if( bHasNamed ) 3624 { 3625 SbxInfo* pInfo = p->GetInfo(); 3626 if( !pInfo ) 3627 { 3628 bool bError_ = true; 3629 3630 SbUnoMethod* pUnoMethod = dynamic_cast<SbUnoMethod*>( p ); 3631 SbUnoProperty* pUnoProperty = dynamic_cast<SbUnoProperty*>( p ); 3632 if( pUnoMethod || pUnoProperty ) 3633 { 3634 SbUnoObject* pParentUnoObj = dynamic_cast<SbUnoObject*>( p->GetParent() ); 3635 if( pParentUnoObj ) 3636 { 3637 Any aUnoAny = pParentUnoObj->getUnoAny(); 3638 Reference< XInvocation > xInvocation; 3639 aUnoAny >>= xInvocation; 3640 if( xInvocation.is() ) // TODO: if( xOLEAutomation.is() ) 3641 { 3642 bError_ = false; 3643 3644 sal_uInt16 nCurPar = 1; 3645 AutomationNamedArgsSbxArray* pArg = 3646 new AutomationNamedArgsSbxArray( nArgCount ); 3647 OUString* pNames = pArg->getNames().getArray(); 3648 for( i = 1 ; i < nArgCount ; i++ ) 3649 { 3650 SbxVariable* pVar = refArgv->Get( i ); 3651 OUString aName = refArgv->GetAlias(i); 3652 if (!aName.isEmpty()) 3653 { 3654 pNames[i] = aName; 3655 } 3656 pArg->Put( pVar, nCurPar++ ); 3657 } 3658 refArgv = pArg; 3659 } 3660 } 3661 } 3662 else if( bVBAEnabled && p->GetType() == SbxOBJECT && (dynamic_cast<const SbxMethod*>( p) == nullptr || !p->IsBroadcaster()) ) 3663 { 3664 // Check for default method with named parameters 3665 SbxBaseRef xObj = p->GetObject(); 3666 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( xObj.get() )) 3667 { 3668 Any aAny = pUnoObj->getUnoAny(); 3669 3670 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) 3671 { 3672 Reference< XDefaultMethod > xDfltMethod( aAny, UNO_QUERY ); 3673 3674 OUString sDefaultMethod; 3675 if ( xDfltMethod.is() ) 3676 { 3677 sDefaultMethod = xDfltMethod->getDefaultMethodName(); 3678 } 3679 if ( !sDefaultMethod.isEmpty() ) 3680 { 3681 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxClassType::Method ); 3682 if( meth != nullptr ) 3683 { 3684 pInfo = meth->GetInfo(); 3685 } 3686 if( pInfo ) 3687 { 3688 bError_ = false; 3689 } 3690 } 3691 } 3692 } 3693 } 3694 if( bError_ ) 3695 { 3696 Error( ERRCODE_BASIC_NO_NAMED_ARGS ); 3697 } 3698 } 3699 else 3700 { 3701 sal_uInt16 nCurPar = 1; 3702 SbxArray* pArg = new SbxArray; 3703 for( i = 1 ; i < nArgCount ; i++ ) 3704 { 3705 SbxVariable* pVar = refArgv->Get( i ); 3706 OUString aName = refArgv->GetAlias(i); 3707 if (!aName.isEmpty()) 3708 { 3709 // nCurPar is set to the found parameter 3710 sal_uInt16 j = 1; 3711 const SbxParamInfo* pParam = pInfo->GetParam( j ); 3712 while( pParam ) 3713 { 3714 if( pParam->aName.equalsIgnoreAsciiCase( aName ) ) 3715 { 3716 nCurPar = j; 3717 break; 3718 } 3719 pParam = pInfo->GetParam( ++j ); 3720 } 3721 if( !pParam ) 3722 { 3723 Error( ERRCODE_BASIC_NAMED_NOT_FOUND ); break; 3724 } 3725 } 3726 pArg->Put( pVar, nCurPar++ ); 3727 } 3728 refArgv = pArg; 3729 } 3730 } 3731 // own var as parameter 0 3732 refArgv->Put( p, 0 ); 3733 p->SetParameters( refArgv.get() ); 3734 PopArgv(); 3735 } 3736 else 3737 { 3738 p->SetParameters( nullptr ); 3739 } 3740 } 3741 3742 // getting an array element 3743 3744 SbxVariable* SbiRuntime::CheckArray( SbxVariable* pElem ) 3745 { 3746 SbxArray* pPar; 3747 if( ( pElem->GetType() & SbxARRAY ) && refRedim.get() != pElem ) 3748 { 3749 SbxBase* pElemObj = pElem->GetObject(); 3750 SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj ); 3751 pPar = pElem->GetParameters(); 3752 if( pDimArray ) 3753 { 3754 // parameters may be missing, if an array is 3755 // passed as an argument 3756 if( pPar ) 3757 pElem = pDimArray->Get( pPar ); 3758 } 3759 else 3760 { 3761 SbxArray* pArray = dynamic_cast<SbxArray*>( pElemObj ); 3762 if( pArray ) 3763 { 3764 if( !pPar ) 3765 { 3766 Error( ERRCODE_BASIC_OUT_OF_RANGE ); 3767 pElem = new SbxVariable; 3768 } 3769 else 3770 { 3771 pElem = pArray->Get( pPar->Get( 1 )->GetInteger() ); 3772 } 3773 } 3774 } 3775 3776 // #42940, set parameter 0 to NULL so that var doesn't contain itself 3777 if( pPar ) 3778 { 3779 pPar->Put( nullptr, 0 ); 3780 } 3781 } 3782 // consider index-access for UnoObjects 3783 else if( pElem->GetType() == SbxOBJECT && 3784 dynamic_cast<const SbxMethod*>( pElem) == nullptr && 3785 ( !bVBAEnabled || dynamic_cast<const SbxProperty*>( pElem) == nullptr ) ) 3786 { 3787 pPar = pElem->GetParameters(); 3788 if ( pPar ) 3789 { 3790 // is it a uno-object? 3791 SbxBaseRef pObj = pElem->GetObject(); 3792 if( pObj.is() ) 3793 { 3794 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj.get())) 3795 { 3796 Any aAny = pUnoObj->getUnoAny(); 3797 3798 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) 3799 { 3800 Reference< XIndexAccess > xIndexAccess( aAny, UNO_QUERY ); 3801 if ( !bVBAEnabled ) 3802 { 3803 if( xIndexAccess.is() ) 3804 { 3805 sal_uInt32 nParamCount = static_cast<sal_uInt32>(pPar->Count()) - 1; 3806 if( nParamCount != 1 ) 3807 { 3808 StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT ); 3809 return pElem; 3810 } 3811 3812 // get index 3813 sal_Int32 nIndex = pPar->Get( 1 )->GetLong(); 3814 Reference< XInterface > xRet; 3815 try 3816 { 3817 Any aAny2 = xIndexAccess->getByIndex( nIndex ); 3818 aAny2 >>= xRet; 3819 } 3820 catch (const IndexOutOfBoundsException&) 3821 { 3822 // usually expect converting problem 3823 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE ); 3824 } 3825 3826 // #57847 always create a new variable, else error 3827 // due to PutObject(NULL) at ReadOnly-properties 3828 pElem = new SbxVariable( SbxVARIANT ); 3829 if( xRet.is() ) 3830 { 3831 aAny <<= xRet; 3832 3833 // #67173 don't specify a name so that the real class name is entered 3834 SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoObject( OUString(), aAny )); 3835 pElem->PutObject( xWrapper.get() ); 3836 } 3837 else 3838 { 3839 pElem->PutObject( nullptr ); 3840 } 3841 } 3842 } 3843 else 3844 { 3845 // check if there isn't a default member between the current variable 3846 // and the params, e.g. 3847 // Dim rst1 As New ADODB.Recordset 3848 // " 3849 // val = rst1("FirstName") 3850 // has the default 'Fields' member between rst1 and '("FirstName")' 3851 Any x = aAny; 3852 SbxVariable* pDflt = getDefaultProp( pElem ); 3853 if ( pDflt ) 3854 { 3855 pDflt->Broadcast( SfxHintId::BasicDataWanted ); 3856 SbxBaseRef pDfltObj = pDflt->GetObject(); 3857 if( pDfltObj.is() ) 3858 { 3859 if (SbUnoObject* pSbObj = dynamic_cast<SbUnoObject*>(pDfltObj.get())) 3860 { 3861 pUnoObj = pSbObj; 3862 Any aUnoAny = pUnoObj->getUnoAny(); 3863 3864 if( aUnoAny.getValueType().getTypeClass() == TypeClass_INTERFACE ) 3865 x = aUnoAny; 3866 pElem = pDflt; 3867 } 3868 } 3869 } 3870 OUString sDefaultMethod; 3871 3872 Reference< XDefaultMethod > xDfltMethod( x, UNO_QUERY ); 3873 3874 if ( xDfltMethod.is() ) 3875 { 3876 sDefaultMethod = xDfltMethod->getDefaultMethodName(); 3877 } 3878 else if( xIndexAccess.is() ) 3879 { 3880 sDefaultMethod = "getByIndex"; 3881 } 3882 if ( !sDefaultMethod.isEmpty() ) 3883 { 3884 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxClassType::Method ); 3885 SbxVariableRef refTemp = meth; 3886 if ( refTemp.is() ) 3887 { 3888 meth->SetParameters( pPar ); 3889 SbxVariable* pNew = new SbxMethod( *static_cast<SbxMethod*>(meth) ); 3890 pElem = pNew; 3891 } 3892 } 3893 } 3894 } 3895 3896 // #42940, set parameter 0 to NULL so that var doesn't contain itself 3897 pPar->Put( nullptr, 0 ); 3898 } 3899 else if (BasicCollection* pCol = dynamic_cast<BasicCollection*>(pObj.get())) 3900 { 3901 pElem = new SbxVariable( SbxVARIANT ); 3902 pPar->Put( pElem, 0 ); 3903 pCol->CollItem( pPar ); 3904 } 3905 } 3906 else if( bVBAEnabled ) // !pObj 3907 { 3908 SbxArray* pParam = pElem->GetParameters(); 3909 if( pParam != nullptr && !pElem->IsSet( SbxFlagBits::VarToDim ) ) 3910 { 3911 Error( ERRCODE_BASIC_NO_OBJECT ); 3912 } 3913 } 3914 } 3915 } 3916 3917 return pElem; 3918 } 3919 3920 // loading an element from the runtime-library (+StringID+type) 3921 3922 void SbiRuntime::StepRTL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 3923 { 3924 PushVar( FindElement( rBasic.pRtl.get(), nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED, false ) ); 3925 } 3926 3927 void SbiRuntime::StepFIND_Impl( SbxObject* pObj, sal_uInt32 nOp1, sal_uInt32 nOp2, 3928 ErrCode nNotFound, bool bStatic ) 3929 { 3930 if( !refLocals.is() ) 3931 { 3932 refLocals = new SbxArray; 3933 } 3934 PushVar( FindElement( pObj, nOp1, nOp2, nNotFound, true/*bLocal*/, bStatic ) ); 3935 } 3936 // loading a local/global variable (+StringID+type) 3937 3938 void SbiRuntime::StepFIND( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 3939 { 3940 StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED ); 3941 } 3942 3943 // Search inside a class module (CM) to enable global search in time 3944 void SbiRuntime::StepFIND_CM( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 3945 { 3946 3947 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pMod ); 3948 if( pClassModuleObject ) 3949 { 3950 pMod->SetFlag( SbxFlagBits::GlobalSearch ); 3951 } 3952 StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED); 3953 3954 if( pClassModuleObject ) 3955 { 3956 pMod->ResetFlag( SbxFlagBits::GlobalSearch ); 3957 } 3958 } 3959 3960 void SbiRuntime::StepFIND_STATIC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 3961 { 3962 StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED, true ); 3963 } 3964 3965 // loading an object-element (+StringID+type) 3966 // the object lies on TOS 3967 3968 void SbiRuntime::StepELEM( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 3969 { 3970 SbxVariableRef pObjVar = PopVar(); 3971 3972 SbxObject* pObj = dynamic_cast<SbxObject*>( pObjVar.get() ); 3973 if( !pObj ) 3974 { 3975 SbxBase* pObjVarObj = pObjVar->GetObject(); 3976 pObj = dynamic_cast<SbxObject*>( pObjVarObj ); 3977 } 3978 3979 // #56368 save reference at StepElem, otherwise objects could 3980 // lose their reference too early in qualification chains like 3981 // ActiveComponent.Selection(0).Text 3982 // #74254 now per list 3983 if( pObj ) 3984 { 3985 aRefSaved.emplace_back(pObj ); 3986 } 3987 PushVar( FindElement( pObj, nOp1, nOp2, ERRCODE_BASIC_NO_METHOD, false ) ); 3988 } 3989 3990 // loading a parameter (+offset+type) 3991 // If the data type is wrong, create a copy. 3992 // The data type SbxEMPTY shows that no parameters are given. 3993 // Get( 0 ) may be EMPTY 3994 3995 void SbiRuntime::StepPARAM( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 3996 { 3997 sal_uInt16 i = static_cast<sal_uInt16>( nOp1 & 0x7FFF ); 3998 SbxDataType t = static_cast<SbxDataType>(nOp2); 3999 SbxVariable* p; 4000 4001 // #57915 solve missing in a cleaner way 4002 sal_uInt16 nParamCount = refParams->Count(); 4003 if( i >= nParamCount ) 4004 { 4005 sal_Int16 iLoop = i; 4006 while( iLoop >= nParamCount ) 4007 { 4008 p = new SbxVariable(); 4009 4010 if( SbiRuntime::isVBAEnabled() && 4011 (t == SbxOBJECT || t == SbxSTRING) ) 4012 { 4013 if( t == SbxOBJECT ) 4014 { 4015 p->PutObject( nullptr ); 4016 } 4017 else 4018 { 4019 p->PutString( OUString() ); 4020 } 4021 } 4022 else 4023 { 4024 p->PutErr( 448 ); // like in VB: Error-Code 448 (ERRCODE_BASIC_NAMED_NOT_FOUND) 4025 } 4026 refParams->Put( p, iLoop ); 4027 iLoop--; 4028 } 4029 } 4030 p = refParams->Get( i ); 4031 4032 if( p->GetType() == SbxERROR && i ) 4033 { 4034 // if there's a parameter missing, it can be OPTIONAL 4035 bool bOpt = false; 4036 if( pMeth ) 4037 { 4038 SbxInfo* pInfo = pMeth->GetInfo(); 4039 if ( pInfo ) 4040 { 4041 const SbxParamInfo* pParam = pInfo->GetParam( i ); 4042 if( pParam && ( pParam->nFlags & SbxFlagBits::Optional ) ) 4043 { 4044 // Default value? 4045 sal_uInt16 nDefaultId = static_cast<sal_uInt16>(pParam->nUserData & 0x0ffff); 4046 if( nDefaultId > 0 ) 4047 { 4048 OUString aDefaultStr = pImg->GetString( nDefaultId ); 4049 p = new SbxVariable(pParam-> eType); 4050 p->PutString( aDefaultStr ); 4051 refParams->Put( p, i ); 4052 } 4053 bOpt = true; 4054 } 4055 } 4056 } 4057 if( !bOpt ) 4058 { 4059 Error( ERRCODE_BASIC_NOT_OPTIONAL ); 4060 } 4061 } 4062 else if( t != SbxVARIANT && static_cast<SbxDataType>(p->GetType() & 0x0FFF ) != t ) 4063 { 4064 SbxVariable* q = new SbxVariable( t ); 4065 aRefSaved.emplace_back(q ); 4066 *q = *p; 4067 p = q; 4068 if ( i ) 4069 { 4070 refParams->Put( p, i ); 4071 } 4072 } 4073 SetupArgs( p, nOp1 ); 4074 PushVar( CheckArray( p ) ); 4075 } 4076 4077 // Case-Test (+True-Target+Test-Opcode) 4078 4079 void SbiRuntime::StepCASEIS( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4080 { 4081 if( !refCaseStk.is() || !refCaseStk->Count() ) 4082 { 4083 StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR ); 4084 } 4085 else 4086 { 4087 SbxVariableRef xComp = PopVar(); 4088 SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 ); 4089 if( xCase->Compare( static_cast<SbxOperator>(nOp2), *xComp ) ) 4090 { 4091 StepJUMP( nOp1 ); 4092 } 4093 } 4094 } 4095 4096 // call of a DLL-procedure (+StringID+type) 4097 // the StringID's MSB shows that Argv is occupied 4098 4099 void SbiRuntime::StepCALL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4100 { 4101 OUString aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ); 4102 SbxArray* pArgs = nullptr; 4103 if( nOp1 & 0x8000 ) 4104 { 4105 pArgs = refArgv.get(); 4106 } 4107 DllCall( aName, aLibName, pArgs, static_cast<SbxDataType>(nOp2), false ); 4108 aLibName.clear(); 4109 if( nOp1 & 0x8000 ) 4110 { 4111 PopArgv(); 4112 } 4113 } 4114 4115 // call of a DLL-procedure after CDecl (+StringID+type) 4116 4117 void SbiRuntime::StepCALLC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4118 { 4119 OUString aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ); 4120 SbxArray* pArgs = nullptr; 4121 if( nOp1 & 0x8000 ) 4122 { 4123 pArgs = refArgv.get(); 4124 } 4125 DllCall( aName, aLibName, pArgs, static_cast<SbxDataType>(nOp2), true ); 4126 aLibName.clear(); 4127 if( nOp1 & 0x8000 ) 4128 { 4129 PopArgv(); 4130 } 4131 } 4132 4133 4134 // beginning of a statement (+Line+Col) 4135 4136 void SbiRuntime::StepSTMNT( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4137 { 4138 // If the Expr-Stack at the beginning of a statement contains a variable, 4139 // some fool has called X as a function, although it's a variable! 4140 bool bFatalExpr = false; 4141 OUString sUnknownMethodName; 4142 if( nExprLvl > 1 ) 4143 { 4144 bFatalExpr = true; 4145 } 4146 else if( nExprLvl ) 4147 { 4148 SbxVariable* p = refExprStk->Get( 0 ); 4149 if( p->GetRefCount() > 1 && 4150 refLocals.is() && refLocals->Find( p->GetName(), p->GetClass() ) ) 4151 { 4152 sUnknownMethodName = p->GetName(); 4153 bFatalExpr = true; 4154 } 4155 } 4156 4157 ClearExprStack(); 4158 4159 aRefSaved.clear(); 4160 4161 // We have to cancel hard here because line and column 4162 // would be wrong later otherwise! 4163 if( bFatalExpr) 4164 { 4165 StarBASIC::FatalError( ERRCODE_BASIC_NO_METHOD, sUnknownMethodName ); 4166 return; 4167 } 4168 pStmnt = pCode - 9; 4169 sal_uInt16 nOld = nLine; 4170 nLine = static_cast<short>( nOp1 ); 4171 4172 // #29955 & 0xFF, to filter out for-loop-level 4173 nCol1 = static_cast<short>( nOp2 & 0xFF ); 4174 4175 // find the next STMNT-command to set the final column 4176 // of this statement 4177 4178 nCol2 = 0xffff; 4179 sal_uInt16 n1, n2; 4180 const sal_uInt8* p = pMod->FindNextStmnt( pCode, n1, n2 ); 4181 if( p ) 4182 { 4183 if( n1 == nOp1 ) 4184 { 4185 // #29955 & 0xFF, to filter out for-loop-level 4186 nCol2 = (n2 & 0xFF) - 1; 4187 } 4188 } 4189 4190 // #29955 correct for-loop-level, #67452 NOT in the error-handler 4191 if( !bInError ) 4192 { 4193 // (there's a difference here in case of a jump out of a loop) 4194 sal_uInt16 nExspectedForLevel = static_cast<sal_uInt16>( nOp2 / 0x100 ); 4195 if( !pGosubStk.empty() ) 4196 { 4197 nExspectedForLevel = nExspectedForLevel + pGosubStk.back().nStartForLvl; 4198 } 4199 4200 // if the actual for-level is too small it'd jump out 4201 // of a loop -> corrected 4202 while( nForLvl > nExspectedForLevel ) 4203 { 4204 PopFor(); 4205 } 4206 } 4207 4208 // 16.10.96: #31460 new concept for StepInto/Over/Out 4209 // see explanation at _ImplGetBreakCallLevel 4210 if( pInst->nCallLvl <= pInst->nBreakCallLvl ) 4211 { 4212 StarBASIC* pStepBasic = GetCurrentBasic( &rBasic ); 4213 BasicDebugFlags nNewFlags = pStepBasic->StepPoint( nLine, nCol1, nCol2 ); 4214 4215 pInst->CalcBreakCallLevel( nNewFlags ); 4216 } 4217 4218 // break points only at STMNT-commands in a new line! 4219 else if( ( nOp1 != nOld ) 4220 && ( nFlags & BasicDebugFlags::Break ) 4221 && pMod->IsBP( static_cast<sal_uInt16>( nOp1 ) ) ) 4222 { 4223 StarBASIC* pBreakBasic = GetCurrentBasic( &rBasic ); 4224 BasicDebugFlags nNewFlags = pBreakBasic->BreakPoint( nLine, nCol1, nCol2 ); 4225 4226 pInst->CalcBreakCallLevel( nNewFlags ); 4227 } 4228 } 4229 4230 // (+StreamMode+Flags) 4231 // Stack: block length 4232 // channel number 4233 // file name 4234 4235 void SbiRuntime::StepOPEN( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4236 { 4237 SbxVariableRef pName = PopVar(); 4238 SbxVariableRef pChan = PopVar(); 4239 SbxVariableRef pLen = PopVar(); 4240 short nBlkLen = pLen->GetInteger(); 4241 short nChan = pChan->GetInteger(); 4242 OString aName(OUStringToOString(pName->GetOUString(), osl_getThreadTextEncoding())); 4243 pIosys->Open( nChan, aName, static_cast<StreamMode>( nOp1 ), 4244 static_cast<SbiStreamFlags>( nOp2 ), nBlkLen ); 4245 Error( pIosys->GetError() ); 4246 } 4247 4248 // create object (+StringID+StringID) 4249 4250 void SbiRuntime::StepCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4251 { 4252 OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); 4253 SbxObject *pObj = SbxBase::CreateObject( aClass ); 4254 if( !pObj ) 4255 { 4256 Error( ERRCODE_BASIC_INVALID_OBJECT ); 4257 } 4258 else 4259 { 4260 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4261 pObj->SetName( aName ); 4262 // the object must be able to call the BASIC 4263 pObj->SetParent( &rBasic ); 4264 SbxVariable* pNew = new SbxVariable; 4265 pNew->PutObject( pObj ); 4266 PushVar( pNew ); 4267 } 4268 } 4269 4270 void SbiRuntime::StepDCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4271 { 4272 StepDCREATE_IMPL( nOp1, nOp2 ); 4273 } 4274 4275 void SbiRuntime::StepDCREATE_REDIMP( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4276 { 4277 StepDCREATE_IMPL( nOp1, nOp2 ); 4278 } 4279 4280 4281 // Helper function for StepDCREATE_IMPL / bRedimp = true 4282 static void implCopyDimArray_DCREATE( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex, 4283 short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds ) 4284 { 4285 sal_Int32& ri = pActualIndices[nActualDim]; 4286 for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ ) 4287 { 4288 if( nActualDim < nMaxDimIndex ) 4289 { 4290 implCopyDimArray_DCREATE( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1, 4291 pActualIndices, pLowerBounds, pUpperBounds ); 4292 } 4293 else 4294 { 4295 SbxVariable* pSource = pOldArray->Get32( pActualIndices ); 4296 pNewArray->Put32( pSource, pActualIndices ); 4297 } 4298 } 4299 } 4300 4301 // #56204 create object array (+StringID+StringID), DCREATE == Dim-Create 4302 void SbiRuntime::StepDCREATE_IMPL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4303 { 4304 SbxVariableRef refVar = PopVar(); 4305 4306 DimImpl( refVar ); 4307 4308 // fill the array with instances of the requested class 4309 SbxBaseRef xObj = refVar->GetObject(); 4310 if( !xObj.is() ) 4311 { 4312 StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT ); 4313 return; 4314 } 4315 4316 SbxDimArray* pArray = dynamic_cast<SbxDimArray*>(xObj.get()); 4317 if (pArray) 4318 { 4319 short nDims = pArray->GetDims(); 4320 sal_Int32 nTotalSize = 0; 4321 4322 // must be a one-dimensional array 4323 sal_Int32 nLower, nUpper; 4324 for( sal_Int32 i = 0 ; i < nDims ; ++i ) 4325 { 4326 pArray->GetDim32( i+1, nLower, nUpper ); 4327 sal_Int32 nSize = nUpper - nLower + 1; 4328 if( i == 0 ) 4329 { 4330 nTotalSize = nSize; 4331 } 4332 else 4333 { 4334 nTotalSize *= nSize; 4335 } 4336 } 4337 4338 // create objects and insert them into the array 4339 OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); 4340 for( sal_Int32 i = 0 ; i < nTotalSize ; ++i ) 4341 { 4342 SbxObject *pClassObj = SbxBase::CreateObject( aClass ); 4343 if( !pClassObj ) 4344 { 4345 Error( ERRCODE_BASIC_INVALID_OBJECT ); 4346 break; 4347 } 4348 else 4349 { 4350 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4351 pClassObj->SetName( aName ); 4352 // the object must be able to call the basic 4353 pClassObj->SetParent( &rBasic ); 4354 pArray->SbxArray::Put32( pClassObj, i ); 4355 } 4356 } 4357 } 4358 4359 SbxDimArray* pOldArray = static_cast<SbxDimArray*>(refRedimpArray.get()); 4360 if( pArray && pOldArray ) 4361 { 4362 short nDimsNew = pArray->GetDims(); 4363 short nDimsOld = pOldArray->GetDims(); 4364 short nDims = nDimsNew; 4365 bool bRangeError = false; 4366 4367 // Store dims to use them for copying later 4368 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]); 4369 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]); 4370 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]); 4371 if( nDimsOld != nDimsNew ) 4372 { 4373 bRangeError = true; 4374 } 4375 else 4376 { 4377 // Compare bounds 4378 for( short i = 1 ; i <= nDims ; i++ ) 4379 { 4380 sal_Int32 lBoundNew, uBoundNew; 4381 sal_Int32 lBoundOld, uBoundOld; 4382 pArray->GetDim32( i, lBoundNew, uBoundNew ); 4383 pOldArray->GetDim32( i, lBoundOld, uBoundOld ); 4384 4385 lBoundNew = std::max( lBoundNew, lBoundOld ); 4386 uBoundNew = std::min( uBoundNew, uBoundOld ); 4387 short j = i - 1; 4388 pActualIndices[j] = pLowerBounds[j] = lBoundNew; 4389 pUpperBounds[j] = uBoundNew; 4390 } 4391 } 4392 4393 if( bRangeError ) 4394 { 4395 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE ); 4396 } 4397 else 4398 { 4399 // Copy data from old array by going recursively through all dimensions 4400 // (It would be faster to work on the flat internal data array of an 4401 // SbyArray but this solution is clearer and easier) 4402 implCopyDimArray_DCREATE( pArray, pOldArray, nDims - 1, 4403 0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() ); 4404 } 4405 refRedimpArray = nullptr; 4406 } 4407 } 4408 4409 void SbiRuntime::StepTCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4410 { 4411 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4412 OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) ); 4413 4414 SbxObject* pCopyObj = createUserTypeImpl( aClass ); 4415 if( pCopyObj ) 4416 { 4417 pCopyObj->SetName( aName ); 4418 } 4419 SbxVariable* pNew = new SbxVariable; 4420 pNew->PutObject( pCopyObj ); 4421 pNew->SetDeclareClassName( aClass ); 4422 PushVar( pNew ); 4423 } 4424 4425 void SbiRuntime::implHandleSbxFlags( SbxVariable* pVar, SbxDataType t, sal_uInt32 nOp2 ) 4426 { 4427 bool bWithEvents = ((t & 0xff) == SbxOBJECT && (nOp2 & SBX_TYPE_WITH_EVENTS_FLAG) != 0); 4428 if( bWithEvents ) 4429 { 4430 pVar->SetFlag( SbxFlagBits::WithEvents ); 4431 } 4432 bool bDimAsNew = ((nOp2 & SBX_TYPE_DIM_AS_NEW_FLAG) != 0); 4433 if( bDimAsNew ) 4434 { 4435 pVar->SetFlag( SbxFlagBits::DimAsNew ); 4436 } 4437 bool bFixedString = ((t & 0xff) == SbxSTRING && (nOp2 & SBX_FIXED_LEN_STRING_FLAG) != 0); 4438 if( bFixedString ) 4439 { 4440 sal_uInt16 nCount = static_cast<sal_uInt16>( nOp2 >> 17 ); // len = all bits above 0x10000 4441 OUStringBuffer aBuf; 4442 comphelper::string::padToLength(aBuf, nCount); 4443 pVar->PutString(aBuf.makeStringAndClear()); 4444 } 4445 4446 bool bVarToDim = ((nOp2 & SBX_TYPE_VAR_TO_DIM_FLAG) != 0); 4447 if( bVarToDim ) 4448 { 4449 pVar->SetFlag( SbxFlagBits::VarToDim ); 4450 } 4451 } 4452 4453 // establishing a local variable (+StringID+type) 4454 4455 void SbiRuntime::StepLOCAL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4456 { 4457 if( !refLocals.is() ) 4458 { 4459 refLocals = new SbxArray; 4460 } 4461 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4462 if( refLocals->Find( aName, SbxClassType::DontCare ) == nullptr ) 4463 { 4464 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4465 SbxVariable* p = new SbxVariable( t ); 4466 p->SetName( aName ); 4467 implHandleSbxFlags( p, t, nOp2 ); 4468 refLocals->Put( p, refLocals->Count() ); 4469 } 4470 } 4471 4472 // establishing a module-global variable (+StringID+type) 4473 4474 void SbiRuntime::StepPUBLIC_Impl( sal_uInt32 nOp1, sal_uInt32 nOp2, bool bUsedForClassModule ) 4475 { 4476 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4477 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4478 bool bFlag = pMod->IsSet( SbxFlagBits::NoModify ); 4479 pMod->SetFlag( SbxFlagBits::NoModify ); 4480 SbxVariableRef p = pMod->Find( aName, SbxClassType::Property ); 4481 if( p.is() ) 4482 { 4483 pMod->Remove (p.get()); 4484 } 4485 SbProperty* pProp = pMod->GetProperty( aName, t ); 4486 if( !bUsedForClassModule ) 4487 { 4488 pProp->SetFlag( SbxFlagBits::Private ); 4489 } 4490 if( !bFlag ) 4491 { 4492 pMod->ResetFlag( SbxFlagBits::NoModify ); 4493 } 4494 if( pProp ) 4495 { 4496 pProp->SetFlag( SbxFlagBits::DontStore ); 4497 // from 2.7.1996: HACK because of 'reference can't be saved' 4498 pProp->SetFlag( SbxFlagBits::NoModify); 4499 4500 implHandleSbxFlags( pProp, t, nOp2 ); 4501 } 4502 } 4503 4504 void SbiRuntime::StepPUBLIC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4505 { 4506 StepPUBLIC_Impl( nOp1, nOp2, false ); 4507 } 4508 4509 void SbiRuntime::StepPUBLIC_P( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4510 { 4511 // Creates module variable that isn't reinitialised when 4512 // between invocations ( for VBASupport & document basic only ) 4513 if( pMod->pImage->bFirstInit ) 4514 { 4515 bool bUsedForClassModule = pImg->IsFlag( SbiImageFlags::CLASSMODULE ); 4516 StepPUBLIC_Impl( nOp1, nOp2, bUsedForClassModule ); 4517 } 4518 } 4519 4520 // establishing a global variable (+StringID+type) 4521 4522 void SbiRuntime::StepGLOBAL( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4523 { 4524 if( pImg->IsFlag( SbiImageFlags::CLASSMODULE ) ) 4525 { 4526 StepPUBLIC_Impl( nOp1, nOp2, true ); 4527 } 4528 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4529 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4530 4531 // Store module scope variables at module scope 4532 // in non vba mode these are stored at the library level :/ 4533 // not sure if this really should not be enabled for ALL basic 4534 SbxObject* pStorage = &rBasic; 4535 if ( SbiRuntime::isVBAEnabled() ) 4536 { 4537 pStorage = pMod; 4538 pMod->AddVarName( aName ); 4539 } 4540 4541 bool bFlag = pStorage->IsSet( SbxFlagBits::NoModify ); 4542 rBasic.SetFlag( SbxFlagBits::NoModify ); 4543 SbxVariableRef p = pStorage->Find( aName, SbxClassType::Property ); 4544 if( p.is() ) 4545 { 4546 pStorage->Remove (p.get()); 4547 } 4548 p = pStorage->Make( aName, SbxClassType::Property, t ); 4549 if( !bFlag ) 4550 { 4551 pStorage->ResetFlag( SbxFlagBits::NoModify ); 4552 } 4553 if( p.is() ) 4554 { 4555 p->SetFlag( SbxFlagBits::DontStore ); 4556 // from 2.7.1996: HACK because of 'reference can't be saved' 4557 p->SetFlag( SbxFlagBits::NoModify); 4558 } 4559 } 4560 4561 4562 // Creates global variable that isn't reinitialised when 4563 // basic is restarted, P=PERSIST (+StringID+Typ) 4564 4565 void SbiRuntime::StepGLOBAL_P( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4566 { 4567 if( pMod->pImage->bFirstInit ) 4568 { 4569 StepGLOBAL( nOp1, nOp2 ); 4570 } 4571 } 4572 4573 4574 // Searches for global variable, behavior depends on the fact 4575 // if the variable is initialised for the first time 4576 4577 void SbiRuntime::StepFIND_G( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4578 { 4579 if( pMod->pImage->bFirstInit ) 4580 { 4581 // Behave like always during first init 4582 StepFIND( nOp1, nOp2 ); 4583 } 4584 else 4585 { 4586 // Return dummy variable 4587 SbxDataType t = static_cast<SbxDataType>(nOp2); 4588 OUString aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) ); 4589 4590 SbxVariable* pDummyVar = new SbxVariable( t ); 4591 pDummyVar->SetName( aName ); 4592 PushVar( pDummyVar ); 4593 } 4594 } 4595 4596 4597 SbxVariable* SbiRuntime::StepSTATIC_Impl( 4598 OUString const & aName, SbxDataType t, sal_uInt32 nOp2 ) 4599 { 4600 SbxVariable* p = nullptr; 4601 if ( pMeth ) 4602 { 4603 SbxArray* pStatics = pMeth->GetStatics(); 4604 if( pStatics && ( pStatics->Find( aName, SbxClassType::DontCare ) == nullptr ) ) 4605 { 4606 p = new SbxVariable( t ); 4607 if( t != SbxVARIANT ) 4608 { 4609 p->SetFlag( SbxFlagBits::Fixed ); 4610 } 4611 p->SetName( aName ); 4612 implHandleSbxFlags( p, t, nOp2 ); 4613 pStatics->Put( p, pStatics->Count() ); 4614 } 4615 } 4616 return p; 4617 } 4618 // establishing a static variable (+StringID+type) 4619 void SbiRuntime::StepSTATIC( sal_uInt32 nOp1, sal_uInt32 nOp2 ) 4620 { 4621 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) ); 4622 SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff); 4623 StepSTATIC_Impl( aName, t, nOp2 ); 4624 } 4625 4626 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */ 4627
