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