xref: /core/basic/source/runtime/runtime.cxx (revision 175a2063)
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