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