xref: /core/basic/source/runtime/runtime.cxx (revision 889dc7bf)
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 <sbunoobj.hxx>
69 #include <basic/codecompletecache.hxx>
70 #include <memory>
71 
72 using com::sun::star::uno::Reference;
73 
74 using namespace com::sun::star::uno;
75 using namespace com::sun::star::container;
76 using namespace com::sun::star::lang;
77 using namespace com::sun::star::beans;
78 using namespace com::sun::star::script;
79 
80 using namespace ::com::sun::star;
81 
82 static void lcl_clearImpl( SbxVariableRef const & refVar, SbxDataType const & eType );
83 static void lcl_eraseImpl( SbxVariableRef const & refVar, bool bVBAEnabled );
84 
85 bool SbiRuntime::isVBAEnabled()
86 {
87     bool bResult = false;
88     SbiInstance* pInst = GetSbData()->pInst;
89     if ( pInst && GetSbData()->pInst->pRun )
90         bResult = pInst->pRun->bVBAEnabled;
91     return bResult;
92 }
93 
94 void StarBASIC::SetVBAEnabled( bool bEnabled )
95 {
96     if ( bDocBasic )
97     {
98         bVBAEnabled = bEnabled;
99     }
100 }
101 
102 bool StarBASIC::isVBAEnabled()
103 {
104     if ( bDocBasic )
105     {
106         if( SbiRuntime::isVBAEnabled() )
107             return true;
108         return bVBAEnabled;
109     }
110     return false;
111 }
112 
113 struct SbiArgv {                   // Argv stack:
114     SbxArrayRef    refArgv;             // Argv
115     short nArgc;                        // Argc
116 
117     SbiArgv(SbxArrayRef const & refArgv_, short nArgc_) :
118         refArgv(refArgv_),
119         nArgc(nArgc_) {}
120 };
121 
122 #define MAXRECURSION 500 //to prevent dead-recursions
123 
124 struct SbiGosub {              // GOSUB-Stack:
125     const sal_uInt8* pCode;         // Return-Pointer
126     sal_uInt16 nStartForLvl;        // #118235: For Level in moment of gosub
127 
128     SbiGosub(const sal_uInt8* pCode_, sal_uInt16 nStartForLvl_) :
129         pCode(pCode_),
130         nStartForLvl(nStartForLvl_) {}
131 };
132 
133 SbiRuntime::pStep0 SbiRuntime::aStep0[] = { // all opcodes without operands
134     &SbiRuntime::StepNOP,
135     &SbiRuntime::StepEXP,
136     &SbiRuntime::StepMUL,
137     &SbiRuntime::StepDIV,
138     &SbiRuntime::StepMOD,
139     &SbiRuntime::StepPLUS,
140     &SbiRuntime::StepMINUS,
141     &SbiRuntime::StepNEG,
142     &SbiRuntime::StepEQ,
143     &SbiRuntime::StepNE,
144     &SbiRuntime::StepLT,
145     &SbiRuntime::StepGT,
146     &SbiRuntime::StepLE,
147     &SbiRuntime::StepGE,
148     &SbiRuntime::StepIDIV,
149     &SbiRuntime::StepAND,
150     &SbiRuntime::StepOR,
151     &SbiRuntime::StepXOR,
152     &SbiRuntime::StepEQV,
153     &SbiRuntime::StepIMP,
154     &SbiRuntime::StepNOT,
155     &SbiRuntime::StepCAT,
156 
157     &SbiRuntime::StepLIKE,
158     &SbiRuntime::StepIS,
159     // load/save
160     &SbiRuntime::StepARGC,      // establish new Argv
161     &SbiRuntime::StepARGV,      // TOS ==> current Argv
162     &SbiRuntime::StepINPUT,     // Input ==> TOS
163     &SbiRuntime::StepLINPUT,        // Line Input ==> TOS
164     &SbiRuntime::StepGET,        // touch TOS
165     &SbiRuntime::StepSET,        // save object TOS ==> TOS-1
166     &SbiRuntime::StepPUT,       // TOS ==> TOS-1
167     &SbiRuntime::StepPUTC,      // TOS ==> TOS-1, then ReadOnly
168     &SbiRuntime::StepDIM,       // DIM
169     &SbiRuntime::StepREDIM,         // REDIM
170     &SbiRuntime::StepREDIMP,        // REDIM PRESERVE
171     &SbiRuntime::StepERASE,         // delete TOS
172     // branch
173     &SbiRuntime::StepSTOP,          // program end
174     &SbiRuntime::StepINITFOR,   // initialize FOR-Variable
175     &SbiRuntime::StepNEXT,      // increment FOR-Variable
176     &SbiRuntime::StepCASE,      // beginning CASE
177     &SbiRuntime::StepENDCASE,   // end CASE
178     &SbiRuntime::StepSTDERROR,      // standard error handling
179     &SbiRuntime::StepNOERROR,   // no error handling
180     &SbiRuntime::StepLEAVE,     // leave UP
181     // E/A
182     &SbiRuntime::StepCHANNEL,   // TOS = channel number
183     &SbiRuntime::StepPRINT,     // print TOS
184     &SbiRuntime::StepPRINTF,        // print TOS in field
185     &SbiRuntime::StepWRITE,     // write TOS
186     &SbiRuntime::StepRENAME,        // Rename Tos+1 to Tos
187     &SbiRuntime::StepPROMPT,        // define Input Prompt from TOS
188     &SbiRuntime::StepRESTART,   // Set restart point
189     &SbiRuntime::StepCHANNEL0,  // set E/A-channel 0
190     &SbiRuntime::StepEMPTY,     // empty expression on stack
191     &SbiRuntime::StepERROR,     // TOS = error code
192     &SbiRuntime::StepLSET,      // save object TOS ==> TOS-1
193     &SbiRuntime::StepRSET,      // save object TOS ==> TOS-1
194     &SbiRuntime::StepREDIMP_ERASE,// Copy array object for REDIMP
195     &SbiRuntime::StepINITFOREACH,// Init for each loop
196     &SbiRuntime::StepVBASET,// vba-like set statement
197     &SbiRuntime::StepERASE_CLEAR,// vba-like set statement
198     &SbiRuntime::StepARRAYACCESS,// access TOS as array
199     &SbiRuntime::StepBYVAL,     // access TOS as array
200 };
201 
202 SbiRuntime::pStep1 SbiRuntime::aStep1[] = { // all opcodes with one operand
203     &SbiRuntime::StepLOADNC,        // loading a numeric constant (+ID)
204     &SbiRuntime::StepLOADSC,        // loading a string constant (+ID)
205     &SbiRuntime::StepLOADI,     // Immediate Load (+value)
206     &SbiRuntime::StepARGN,      // save a named Args in Argv (+StringID)
207     &SbiRuntime::StepPAD,       // bring string to a definite length (+length)
208     // branches
209     &SbiRuntime::StepJUMP,      // jump (+Target)
210     &SbiRuntime::StepJUMPT,     // evaluate TOS, conditional jump (+Target)
211     &SbiRuntime::StepJUMPF,     // evaluate TOS, conditional jump (+Target)
212     &SbiRuntime::StepONJUMP,        // evaluate TOS, jump into JUMP-table (+MaxVal)
213     &SbiRuntime::StepGOSUB,     // UP-call (+Target)
214     &SbiRuntime::StepRETURN,        // UP-return (+0 or Target)
215     &SbiRuntime::StepTESTFOR,   // check FOR-variable, increment (+Endlabel)
216     &SbiRuntime::StepCASETO,        // Tos+1 <= Case <= Tos), 2xremove (+Target)
217     &SbiRuntime::StepERRHDL,        // error handler (+Offset)
218     &SbiRuntime::StepRESUME,        // resume after errors (+0 or 1 or Label)
219     // E/A
220     &SbiRuntime::StepCLOSE,     // (+channel/0)
221     &SbiRuntime::StepPRCHAR,        // (+char)
222     // management
223     &SbiRuntime::StepSETCLASS,  // check set + class names (+StringId)
224     &SbiRuntime::StepTESTCLASS, // Check TOS class (+StringId)
225     &SbiRuntime::StepLIB,       // lib for declare-call (+StringId)
226     &SbiRuntime::StepBASED,     // TOS is incremented by BASE, BASE is pushed before
227     &SbiRuntime::StepARGTYP,        // convert last parameter in Argv (+Type)
228     &SbiRuntime::StepVBASETCLASS,// vba-like set statement
229 };
230 
231 SbiRuntime::pStep2 SbiRuntime::aStep2[] = {// all opcodes with two operands
232     &SbiRuntime::StepRTL,       // load from RTL (+StringID+Typ)
233     &SbiRuntime::StepFIND,      // load (+StringID+Typ)
234     &SbiRuntime::StepELEM,          // load element (+StringID+Typ)
235     &SbiRuntime::StepPARAM,     // Parameter (+Offset+Typ)
236     // branches
237     &SbiRuntime::StepCALL,      // Declare-Call (+StringID+Typ)
238     &SbiRuntime::StepCALLC,     // CDecl-Declare-Call (+StringID+Typ)
239     &SbiRuntime::StepCASEIS,        // Case-Test (+Test-Opcode+False-Target)
240     // management
241     &SbiRuntime::StepSTMNT,         // beginning of a statement (+Line+Col)
242     // E/A
243     &SbiRuntime::StepOPEN,          // (+StreamMode+Flags)
244     // Objects
245     &SbiRuntime::StepLOCAL,     // define local variable (+StringId+Typ)
246     &SbiRuntime::StepPUBLIC,        // module global variable (+StringID+Typ)
247     &SbiRuntime::StepGLOBAL,        // define global variable (+StringID+Typ)
248     &SbiRuntime::StepCREATE,        // create object (+StringId+StringId)
249     &SbiRuntime::StepSTATIC,     // static variable (+StringId+StringId)
250     &SbiRuntime::StepTCREATE,    // user-defined objects (+StringId+StringId)
251     &SbiRuntime::StepDCREATE,    // create object-array (+StringID+StringID)
252     &SbiRuntime::StepGLOBAL_P,   // define global variable which is not overwritten
253                                  // by the Basic on a restart (+StringID+Typ)
254     &SbiRuntime::StepFIND_G,        // finds global variable with special treatment because of _GLOBAL_P
255     &SbiRuntime::StepDCREATE_REDIMP, // redimension object array (+StringID+StringID)
256     &SbiRuntime::StepFIND_CM,    // Search inside a class module (CM) to enable global search in time
257     &SbiRuntime::StepPUBLIC_P,    // Search inside a class module (CM) to enable global search in time
258     &SbiRuntime::StepFIND_STATIC,    // Search inside a class module (CM) to enable global search in time
259 };
260 
261 
262 //                              SbiRTLData
263 
264 SbiRTLData::SbiRTLData()
265 {
266     nDirFlags   = SbAttributes::NONE;
267     nCurDirPos  = 0;
268 }
269 
270 SbiRTLData::~SbiRTLData()
271 {
272 }
273 
274 //                              SbiInstance
275 
276 // 16.10.96: #31460 new concept for StepInto/Over/Out
277 // The decision whether StepPoint shall be called is done with the help of
278 // the CallLevel. It's stopped when the current CallLevel is <= nBreakCallLvl.
279 // The current CallLevel can never be smaller than 1, as it's also incremented
280 // during the call of a method (also main). Therefore a BreakCallLvl from 0
281 // means that the program isn't stopped at all.
282 // (also have a look at: step2.cxx, SbiRuntime::StepSTMNT() )
283 
284 
285 void SbiInstance::CalcBreakCallLevel( BasicDebugFlags nFlags )
286 {
287 
288     nFlags &= ~BasicDebugFlags::Break;
289 
290     sal_uInt16 nRet;
291     if (nFlags  == BasicDebugFlags::StepInto) {
292         nRet = nCallLvl + 1;    // CallLevel+1 is also stopped
293     } else if (nFlags == (BasicDebugFlags::StepOver | BasicDebugFlags::StepInto)) {
294         nRet = nCallLvl;        // current CallLevel is stopped
295     } else if (nFlags == BasicDebugFlags::StepOut) {
296         nRet = nCallLvl - 1;    // smaller CallLevel is stopped
297     } else {
298         // Basic-IDE returns 0 instead of BasicDebugFlags::Continue, so also default=continue
299         nRet = 0;               // CallLevel is always > 0 -> no StepPoint
300     }
301     nBreakCallLvl = nRet;           // take result
302 }
303 
304 SbiInstance::SbiInstance( StarBASIC* p )
305     : pIosys(new SbiIoSystem)
306     , pDdeCtrl(new SbiDdeControl)
307     , pBasic(p)
308     , meFormatterLangType(LANGUAGE_DONTKNOW)
309     , meFormatterDateOrder(DateOrder::YMD)
310     , nStdDateIdx(0)
311     , nStdTimeIdx(0)
312     , nStdDateTimeIdx(0)
313     , nErr(0)
314     , nErl(0)
315     , bReschedule(true)
316     , bCompatibility(false)
317     , pRun(nullptr)
318     , nCallLvl(0)
319     , nBreakCallLvl(0)
320 {
321 }
322 
323 SbiInstance::~SbiInstance()
324 {
325     while( pRun )
326     {
327         SbiRuntime* p = pRun->pNext;
328         delete pRun;
329         pRun = p;
330     }
331 
332     try
333     {
334         int nSize = ComponentVector.size();
335         if( nSize )
336         {
337             for( int i = nSize - 1 ; i >= 0 ; --i )
338             {
339                 Reference< XComponent > xDlgComponent = ComponentVector[i];
340                 if( xDlgComponent.is() )
341                     xDlgComponent->dispose();
342             }
343         }
344     }
345     catch( const Exception& )
346     {
347         TOOLS_WARN_EXCEPTION("basic", "SbiInstance::~SbiInstance: caught an exception while disposing the components" );
348     }
349 }
350 
351 SbiDllMgr* SbiInstance::GetDllMgr()
352 {
353     if( !pDllMgr )
354     {
355         pDllMgr.reset(new SbiDllMgr);
356     }
357     return pDllMgr.get();
358 }
359 
360 // #39629 create NumberFormatter with the help of a static method now
361 std::shared_ptr<SvNumberFormatter> const & SbiInstance::GetNumberFormatter()
362 {
363     LanguageType eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
364     SvtSysLocale aSysLocale;
365     DateOrder eDate = aSysLocale.GetLocaleData().getDateOrder();
366     if( pNumberFormatter )
367     {
368         if( eLangType != meFormatterLangType ||
369             eDate != meFormatterDateOrder )
370         {
371             pNumberFormatter.reset();
372         }
373     }
374     meFormatterLangType = eLangType;
375     meFormatterDateOrder = eDate;
376     if( !pNumberFormatter )
377     {
378         pNumberFormatter = PrepareNumberFormatter( nStdDateIdx, nStdTimeIdx, nStdDateTimeIdx,
379                 &meFormatterLangType, &meFormatterDateOrder);
380     }
381     return pNumberFormatter;
382 }
383 
384 // #39629 offer NumberFormatter static too
385 std::shared_ptr<SvNumberFormatter> SbiInstance::PrepareNumberFormatter( sal_uInt32 &rnStdDateIdx,
386     sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx,
387     LanguageType const * peFormatterLangType, DateOrder const * peFormatterDateOrder )
388 {
389     LanguageType eLangType;
390     if( peFormatterLangType )
391     {
392         eLangType = *peFormatterLangType;
393     }
394     else
395     {
396         eLangType = Application::GetSettings().GetLanguageTag().getLanguageType();
397     }
398     DateOrder eDate;
399     if( peFormatterDateOrder )
400     {
401         eDate = *peFormatterDateOrder;
402     }
403     else
404     {
405         SvtSysLocale aSysLocale;
406         eDate = aSysLocale.GetLocaleData().getDateOrder();
407     }
408 
409     std::shared_ptr<SvNumberFormatter> pNumberFormatter(
410             new SvNumberFormatter( comphelper::getProcessComponentContext(), eLangType ));
411 
412     // Several parser methods pass SvNumberFormatter::IsNumberFormat() a number
413     // format index to parse against. Tell the formatter the proper date
414     // evaluation order, which also determines the date acceptance patterns to
415     // use if a format was passed. NF_EVALDATEFORMAT_FORMAT restricts to the
416     // format's locale's date patterns/order (no init/system locale match
417     // tried) and falls back to NF_EVALDATEFORMAT_INTL if no specific (i.e. 0)
418     // (or an unknown) format index was passed.
419     pNumberFormatter->SetEvalDateFormat( NF_EVALDATEFORMAT_FORMAT);
420 
421     sal_Int32 nCheckPos = 0;
422     SvNumFormatType nType;
423     rnStdTimeIdx = pNumberFormatter->GetStandardFormat( SvNumFormatType::TIME, eLangType );
424 
425     // the formatter's standard templates have only got a two-digit date
426     // -> registering an own format
427 
428     // HACK, because the numberformatter doesn't swap the place holders
429     // for month, day and year according to the system setting.
430     // Problem: Print Year(Date) under engl. BS
431     // also have a look at: basic/source/sbx/sbxdate.cxx
432 
433     OUString aDateStr;
434     switch( eDate )
435     {
436         default:
437         case DateOrder::MDY: aDateStr = "MM/DD/YYYY"; break;
438         case DateOrder::DMY: aDateStr = "DD/MM/YYYY"; break;
439         case DateOrder::YMD: aDateStr = "YYYY/MM/DD"; break;
440     }
441     OUString aStr( aDateStr );      // PutandConvertEntry() modifies string!
442     pNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType,
443         rnStdDateIdx, LANGUAGE_ENGLISH_US, eLangType, true);
444     nCheckPos = 0;
445     aDateStr += " HH:MM:SS";
446     aStr = aDateStr;
447     pNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType,
448         rnStdDateTimeIdx, LANGUAGE_ENGLISH_US, eLangType, true);
449     return pNumberFormatter;
450 }
451 
452 
453 // Let engine run. If Flags == BasicDebugFlags::Continue, take Flags over
454 
455 void SbiInstance::Stop()
456 {
457     for( SbiRuntime* p = pRun; p; p = p->pNext )
458     {
459         p->Stop();
460     }
461 }
462 
463 // Allows Basic IDE to set watch mode to suppress errors
464 static bool bWatchMode = false;
465 
466 void setBasicWatchMode( bool bOn )
467 {
468     bWatchMode = bOn;
469 }
470 
471 void SbiInstance::Error( ErrCode n )
472 {
473     Error( n, OUString() );
474 }
475 
476 void SbiInstance::Error( ErrCode n, const OUString& rMsg )
477 {
478     if( !bWatchMode )
479     {
480         aErrorMsg = rMsg;
481         pRun->Error( n );
482     }
483 }
484 
485 void SbiInstance::ErrorVB( sal_Int32 nVBNumber, const OUString& rMsg )
486 {
487     if( !bWatchMode )
488     {
489         ErrCode n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) );
490         if ( !n )
491         {
492             n = ErrCode(nVBNumber); // force orig number, probably should have a specific table of vb ( localized ) errors
493         }
494         aErrorMsg = rMsg;
495         SbiRuntime::translateErrorToVba( n, aErrorMsg );
496 
497         pRun->Error( ERRCODE_BASIC_COMPAT, true/*bVBATranslationAlreadyDone*/ );
498     }
499 }
500 
501 void SbiInstance::setErrorVB( sal_Int32 nVBNumber )
502 {
503     ErrCode n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) );
504     if( !n )
505     {
506         n = ErrCode(nVBNumber); // force orig number, probably should have a specific table of vb ( localized ) errors
507     }
508     aErrorMsg = OUString();
509     SbiRuntime::translateErrorToVba( n, aErrorMsg );
510 
511     nErr = n;
512 }
513 
514 
515 void SbiInstance::FatalError( ErrCode n )
516 {
517     pRun->FatalError( n );
518 }
519 
520 void SbiInstance::FatalError( ErrCode _errCode, const OUString& _details )
521 {
522     pRun->FatalError( _errCode, _details );
523 }
524 
525 void SbiInstance::Abort()
526 {
527     StarBASIC* pErrBasic = GetCurrentBasic( pBasic );
528     pErrBasic->RTError( nErr, aErrorMsg, pRun->nLine, pRun->nCol1, pRun->nCol2 );
529     StarBASIC::Stop();
530 }
531 
532 // can be unequal to pRTBasic
533 StarBASIC* GetCurrentBasic( StarBASIC* pRTBasic )
534 {
535     StarBASIC* pCurBasic = pRTBasic;
536     SbModule* pActiveModule = StarBASIC::GetActiveModule();
537     if( pActiveModule )
538     {
539         SbxObject* pParent = pActiveModule->GetParent();
540         if (StarBASIC *pBasic = dynamic_cast<StarBASIC*>(pParent))
541             pCurBasic = pBasic;
542     }
543     return pCurBasic;
544 }
545 
546 SbModule* SbiInstance::GetActiveModule()
547 {
548     if( pRun )
549     {
550         return pRun->GetModule();
551     }
552     else
553     {
554         return nullptr;
555     }
556 }
557 
558 SbMethod* SbiInstance::GetCaller( sal_uInt16 nLevel )
559 {
560     SbiRuntime* p = pRun;
561     while( nLevel-- && p )
562     {
563         p = p->pNext;
564     }
565     return p ? p->GetCaller() : nullptr;
566 }
567 
568 //                              SbiInstance
569 
570 // Attention: pMeth can also be NULL (on a call of the init-code)
571 
572 SbiRuntime::SbiRuntime( SbModule* pm, SbMethod* pe, sal_uInt32 nStart )
573          : rBasic( *static_cast<StarBASIC*>(pm->pParent) ), pInst( GetSbData()->pInst ),
574            pMod( pm ), pMeth( pe ), pImg( pMod->pImage.get() ), mpExtCaller(nullptr), m_nLastTime(0)
575 {
576     nFlags    = pe ? pe->GetDebugFlags() : BasicDebugFlags::NONE;
577     pIosys    = pInst->GetIoSystem();
578     pForStk   = nullptr;
579     pError    = nullptr;
580     pErrCode  =
581     pErrStmnt =
582     pRestart  = nullptr;
583     pNext     = nullptr;
584     pCode     =
585     pStmnt    = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nStart;
586     bRun      =
587     bError    = true;
588     bInError  = false;
589     bBlocked  = false;
590     nLine     = 0;
591     nCol1     = 0;
592     nCol2     = 0;
593     nExprLvl  = 0;
594     nArgc     = 0;
595     nError    = ERRCODE_NONE;
596     nForLvl   = 0;
597     nOps      = 0;
598     refExprStk = new SbxArray;
599     SetVBAEnabled( pMod->IsVBACompat() );
600     SetParameters( pe ? pe->GetParameters() : nullptr );
601 }
602 
603 SbiRuntime::~SbiRuntime()
604 {
605     ClearArgvStack();
606     ClearForStack();
607 }
608 
609 void SbiRuntime::SetVBAEnabled(bool bEnabled )
610 {
611     bVBAEnabled = bEnabled;
612     if ( bVBAEnabled )
613     {
614         if ( pMeth )
615         {
616             mpExtCaller = pMeth->mCaller;
617         }
618     }
619     else
620     {
621         mpExtCaller = nullptr;
622     }
623 }
624 
625 // Construction of the parameter list. All ByRef-parameters are directly
626 // taken over; copies of ByVal-parameters are created. If a particular
627 // data type is requested, it is converted.
628 
629 void SbiRuntime::SetParameters( SbxArray* pParams )
630 {
631     refParams = new SbxArray;
632     // for the return value
633     refParams->Put( pMeth, 0 );
634 
635     SbxInfo* pInfo = pMeth ? pMeth->GetInfo() : nullptr;
636     sal_uInt16 nParamCount = pParams ? pParams->Count() : 1;
637     if( nParamCount > 1 )
638     {
639         for( sal_uInt16 i = 1 ; i < nParamCount ; i++ )
640         {
641             const SbxParamInfo* p = pInfo ? pInfo->GetParam( i ) : nullptr;
642 
643             // #111897 ParamArray
644             if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 )
645             {
646                 SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
647                 sal_uInt16 nParamArrayParamCount = nParamCount - i;
648                 pArray->unoAddDim( 0, nParamArrayParamCount - 1 );
649                 for (sal_uInt16 j = i; j < nParamCount ; ++j)
650                 {
651                     SbxVariable* v = pParams->Get( j );
652                     short aDimIndex[1];
653                     aDimIndex[0] = j - i;
654                     pArray->Put(v, aDimIndex);
655                 }
656                 SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT );
657                 pArrayVar->SetFlag( SbxFlagBits::ReadWrite );
658                 pArrayVar->PutObject( pArray );
659                 refParams->Put( pArrayVar, i );
660 
661                 // Block ParamArray for missing parameter
662                 pInfo = nullptr;
663                 break;
664             }
665 
666             SbxVariable* v = pParams->Get( 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->Put( 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->Put( v, i );
709             }
710             if( p )
711             {
712                 refParams->PutAlias( 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( nParamCount );
722         if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 )
723         {
724             SbxDimArray* pArray = new SbxDimArray( SbxVARIANT );
725             pArray->unoAddDim( 0, -1 );
726             SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT );
727             pArrayVar->SetFlag( SbxFlagBits::ReadWrite );
728             pArrayVar->PutObject( pArray );
729             refParams->Put( 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->Put( 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->Get( --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->Get( static_cast<sal_uInt16>(n) );
1012 }
1013 
1014 
1015 void SbiRuntime::TOSMakeTemp()
1016 {
1017     SbxVariable* p = refExprStk->Get( 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->Put( p, nExprLvl - 1 );
1035     }
1036     else if( p->GetRefCount() != 1 )
1037     {
1038         SbxVariable* pNew = new SbxVariable( *p );
1039         pNew->SetFlag( SbxFlagBits::ReadWrite );
1040         refExprStk->Put( 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         short nDims = pArray->GetDims();
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( short 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()
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 
1700 // VBA Dim As New behavior handling, save init object information
1701 struct DimAsNewRecoverItem
1702 {
1703     OUString        m_aObjClass;
1704     OUString        m_aObjName;
1705     SbxObject*      m_pObjParent;
1706     SbModule*       m_pClassModule;
1707 
1708     DimAsNewRecoverItem()
1709         : m_pObjParent( nullptr )
1710         , m_pClassModule( nullptr )
1711     {}
1712 
1713     DimAsNewRecoverItem( const OUString& rObjClass, const OUString& rObjName,
1714                          SbxObject* pObjParent, SbModule* pClassModule )
1715             : m_aObjClass( rObjClass )
1716             , m_aObjName( rObjName )
1717             , m_pObjParent( pObjParent )
1718             , m_pClassModule( pClassModule )
1719     {}
1720 
1721 };
1722 
1723 
1724 struct SbxVariablePtrHash
1725 {
1726     size_t operator()( SbxVariable* pVar ) const
1727         { return reinterpret_cast<size_t>(pVar); }
1728 };
1729 
1730 typedef std::unordered_map< SbxVariable*, DimAsNewRecoverItem,
1731                               SbxVariablePtrHash >  DimAsNewRecoverHash;
1732 
1733 class GaDimAsNewRecoverHash : public rtl::Static<DimAsNewRecoverHash, GaDimAsNewRecoverHash> {};
1734 
1735 void removeDimAsNewRecoverItem( SbxVariable* pVar )
1736 {
1737     DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get();
1738     DimAsNewRecoverHash::iterator it = rDimAsNewRecoverHash.find( pVar );
1739     if( it != rDimAsNewRecoverHash.end() )
1740     {
1741         rDimAsNewRecoverHash.erase( it );
1742     }
1743 }
1744 
1745 
1746 // saving object variable
1747 // not-object variables will cause errors
1748 
1749 static const char pCollectionStr[] = "Collection";
1750 
1751 void SbiRuntime::StepSET_Impl( SbxVariableRef& refVal, SbxVariableRef& refVar, bool bHandleDefaultProp )
1752 {
1753     // #67733 types with array-flag are OK too
1754 
1755     // Check var, !object is no error for sure if, only if type is fixed
1756     SbxDataType eVarType = refVar->GetType();
1757     if( !bHandleDefaultProp && eVarType != SbxOBJECT && !(eVarType & SbxARRAY) && refVar->IsFixed() )
1758     {
1759         Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
1760         return;
1761     }
1762 
1763     // Check value, !object is no error for sure if, only if type is fixed
1764     SbxDataType eValType = refVal->GetType();
1765     if( !bHandleDefaultProp && eValType != SbxOBJECT && !(eValType & SbxARRAY) && refVal->IsFixed() )
1766     {
1767         Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
1768         return;
1769     }
1770 
1771     // Getting in here causes problems with objects with default properties
1772     // if they are SbxEMPTY I guess
1773     if ( !bHandleDefaultProp || eValType == SbxOBJECT )
1774     {
1775     // activate GetObject for collections on refVal
1776         SbxBase* pObjVarObj = refVal->GetObject();
1777         if( pObjVarObj )
1778         {
1779             SbxVariableRef refObjVal = dynamic_cast<SbxObject*>( pObjVarObj );
1780 
1781             if( refObjVal.is() )
1782             {
1783                 refVal = refObjVal;
1784             }
1785             else if( !(eValType & SbxARRAY) )
1786             {
1787                 refVal = nullptr;
1788             }
1789         }
1790     }
1791 
1792     // #52896 refVal can be invalid here, if uno-sequences - or more
1793     // general arrays - are assigned to variables that are declared
1794     // as an object!
1795     if( !refVal.is() )
1796     {
1797         Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
1798     }
1799     else
1800     {
1801         bool bFlagsChanged = false;
1802         SbxFlagBits n = SbxFlagBits::NONE;
1803         if( refVar.get() == pMeth )
1804         {
1805             bFlagsChanged = true;
1806             n = refVar->GetFlags();
1807             refVar->SetFlag( SbxFlagBits::Write );
1808         }
1809         SbProcedureProperty* pProcProperty = dynamic_cast<SbProcedureProperty*>( refVar.get() );
1810         if( pProcProperty )
1811         {
1812             pProcProperty->setSet( true );
1813         }
1814         if ( bHandleDefaultProp )
1815         {
1816             // get default properties for lhs & rhs where necessary
1817             // SbxVariable* defaultProp = NULL; unused variable
1818             // LHS try determine if a default prop exists
1819             // again like in StepPUT (see there too ) we are tweaking the
1820             // heuristics again for when to assign an object reference or
1821             // use default members if they exist
1822             // #FIXME we really need to get to the bottom of this mess
1823             bool bObjAssign = false;
1824             if ( refVar->GetType() == SbxOBJECT )
1825             {
1826                 if ( dynamic_cast<const SbxMethod *>(refVar.get()) != nullptr || ! refVar->GetParent() )
1827                 {
1828                     SbxVariable* pDflt = getDefaultProp( refVar.get() );
1829                     if ( pDflt )
1830                     {
1831                         refVar = pDflt;
1832                     }
1833                 }
1834                 else
1835                     bObjAssign = true;
1836             }
1837             // RHS only get a default prop is the rhs has one
1838             if (  refVal->GetType() == SbxOBJECT )
1839             {
1840                 // check if lhs is a null object
1841                 // if it is then use the object not the default property
1842                 SbxObject* pObj = dynamic_cast<SbxObject*>( refVar.get() );
1843 
1844                 // calling GetObject on a SbxEMPTY variable raises
1845                 // object not set errors, make sure it's an Object
1846                 if ( !pObj && refVar->GetType() == SbxOBJECT )
1847                 {
1848                     SbxBase* pObjVarObj = refVar->GetObject();
1849                     pObj = dynamic_cast<SbxObject*>( pObjVarObj );
1850                 }
1851                 SbxVariable* pDflt = nullptr;
1852                 if ( pObj && !bObjAssign )
1853                 {
1854                     // lhs is either a valid object || or has a defaultProp
1855                     pDflt = getDefaultProp( refVal.get() );
1856                 }
1857                 if ( pDflt )
1858                 {
1859                     refVal = pDflt;
1860                 }
1861             }
1862         }
1863 
1864         // Handle Dim As New
1865         bool bDimAsNew = bVBAEnabled && refVar->IsSet( SbxFlagBits::DimAsNew );
1866         SbxBaseRef xPrevVarObj;
1867         if( bDimAsNew )
1868         {
1869             xPrevVarObj = refVar->GetObject();
1870         }
1871         // Handle withevents
1872         bool bWithEvents = refVar->IsSet( SbxFlagBits::WithEvents );
1873         if ( bWithEvents )
1874         {
1875             Reference< XInterface > xComListener;
1876 
1877             SbxBase* pObj = refVal->GetObject();
1878             SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj );
1879             if( pUnoObj != nullptr )
1880             {
1881                 Any aControlAny = pUnoObj->getUnoAny();
1882                 OUString aDeclareClassName = refVar->GetDeclareClassName();
1883                 OUString aPrefix = refVar->GetName();
1884                 SbxObjectRef xScopeObj = refVar->GetParent();
1885                 xComListener = createComListener( aControlAny, aDeclareClassName, aPrefix, xScopeObj );
1886 
1887                 refVal->SetDeclareClassName( aDeclareClassName );
1888                 refVal->SetComListener( xComListener, &rBasic );        // Hold reference
1889             }
1890 
1891         }
1892 
1893         // lhs is a property who's value is currently (Empty e.g. no broadcast yet)
1894         // in this case if there is a default prop involved the value of the
1895         // default property may in fact be void so the type will also be SbxEMPTY
1896         // in this case we do not want to call checkUnoStructCopy 'cause that will
1897         // cause an error also
1898         if ( !checkUnoStructCopy( bHandleDefaultProp, refVal, refVar ) )
1899         {
1900             *refVar = *refVal;
1901         }
1902         if ( bDimAsNew )
1903         {
1904             if( dynamic_cast<const SbxObject*>( refVar.get() ) == nullptr )
1905             {
1906                 SbxBase* pValObjBase = refVal->GetObject();
1907                 if( pValObjBase == nullptr )
1908                 {
1909                     if( xPrevVarObj.is() )
1910                     {
1911                         // Object is overwritten with NULL, instantiate init object
1912                         DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get();
1913                         DimAsNewRecoverHash::iterator it = rDimAsNewRecoverHash.find( refVar.get() );
1914                         if( it != rDimAsNewRecoverHash.end() )
1915                         {
1916                             const DimAsNewRecoverItem& rItem = it->second;
1917                             if( rItem.m_pClassModule != nullptr )
1918                             {
1919                                 SbClassModuleObject* pNewObj = new SbClassModuleObject( rItem.m_pClassModule );
1920                                 pNewObj->SetName( rItem.m_aObjName );
1921                                 pNewObj->SetParent( rItem.m_pObjParent );
1922                                 refVar->PutObject( pNewObj );
1923                             }
1924                             else if( rItem.m_aObjClass.equalsIgnoreAsciiCase( pCollectionStr ) )
1925                             {
1926                                 BasicCollection* pNewCollection = new BasicCollection( pCollectionStr );
1927                                 pNewCollection->SetName( rItem.m_aObjName );
1928                                 pNewCollection->SetParent( rItem.m_pObjParent );
1929                                 refVar->PutObject( pNewCollection );
1930                             }
1931                         }
1932                     }
1933                 }
1934                 else
1935                 {
1936                     // Does old value exist?
1937                     bool bFirstInit = !xPrevVarObj.is();
1938                     if( bFirstInit )
1939                     {
1940                         // Store information to instantiate object later
1941                         SbxObject* pValObj = dynamic_cast<SbxObject*>( pValObjBase );
1942                         if( pValObj != nullptr )
1943                         {
1944                             OUString aObjClass = pValObj->GetClassName();
1945 
1946                             SbClassModuleObject* pClassModuleObj = dynamic_cast<SbClassModuleObject*>( pValObjBase );
1947                             DimAsNewRecoverHash &rDimAsNewRecoverHash = GaDimAsNewRecoverHash::get();
1948                             if( pClassModuleObj != nullptr )
1949                             {
1950                                 SbModule* pClassModule = pClassModuleObj->getClassModule();
1951                                 rDimAsNewRecoverHash[refVar.get()] =
1952                                     DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), pClassModule );
1953                             }
1954                             else if( aObjClass.equalsIgnoreAsciiCase( "Collection" ) )
1955                             {
1956                                 rDimAsNewRecoverHash[refVar.get()] =
1957                                     DimAsNewRecoverItem( aObjClass, pValObj->GetName(), pValObj->GetParent(), nullptr );
1958                             }
1959                         }
1960                     }
1961                 }
1962             }
1963         }
1964 
1965         if( bFlagsChanged )
1966         {
1967             refVar->SetFlags( n );
1968         }
1969     }
1970 }
1971 
1972 void SbiRuntime::StepSET()
1973 {
1974     SbxVariableRef refVal = PopVar();
1975     SbxVariableRef refVar = PopVar();
1976     StepSET_Impl( refVal, refVar, bVBAEnabled ); // this is really assignment
1977 }
1978 
1979 void SbiRuntime::StepVBASET()
1980 {
1981     SbxVariableRef refVal = PopVar();
1982     SbxVariableRef refVar = PopVar();
1983     // don't handle default property
1984     StepSET_Impl( refVal, refVar ); // set obj = something
1985 }
1986 
1987 
1988 void SbiRuntime::StepLSET()
1989 {
1990     SbxVariableRef refVal = PopVar();
1991     SbxVariableRef refVar = PopVar();
1992     if( refVar->GetType() != SbxSTRING ||
1993         refVal->GetType() != SbxSTRING )
1994     {
1995         Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
1996     }
1997     else
1998     {
1999         SbxFlagBits n = refVar->GetFlags();
2000         if( refVar.get() == pMeth )
2001         {
2002             refVar->SetFlag( SbxFlagBits::Write );
2003         }
2004         OUString aRefVarString = refVar->GetOUString();
2005         OUString aRefValString = refVal->GetOUString();
2006 
2007         sal_Int32 nVarStrLen = aRefVarString.getLength();
2008         sal_Int32 nValStrLen = aRefValString.getLength();
2009         OUString aNewStr;
2010         if( nVarStrLen > nValStrLen )
2011         {
2012             OUStringBuffer buf(aRefValString);
2013             comphelper::string::padToLength(buf, nVarStrLen, ' ');
2014             aNewStr = buf.makeStringAndClear();
2015         }
2016         else
2017         {
2018             aNewStr = aRefValString.copy( 0, nVarStrLen );
2019         }
2020 
2021         refVar->PutString(aNewStr);
2022         refVar->SetFlags( n );
2023     }
2024 }
2025 
2026 void SbiRuntime::StepRSET()
2027 {
2028     SbxVariableRef refVal = PopVar();
2029     SbxVariableRef refVar = PopVar();
2030     if( refVar->GetType() != SbxSTRING || refVal->GetType() != SbxSTRING )
2031     {
2032         Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
2033     }
2034     else
2035     {
2036         SbxFlagBits n = refVar->GetFlags();
2037         if( refVar.get() == pMeth )
2038         {
2039             refVar->SetFlag( SbxFlagBits::Write );
2040         }
2041         OUString aRefVarString = refVar->GetOUString();
2042         OUString aRefValString = refVal->GetOUString();
2043         sal_Int32 nVarStrLen = aRefVarString.getLength();
2044         sal_Int32 nValStrLen = aRefValString.getLength();
2045 
2046         OUStringBuffer aNewStr(nVarStrLen);
2047         if (nVarStrLen > nValStrLen)
2048         {
2049             comphelper::string::padToLength(aNewStr, nVarStrLen - nValStrLen, ' ');
2050             aNewStr.append(aRefValString);
2051         }
2052         else
2053         {
2054             aNewStr.append(std::u16string_view(aRefValString).substr(0, nVarStrLen));
2055         }
2056         refVar->PutString(aNewStr.makeStringAndClear());
2057 
2058         refVar->SetFlags( n );
2059     }
2060 }
2061 
2062 // laying down TOS in TOS-1, then set ReadOnly-Bit
2063 
2064 void SbiRuntime::StepPUTC()
2065 {
2066     SbxVariableRef refVal = PopVar();
2067     SbxVariableRef refVar = PopVar();
2068     refVar->SetFlag( SbxFlagBits::Write );
2069     *refVar = *refVal;
2070     refVar->ResetFlag( SbxFlagBits::Write );
2071     refVar->SetFlag( SbxFlagBits::Const );
2072 }
2073 
2074 // DIM
2075 // TOS = variable for the array with dimension information as parameter
2076 
2077 void SbiRuntime::StepDIM()
2078 {
2079     SbxVariableRef refVar = PopVar();
2080     DimImpl( refVar );
2081 }
2082 
2083 // #56204 swap out DIM-functionality into a help method (step0.cxx)
2084 void SbiRuntime::DimImpl(const SbxVariableRef& refVar)
2085 {
2086     // If refDim then this DIM statement is terminating a ReDIM and
2087     // previous StepERASE_CLEAR for an array, the following actions have
2088     // been delayed from ( StepERASE_CLEAR ) 'till here
2089     if ( refRedim.is() )
2090     {
2091         if ( !refRedimpArray.is() ) // only erase the array not ReDim Preserve
2092         {
2093             lcl_eraseImpl( refVar, bVBAEnabled );
2094         }
2095         SbxDataType eType = refVar->GetType();
2096         lcl_clearImpl( refVar, eType );
2097         refRedim = nullptr;
2098     }
2099     SbxArray* pDims = refVar->GetParameters();
2100     // must have an even number of arguments
2101     // have in mind that Arg[0] does not count!
2102     if( pDims && !( pDims->Count() & 1 ) )
2103     {
2104         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2105     }
2106     else
2107     {
2108         SbxDataType eType = refVar->IsFixed() ? refVar->GetType() : SbxVARIANT;
2109         SbxDimArray* pArray = new SbxDimArray( eType );
2110         // allow arrays without dimension information, too (VB-compatible)
2111         if( pDims )
2112         {
2113             refVar->ResetFlag( SbxFlagBits::VarToDim );
2114 
2115             for( sal_uInt16 i = 1; i < pDims->Count(); )
2116             {
2117                 sal_Int32 lb = pDims->Get( i++ )->GetLong();
2118                 sal_Int32 ub = pDims->Get( i++ )->GetLong();
2119                 if( ub < lb )
2120                 {
2121                     Error( ERRCODE_BASIC_OUT_OF_RANGE );
2122                     ub = lb;
2123                 }
2124                 pArray->AddDim32( lb, ub );
2125                 if ( lb != ub )
2126                 {
2127                     pArray->setHasFixedSize( true );
2128                 }
2129             }
2130         }
2131         else
2132         {
2133             // #62867 On creating an array of the length 0, create
2134             // a dimension (like for Uno-Sequences of the length 0)
2135             pArray->unoAddDim( 0, -1 );
2136         }
2137         SbxFlagBits nSavFlags = refVar->GetFlags();
2138         refVar->ResetFlag( SbxFlagBits::Fixed );
2139         refVar->PutObject( pArray );
2140         refVar->SetFlags( nSavFlags );
2141         refVar->SetParameters( nullptr );
2142     }
2143 }
2144 
2145 // REDIM
2146 // TOS  = variable for the array
2147 // argv = dimension information
2148 
2149 void SbiRuntime::StepREDIM()
2150 {
2151     // Nothing different than dim at the moment because
2152     // a double dim is already recognized by the compiler.
2153     StepDIM();
2154 }
2155 
2156 
2157 // Helper function for StepREDIMP
2158 static void implCopyDimArray( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex,
2159     short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
2160 {
2161     sal_Int32& ri = pActualIndices[nActualDim];
2162     for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ )
2163     {
2164         if( nActualDim < nMaxDimIndex )
2165         {
2166             implCopyDimArray( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1,
2167                 pActualIndices, pLowerBounds, pUpperBounds );
2168         }
2169         else
2170         {
2171             SbxVariable* pSource = pOldArray->Get32( pActualIndices );
2172             SbxVariable* pDest   = pNewArray->Get32( pActualIndices );
2173             if( pSource && pDest )
2174             {
2175                 *pDest = *pSource;
2176             }
2177         }
2178     }
2179 }
2180 
2181 // REDIM PRESERVE
2182 // TOS  = variable for the array
2183 // argv = dimension information
2184 
2185 void SbiRuntime::StepREDIMP()
2186 {
2187     SbxVariableRef refVar = PopVar();
2188     DimImpl( refVar );
2189 
2190     // Now check, if we can copy from the old array
2191     if( refRedimpArray.is() )
2192     {
2193         SbxBase* pElemObj = refVar->GetObject();
2194         SbxDimArray* pNewArray = dynamic_cast<SbxDimArray*>( pElemObj );
2195         SbxDimArray* pOldArray = static_cast<SbxDimArray*>(refRedimpArray.get());
2196         if( pNewArray )
2197         {
2198             short nDimsNew = pNewArray->GetDims();
2199             short nDimsOld = pOldArray->GetDims();
2200             short nDims = nDimsNew;
2201 
2202             if( nDimsOld != nDimsNew )
2203             {
2204                 StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
2205             }
2206             else if (nDims > 0)
2207             {
2208                 // Store dims to use them for copying later
2209                 std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
2210                 std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
2211                 std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
2212 
2213                 // Compare bounds
2214                 for( short i = 1 ; i <= nDims ; i++ )
2215                 {
2216                     sal_Int32 lBoundNew, uBoundNew;
2217                     sal_Int32 lBoundOld, uBoundOld;
2218                     pNewArray->GetDim32( i, lBoundNew, uBoundNew );
2219                     pOldArray->GetDim32( i, lBoundOld, uBoundOld );
2220                     lBoundNew = std::max( lBoundNew, lBoundOld );
2221                     uBoundNew = std::min( uBoundNew, uBoundOld );
2222                     short j = i - 1;
2223                     pActualIndices[j] = pLowerBounds[j] = lBoundNew;
2224                     pUpperBounds[j] = uBoundNew;
2225                 }
2226                 // Copy data from old array by going recursively through all dimensions
2227                 // (It would be faster to work on the flat internal data array of an
2228                 // SbyArray but this solution is clearer and easier)
2229                 implCopyDimArray( pNewArray, pOldArray, nDims - 1,
2230                                   0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
2231             }
2232 
2233             refRedimpArray = nullptr;
2234         }
2235     }
2236 
2237 }
2238 
2239 // REDIM_COPY
2240 // TOS  = Array-Variable, Reference to array is copied
2241 //        Variable is cleared as in ERASE
2242 
2243 void SbiRuntime::StepREDIMP_ERASE()
2244 {
2245     SbxVariableRef refVar = PopVar();
2246     refRedim = refVar;
2247     SbxDataType eType = refVar->GetType();
2248     if( eType & SbxARRAY )
2249     {
2250         SbxBase* pElemObj = refVar->GetObject();
2251         SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj );
2252         if( pDimArray )
2253         {
2254             refRedimpArray = pDimArray;
2255         }
2256 
2257     }
2258     else if( refVar->IsFixed() )
2259     {
2260         refVar->Clear();
2261     }
2262     else
2263     {
2264         refVar->SetType( SbxEMPTY );
2265     }
2266 }
2267 
2268 static void lcl_clearImpl( SbxVariableRef const & refVar, SbxDataType const & eType )
2269 {
2270     SbxFlagBits nSavFlags = refVar->GetFlags();
2271     refVar->ResetFlag( SbxFlagBits::Fixed );
2272     refVar->SetType( SbxDataType(eType & 0x0FFF) );
2273     refVar->SetFlags( nSavFlags );
2274     refVar->Clear();
2275 }
2276 
2277 static void lcl_eraseImpl( SbxVariableRef const & refVar, bool bVBAEnabled )
2278 {
2279     SbxDataType eType = refVar->GetType();
2280     if( eType & SbxARRAY )
2281     {
2282         if ( bVBAEnabled )
2283         {
2284             SbxBase* pElemObj = refVar->GetObject();
2285             SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj );
2286             if( pDimArray )
2287             {
2288                 if ( pDimArray->hasFixedSize() )
2289                 {
2290                     // Clear all Value(s)
2291                     pDimArray->SbxArray::Clear();
2292                 }
2293                 else
2294                 {
2295                     pDimArray->Clear(); // clear dims and values
2296                 }
2297             }
2298             else
2299             {
2300                 SbxArray* pArray = dynamic_cast<SbxArray*>( pElemObj );
2301                 if ( pArray )
2302                 {
2303                     pArray->Clear();
2304                 }
2305             }
2306         }
2307         else
2308         {
2309             // Arrays have on an erase to VB quite a complex behaviour. Here are
2310             // only the type problems at REDIM (#26295) removed at first:
2311             // Set type hard onto the array-type, because a variable with array is
2312             // SbxOBJECT. At REDIM there's an SbxOBJECT-array generated then and
2313             // the original type is lost -> runtime error
2314             lcl_clearImpl( refVar, eType );
2315         }
2316     }
2317     else if( refVar->IsFixed() )
2318     {
2319         refVar->Clear();
2320     }
2321     else
2322     {
2323         refVar->SetType( SbxEMPTY );
2324     }
2325 }
2326 
2327 // delete variable
2328 // TOS = variable
2329 
2330 void SbiRuntime::StepERASE()
2331 {
2332     SbxVariableRef refVar = PopVar();
2333     lcl_eraseImpl( refVar, bVBAEnabled );
2334 }
2335 
2336 void SbiRuntime::StepERASE_CLEAR()
2337 {
2338     refRedim = PopVar();
2339 }
2340 
2341 void SbiRuntime::StepARRAYACCESS()
2342 {
2343     if( !refArgv.is() )
2344     {
2345         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2346     }
2347     SbxVariableRef refVar = PopVar();
2348     refVar->SetParameters( refArgv.get() );
2349     PopArgv();
2350     PushVar( CheckArray( refVar.get() ) );
2351 }
2352 
2353 void SbiRuntime::StepBYVAL()
2354 {
2355     // Copy variable on stack to break call by reference
2356     SbxVariableRef pVar = PopVar();
2357     SbxDataType t = pVar->GetType();
2358 
2359     SbxVariable* pCopyVar = new SbxVariable( t );
2360     pCopyVar->SetFlag( SbxFlagBits::ReadWrite );
2361     *pCopyVar = *pVar;
2362 
2363     PushVar( pCopyVar );
2364 }
2365 
2366 // establishing an argv
2367 // nOp1 stays as it is -> 1st element is the return value
2368 
2369 void SbiRuntime::StepARGC()
2370 {
2371     PushArgv();
2372     refArgv = new SbxArray;
2373     nArgc = 1;
2374 }
2375 
2376 // storing an argument in Argv
2377 
2378 void SbiRuntime::StepARGV()
2379 {
2380     if( !refArgv.is() )
2381     {
2382         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2383     }
2384     else
2385     {
2386         SbxVariableRef pVal = PopVar();
2387 
2388         // Before fix of #94916:
2389         if( dynamic_cast<const SbxMethod*>( pVal.get() ) != nullptr
2390             || dynamic_cast<const SbUnoProperty*>( pVal.get() ) != nullptr
2391             || dynamic_cast<const SbProcedureProperty*>( pVal.get() ) != nullptr )
2392         {
2393             // evaluate methods and properties!
2394             SbxVariable* pRes = new SbxVariable( *pVal );
2395             pVal = pRes;
2396         }
2397         refArgv->Put( pVal.get(), nArgc++ );
2398     }
2399 }
2400 
2401 // Input to Variable. The variable is on TOS and is
2402 // is removed afterwards.
2403 void SbiRuntime::StepINPUT()
2404 {
2405     OUStringBuffer sin;
2406     OUString s;
2407     char ch = 0;
2408     ErrCode err;
2409     // Skip whitespace
2410     while( ( err = pIosys->GetError() ) == ERRCODE_NONE )
2411     {
2412         ch = pIosys->Read();
2413         if( ch != ' ' && ch != '\t' && ch != '\n' )
2414         {
2415             break;
2416         }
2417     }
2418     if( !err )
2419     {
2420         // Scan until comma or whitespace
2421         char sep = ( ch == '"' ) ? ch : 0;
2422         if( sep )
2423         {
2424             ch = pIosys->Read();
2425         }
2426         while( ( err = pIosys->GetError() ) == ERRCODE_NONE )
2427         {
2428             if( ch == sep )
2429             {
2430                 ch = pIosys->Read();
2431                 if( ch != sep )
2432                 {
2433                     break;
2434                 }
2435             }
2436             else if( !sep && (ch == ',' || ch == '\n') )
2437             {
2438                 break;
2439             }
2440             sin.append( ch );
2441             ch = pIosys->Read();
2442         }
2443         // skip whitespace
2444         if( ch == ' ' || ch == '\t' )
2445         {
2446             while( ( err = pIosys->GetError() ) == ERRCODE_NONE )
2447             {
2448                 if( ch != ' ' && ch != '\t' && ch != '\n' )
2449                 {
2450                     break;
2451                 }
2452                 ch = pIosys->Read();
2453             }
2454         }
2455     }
2456     if( !err )
2457     {
2458         s = sin.makeStringAndClear();
2459         SbxVariableRef pVar = GetTOS();
2460         // try to fill the variable with a numeric value first,
2461         // then with a string value
2462         if( !pVar->IsFixed() || pVar->IsNumeric() )
2463         {
2464             sal_uInt16 nLen = 0;
2465             if( !pVar->Scan( s, &nLen ) )
2466             {
2467                 err = SbxBase::GetError();
2468                 SbxBase::ResetError();
2469             }
2470             // the value has to be scanned in completely
2471             else if( nLen != s.getLength() && !pVar->PutString( s ) )
2472             {
2473                 err = SbxBase::GetError();
2474                 SbxBase::ResetError();
2475             }
2476             else if( nLen != s.getLength() && pVar->IsNumeric() )
2477             {
2478                 err = SbxBase::GetError();
2479                 SbxBase::ResetError();
2480                 if( !err )
2481                 {
2482                     err = ERRCODE_BASIC_CONVERSION;
2483                 }
2484             }
2485         }
2486         else
2487         {
2488             pVar->PutString( s );
2489             err = SbxBase::GetError();
2490             SbxBase::ResetError();
2491         }
2492     }
2493     if( err == ERRCODE_BASIC_USER_ABORT )
2494     {
2495         Error( err );
2496     }
2497     else if( err )
2498     {
2499         if( pRestart && !pIosys->GetChannel() )
2500         {
2501             pCode = pRestart;
2502         }
2503         else
2504         {
2505             Error( err );
2506         }
2507     }
2508     else
2509     {
2510         PopVar();
2511     }
2512 }
2513 
2514 // Line Input to Variable. The variable is on TOS and is
2515 // deleted afterwards.
2516 
2517 void SbiRuntime::StepLINPUT()
2518 {
2519     OString aInput;
2520     pIosys->Read( aInput );
2521     Error( pIosys->GetError() );
2522     SbxVariableRef p = PopVar();
2523     p->PutString(OStringToOUString(aInput, osl_getThreadTextEncoding()));
2524 }
2525 
2526 // end of program
2527 
2528 void SbiRuntime::StepSTOP()
2529 {
2530     pInst->Stop();
2531 }
2532 
2533 
2534 void SbiRuntime::StepINITFOR()
2535 {
2536     PushFor();
2537 }
2538 
2539 void SbiRuntime::StepINITFOREACH()
2540 {
2541     PushForEach();
2542 }
2543 
2544 // increment FOR-variable
2545 
2546 void SbiRuntime::StepNEXT()
2547 {
2548     if( !pForStk )
2549     {
2550         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2551         return;
2552     }
2553     if( pForStk->eForType == ForType::To )
2554     {
2555         pForStk->refVar->Compute( SbxPLUS, *pForStk->refInc );
2556     }
2557 }
2558 
2559 // beginning CASE: TOS in CASE-stack
2560 
2561 void SbiRuntime::StepCASE()
2562 {
2563     if( !refCaseStk.is() )
2564     {
2565         refCaseStk = new SbxArray;
2566     }
2567     SbxVariableRef xVar = PopVar();
2568     refCaseStk->Put( xVar.get(), refCaseStk->Count() );
2569 }
2570 
2571 // end CASE: free variable
2572 
2573 void SbiRuntime::StepENDCASE()
2574 {
2575     if( !refCaseStk.is() || !refCaseStk->Count() )
2576     {
2577         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2578     }
2579     else
2580     {
2581         refCaseStk->Remove( refCaseStk->Count() - 1 );
2582     }
2583 }
2584 
2585 
2586 void SbiRuntime::StepSTDERROR()
2587 {
2588     pError = nullptr; bError = true;
2589     pInst->aErrorMsg.clear();
2590     pInst->nErr = ERRCODE_NONE;
2591     pInst->nErl = 0;
2592     nError = ERRCODE_NONE;
2593     SbxErrObject::getUnoErrObject()->Clear();
2594 }
2595 
2596 void SbiRuntime::StepNOERROR()
2597 {
2598     pInst->aErrorMsg.clear();
2599     pInst->nErr = ERRCODE_NONE;
2600     pInst->nErl = 0;
2601     nError = ERRCODE_NONE;
2602     SbxErrObject::getUnoErrObject()->Clear();
2603     bError = false;
2604 }
2605 
2606 // leave UP
2607 
2608 void SbiRuntime::StepLEAVE()
2609 {
2610     bRun = false;
2611         // If VBA and we are leaving an ErrorHandler then clear the error ( it's been processed )
2612     if ( bInError && pError )
2613     {
2614         SbxErrObject::getUnoErrObject()->Clear();
2615     }
2616 }
2617 
2618 void SbiRuntime::StepCHANNEL()      // TOS = channel number
2619 {
2620     SbxVariableRef pChan = PopVar();
2621     short nChan = pChan->GetInteger();
2622     pIosys->SetChannel( nChan );
2623     Error( pIosys->GetError() );
2624 }
2625 
2626 void SbiRuntime::StepCHANNEL0()
2627 {
2628     pIosys->ResetChannel();
2629 }
2630 
2631 void SbiRuntime::StepPRINT()        // print TOS
2632 {
2633     SbxVariableRef p = PopVar();
2634     OUString s1 = p->GetOUString();
2635     OUString s;
2636     if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE )
2637     {
2638         s = " ";    // one blank before
2639     }
2640     s += s1;
2641     pIosys->Write( s );
2642     Error( pIosys->GetError() );
2643 }
2644 
2645 void SbiRuntime::StepPRINTF()       // print TOS in field
2646 {
2647     SbxVariableRef p = PopVar();
2648     OUString s1 = p->GetOUString();
2649     OUStringBuffer s;
2650     if( p->GetType() >= SbxINTEGER && p->GetType() <= SbxDOUBLE )
2651     {
2652         s.append(' ');
2653     }
2654     s.append(s1);
2655     comphelper::string::padToLength(s, 14, ' ');
2656     pIosys->Write( s.makeStringAndClear() );
2657     Error( pIosys->GetError() );
2658 }
2659 
2660 void SbiRuntime::StepWRITE()        // write TOS
2661 {
2662     SbxVariableRef p = PopVar();
2663     // Does the string have to be encapsulated?
2664     char ch = 0;
2665     switch (p->GetType() )
2666     {
2667     case SbxSTRING: ch = '"'; break;
2668     case SbxCURRENCY:
2669     case SbxBOOL:
2670     case SbxDATE: ch = '#'; break;
2671     default: break;
2672     }
2673     OUString s;
2674     if( ch )
2675     {
2676         s += OUString(ch);
2677     }
2678     s += p->GetOUString();
2679     if( ch )
2680     {
2681         s += OUString(ch);
2682     }
2683     pIosys->Write( s );
2684     Error( pIosys->GetError() );
2685 }
2686 
2687 void SbiRuntime::StepRENAME()       // Rename Tos+1 to Tos
2688 {
2689     SbxVariableRef pTos1 = PopVar();
2690     SbxVariableRef pTos  = PopVar();
2691     OUString aDest = pTos1->GetOUString();
2692     OUString aSource = pTos->GetOUString();
2693 
2694     if( hasUno() )
2695     {
2696         implStepRenameUCB( aSource, aDest );
2697     }
2698     else
2699     {
2700         implStepRenameOSL( aSource, aDest );
2701     }
2702 }
2703 
2704 // TOS = Prompt
2705 
2706 void SbiRuntime::StepPROMPT()
2707 {
2708     SbxVariableRef p = PopVar();
2709     OString aStr(OUStringToOString(p->GetOUString(), osl_getThreadTextEncoding()));
2710     pIosys->SetPrompt( aStr );
2711 }
2712 
2713 // Set Restart point
2714 
2715 void SbiRuntime::StepRESTART()
2716 {
2717     pRestart = pCode;
2718 }
2719 
2720 // empty expression on stack for missing parameter
2721 
2722 void SbiRuntime::StepEMPTY()
2723 {
2724     // #57915 The semantics of StepEMPTY() is the representation of a missing argument.
2725     // This is represented by the value 448 (ERRCODE_BASIC_NAMED_NOT_FOUND) of the type error
2726     // in VB. StepEmpty should now rather be named StepMISSING() but the name is kept
2727     // to simplify matters.
2728     SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
2729     xVar->PutErr( 448 );
2730     PushVar( xVar.get() );
2731 }
2732 
2733 // TOS = error code
2734 
2735 void SbiRuntime::StepERROR()
2736 {
2737     SbxVariableRef refCode = PopVar();
2738     sal_uInt16 n = refCode->GetUShort();
2739     ErrCode error = StarBASIC::GetSfxFromVBError( n );
2740     if ( bVBAEnabled )
2741     {
2742         pInst->Error( error );
2743     }
2744     else
2745     {
2746         Error( error );
2747     }
2748 }
2749 
2750 // loading a numeric constant (+ID)
2751 
2752 void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 )
2753 {
2754     SbxVariable* p = new SbxVariable( SbxDOUBLE );
2755 
2756     // #57844 use localized function
2757     OUString aStr = pImg->GetString( static_cast<short>( nOp1 ) );
2758     // also allow , !!!
2759     sal_Int32 iComma = aStr.indexOf(',');
2760     if( iComma >= 0 )
2761     {
2762         aStr = aStr.replaceAt(iComma, 1, ".");
2763     }
2764     double n = ::rtl::math::stringToDouble( aStr, '.', ',' );
2765 
2766     p->PutDouble( n );
2767     PushVar( p );
2768 }
2769 
2770 // loading a string constant (+ID)
2771 
2772 void SbiRuntime::StepLOADSC( sal_uInt32 nOp1 )
2773 {
2774     SbxVariable* p = new SbxVariable;
2775     p->PutString( pImg->GetString( static_cast<short>( nOp1 ) ) );
2776     PushVar( p );
2777 }
2778 
2779 // Immediate Load (+value)
2780 
2781 void SbiRuntime::StepLOADI( sal_uInt32 nOp1 )
2782 {
2783     SbxVariable* p = new SbxVariable;
2784     p->PutInteger( static_cast<sal_Int16>( nOp1 ) );
2785     PushVar( p );
2786 }
2787 
2788 // store a named argument in Argv (+Arg-no. from 1!)
2789 
2790 void SbiRuntime::StepARGN( sal_uInt32 nOp1 )
2791 {
2792     if( !refArgv.is() )
2793         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2794     else
2795     {
2796         OUString aAlias( pImg->GetString( static_cast<short>( nOp1 ) ) );
2797         SbxVariableRef pVal = PopVar();
2798         if( bVBAEnabled &&
2799                 ( dynamic_cast<const SbxMethod*>( pVal.get()) != nullptr
2800                   || dynamic_cast<const SbUnoProperty*>( pVal.get()) != nullptr
2801                   || dynamic_cast<const SbProcedureProperty*>( pVal.get()) != nullptr ) )
2802         {
2803             // named variables ( that are Any especially properties ) can be empty at this point and need a broadcast
2804             if ( pVal->GetType() == SbxEMPTY )
2805                 pVal->Broadcast( SfxHintId::BasicDataWanted );
2806             // evaluate methods and properties!
2807             SbxVariable* pRes = new SbxVariable( *pVal );
2808             pVal = pRes;
2809         }
2810         refArgv->Put( pVal.get(), nArgc );
2811         refArgv->PutAlias( aAlias, nArgc++ );
2812     }
2813 }
2814 
2815 // converting the type of an argument in Argv for DECLARE-Fkt. (+type)
2816 
2817 void SbiRuntime::StepARGTYP( sal_uInt32 nOp1 )
2818 {
2819     if( !refArgv.is() )
2820         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2821     else
2822     {
2823         bool bByVal = (nOp1 & 0x8000) != 0;         // Is BYVAL requested?
2824         SbxDataType t = static_cast<SbxDataType>(nOp1 & 0x7FFF);
2825         SbxVariable* pVar = refArgv->Get( refArgv->Count() - 1 );   // last Arg
2826 
2827         // check BYVAL
2828         if( pVar->GetRefCount() > 2 )       // 2 is normal for BYVAL
2829         {
2830             // parameter is a reference
2831             if( bByVal )
2832             {
2833                 // Call by Value is requested -> create a copy
2834                 pVar = new SbxVariable( *pVar );
2835                 pVar->SetFlag( SbxFlagBits::ReadWrite );
2836                 refExprStk->Put( pVar, refArgv->Count() - 1 );
2837             }
2838             else
2839                 pVar->SetFlag( SbxFlagBits::Reference );     // Ref-Flag for DllMgr
2840         }
2841         else
2842         {
2843             // parameter is NO reference
2844             if( bByVal )
2845                 pVar->ResetFlag( SbxFlagBits::Reference );   // no reference -> OK
2846             else
2847                 Error( ERRCODE_BASIC_BAD_PARAMETERS );      // reference needed
2848         }
2849 
2850         if( pVar->GetType() != t )
2851         {
2852             // variant for correct conversion
2853             // besides error, if SbxBYREF
2854             pVar->Convert( SbxVARIANT );
2855             pVar->Convert( t );
2856         }
2857     }
2858 }
2859 
2860 // bring string to a definite length (+length)
2861 
2862 void SbiRuntime::StepPAD( sal_uInt32 nOp1 )
2863 {
2864     SbxVariable* p = GetTOS();
2865     OUString s = p->GetOUString();
2866     sal_Int32 nLen(nOp1);
2867     if( s.getLength() != nLen )
2868     {
2869         OUStringBuffer aBuf(s);
2870         if (aBuf.getLength() > nLen)
2871         {
2872             comphelper::string::truncateToLength(aBuf, nLen);
2873         }
2874         else
2875         {
2876             comphelper::string::padToLength(aBuf, nLen, ' ');
2877         }
2878         s = aBuf.makeStringAndClear();
2879     }
2880 }
2881 
2882 // jump (+target)
2883 
2884 void SbiRuntime::StepJUMP( sal_uInt32 nOp1 )
2885 {
2886 #ifdef DBG_UTIL
2887     // #QUESTION shouldn't this be
2888     // if( (sal_uInt8*)( nOp1+pImagGetCode() ) >= pImg->GetCodeSize() )
2889     if( nOp1 >= pImg->GetCodeSize() )
2890         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2891 #endif
2892     pCode = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nOp1;
2893 }
2894 
2895 // evaluate TOS, conditional jump (+target)
2896 
2897 void SbiRuntime::StepJUMPT( sal_uInt32 nOp1 )
2898 {
2899     SbxVariableRef p = PopVar();
2900     if( p->GetBool() )
2901         StepJUMP( nOp1 );
2902 }
2903 
2904 // evaluate TOS, conditional jump (+target)
2905 
2906 void SbiRuntime::StepJUMPF( sal_uInt32 nOp1 )
2907 {
2908     SbxVariableRef p = PopVar();
2909     // In a test e.g. If Null then
2910         // will evaluate Null will act as if False
2911     if( ( bVBAEnabled && p->IsNull() ) || !p->GetBool() )
2912         StepJUMP( nOp1 );
2913 }
2914 
2915 // evaluate TOS, jump into JUMP-table (+MaxVal)
2916 // looks like this:
2917 // ONJUMP 2
2918 // JUMP target1
2919 // JUMP target2
2920 
2921 // if 0x8000 is set in the operand, push the return address (ON..GOSUB)
2922 
2923 void SbiRuntime::StepONJUMP( sal_uInt32 nOp1 )
2924 {
2925     SbxVariableRef p = PopVar();
2926     sal_Int16 n = p->GetInteger();
2927     if( nOp1 & 0x8000 )
2928     {
2929         nOp1 &= 0x7FFF;
2930         PushGosub( pCode + 5 * nOp1 );
2931     }
2932     if( n < 1 || static_cast<sal_uInt32>(n) > nOp1 )
2933         n = static_cast<sal_Int16>( nOp1 + 1 );
2934     nOp1 = static_cast<sal_uInt32>( reinterpret_cast<const char*>(pCode) - pImg->GetCode() ) + 5 * --n;
2935     StepJUMP( nOp1 );
2936 }
2937 
2938 // UP-call (+target)
2939 
2940 void SbiRuntime::StepGOSUB( sal_uInt32 nOp1 )
2941 {
2942     PushGosub( pCode );
2943     if( nOp1 >= pImg->GetCodeSize() )
2944         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2945     pCode = reinterpret_cast<const sal_uInt8*>(pImg->GetCode()) + nOp1;
2946 }
2947 
2948 // UP-return (+0 or target)
2949 
2950 void SbiRuntime::StepRETURN( sal_uInt32 nOp1 )
2951 {
2952     PopGosub();
2953     if( nOp1 )
2954         StepJUMP( nOp1 );
2955 }
2956 
2957 // check FOR-variable (+Endlabel)
2958 
2959 void SbiRuntime::StepTESTFOR( sal_uInt32 nOp1 )
2960 {
2961     if( !pForStk )
2962     {
2963         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
2964         return;
2965     }
2966 
2967     bool bEndLoop = false;
2968     switch( pForStk->eForType )
2969     {
2970         case ForType::To:
2971         {
2972             SbxOperator eOp = ( pForStk->refInc->GetDouble() < 0 ) ? SbxLT : SbxGT;
2973             if( pForStk->refVar->Compare( eOp, *pForStk->refEnd ) )
2974                 bEndLoop = true;
2975             break;
2976         }
2977         case ForType::EachArray:
2978         {
2979             SbiForStack* p = pForStk;
2980             if( p->pArrayCurIndices == nullptr )
2981             {
2982                 bEndLoop = true;
2983             }
2984             else
2985             {
2986                 SbxDimArray* pArray = reinterpret_cast<SbxDimArray*>(p->refEnd.get());
2987                 short nDims = pArray->GetDims();
2988 
2989                 // Empty array?
2990                 if( nDims == 1 && p->pArrayLowerBounds[0] > p->pArrayUpperBounds[0] )
2991                 {
2992                     bEndLoop = true;
2993                     break;
2994                 }
2995                 SbxVariable* pVal = pArray->Get32( p->pArrayCurIndices.get() );
2996                 *(p->refVar) = *pVal;
2997 
2998                 bool bFoundNext = false;
2999                 for( short i = 0 ; i < nDims ; i++ )
3000                 {
3001                     if( p->pArrayCurIndices[i] < p->pArrayUpperBounds[i] )
3002                     {
3003                         bFoundNext = true;
3004                         p->pArrayCurIndices[i]++;
3005                         for( short j = i - 1 ; j >= 0 ; j-- )
3006                             p->pArrayCurIndices[j] = p->pArrayLowerBounds[j];
3007                         break;
3008                     }
3009                 }
3010                 if( !bFoundNext )
3011                 {
3012                     p->pArrayCurIndices.reset();
3013                 }
3014             }
3015             break;
3016         }
3017         case ForType::EachCollection:
3018         {
3019             BasicCollection* pCollection = static_cast<BasicCollection*>(pForStk->refEnd.get());
3020             SbxArrayRef xItemArray = pCollection->xItemArray;
3021             sal_Int32 nCount = xItemArray->Count32();
3022             if( pForStk->nCurCollectionIndex < nCount )
3023             {
3024                 SbxVariable* pRes = xItemArray->Get32( pForStk->nCurCollectionIndex );
3025                 pForStk->nCurCollectionIndex++;
3026                 (*pForStk->refVar) = *pRes;
3027             }
3028             else
3029             {
3030                 bEndLoop = true;
3031             }
3032             break;
3033         }
3034         case ForType::EachXEnumeration:
3035         {
3036             SbiForStack* p = pForStk;
3037             if( p->xEnumeration->hasMoreElements() )
3038             {
3039                 Any aElem = p->xEnumeration->nextElement();
3040                 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
3041                 unoToSbxValue( xVar.get(), aElem );
3042                 (*pForStk->refVar) = *xVar;
3043             }
3044             else
3045             {
3046                 bEndLoop = true;
3047             }
3048             break;
3049         }
3050     }
3051     if( bEndLoop )
3052     {
3053         PopFor();
3054         StepJUMP( nOp1 );
3055     }
3056 }
3057 
3058 // Tos+1 <= Tos+2 <= Tos, 2xremove (+Target)
3059 
3060 void SbiRuntime::StepCASETO( sal_uInt32 nOp1 )
3061 {
3062     if( !refCaseStk.is() || !refCaseStk->Count() )
3063         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
3064     else
3065     {
3066         SbxVariableRef xTo   = PopVar();
3067         SbxVariableRef xFrom = PopVar();
3068         SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 );
3069         if( *xCase >= *xFrom && *xCase <= *xTo )
3070             StepJUMP( nOp1 );
3071     }
3072 }
3073 
3074 
3075 void SbiRuntime::StepERRHDL( sal_uInt32 nOp1 )
3076 {
3077     const sal_uInt8* p = pCode;
3078     StepJUMP( nOp1 );
3079     pError = pCode;
3080     pCode = p;
3081     pInst->aErrorMsg.clear();
3082     pInst->nErr = ERRCODE_NONE;
3083     pInst->nErl = 0;
3084     nError = ERRCODE_NONE;
3085     SbxErrObject::getUnoErrObject()->Clear();
3086 }
3087 
3088 // Resume after errors (+0=statement, 1=next or Label)
3089 
3090 void SbiRuntime::StepRESUME( sal_uInt32 nOp1 )
3091 {
3092     // #32714 Resume without error? -> error
3093     if( !bInError )
3094     {
3095         Error( ERRCODE_BASIC_BAD_RESUME );
3096         return;
3097     }
3098     if( nOp1 )
3099     {
3100         // set Code-pointer to the next statement
3101         sal_uInt16 n1, n2;
3102         pCode = pMod->FindNextStmnt( pErrCode, n1, n2, true, pImg );
3103     }
3104     else
3105         pCode = pErrStmnt;
3106     if ( pError ) // current in error handler ( and got a Resume Next statement )
3107         SbxErrObject::getUnoErrObject()->Clear();
3108 
3109     if( nOp1 > 1 )
3110         StepJUMP( nOp1 );
3111     pInst->aErrorMsg.clear();
3112     pInst->nErr = ERRCODE_NONE;
3113     pInst->nErl = 0;
3114     nError = ERRCODE_NONE;
3115     bInError = false;
3116 }
3117 
3118 // close channel (+channel, 0=all)
3119 void SbiRuntime::StepCLOSE( sal_uInt32 nOp1 )
3120 {
3121     ErrCode err;
3122     if( !nOp1 )
3123         pIosys->Shutdown();
3124     else
3125     {
3126         err = pIosys->GetError();
3127         if( !err )
3128         {
3129             pIosys->Close();
3130         }
3131     }
3132     err = pIosys->GetError();
3133     Error( err );
3134 }
3135 
3136 // output character (+char)
3137 
3138 void SbiRuntime::StepPRCHAR( sal_uInt32 nOp1 )
3139 {
3140     OUString s(static_cast<sal_Unicode>(nOp1));
3141     pIosys->Write( s );
3142     Error( pIosys->GetError() );
3143 }
3144 
3145 // check whether TOS is a certain object class (+StringID)
3146 
3147 bool SbiRuntime::implIsClass( SbxObject const * pObj, const OUString& aClass )
3148 {
3149     bool bRet = true;
3150 
3151     if( !aClass.isEmpty() )
3152     {
3153         bRet = pObj->IsClass( aClass );
3154         if( !bRet )
3155             bRet = aClass.equalsIgnoreAsciiCase( "object" );
3156         if( !bRet )
3157         {
3158             const OUString& aObjClass = pObj->GetClassName();
3159             SbModule* pClassMod = GetSbData()->pClassFac->FindClass( aObjClass );
3160             if( pClassMod && pClassMod->pClassData )
3161             {
3162                 SbxVariable* pClassVar = pClassMod->pClassData->mxIfaces->Find( aClass, SbxClassType::DontCare );
3163                 bRet = (pClassVar != nullptr);
3164             }
3165         }
3166     }
3167     return bRet;
3168 }
3169 
3170 bool SbiRuntime::checkClass_Impl( const SbxVariableRef& refVal,
3171     const OUString& aClass, bool bRaiseErrors, bool bDefault )
3172 {
3173     bool bOk = bDefault;
3174 
3175     SbxDataType t = refVal->GetType();
3176     SbxVariable* pVal = refVal.get();
3177     // we don't know the type of uno properties that are (maybevoid)
3178     if ( t == SbxEMPTY )
3179     {
3180         if ( auto pProp = dynamic_cast<SbUnoProperty*>( refVal.get() ) )
3181         {
3182             t = pProp->getRealType();
3183         }
3184     }
3185     if( t == SbxOBJECT || bVBAEnabled )
3186     {
3187         SbxObject* pObj = dynamic_cast<SbxObject*>(pVal);
3188         if (!pObj)
3189         {
3190             pObj = dynamic_cast<SbxObject*>(refVal->GetObject());
3191         }
3192         if( pObj )
3193         {
3194             if( !implIsClass( pObj, aClass ) )
3195             {
3196                 SbUnoObject* pUnoObj(nullptr);
3197                 if (bVBAEnabled || CodeCompleteOptions::IsExtendedTypeDeclaration())
3198                 {
3199                     pUnoObj = dynamic_cast<SbUnoObject*>(pObj);
3200                 }
3201 
3202                 if (pUnoObj)
3203                     bOk = checkUnoObjectType(*pUnoObj, aClass);
3204                 else
3205                     bOk = false;
3206                 if ( !bOk && bRaiseErrors )
3207                     Error( ERRCODE_BASIC_INVALID_USAGE_OBJECT );
3208             }
3209             else
3210             {
3211                 bOk = true;
3212 
3213                 SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pObj );
3214                 if( pClassModuleObject != nullptr )
3215                     pClassModuleObject->triggerInitializeEvent();
3216             }
3217         }
3218     }
3219     else
3220     {
3221         if( bRaiseErrors )
3222             Error( ERRCODE_BASIC_NEEDS_OBJECT );
3223         bOk = false;
3224     }
3225     return bOk;
3226 }
3227 
3228 void SbiRuntime::StepSETCLASS_impl( sal_uInt32 nOp1, bool bHandleDflt )
3229 {
3230     SbxVariableRef refVal = PopVar();
3231     SbxVariableRef refVar = PopVar();
3232     OUString aClass( pImg->GetString( static_cast<short>( nOp1 ) ) );
3233 
3234     bool bOk = checkClass_Impl( refVal, aClass, true, true );
3235     if( bOk )
3236     {
3237         StepSET_Impl( refVal, refVar, bHandleDflt ); // don't do handle default prop for a "proper" set
3238     }
3239 }
3240 
3241 void SbiRuntime::StepVBASETCLASS( sal_uInt32 nOp1 )
3242 {
3243     StepSETCLASS_impl( nOp1, false );
3244 }
3245 
3246 void SbiRuntime::StepSETCLASS( sal_uInt32 nOp1 )
3247 {
3248     StepSETCLASS_impl( nOp1, true );
3249 }
3250 
3251 void SbiRuntime::StepTESTCLASS( sal_uInt32 nOp1 )
3252 {
3253     SbxVariableRef xObjVal = PopVar();
3254     OUString aClass( pImg->GetString( static_cast<short>( nOp1 ) ) );
3255     bool bDefault = !bVBAEnabled;
3256     bool bOk = checkClass_Impl( xObjVal, aClass, false, bDefault );
3257 
3258     SbxVariable* pRet = new SbxVariable;
3259     pRet->PutBool( bOk );
3260     PushVar( pRet );
3261 }
3262 
3263 // define library for following declare-call
3264 
3265 void SbiRuntime::StepLIB( sal_uInt32 nOp1 )
3266 {
3267     aLibName = pImg->GetString( static_cast<short>( nOp1 ) );
3268 }
3269 
3270 // TOS is incremented by BASE, BASE is pushed before (+BASE)
3271 // This opcode is pushed before DIM/REDIM-commands,
3272 // if there's been only one index named.
3273 
3274 void SbiRuntime::StepBASED( sal_uInt32 nOp1 )
3275 {
3276     SbxVariable* p1 = new SbxVariable;
3277     SbxVariableRef x2 = PopVar();
3278 
3279     // #109275 Check compatibility mode
3280     bool bCompatible = ((nOp1 & 0x8000) != 0);
3281     sal_uInt16 uBase = static_cast<sal_uInt16>(nOp1 & 1);       // Can only be 0 or 1
3282     p1->PutInteger( uBase );
3283     if( !bCompatible )
3284         x2->Compute( SbxPLUS, *p1 );
3285     PushVar( x2.get() );  // first the Expr
3286     PushVar( p1 );  // then the Base
3287 }
3288 
3289 // the bits in the String-ID:
3290 // 0x8000 - Argv is reserved
3291 
3292 SbxVariable* SbiRuntime::FindElement( SbxObject* pObj, sal_uInt32 nOp1, sal_uInt32 nOp2,
3293                                       ErrCode nNotFound, bool bLocal, bool bStatic )
3294 {
3295     bool bIsVBAInterOp = SbiRuntime::isVBAEnabled();
3296     if( bIsVBAInterOp )
3297     {
3298         StarBASIC* pMSOMacroRuntimeLib = GetSbData()->pMSOMacroRuntimLib;
3299         if( pMSOMacroRuntimeLib != nullptr )
3300         {
3301             pMSOMacroRuntimeLib->ResetFlag( SbxFlagBits::ExtSearch );
3302         }
3303     }
3304 
3305     SbxVariable* pElem = nullptr;
3306     if( !pObj )
3307     {
3308         Error( ERRCODE_BASIC_NO_OBJECT );
3309         pElem = new SbxVariable;
3310     }
3311     else
3312     {
3313         bool bFatalError = false;
3314         SbxDataType t = static_cast<SbxDataType>(nOp2);
3315         OUString aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) );
3316         // Hacky capture of Evaluate [] syntax
3317         // this should be tackled I feel at the pcode level
3318         if ( bIsVBAInterOp && aName.startsWith("[") )
3319         {
3320             // emulate pcode here
3321             StepARGC();
3322             // pseudo StepLOADSC
3323             OUString sArg = aName.copy( 1, aName.getLength() - 2 );
3324             SbxVariable* p = new SbxVariable;
3325             p->PutString( sArg );
3326             PushVar( p );
3327             StepARGV();
3328             nOp1 = nOp1 | 0x8000; // indicate params are present
3329             aName = "Evaluate";
3330         }
3331         if( bLocal )
3332         {
3333             if ( bStatic && pMeth )
3334             {
3335                 pElem = pMeth->GetStatics()->Find( aName, SbxClassType::DontCare );
3336             }
3337 
3338             if ( !pElem )
3339             {
3340                 pElem = refLocals->Find( aName, SbxClassType::DontCare );
3341             }
3342         }
3343         if( !pElem )
3344         {
3345             bool bSave = rBasic.bNoRtl;
3346             rBasic.bNoRtl = true;
3347             pElem = pObj->Find( aName, SbxClassType::DontCare );
3348 
3349             // #110004, #112015: Make private really private
3350             if( bLocal && pElem )   // Local as flag for global search
3351             {
3352                 if( pElem->IsSet( SbxFlagBits::Private ) )
3353                 {
3354                     SbiInstance* pInst_ = GetSbData()->pInst;
3355                     if( pInst_ && pInst_->IsCompatibility() && pObj != pElem->GetParent() )
3356                     {
3357                         pElem = nullptr;   // Found but in wrong module!
3358                     }
3359                     // Interfaces: Use SbxFlagBits::ExtFound
3360                 }
3361             }
3362             rBasic.bNoRtl = bSave;
3363 
3364             // is it a global uno-identifier?
3365             if( bLocal && !pElem )
3366             {
3367                 bool bSetName = true; // preserve normal behaviour
3368 
3369                 // i#i68894# if VBAInterOp favour searching vba globals
3370                 // over searching for uno classes
3371                 if ( bVBAEnabled )
3372                 {
3373                     // Try Find in VBA symbols space
3374                     pElem = rBasic.VBAFind( aName, SbxClassType::DontCare );
3375                     if ( pElem )
3376                     {
3377                         bSetName = false; // don't overwrite uno name
3378                     }
3379                     else
3380                     {
3381                         pElem = VBAConstantHelper::instance().getVBAConstant( aName );
3382                     }
3383                 }
3384 
3385                 if( !pElem )
3386                 {
3387                     // #72382 ATTENTION! ALWAYS returns a result now
3388                     // because of unknown modules!
3389                     SbUnoClass* pUnoClass = findUnoClass( aName );
3390                     if( pUnoClass )
3391                     {
3392                         pElem = new SbxVariable( t );
3393                         SbxValues aRes( SbxOBJECT );
3394                         aRes.pObj = pUnoClass;
3395                         pElem->SbxVariable::Put( aRes );
3396                     }
3397                 }
3398 
3399                 // #62939 If a uno-class has been found, the wrapper
3400                 // object has to be held, because the uno-class, e. g.
3401                 // "stardiv", has to be read out of the registry
3402                 // every time again otherwise
3403                 if( pElem )
3404                 {
3405                     // #63774 May not be saved too!!!
3406                     pElem->SetFlag( SbxFlagBits::DontStore );
3407                     pElem->SetFlag( SbxFlagBits::NoModify);
3408 
3409                     // #72382 save locally, all variables that have been declared
3410                     // implicit would become global automatically otherwise!
3411                     if ( bSetName )
3412                     {
3413                         pElem->SetName( aName );
3414                     }
3415                     refLocals->Put( pElem, refLocals->Count() );
3416                 }
3417             }
3418 
3419             if( !pElem )
3420             {
3421                 // not there and not in the object?
3422                 // don't establish if that thing has parameters!
3423                 if( nOp1 & 0x8000 )
3424                 {
3425                     bFatalError = true;
3426                 }
3427 
3428                 // else, if there are parameters, use different error code
3429                 if( !bLocal || pImg->IsFlag( SbiImageFlags::EXPLICIT ) )
3430                 {
3431                     // #39108 if explicit and as ELEM always a fatal error
3432                     bFatalError = true;
3433 
3434 
3435                     if( !( nOp1 & 0x8000 ) && nNotFound == ERRCODE_BASIC_PROC_UNDEFINED )
3436                     {
3437                         nNotFound = ERRCODE_BASIC_VAR_UNDEFINED;
3438                     }
3439                 }
3440                 if( bFatalError )
3441                 {
3442                     // #39108 use dummy variable instead of fatal error
3443                     if( !xDummyVar.is() )
3444                     {
3445                         xDummyVar = new SbxVariable( SbxVARIANT );
3446                     }
3447                     pElem = xDummyVar.get();
3448 
3449                     ClearArgvStack();
3450 
3451                     Error( nNotFound, aName );
3452                 }
3453                 else
3454                 {
3455                     if ( bStatic )
3456                     {
3457                         pElem = StepSTATIC_Impl( aName, t, 0 );
3458                     }
3459                     if ( !pElem )
3460                     {
3461                         pElem = new SbxVariable( t );
3462                         if( t != SbxVARIANT )
3463                         {
3464                             pElem->SetFlag( SbxFlagBits::Fixed );
3465                         }
3466                         pElem->SetName( aName );
3467                         refLocals->Put( pElem, refLocals->Count() );
3468                     }
3469                 }
3470             }
3471         }
3472         // #39108 Args can already be deleted!
3473         if( !bFatalError )
3474         {
3475             SetupArgs( pElem, nOp1 );
3476         }
3477         // because a particular call-type is requested
3478         if (SbxMethod* pMethod = dynamic_cast<SbxMethod*>(pElem))
3479         {
3480             // shall the type be converted?
3481             SbxDataType t2 = pElem->GetType();
3482             bool bSet = false;
3483             if( (pElem->GetFlags() & SbxFlagBits::Fixed) == SbxFlagBits::NONE )
3484             {
3485                 if( t != SbxVARIANT && t != t2 &&
3486                     t >= SbxINTEGER && t <= SbxSTRING )
3487                 {
3488                     pElem->SetType( t );
3489                     bSet = true;
3490                 }
3491             }
3492             // assign pElem to a Ref, to delete a temp-var if applicable
3493             SbxVariableRef refTemp = pElem;
3494 
3495             // remove potential rests of the last call of the SbxMethod
3496             // free Write before, so that there's no error
3497             SbxFlagBits nSavFlags = pElem->GetFlags();
3498             pElem->SetFlag( SbxFlagBits::ReadWrite | SbxFlagBits::NoBroadcast );
3499             pElem->SbxValue::Clear();
3500             pElem->SetFlags( nSavFlags );
3501 
3502             // don't touch before setting, as e. g. LEFT()
3503             // has to know the difference between Left$() and Left()
3504 
3505             // because the methods' parameters are cut away in PopVar()
3506             SbxVariable* pNew = new SbxMethod(*pMethod);
3507             //OLD: SbxVariable* pNew = new SbxVariable( *pElem );
3508 
3509             pElem->SetParameters(nullptr);
3510             pNew->SetFlag( SbxFlagBits::ReadWrite );
3511 
3512             if( bSet )
3513             {
3514                 pElem->SetType( t2 );
3515             }
3516             pElem = pNew;
3517         }
3518         // consider index-access for UnoObjects
3519         // definitely we want this for VBA where properties are often
3520         // collections ( which need index access ), but lets only do
3521         // this if we actually have params following
3522         else if( bVBAEnabled && dynamic_cast<const SbUnoProperty*>( pElem) != nullptr && pElem->GetParameters() )
3523         {
3524             SbxVariableRef refTemp = pElem;
3525 
3526             // dissolve the notify while copying variable
3527             SbxVariable* pNew = new SbxVariable( *pElem );
3528             pElem->SetParameters( nullptr );
3529             pElem = pNew;
3530         }
3531     }
3532     return CheckArray( pElem );
3533 }
3534 
3535 // for current scope (e. g. query from BASIC-IDE)
3536 SbxBase* SbiRuntime::FindElementExtern( const OUString& rName )
3537 {
3538     // don't expect pMeth to be != 0, as there are none set
3539     // in the RunInit yet
3540 
3541     SbxVariable* pElem = nullptr;
3542     if( !pMod || rName.isEmpty() )
3543     {
3544         return nullptr;
3545     }
3546     if( refLocals.is() )
3547     {
3548         pElem = refLocals->Find( rName, SbxClassType::DontCare );
3549     }
3550     if ( !pElem && pMeth )
3551     {
3552         // for statics, set the method's name in front
3553         OUString aMethName = pMeth->GetName() + ":" + rName;
3554         pElem = pMod->Find(aMethName, SbxClassType::DontCare);
3555     }
3556 
3557     // search in parameter list
3558     if( !pElem && pMeth )
3559     {
3560         SbxInfo* pInfo = pMeth->GetInfo();
3561         if( pInfo && refParams.is() )
3562         {
3563             sal_uInt16 nParamCount = refParams->Count();
3564             sal_uInt16 j = 1;
3565             const SbxParamInfo* pParam = pInfo->GetParam( j );
3566             while( pParam )
3567             {
3568                 if( pParam->aName.equalsIgnoreAsciiCase( rName ) )
3569                 {
3570                     if( j >= nParamCount )
3571                     {
3572                         // Parameter is missing
3573                         pElem = new SbxVariable( SbxSTRING );
3574                         pElem->PutString( "<missing parameter>");
3575                     }
3576                     else
3577                     {
3578                         pElem = refParams->Get( j );
3579                     }
3580                     break;
3581                 }
3582                 pParam = pInfo->GetParam( ++j );
3583             }
3584         }
3585     }
3586 
3587     // search in module
3588     if( !pElem )
3589     {
3590         bool bSave = rBasic.bNoRtl;
3591         rBasic.bNoRtl = true;
3592         pElem = pMod->Find( rName, SbxClassType::DontCare );
3593         rBasic.bNoRtl = bSave;
3594     }
3595     return pElem;
3596 }
3597 
3598 
3599 void SbiRuntime::SetupArgs( SbxVariable* p, sal_uInt32 nOp1 )
3600 {
3601     if( nOp1 & 0x8000 )
3602     {
3603         if( !refArgv.is() )
3604         {
3605             StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
3606         }
3607         bool bHasNamed = false;
3608         sal_uInt16 i;
3609         sal_uInt16 nArgCount = refArgv->Count();
3610         for( i = 1 ; i < nArgCount ; i++ )
3611         {
3612             if( !refArgv->GetAlias(i).isEmpty() )
3613             {
3614                 bHasNamed = true; break;
3615             }
3616         }
3617         if( bHasNamed )
3618         {
3619             SbxInfo* pInfo = p->GetInfo();
3620             if( !pInfo )
3621             {
3622                 bool bError_ = true;
3623 
3624                 SbUnoMethod* pUnoMethod = dynamic_cast<SbUnoMethod*>( p );
3625                 SbUnoProperty* pUnoProperty = dynamic_cast<SbUnoProperty*>( p );
3626                 if( pUnoMethod || pUnoProperty )
3627                 {
3628                     SbUnoObject* pParentUnoObj = dynamic_cast<SbUnoObject*>( p->GetParent()  );
3629                     if( pParentUnoObj )
3630                     {
3631                         Any aUnoAny = pParentUnoObj->getUnoAny();
3632                         Reference< XInvocation > xInvocation;
3633                         aUnoAny >>= xInvocation;
3634                         if( xInvocation.is() )  // TODO: if( xOLEAutomation.is() )
3635                         {
3636                             bError_ = false;
3637 
3638                             sal_uInt16 nCurPar = 1;
3639                             AutomationNamedArgsSbxArray* pArg =
3640                                 new AutomationNamedArgsSbxArray( nArgCount );
3641                             OUString* pNames = pArg->getNames().getArray();
3642                             for( i = 1 ; i < nArgCount ; i++ )
3643                             {
3644                                 SbxVariable* pVar = refArgv->Get( i );
3645                                 OUString aName = refArgv->GetAlias(i);
3646                                 if (!aName.isEmpty())
3647                                 {
3648                                     pNames[i] = aName;
3649                                 }
3650                                 pArg->Put( pVar, nCurPar++ );
3651                             }
3652                             refArgv = pArg;
3653                         }
3654                     }
3655                 }
3656                 else if( bVBAEnabled && p->GetType() == SbxOBJECT && (dynamic_cast<const SbxMethod*>( p) == nullptr || !p->IsBroadcaster()) )
3657                 {
3658                     // Check for default method with named parameters
3659                     SbxBaseRef xObj = p->GetObject();
3660                     if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( xObj.get() ))
3661                     {
3662                         Any aAny = pUnoObj->getUnoAny();
3663 
3664                         if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
3665                         {
3666                             Reference< XDefaultMethod > xDfltMethod( aAny, UNO_QUERY );
3667 
3668                             OUString sDefaultMethod;
3669                             if ( xDfltMethod.is() )
3670                             {
3671                                 sDefaultMethod = xDfltMethod->getDefaultMethodName();
3672                             }
3673                             if ( !sDefaultMethod.isEmpty() )
3674                             {
3675                                 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxClassType::Method );
3676                                 if( meth != nullptr )
3677                                 {
3678                                     pInfo = meth->GetInfo();
3679                                 }
3680                                 if( pInfo )
3681                                 {
3682                                     bError_ = false;
3683                                 }
3684                             }
3685                         }
3686                     }
3687                 }
3688                 if( bError_ )
3689                 {
3690                     Error( ERRCODE_BASIC_NO_NAMED_ARGS );
3691                 }
3692             }
3693             else
3694             {
3695                 sal_uInt16 nCurPar = 1;
3696                 SbxArray* pArg = new SbxArray;
3697                 for( i = 1 ; i < nArgCount ; i++ )
3698                 {
3699                     SbxVariable* pVar = refArgv->Get( i );
3700                     OUString aName = refArgv->GetAlias(i);
3701                     if (!aName.isEmpty())
3702                     {
3703                         // nCurPar is set to the found parameter
3704                         sal_uInt16 j = 1;
3705                         const SbxParamInfo* pParam = pInfo->GetParam( j );
3706                         while( pParam )
3707                         {
3708                             if( pParam->aName.equalsIgnoreAsciiCase( aName ) )
3709                             {
3710                                 nCurPar = j;
3711                                 break;
3712                             }
3713                             pParam = pInfo->GetParam( ++j );
3714                         }
3715                         if( !pParam )
3716                         {
3717                             Error( ERRCODE_BASIC_NAMED_NOT_FOUND ); break;
3718                         }
3719                     }
3720                     pArg->Put( pVar, nCurPar++ );
3721                 }
3722                 refArgv = pArg;
3723             }
3724         }
3725         // own var as parameter 0
3726         refArgv->Put( p, 0 );
3727         p->SetParameters( refArgv.get() );
3728         PopArgv();
3729     }
3730     else
3731     {
3732         p->SetParameters( nullptr );
3733     }
3734 }
3735 
3736 // getting an array element
3737 
3738 SbxVariable* SbiRuntime::CheckArray( SbxVariable* pElem )
3739 {
3740     SbxArray* pPar;
3741     if( ( pElem->GetType() & SbxARRAY ) && refRedim.get() != pElem )
3742     {
3743         SbxBase* pElemObj = pElem->GetObject();
3744         SbxDimArray* pDimArray = dynamic_cast<SbxDimArray*>( pElemObj );
3745         pPar = pElem->GetParameters();
3746         if( pDimArray )
3747         {
3748             // parameters may be missing, if an array is
3749             // passed as an argument
3750             if( pPar )
3751                 pElem = pDimArray->Get( pPar );
3752         }
3753         else
3754         {
3755             SbxArray* pArray = dynamic_cast<SbxArray*>( pElemObj );
3756             if( pArray )
3757             {
3758                 if( !pPar )
3759                 {
3760                     Error( ERRCODE_BASIC_OUT_OF_RANGE );
3761                     pElem = new SbxVariable;
3762                 }
3763                 else
3764                 {
3765                     pElem = pArray->Get( pPar->Get( 1 )->GetInteger() );
3766                 }
3767             }
3768         }
3769 
3770         // #42940, set parameter 0 to NULL so that var doesn't contain itself
3771         if( pPar )
3772         {
3773             pPar->Put( nullptr, 0 );
3774         }
3775     }
3776     // consider index-access for UnoObjects
3777     else if( pElem->GetType() == SbxOBJECT &&
3778             dynamic_cast<const SbxMethod*>( pElem) == nullptr &&
3779             ( !bVBAEnabled || dynamic_cast<const SbxProperty*>( pElem) == nullptr ) )
3780     {
3781         pPar = pElem->GetParameters();
3782         if ( pPar )
3783         {
3784             // is it a uno-object?
3785             SbxBaseRef pObj = pElem->GetObject();
3786             if( pObj.is() )
3787             {
3788                 if (SbUnoObject* pUnoObj = dynamic_cast<SbUnoObject*>( pObj.get()))
3789                 {
3790                     Any aAny = pUnoObj->getUnoAny();
3791 
3792                     if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
3793                     {
3794                         Reference< XIndexAccess > xIndexAccess( aAny, UNO_QUERY );
3795                         if ( !bVBAEnabled )
3796                         {
3797                             if( xIndexAccess.is() )
3798                             {
3799                                 sal_uInt32 nParamCount = static_cast<sal_uInt32>(pPar->Count()) - 1;
3800                                 if( nParamCount != 1 )
3801                                 {
3802                                     StarBASIC::Error( ERRCODE_BASIC_BAD_ARGUMENT );
3803                                     return pElem;
3804                                 }
3805 
3806                                 // get index
3807                                 sal_Int32 nIndex = pPar->Get( 1 )->GetLong();
3808                                 Reference< XInterface > xRet;
3809                                 try
3810                                 {
3811                                     Any aAny2 = xIndexAccess->getByIndex( nIndex );
3812                                     aAny2 >>= xRet;
3813                                 }
3814                                 catch (const IndexOutOfBoundsException&)
3815                                 {
3816                                     // usually expect converting problem
3817                                     StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
3818                                 }
3819 
3820                                 // #57847 always create a new variable, else error
3821                                 // due to PutObject(NULL) at ReadOnly-properties
3822                                 pElem = new SbxVariable( SbxVARIANT );
3823                                 if( xRet.is() )
3824                                 {
3825                                     aAny <<= xRet;
3826 
3827                                     // #67173 don't specify a name so that the real class name is entered
3828                                     SbxObjectRef xWrapper = static_cast<SbxObject*>(new SbUnoObject( OUString(), aAny ));
3829                                     pElem->PutObject( xWrapper.get() );
3830                                 }
3831                                 else
3832                                 {
3833                                     pElem->PutObject( nullptr );
3834                                 }
3835                             }
3836                         }
3837                         else
3838                         {
3839                             // check if there isn't a default member between the current variable
3840                             // and the params, e.g.
3841                             //   Dim rst1 As New ADODB.Recordset
3842                             //      "
3843                             //   val = rst1("FirstName")
3844                             // has the default 'Fields' member between rst1 and '("FirstName")'
3845                             Any x = aAny;
3846                             SbxVariable* pDflt = getDefaultProp( pElem );
3847                             if ( pDflt )
3848                             {
3849                                 pDflt->Broadcast( SfxHintId::BasicDataWanted );
3850                                 SbxBaseRef pDfltObj = pDflt->GetObject();
3851                                 if( pDfltObj.is() )
3852                                 {
3853                                     if (SbUnoObject* pSbObj = dynamic_cast<SbUnoObject*>(pDfltObj.get()))
3854                                     {
3855                                         pUnoObj = pSbObj;
3856                                         Any aUnoAny = pUnoObj->getUnoAny();
3857 
3858                                         if( aUnoAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
3859                                             x = aUnoAny;
3860                                         pElem = pDflt;
3861                                     }
3862                                 }
3863                             }
3864                             OUString sDefaultMethod;
3865 
3866                             Reference< XDefaultMethod > xDfltMethod( x, UNO_QUERY );
3867 
3868                             if ( xDfltMethod.is() )
3869                             {
3870                                 sDefaultMethod = xDfltMethod->getDefaultMethodName();
3871                             }
3872                             else if( xIndexAccess.is() )
3873                             {
3874                                 sDefaultMethod = "getByIndex";
3875                             }
3876                             if ( !sDefaultMethod.isEmpty() )
3877                             {
3878                                 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxClassType::Method );
3879                                 SbxVariableRef refTemp = meth;
3880                                 if ( refTemp.is() )
3881                                 {
3882                                     meth->SetParameters( pPar );
3883                                     SbxVariable* pNew = new SbxMethod( *static_cast<SbxMethod*>(meth) );
3884                                     pElem = pNew;
3885                                 }
3886                             }
3887                         }
3888                     }
3889 
3890                     // #42940, set parameter 0 to NULL so that var doesn't contain itself
3891                     pPar->Put( nullptr, 0 );
3892                 }
3893                 else if (BasicCollection* pCol = dynamic_cast<BasicCollection*>(pObj.get()))
3894                 {
3895                     pElem = new SbxVariable( SbxVARIANT );
3896                     pPar->Put( pElem, 0 );
3897                     pCol->CollItem( pPar );
3898                 }
3899             }
3900             else if( bVBAEnabled )  // !pObj
3901             {
3902                 SbxArray* pParam = pElem->GetParameters();
3903                 if( pParam != nullptr && !pElem->IsSet( SbxFlagBits::VarToDim ) )
3904                 {
3905                     Error( ERRCODE_BASIC_NO_OBJECT );
3906                 }
3907             }
3908         }
3909     }
3910 
3911     return pElem;
3912 }
3913 
3914 // loading an element from the runtime-library (+StringID+type)
3915 
3916 void SbiRuntime::StepRTL( sal_uInt32 nOp1, sal_uInt32 nOp2 )
3917 {
3918     PushVar( FindElement( rBasic.pRtl.get(), nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED, false ) );
3919 }
3920 
3921 void SbiRuntime::StepFIND_Impl( SbxObject* pObj, sal_uInt32 nOp1, sal_uInt32 nOp2,
3922                                 ErrCode nNotFound, bool bStatic )
3923 {
3924     if( !refLocals.is() )
3925     {
3926         refLocals = new SbxArray;
3927     }
3928     PushVar( FindElement( pObj, nOp1, nOp2, nNotFound, true/*bLocal*/, bStatic ) );
3929 }
3930 // loading a local/global variable (+StringID+type)
3931 
3932 void SbiRuntime::StepFIND( sal_uInt32 nOp1, sal_uInt32 nOp2 )
3933 {
3934     StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED );
3935 }
3936 
3937 // Search inside a class module (CM) to enable global search in time
3938 void SbiRuntime::StepFIND_CM( sal_uInt32 nOp1, sal_uInt32 nOp2 )
3939 {
3940 
3941     SbClassModuleObject* pClassModuleObject = dynamic_cast<SbClassModuleObject*>( pMod );
3942     if( pClassModuleObject )
3943     {
3944         pMod->SetFlag( SbxFlagBits::GlobalSearch );
3945     }
3946     StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED);
3947 
3948     if( pClassModuleObject )
3949     {
3950         pMod->ResetFlag( SbxFlagBits::GlobalSearch );
3951     }
3952 }
3953 
3954 void SbiRuntime::StepFIND_STATIC( sal_uInt32 nOp1, sal_uInt32 nOp2 )
3955 {
3956     StepFIND_Impl( pMod, nOp1, nOp2, ERRCODE_BASIC_PROC_UNDEFINED, true );
3957 }
3958 
3959 // loading an object-element (+StringID+type)
3960 // the object lies on TOS
3961 
3962 void SbiRuntime::StepELEM( sal_uInt32 nOp1, sal_uInt32 nOp2 )
3963 {
3964     SbxVariableRef pObjVar = PopVar();
3965 
3966     SbxObject* pObj = dynamic_cast<SbxObject*>( pObjVar.get() );
3967     if( !pObj )
3968     {
3969         SbxBase* pObjVarObj = pObjVar->GetObject();
3970         pObj = dynamic_cast<SbxObject*>( pObjVarObj );
3971     }
3972 
3973     // #56368 save reference at StepElem, otherwise objects could
3974     // lose their reference too early in qualification chains like
3975     // ActiveComponent.Selection(0).Text
3976     // #74254 now per list
3977     if( pObj )
3978     {
3979         aRefSaved.emplace_back(pObj );
3980     }
3981     PushVar( FindElement( pObj, nOp1, nOp2, ERRCODE_BASIC_NO_METHOD, false ) );
3982 }
3983 
3984 // loading a parameter (+offset+type)
3985 // If the data type is wrong, create a copy.
3986 // The data type SbxEMPTY shows that no parameters are given.
3987 // Get( 0 ) may be EMPTY
3988 
3989 void SbiRuntime::StepPARAM( sal_uInt32 nOp1, sal_uInt32 nOp2 )
3990 {
3991     sal_uInt16 i = static_cast<sal_uInt16>( nOp1 & 0x7FFF );
3992     SbxDataType t = static_cast<SbxDataType>(nOp2);
3993     SbxVariable* p;
3994 
3995     // #57915 solve missing in a cleaner way
3996     sal_uInt16 nParamCount = refParams->Count();
3997     if( i >= nParamCount )
3998     {
3999         sal_Int16 iLoop = i;
4000         while( iLoop >= nParamCount )
4001         {
4002             p = new SbxVariable();
4003 
4004             if( SbiRuntime::isVBAEnabled() &&
4005                 (t == SbxOBJECT || t == SbxSTRING) )
4006             {
4007                 if( t == SbxOBJECT )
4008                 {
4009                     p->PutObject( nullptr );
4010                 }
4011                 else
4012                 {
4013                     p->PutString( OUString() );
4014                 }
4015             }
4016             else
4017             {
4018                 p->PutErr( 448 );       // like in VB: Error-Code 448 (ERRCODE_BASIC_NAMED_NOT_FOUND)
4019             }
4020             refParams->Put( p, iLoop );
4021             iLoop--;
4022         }
4023     }
4024     p = refParams->Get( i );
4025 
4026     if( p->GetType() == SbxERROR && i )
4027     {
4028         // if there's a parameter missing, it can be OPTIONAL
4029         bool bOpt = false;
4030         if( pMeth )
4031         {
4032             SbxInfo* pInfo = pMeth->GetInfo();
4033             if ( pInfo )
4034             {
4035                 const SbxParamInfo* pParam = pInfo->GetParam( i );
4036                 if( pParam && ( pParam->nFlags & SbxFlagBits::Optional ) )
4037                 {
4038                     // Default value?
4039                     sal_uInt16 nDefaultId = static_cast<sal_uInt16>(pParam->nUserData & 0x0ffff);
4040                     if( nDefaultId > 0 )
4041                     {
4042                         OUString aDefaultStr = pImg->GetString( nDefaultId );
4043                         p = new SbxVariable();
4044                         p->PutString( aDefaultStr );
4045                         refParams->Put( p, i );
4046                     }
4047                     bOpt = true;
4048                 }
4049             }
4050         }
4051         if( !bOpt )
4052         {
4053             Error( ERRCODE_BASIC_NOT_OPTIONAL );
4054         }
4055     }
4056     else if( t != SbxVARIANT && static_cast<SbxDataType>(p->GetType() & 0x0FFF ) != t )
4057     {
4058         SbxVariable* q = new SbxVariable( t );
4059         aRefSaved.emplace_back(q );
4060         *q = *p;
4061         p = q;
4062         if ( i )
4063         {
4064             refParams->Put( p, i );
4065         }
4066     }
4067     SetupArgs( p, nOp1 );
4068     PushVar( CheckArray( p ) );
4069 }
4070 
4071 // Case-Test (+True-Target+Test-Opcode)
4072 
4073 void SbiRuntime::StepCASEIS( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4074 {
4075     if( !refCaseStk.is() || !refCaseStk->Count() )
4076     {
4077         StarBASIC::FatalError( ERRCODE_BASIC_INTERNAL_ERROR );
4078     }
4079     else
4080     {
4081         SbxVariableRef xComp = PopVar();
4082         SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 );
4083         if( xCase->Compare( static_cast<SbxOperator>(nOp2), *xComp ) )
4084         {
4085             StepJUMP( nOp1 );
4086         }
4087     }
4088 }
4089 
4090 // call of a DLL-procedure (+StringID+type)
4091 // the StringID's MSB shows that Argv is occupied
4092 
4093 void SbiRuntime::StepCALL( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4094 {
4095     OUString aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) );
4096     SbxArray* pArgs = nullptr;
4097     if( nOp1 & 0x8000 )
4098     {
4099         pArgs = refArgv.get();
4100     }
4101     DllCall( aName, aLibName, pArgs, static_cast<SbxDataType>(nOp2), false );
4102     aLibName.clear();
4103     if( nOp1 & 0x8000 )
4104     {
4105         PopArgv();
4106     }
4107 }
4108 
4109 // call of a DLL-procedure after CDecl (+StringID+type)
4110 
4111 void SbiRuntime::StepCALLC( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4112 {
4113     OUString aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) );
4114     SbxArray* pArgs = nullptr;
4115     if( nOp1 & 0x8000 )
4116     {
4117         pArgs = refArgv.get();
4118     }
4119     DllCall( aName, aLibName, pArgs, static_cast<SbxDataType>(nOp2), true );
4120     aLibName.clear();
4121     if( nOp1 & 0x8000 )
4122     {
4123         PopArgv();
4124     }
4125 }
4126 
4127 
4128 // beginning of a statement (+Line+Col)
4129 
4130 void SbiRuntime::StepSTMNT( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4131 {
4132     // If the Expr-Stack at the beginning of a statement contains a variable,
4133     // some fool has called X as a function, although it's a variable!
4134     bool bFatalExpr = false;
4135     OUString sUnknownMethodName;
4136     if( nExprLvl > 1 )
4137     {
4138         bFatalExpr = true;
4139     }
4140     else if( nExprLvl )
4141     {
4142         SbxVariable* p = refExprStk->Get( 0 );
4143         if( p->GetRefCount() > 1 &&
4144             refLocals.is() && refLocals->Find( p->GetName(), p->GetClass() ) )
4145         {
4146             sUnknownMethodName = p->GetName();
4147             bFatalExpr = true;
4148         }
4149     }
4150 
4151     ClearExprStack();
4152 
4153     aRefSaved.clear();
4154 
4155     // We have to cancel hard here because line and column
4156     // would be wrong later otherwise!
4157     if( bFatalExpr)
4158     {
4159         StarBASIC::FatalError( ERRCODE_BASIC_NO_METHOD, sUnknownMethodName );
4160         return;
4161     }
4162     pStmnt = pCode - 9;
4163     sal_uInt16 nOld = nLine;
4164     nLine = static_cast<short>( nOp1 );
4165 
4166     // #29955 & 0xFF, to filter out for-loop-level
4167     nCol1 = static_cast<short>( nOp2 & 0xFF );
4168 
4169     // find the next STMNT-command to set the final column
4170     // of this statement
4171 
4172     nCol2 = 0xffff;
4173     sal_uInt16 n1, n2;
4174     const sal_uInt8* p = pMod->FindNextStmnt( pCode, n1, n2 );
4175     if( p )
4176     {
4177         if( n1 == nOp1 )
4178         {
4179             // #29955 & 0xFF, to filter out for-loop-level
4180             nCol2 = (n2 & 0xFF) - 1;
4181         }
4182     }
4183 
4184     // #29955 correct for-loop-level, #67452 NOT in the error-handler
4185     if( !bInError )
4186     {
4187         // (there's a difference here in case of a jump out of a loop)
4188         sal_uInt16 nExspectedForLevel = static_cast<sal_uInt16>( nOp2 / 0x100 );
4189         if( !pGosubStk.empty() )
4190         {
4191             nExspectedForLevel = nExspectedForLevel + pGosubStk.back().nStartForLvl;
4192         }
4193 
4194         // if the actual for-level is too small it'd jump out
4195         // of a loop -> corrected
4196         while( nForLvl > nExspectedForLevel )
4197         {
4198             PopFor();
4199         }
4200     }
4201 
4202     // 16.10.96: #31460 new concept for StepInto/Over/Out
4203     // see explanation at _ImplGetBreakCallLevel
4204     if( pInst->nCallLvl <= pInst->nBreakCallLvl )
4205     {
4206         StarBASIC* pStepBasic = GetCurrentBasic( &rBasic );
4207         BasicDebugFlags nNewFlags = pStepBasic->StepPoint( nLine, nCol1, nCol2 );
4208 
4209         pInst->CalcBreakCallLevel( nNewFlags );
4210     }
4211 
4212     // break points only at STMNT-commands in a new line!
4213     else if( ( nOp1 != nOld )
4214         && ( nFlags & BasicDebugFlags::Break )
4215         && pMod->IsBP( static_cast<sal_uInt16>( nOp1 ) ) )
4216     {
4217         StarBASIC* pBreakBasic = GetCurrentBasic( &rBasic );
4218         BasicDebugFlags nNewFlags = pBreakBasic->BreakPoint( nLine, nCol1, nCol2 );
4219 
4220         pInst->CalcBreakCallLevel( nNewFlags );
4221     }
4222 }
4223 
4224 // (+StreamMode+Flags)
4225 // Stack: block length
4226 //        channel number
4227 //        file name
4228 
4229 void SbiRuntime::StepOPEN( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4230 {
4231     SbxVariableRef pName = PopVar();
4232     SbxVariableRef pChan = PopVar();
4233     SbxVariableRef pLen  = PopVar();
4234     short nBlkLen = pLen->GetInteger();
4235     short nChan   = pChan->GetInteger();
4236     OString aName(OUStringToOString(pName->GetOUString(), osl_getThreadTextEncoding()));
4237     pIosys->Open( nChan, aName, static_cast<StreamMode>( nOp1 ),
4238                   static_cast<SbiStreamFlags>( nOp2 ), nBlkLen );
4239     Error( pIosys->GetError() );
4240 }
4241 
4242 // create object (+StringID+StringID)
4243 
4244 void SbiRuntime::StepCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4245 {
4246     OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) );
4247     SbxObject *pObj = SbxBase::CreateObject( aClass );
4248     if( !pObj )
4249     {
4250         Error( ERRCODE_BASIC_INVALID_OBJECT );
4251     }
4252     else
4253     {
4254         OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4255         pObj->SetName( aName );
4256         // the object must be able to call the BASIC
4257         pObj->SetParent( &rBasic );
4258         SbxVariable* pNew = new SbxVariable;
4259         pNew->PutObject( pObj );
4260         PushVar( pNew );
4261     }
4262 }
4263 
4264 void SbiRuntime::StepDCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4265 {
4266     StepDCREATE_IMPL( nOp1, nOp2 );
4267 }
4268 
4269 void SbiRuntime::StepDCREATE_REDIMP( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4270 {
4271     StepDCREATE_IMPL( nOp1, nOp2 );
4272 }
4273 
4274 
4275 // Helper function for StepDCREATE_IMPL / bRedimp = true
4276 static void implCopyDimArray_DCREATE( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex,
4277     short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
4278 {
4279     sal_Int32& ri = pActualIndices[nActualDim];
4280     for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ )
4281     {
4282         if( nActualDim < nMaxDimIndex )
4283         {
4284             implCopyDimArray_DCREATE( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1,
4285                 pActualIndices, pLowerBounds, pUpperBounds );
4286         }
4287         else
4288         {
4289             SbxVariable* pSource = pOldArray->Get32( pActualIndices );
4290             pNewArray->Put32( pSource, pActualIndices );
4291         }
4292     }
4293 }
4294 
4295 // #56204 create object array (+StringID+StringID), DCREATE == Dim-Create
4296 void SbiRuntime::StepDCREATE_IMPL( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4297 {
4298     SbxVariableRef refVar = PopVar();
4299 
4300     DimImpl( refVar );
4301 
4302     // fill the array with instances of the requested class
4303     SbxBaseRef xObj = refVar->GetObject();
4304     if( !xObj.is() )
4305     {
4306         StarBASIC::Error( ERRCODE_BASIC_INVALID_OBJECT );
4307         return;
4308     }
4309 
4310     SbxDimArray* pArray = dynamic_cast<SbxDimArray*>(xObj.get());
4311     if (pArray)
4312     {
4313         short nDims = pArray->GetDims();
4314         sal_Int32 nTotalSize = 0;
4315 
4316         // must be a one-dimensional array
4317         sal_Int32 nLower, nUpper;
4318         for( sal_Int32 i = 0 ; i < nDims ; ++i )
4319         {
4320             pArray->GetDim32( i+1, nLower, nUpper );
4321             sal_Int32 nSize = nUpper - nLower + 1;
4322             if( i == 0 )
4323             {
4324                 nTotalSize = nSize;
4325             }
4326             else
4327             {
4328                 nTotalSize *= nSize;
4329             }
4330         }
4331 
4332         // create objects and insert them into the array
4333         OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) );
4334         for( sal_Int32 i = 0 ; i < nTotalSize ; ++i )
4335         {
4336             SbxObject *pClassObj = SbxBase::CreateObject( aClass );
4337             if( !pClassObj )
4338             {
4339                 Error( ERRCODE_BASIC_INVALID_OBJECT );
4340                 break;
4341             }
4342             else
4343             {
4344                 OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4345                 pClassObj->SetName( aName );
4346                 // the object must be able to call the basic
4347                 pClassObj->SetParent( &rBasic );
4348                 pArray->SbxArray::Put32( pClassObj, i );
4349             }
4350         }
4351     }
4352 
4353     SbxDimArray* pOldArray = static_cast<SbxDimArray*>(refRedimpArray.get());
4354     if( pArray && pOldArray )
4355     {
4356         short nDimsNew = pArray->GetDims();
4357         short nDimsOld = pOldArray->GetDims();
4358         short nDims = nDimsNew;
4359         bool bRangeError = false;
4360 
4361         // Store dims to use them for copying later
4362         std::unique_ptr<sal_Int32[]> pLowerBounds(new sal_Int32[nDims]);
4363         std::unique_ptr<sal_Int32[]> pUpperBounds(new sal_Int32[nDims]);
4364         std::unique_ptr<sal_Int32[]> pActualIndices(new sal_Int32[nDims]);
4365         if( nDimsOld != nDimsNew )
4366         {
4367             bRangeError = true;
4368         }
4369         else
4370         {
4371             // Compare bounds
4372             for( short i = 1 ; i <= nDims ; i++ )
4373             {
4374                 sal_Int32 lBoundNew, uBoundNew;
4375                 sal_Int32 lBoundOld, uBoundOld;
4376                 pArray->GetDim32( i, lBoundNew, uBoundNew );
4377                 pOldArray->GetDim32( i, lBoundOld, uBoundOld );
4378 
4379                 lBoundNew = std::max( lBoundNew, lBoundOld );
4380                 uBoundNew = std::min( uBoundNew, uBoundOld );
4381                 short j = i - 1;
4382                 pActualIndices[j] = pLowerBounds[j] = lBoundNew;
4383                 pUpperBounds[j] = uBoundNew;
4384             }
4385         }
4386 
4387         if( bRangeError )
4388         {
4389             StarBASIC::Error( ERRCODE_BASIC_OUT_OF_RANGE );
4390         }
4391         else
4392         {
4393             // Copy data from old array by going recursively through all dimensions
4394             // (It would be faster to work on the flat internal data array of an
4395             // SbyArray but this solution is clearer and easier)
4396             implCopyDimArray_DCREATE( pArray, pOldArray, nDims - 1,
4397                                       0, pActualIndices.get(), pLowerBounds.get(), pUpperBounds.get() );
4398         }
4399         refRedimpArray = nullptr;
4400     }
4401 }
4402 
4403 void SbiRuntime::StepTCREATE( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4404 {
4405     OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4406     OUString aClass( pImg->GetString( static_cast<short>( nOp2 ) ) );
4407 
4408     SbxObject* pCopyObj = createUserTypeImpl( aClass );
4409     if( pCopyObj )
4410     {
4411         pCopyObj->SetName( aName );
4412     }
4413     SbxVariable* pNew = new SbxVariable;
4414     pNew->PutObject( pCopyObj );
4415     pNew->SetDeclareClassName( aClass );
4416     PushVar( pNew );
4417 }
4418 
4419 void SbiRuntime::implHandleSbxFlags( SbxVariable* pVar, SbxDataType t, sal_uInt32 nOp2 )
4420 {
4421     bool bWithEvents = ((t & 0xff) == SbxOBJECT && (nOp2 & SBX_TYPE_WITH_EVENTS_FLAG) != 0);
4422     if( bWithEvents )
4423     {
4424         pVar->SetFlag( SbxFlagBits::WithEvents );
4425     }
4426     bool bDimAsNew = ((nOp2 & SBX_TYPE_DIM_AS_NEW_FLAG) != 0);
4427     if( bDimAsNew )
4428     {
4429         pVar->SetFlag( SbxFlagBits::DimAsNew );
4430     }
4431     bool bFixedString = ((t & 0xff) == SbxSTRING && (nOp2 & SBX_FIXED_LEN_STRING_FLAG) != 0);
4432     if( bFixedString )
4433     {
4434         sal_uInt16 nCount = static_cast<sal_uInt16>( nOp2 >> 17 );      // len = all bits above 0x10000
4435         OUStringBuffer aBuf;
4436         comphelper::string::padToLength(aBuf, nCount);
4437         pVar->PutString(aBuf.makeStringAndClear());
4438     }
4439 
4440     bool bVarToDim = ((nOp2 & SBX_TYPE_VAR_TO_DIM_FLAG) != 0);
4441     if( bVarToDim )
4442     {
4443         pVar->SetFlag( SbxFlagBits::VarToDim );
4444     }
4445 }
4446 
4447 // establishing a local variable (+StringID+type)
4448 
4449 void SbiRuntime::StepLOCAL( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4450 {
4451     if( !refLocals.is() )
4452     {
4453         refLocals = new SbxArray;
4454     }
4455     OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4456     if( refLocals->Find( aName, SbxClassType::DontCare ) == nullptr )
4457     {
4458         SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff);
4459         SbxVariable* p = new SbxVariable( t );
4460         p->SetName( aName );
4461         implHandleSbxFlags( p, t, nOp2 );
4462         refLocals->Put( p, refLocals->Count() );
4463     }
4464 }
4465 
4466 // establishing a module-global variable (+StringID+type)
4467 
4468 void SbiRuntime::StepPUBLIC_Impl( sal_uInt32 nOp1, sal_uInt32 nOp2, bool bUsedForClassModule )
4469 {
4470     OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4471     SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff);
4472     bool bFlag = pMod->IsSet( SbxFlagBits::NoModify );
4473     pMod->SetFlag( SbxFlagBits::NoModify );
4474     SbxVariableRef p = pMod->Find( aName, SbxClassType::Property );
4475     if( p.is() )
4476     {
4477         pMod->Remove (p.get());
4478     }
4479     SbProperty* pProp = pMod->GetProperty( aName, t );
4480     if( !bUsedForClassModule )
4481     {
4482         pProp->SetFlag( SbxFlagBits::Private );
4483     }
4484     if( !bFlag )
4485     {
4486         pMod->ResetFlag( SbxFlagBits::NoModify );
4487     }
4488     if( pProp )
4489     {
4490         pProp->SetFlag( SbxFlagBits::DontStore );
4491         // from 2.7.1996: HACK because of 'reference can't be saved'
4492         pProp->SetFlag( SbxFlagBits::NoModify);
4493 
4494         implHandleSbxFlags( pProp, t, nOp2 );
4495     }
4496 }
4497 
4498 void SbiRuntime::StepPUBLIC( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4499 {
4500     StepPUBLIC_Impl( nOp1, nOp2, false );
4501 }
4502 
4503 void SbiRuntime::StepPUBLIC_P( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4504 {
4505     // Creates module variable that isn't reinitialised when
4506     // between invocations ( for VBASupport & document basic only )
4507     if( pMod->pImage->bFirstInit )
4508     {
4509         bool bUsedForClassModule = pImg->IsFlag( SbiImageFlags::CLASSMODULE );
4510         StepPUBLIC_Impl( nOp1, nOp2, bUsedForClassModule );
4511     }
4512 }
4513 
4514 // establishing a global variable (+StringID+type)
4515 
4516 void SbiRuntime::StepGLOBAL( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4517 {
4518     if( pImg->IsFlag( SbiImageFlags::CLASSMODULE ) )
4519     {
4520         StepPUBLIC_Impl( nOp1, nOp2, true );
4521     }
4522     OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4523     SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff);
4524 
4525     // Store module scope variables at module scope
4526     // in non vba mode these are stored at the library level :/
4527     // not sure if this really should not be enabled for ALL basic
4528     SbxObject* pStorage = &rBasic;
4529     if ( SbiRuntime::isVBAEnabled() )
4530     {
4531         pStorage = pMod;
4532         pMod->AddVarName( aName );
4533     }
4534 
4535     bool bFlag = pStorage->IsSet( SbxFlagBits::NoModify );
4536     rBasic.SetFlag( SbxFlagBits::NoModify );
4537     SbxVariableRef p = pStorage->Find( aName, SbxClassType::Property );
4538     if( p.is() )
4539     {
4540         pStorage->Remove (p.get());
4541     }
4542     p = pStorage->Make( aName, SbxClassType::Property, t );
4543     if( !bFlag )
4544     {
4545         pStorage->ResetFlag( SbxFlagBits::NoModify );
4546     }
4547     if( p.is() )
4548     {
4549         p->SetFlag( SbxFlagBits::DontStore );
4550         // from 2.7.1996: HACK because of 'reference can't be saved'
4551         p->SetFlag( SbxFlagBits::NoModify);
4552     }
4553 }
4554 
4555 
4556 // Creates global variable that isn't reinitialised when
4557 // basic is restarted, P=PERSIST (+StringID+Typ)
4558 
4559 void SbiRuntime::StepGLOBAL_P( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4560 {
4561     if( pMod->pImage->bFirstInit )
4562     {
4563         StepGLOBAL( nOp1, nOp2 );
4564     }
4565 }
4566 
4567 
4568 // Searches for global variable, behavior depends on the fact
4569 // if the variable is initialised for the first time
4570 
4571 void SbiRuntime::StepFIND_G( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4572 {
4573     if( pMod->pImage->bFirstInit )
4574     {
4575         // Behave like always during first init
4576         StepFIND( nOp1, nOp2 );
4577     }
4578     else
4579     {
4580         // Return dummy variable
4581         SbxDataType t = static_cast<SbxDataType>(nOp2);
4582         OUString aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) );
4583 
4584         SbxVariable* pDummyVar = new SbxVariable( t );
4585         pDummyVar->SetName( aName );
4586         PushVar( pDummyVar );
4587     }
4588 }
4589 
4590 
4591 SbxVariable* SbiRuntime::StepSTATIC_Impl(
4592     OUString const & aName, SbxDataType t, sal_uInt32 nOp2 )
4593 {
4594     SbxVariable* p = nullptr;
4595     if ( pMeth )
4596     {
4597         SbxArray* pStatics = pMeth->GetStatics();
4598         if( pStatics && ( pStatics->Find( aName, SbxClassType::DontCare ) == nullptr ) )
4599         {
4600             p = new SbxVariable( t );
4601             if( t != SbxVARIANT )
4602             {
4603                 p->SetFlag( SbxFlagBits::Fixed );
4604             }
4605             p->SetName( aName );
4606             implHandleSbxFlags( p, t, nOp2 );
4607             pStatics->Put( p, pStatics->Count() );
4608         }
4609     }
4610     return p;
4611 }
4612 // establishing a static variable (+StringID+type)
4613 void SbiRuntime::StepSTATIC( sal_uInt32 nOp1, sal_uInt32 nOp2 )
4614 {
4615     OUString aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
4616     SbxDataType t = static_cast<SbxDataType>(nOp2 & 0xffff);
4617     StepSTATIC_Impl( aName, t, nOp2 );
4618 }
4619 
4620 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
4621