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