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