merge the formfield patch from ooo-build
[ooovba.git] / basic / source / runtime / step2.cxx
blobac988754bc793c93b6e463fb3dcd42d69e793d3d
1 /*************************************************************************
3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
5 * Copyright 2008 by Sun Microsystems, Inc.
7 * OpenOffice.org - a multi-platform office productivity suite
9 * $RCSfile: step2.cxx,v $
10 * $Revision: 1.35 $
12 * This file is part of OpenOffice.org.
14 * OpenOffice.org is free software: you can redistribute it and/or modify
15 * it under the terms of the GNU Lesser General Public License version 3
16 * only, as published by the Free Software Foundation.
18 * OpenOffice.org is distributed in the hope that it will be useful,
19 * but WITHOUT ANY WARRANTY; without even the implied warranty of
20 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
21 * GNU Lesser General Public License version 3 for more details
22 * (a copy is included in the LICENSE file that accompanied this code).
24 * You should have received a copy of the GNU Lesser General Public License
25 * version 3 along with OpenOffice.org. If not, see
26 * <http://www.openoffice.org/license.html>
27 * for a copy of the LGPLv3 License.
29 ************************************************************************/
31 // MARKER(update_precomp.py): autogen include statement, do not remove
32 #include "precompiled_basic.hxx"
34 #include "runtime.hxx"
35 #ifndef GCC
36 #endif
37 #include "iosys.hxx"
38 #include "image.hxx"
39 #include "sbintern.hxx"
40 #include "sbunoobj.hxx"
41 #include "opcodes.hxx"
43 #include <com/sun/star/container/XIndexAccess.hpp>
44 #include <com/sun/star/script/XDefaultMethod.hpp>
45 #include <com/sun/star/beans/XPropertySet.hpp>
46 #include <com/sun/star/uno/Any.hxx>
47 #include <comphelper/processfactory.hxx>
49 using namespace com::sun::star::uno;
50 using namespace com::sun::star::container;
51 using namespace com::sun::star::lang;
52 using namespace com::sun::star::beans;
53 using namespace com::sun::star::script;
55 using com::sun::star::uno::Reference;
57 // Suchen eines Elements
58 // Die Bits im String-ID:
59 // 0x8000 - Argv ist belegt
61 SbxVariable* SbiRuntime::FindElement
62 ( SbxObject* pObj, UINT32 nOp1, UINT32 nOp2, SbError nNotFound, BOOL bLocal, BOOL bStatic )
64 bool bIsVBAInterOp = SbiRuntime::isVBAEnabled();
65 if( bIsVBAInterOp )
67 StarBASIC* pMSOMacroRuntimeLib = GetSbData()->pMSOMacroRuntimLib;
68 if( pMSOMacroRuntimeLib != NULL )
69 pMSOMacroRuntimeLib->ResetFlag( SBX_EXTSEARCH );
72 SbxVariable* pElem = NULL;
73 if( !pObj )
75 Error( SbERR_NO_OBJECT );
76 pElem = new SbxVariable;
78 else
80 BOOL bFatalError = FALSE;
81 SbxDataType t = (SbxDataType) nOp2;
82 String aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) );
83 // Hacky capture of Evaluate [] syntax
84 // this should be tackled I feel at the pcode level
85 if ( bIsVBAInterOp && aName.Search('[') == 0 )
87 // emulate pcode here
88 StepARGC();
89 // psuedo StepLOADSC
90 String sArg = aName.Copy( 1, aName.Len() - 2 );
91 SbxVariable* p = new SbxVariable;
92 p->PutString( sArg );
93 PushVar( p );
95 StepARGV();
96 nOp1 = nOp1 | 0x8000; // indicate params are present
97 aName = String::CreateFromAscii("Evaluate");
99 if( bLocal )
101 if ( bStatic )
103 if ( pMeth )
104 pElem = pMeth->GetStatics()->Find( aName, SbxCLASS_DONTCARE );
107 if ( !pElem )
108 pElem = refLocals->Find( aName, SbxCLASS_DONTCARE );
110 if( !pElem )
112 // Die RTL brauchen wir nicht mehr zu durchsuchen!
113 BOOL bSave = rBasic.bNoRtl;
114 rBasic.bNoRtl = TRUE;
115 pElem = pObj->Find( aName, SbxCLASS_DONTCARE );
117 // #110004, #112015: Make private really private
118 if( bLocal && pElem ) // Local as flag for global search
120 if( pElem->IsSet( SBX_PRIVATE ) )
122 SbiInstance* pInst_ = pINST;
123 if( pInst_ && pInst_->IsCompatibility() && pObj != pElem->GetParent() )
124 pElem = NULL; // Found but in wrong module!
126 // Interfaces: Use SBX_EXTFOUND
129 rBasic.bNoRtl = bSave;
131 // Ist es ein globaler Uno-Bezeichner?
132 if( bLocal && !pElem )
134 bool bSetName = true; // preserve normal behaviour
136 // i#i68894# if VBAInterOp favour searching vba globals
137 // over searching for uno classess
138 if ( bVBAEnabled )
140 // Try Find in VBA symbols space
141 pElem = rBasic.VBAFind( aName, SbxCLASS_DONTCARE );
142 if ( pElem )
143 bSetName = false; // don't overwrite uno name
144 else
145 pElem = VBAConstantHelper::instance().getVBAConstant( aName );
147 // #72382 VORSICHT! Liefert jetzt wegen unbekannten
148 // Modulen IMMER ein Ergebnis!
149 SbUnoClass* pUnoClass = findUnoClass( aName );
150 if( pUnoClass )
152 pElem = new SbxVariable( t );
153 SbxValues aRes( SbxOBJECT );
154 aRes.pObj = pUnoClass;
155 pElem->SbxVariable::Put( aRes );
158 // #62939 Wenn eine Uno-Klasse gefunden wurde, muss
159 // das Wrapper-Objekt gehalten werden, da sonst auch
160 // die Uno-Klasse, z.B. "stardiv" immer wieder neu
161 // aus der Registry gelesen werden muss
162 if( pElem )
164 // #63774 Darf nicht mit gespeichert werden!!!
165 pElem->SetFlag( SBX_DONTSTORE );
166 pElem->SetFlag( SBX_NO_MODIFY);
168 // #72382 Lokal speichern, sonst werden alle implizit
169 // deklarierten Vars automatisch global !
170 if ( bSetName )
171 pElem->SetName( aName );
172 refLocals->Put( pElem, refLocals->Count() );
176 if( !pElem )
178 // Nicht da und nicht im Objekt?
179 // Hat das Ding Parameter, nicht einrichten!
180 if( nOp1 & 0x8000 )
181 bFatalError = TRUE;
182 // ALT: StarBASIC::FatalError( nNotFound );
184 // Sonst, falls keine Parameter sind, anderen Error Code verwenden
185 if( !bLocal || pImg->GetFlag( SBIMG_EXPLICIT ) )
187 // #39108 Bei explizit und als ELEM immer ein Fatal Error
188 bFatalError = TRUE;
190 // Falls keine Parameter sind, anderen Error Code verwenden
191 if( !( nOp1 & 0x8000 ) && nNotFound == SbERR_PROC_UNDEFINED )
192 nNotFound = SbERR_VAR_UNDEFINED;
194 if( bFatalError )
196 // #39108 Statt FatalError zu setzen, Dummy-Variable liefern
197 if( !xDummyVar.Is() )
198 xDummyVar = new SbxVariable( SbxVARIANT );
199 pElem = xDummyVar;
201 // Parameter von Hand loeschen
202 ClearArgvStack();
204 // Normalen Error setzen
205 Error( nNotFound, aName );
207 else
209 if ( bStatic )
210 pElem = StepSTATIC_Impl( aName, t );
211 if ( !pElem )
213 // Sonst Variable neu anlegen
214 pElem = new SbxVariable( t );
215 if( t != SbxVARIANT )
216 pElem->SetFlag( SBX_FIXED );
217 pElem->SetName( aName );
218 refLocals->Put( pElem, refLocals->Count() );
223 // #39108 Args koennen schon geloescht sein!
224 if( !bFatalError )
225 SetupArgs( pElem, nOp1 );
226 // Ein bestimmter Call-Type wurde gewuenscht, daher muessen
227 // wir hier den Typ setzen und das Ding anfassen, um den
228 // korrekten Returnwert zu erhalten!
229 if( pElem->IsA( TYPE(SbxMethod) ) )
231 // Soll der Typ konvertiert werden?
232 SbxDataType t2 = pElem->GetType();
233 BOOL bSet = FALSE;
234 if( !( pElem->GetFlags() & SBX_FIXED ) )
236 if( t != SbxVARIANT && t != t2 &&
237 t >= SbxINTEGER && t <= SbxSTRING )
238 pElem->SetType( t ), bSet = TRUE;
240 // pElem auf eine Ref zuweisen, um ggf. eine Temp-Var zu loeschen
241 SbxVariableRef refTemp = pElem;
243 // Moegliche Reste vom letzten Aufruf der SbxMethod beseitigen
244 // Vorher Schreiben freigeben, damit kein Error gesetzt wird.
245 USHORT nSavFlags = pElem->GetFlags();
246 pElem->SetFlag( SBX_READWRITE | SBX_NO_BROADCAST );
247 pElem->SbxValue::Clear();
248 pElem->SetFlags( nSavFlags );
250 // Erst nach dem Setzen anfassen, da z.B. LEFT()
251 // den Unterschied zwischen Left$() und Left() kennen muss
253 // AB 12.8.96: Da in PopVar() die Parameter von Methoden weggehauen
254 // werden, muessen wir hier explizit eine neue SbxMethod anlegen
255 SbxVariable* pNew = new SbxMethod( *((SbxMethod*)pElem) ); // das ist der Call!
256 //ALT: SbxVariable* pNew = new SbxVariable( *pElem ); // das ist der Call!
258 pElem->SetParameters(0); // sonst bleibt Ref auf sich selbst
259 pNew->SetFlag( SBX_READWRITE );
261 // den Datentypen zuruecksetzen?
262 if( bSet )
263 pElem->SetType( t2 );
264 pElem = pNew;
266 // Index-Access bei UnoObjekten beruecksichtigen
267 // definitely we want this for VBA where properties are often
268 // collections ( which need index access ), but lets only do
269 // this if we actually have params following
270 else if( bVBAEnabled && pElem->ISA(SbUnoProperty) && pElem->GetParameters() )
272 // pElem auf eine Ref zuweisen, um ggf. eine Temp-Var zu loeschen
273 SbxVariableRef refTemp = pElem;
275 // Variable kopieren und dabei den Notify aufloesen
276 SbxVariable* pNew = new SbxVariable( *((SbxVariable*)pElem) ); // das ist der Call!
277 pElem->SetParameters( NULL ); // sonst bleibt Ref auf sich selbst
278 pElem = pNew;
281 return CheckArray( pElem );
284 // Find-Funktion ueber Name fuer aktuellen Scope (z.B. Abfrage aus BASIC-IDE)
285 SbxBase* SbiRuntime::FindElementExtern( const String& rName )
287 // Hinweis zu #35281#: Es darf nicht davon ausgegangen werden, dass
288 // pMeth != null, da im RunInit noch keine gesetzt ist.
290 SbxVariable* pElem = NULL;
291 if( !pMod || !rName.Len() )
292 return NULL;
294 // Lokal suchen
295 if( refLocals )
296 pElem = refLocals->Find( rName, SbxCLASS_DONTCARE );
298 // In Statics suchen
299 if ( !pElem && pMeth )
301 // Bei Statics, Name der Methode davor setzen
302 String aMethName = pMeth->GetName();
303 aMethName += ':';
304 aMethName += rName;
305 pElem = pMod->Find(aMethName, SbxCLASS_DONTCARE);
308 // In Parameter-Liste suchen
309 if( !pElem && pMeth )
311 SbxInfo* pInfo = pMeth->GetInfo();
312 if( pInfo && refParams )
314 USHORT nParamCount = refParams->Count();
315 USHORT j = 1;
316 const SbxParamInfo* pParam = pInfo->GetParam( j );
317 while( pParam )
319 if( pParam->aName.EqualsIgnoreCaseAscii( rName ) )
321 if( j >= nParamCount )
323 // Parameter is missing
324 pElem = new SbxVariable( SbxSTRING );
325 pElem->PutString( String( RTL_CONSTASCII_USTRINGPARAM("<missing parameter>" ) ) );
327 else
329 pElem = refParams->Get( j );
331 break;
333 pParam = pInfo->GetParam( ++j );
338 // Im Modul suchen
339 if( !pElem )
341 // RTL nicht durchsuchen!
342 BOOL bSave = rBasic.bNoRtl;
343 rBasic.bNoRtl = TRUE;
344 pElem = pMod->Find( rName, SbxCLASS_DONTCARE );
345 rBasic.bNoRtl = bSave;
347 return pElem;
351 // Argumente eines Elements setzen
352 // Dabei auch die Argumente umsetzen, falls benannte Parameter
353 // verwendet wurden
355 void SbiRuntime::SetupArgs( SbxVariable* p, UINT32 nOp1 )
357 if( nOp1 & 0x8000 )
359 if( !refArgv )
360 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
361 BOOL bHasNamed = FALSE;
362 USHORT i;
363 USHORT nArgCount = refArgv->Count();
364 for( i = 1 ; i < nArgCount ; i++ )
366 if( refArgv->GetAlias( i ).Len() )
368 bHasNamed = TRUE; break;
371 if( bHasNamed )
373 // Wir haben mindestens einen benannten Parameter!
374 // Wir muessen also umsortieren
375 // Gibt es Parameter-Infos?
376 SbxInfo* pInfo = p->GetInfo();
377 if( !pInfo )
379 bool bError_ = true;
381 SbUnoMethod* pUnoMethod = PTR_CAST(SbUnoMethod,p);
382 SbUnoProperty* pUnoProperty = PTR_CAST(SbUnoProperty,p);
383 if( pUnoMethod || pUnoProperty )
385 SbUnoObject* pParentUnoObj = PTR_CAST( SbUnoObject,p->GetParent() );
386 if( pParentUnoObj )
388 Any aUnoAny = pParentUnoObj->getUnoAny();
389 Reference< XInvocation > xInvocation;
390 aUnoAny >>= xInvocation;
391 if( xInvocation.is() ) // TODO: if( xOLEAutomation.is() )
393 bError_ = false;
395 USHORT nCurPar = 1;
396 AutomationNamedArgsSbxArray* pArg =
397 new AutomationNamedArgsSbxArray( nArgCount );
398 ::rtl::OUString* pNames = pArg->getNames().getArray();
399 for( i = 1 ; i < nArgCount ; i++ )
401 SbxVariable* pVar = refArgv->Get( i );
402 const String& rName = refArgv->GetAlias( i );
403 if( rName.Len() )
404 pNames[i] = rName;
405 pArg->Put( pVar, nCurPar++ );
407 refArgv = pArg;
411 if( bError_ )
412 Error( SbERR_NO_NAMED_ARGS );
414 else
416 USHORT nCurPar = 1;
417 SbxArray* pArg = new SbxArray;
418 for( i = 1 ; i < nArgCount ; i++ )
420 SbxVariable* pVar = refArgv->Get( i );
421 const String& rName = refArgv->GetAlias( i );
422 if( rName.Len() )
424 // nCurPar wird auf den gefundenen Parameter gesetzt
425 USHORT j = 1;
426 const SbxParamInfo* pParam = pInfo->GetParam( j );
427 while( pParam )
429 if( pParam->aName.EqualsIgnoreCaseAscii( rName ) )
431 nCurPar = j;
432 break;
434 pParam = pInfo->GetParam( ++j );
436 if( !pParam )
438 Error( SbERR_NAMED_NOT_FOUND ); break;
441 pArg->Put( pVar, nCurPar++ );
443 refArgv = pArg;
446 // Eigene Var als Parameter 0
447 refArgv->Put( p, 0 );
448 p->SetParameters( refArgv );
449 PopArgv();
451 else
452 p->SetParameters( NULL );
455 // Holen eines Array-Elements
457 SbxVariable* SbiRuntime::CheckArray( SbxVariable* pElem )
459 // Falls wir ein Array haben, wollen wir bitte das Array-Element!
460 SbxArray* pPar;
461 if( ( pElem->GetType() & SbxARRAY ) && (SbxVariable*)refRedim != pElem )
463 SbxBase* pElemObj = pElem->GetObject();
464 SbxDimArray* pDimArray = PTR_CAST(SbxDimArray,pElemObj);
465 pPar = pElem->GetParameters();
466 if( pDimArray )
468 // Die Parameter koennen fehlen, wenn ein Array als
469 // Argument uebergeben wird.
470 if( pPar )
471 pElem = pDimArray->Get( pPar );
473 else
475 SbxArray* pArray = PTR_CAST(SbxArray,pElemObj);
476 if( pArray )
478 if( !pPar )
480 Error( SbERR_OUT_OF_RANGE );
481 pElem = new SbxVariable;
483 else
484 pElem = pArray->Get( pPar->Get( 1 )->GetInteger() );
488 // #42940, 0.Parameter zu NULL setzen, damit sich Var nicht selbst haelt
489 if( pPar )
490 pPar->Put( NULL, 0 );
492 // Index-Access bei UnoObjekten beruecksichtigen
493 else if( pElem->GetType() == SbxOBJECT && !pElem->ISA(SbxMethod) )
495 pPar = pElem->GetParameters();
496 if ( pPar )
498 // Ist es ein Uno-Objekt?
499 SbxBaseRef pObj = (SbxBase*)pElem->GetObject();
500 if( pObj )
502 if( pObj->ISA(SbUnoObject) )
504 SbUnoObject* pUnoObj = (SbUnoObject*)(SbxBase*)pObj;
505 Any aAny = pUnoObj->getUnoAny();
507 if( aAny.getValueType().getTypeClass() == TypeClass_INTERFACE )
509 Reference< XInterface > x = *(Reference< XInterface >*)aAny.getValue();
510 Reference< XIndexAccess > xIndexAccess( x, UNO_QUERY );
511 if ( !bVBAEnabled )
513 // Haben wir Index-Access?
514 if( xIndexAccess.is() )
516 UINT32 nParamCount = (UINT32)pPar->Count() - 1;
517 if( nParamCount != 1 )
519 StarBASIC::Error( SbERR_BAD_ARGUMENT );
520 return pElem;
523 // Index holen
524 INT32 nIndex = pPar->Get( 1 )->GetLong();
525 Reference< XInterface > xRet;
528 Any aAny2 = xIndexAccess->getByIndex( nIndex );
529 TypeClass eType = aAny2.getValueType().getTypeClass();
530 if( eType == TypeClass_INTERFACE )
531 xRet = *(Reference< XInterface >*)aAny2.getValue();
533 catch (IndexOutOfBoundsException&)
535 // Bei Exception erstmal immer von Konvertierungs-Problem ausgehen
536 StarBASIC::Error( SbERR_OUT_OF_RANGE );
539 // #57847 Immer neue Variable anlegen, sonst Fehler
540 // durch PutObject(NULL) bei ReadOnly-Properties.
541 pElem = new SbxVariable( SbxVARIANT );
542 if( xRet.is() )
544 aAny <<= xRet;
546 // #67173 Kein Namen angeben, damit echter Klassen-Namen eintragen wird
547 String aName;
548 SbxObjectRef xWrapper = (SbxObject*)new SbUnoObject( aName, aAny );
549 pElem->PutObject( xWrapper );
551 else
553 pElem->PutObject( NULL );
557 else
559 rtl::OUString sDefaultMethod;
561 Reference< XDefaultMethod > xDfltMethod( x, UNO_QUERY );
563 if ( xDfltMethod.is() )
564 sDefaultMethod = xDfltMethod->getDefaultMethodName();
565 else if( xIndexAccess.is() )
566 sDefaultMethod = rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "getByIndex" ) );
568 if ( sDefaultMethod.getLength() )
570 SbxVariable* meth = pUnoObj->Find( sDefaultMethod, SbxCLASS_METHOD );
571 SbxVariableRef refTemp = meth;
572 if ( refTemp )
574 meth->SetParameters( pPar );
575 SbxVariable* pNew = new SbxMethod( *(SbxMethod*)meth );
576 pElem = pNew;
582 // #42940, 0.Parameter zu NULL setzen, damit sich Var nicht selbst haelt
583 pPar->Put( NULL, 0 );
585 else if( pObj->ISA(BasicCollection) )
587 BasicCollection* pCol = (BasicCollection*)(SbxBase*)pObj;
588 pElem = new SbxVariable( SbxVARIANT );
589 pPar->Put( pElem, 0 );
590 pCol->CollItem( pPar );
596 return pElem;
599 // Laden eines Elements aus der Runtime-Library (+StringID+Typ)
601 void SbiRuntime::StepRTL( UINT32 nOp1, UINT32 nOp2 )
603 PushVar( FindElement( rBasic.pRtl, nOp1, nOp2, SbERR_PROC_UNDEFINED, FALSE ) );
606 void
607 SbiRuntime::StepFIND_Impl( SbxObject* pObj, UINT32 nOp1, UINT32 nOp2, SbError nNotFound, BOOL bLocal, BOOL bStatic )
609 if( !refLocals )
610 refLocals = new SbxArray;
611 PushVar( FindElement( pObj, nOp1, nOp2, nNotFound, bLocal, bStatic ) );
613 // Laden einer lokalen/globalen Variablen (+StringID+Typ)
615 void SbiRuntime::StepFIND( UINT32 nOp1, UINT32 nOp2 )
617 StepFIND_Impl( pMod, nOp1, nOp2, SbERR_PROC_UNDEFINED, TRUE );
620 // Search inside a class module (CM) to enable global search in time
621 void SbiRuntime::StepFIND_CM( UINT32 nOp1, UINT32 nOp2 )
624 SbClassModuleObject* pClassModuleObject = PTR_CAST(SbClassModuleObject,pMod);
625 if( pClassModuleObject )
626 pMod->SetFlag( SBX_GBLSEARCH );
628 StepFIND_Impl( pMod, nOp1, nOp2, SbERR_PROC_UNDEFINED, TRUE );
630 if( pClassModuleObject )
631 pMod->ResetFlag( SBX_GBLSEARCH );
634 void SbiRuntime::StepFIND_STATIC( UINT32 nOp1, UINT32 nOp2 )
636 StepFIND_Impl( pMod, nOp1, nOp2, SbERR_PROC_UNDEFINED, TRUE, TRUE );
639 // Laden eines Objekt-Elements (+StringID+Typ)
640 // Das Objekt liegt auf TOS
642 void SbiRuntime::StepELEM( UINT32 nOp1, UINT32 nOp2 )
644 // Liegt auf dem TOS ein Objekt?
645 SbxVariableRef pObjVar = PopVar();
647 SbxObject* pObj = PTR_CAST(SbxObject,(SbxVariable*) pObjVar);
648 if( !pObj )
650 SbxBase* pObjVarObj = pObjVar->GetObject();
651 pObj = PTR_CAST(SbxObject,pObjVarObj);
654 // #56368 Bei StepElem Referenz sichern, sonst koennen Objekte
655 // in Qualifizierungsketten wie ActiveComponent.Selection(0).Text
656 // zu fueh die Referenz verlieren
657 // #74254 Jetzt per Liste
658 if( pObj )
659 SaveRef( (SbxVariable*)pObj );
661 PushVar( FindElement( pObj, nOp1, nOp2, SbERR_NO_METHOD, FALSE ) );
664 // Laden eines Parameters (+Offset+Typ)
665 // Wenn der Datentyp nicht stimmen sollte, eine Kopie anlegen
666 // Der Datentyp SbxEMPTY zeigt an, daa kein Parameter angegeben ist.
667 // Get( 0 ) darf EMPTY sein
669 void SbiRuntime::StepPARAM( UINT32 nOp1, UINT32 nOp2 )
671 USHORT i = static_cast<USHORT>( nOp1 & 0x7FFF );
672 SbxDataType t = (SbxDataType) nOp2;
673 SbxVariable* p;
675 // #57915 Missing sauberer loesen
676 USHORT nParamCount = refParams->Count();
677 if( i >= nParamCount )
679 INT16 iLoop = i;
680 while( iLoop >= nParamCount )
682 p = new SbxVariable();
683 p->PutErr( 448 ); // Wie in VB: Error-Code 448 (SbERR_NAMED_NOT_FOUND)
684 refParams->Put( p, iLoop );
685 iLoop--;
688 p = refParams->Get( i );
690 if( p->GetType() == SbxERROR && ( i ) )
691 //if( p->GetType() == SbxEMPTY && ( i ) )
693 // Wenn ein Parameter fehlt, kann er OPTIONAL sein
694 BOOL bOpt = FALSE;
695 if( pMeth )
697 SbxInfo* pInfo = pMeth->GetInfo();
698 if ( pInfo )
700 const SbxParamInfo* pParam = pInfo->GetParam( i );
701 if( pParam && ( (pParam->nFlags & SBX_OPTIONAL) != 0 ) )
703 // Default value?
704 USHORT nDefaultId = sal::static_int_cast< USHORT >(
705 pParam->nUserData & 0xffff );
706 if( nDefaultId > 0 )
708 String aDefaultStr = pImg->GetString( nDefaultId );
709 p = new SbxVariable();
710 p->PutString( aDefaultStr );
711 refParams->Put( p, i );
713 bOpt = TRUE;
717 if( bOpt == FALSE )
718 Error( SbERR_NOT_OPTIONAL );
720 else if( t != SbxVARIANT && (SbxDataType)(p->GetType() & 0x0FFF ) != t )
722 SbxVariable* q = new SbxVariable( t );
723 SaveRef( q );
724 *q = *p;
725 p = q;
726 if ( i )
727 refParams->Put( p, i );
729 SetupArgs( p, nOp1 );
730 PushVar( CheckArray( p ) );
733 // Case-Test (+True-Target+Test-Opcode)
735 void SbiRuntime::StepCASEIS( UINT32 nOp1, UINT32 nOp2 )
737 if( !refCaseStk || !refCaseStk->Count() )
738 StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
739 else
741 SbxVariableRef xComp = PopVar();
742 SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 );
743 if( xCase->Compare( (SbxOperator) nOp2, *xComp ) )
744 StepJUMP( nOp1 );
748 // Aufruf einer DLL-Prozedur (+StringID+Typ)
749 // Auch hier zeigt das MSB des StringIDs an, dass Argv belegt ist
751 void SbiRuntime::StepCALL( UINT32 nOp1, UINT32 nOp2 )
753 String aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) );
754 SbxArray* pArgs = NULL;
755 if( nOp1 & 0x8000 )
756 pArgs = refArgv;
757 DllCall( aName, aLibName, pArgs, (SbxDataType) nOp2, FALSE );
758 aLibName = String();
759 if( nOp1 & 0x8000 )
760 PopArgv();
763 // Aufruf einer DLL-Prozedur nach CDecl (+StringID+Typ)
764 // Auch hier zeigt das MSB des StringIDs an, dass Argv belegt ist
766 void SbiRuntime::StepCALLC( UINT32 nOp1, UINT32 nOp2 )
768 String aName = pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) );
769 SbxArray* pArgs = NULL;
770 if( nOp1 & 0x8000 )
771 pArgs = refArgv;
772 DllCall( aName, aLibName, pArgs, (SbxDataType) nOp2, TRUE );
773 aLibName = String();
774 if( nOp1 & 0x8000 )
775 PopArgv();
779 // Beginn eines Statements (+Line+Col)
781 void SbiRuntime::StepSTMNT( UINT32 nOp1, UINT32 nOp2 )
783 // Wenn der Expr-Stack am Anfang einen Statements eine Variable enthaelt,
784 // hat ein Trottel X als Funktion aufgerufen, obwohl es eine Variable ist!
785 BOOL bFatalExpr = FALSE;
786 String sUnknownMethodName;
787 if( nExprLvl > 1 )
788 bFatalExpr = TRUE;
789 else if( nExprLvl )
791 SbxVariable* p = refExprStk->Get( 0 );
792 if( p->GetRefCount() > 1
793 && refLocals.Is() && refLocals->Find( p->GetName(), p->GetClass() ) )
795 sUnknownMethodName = p->GetName();
796 bFatalExpr = TRUE;
799 // Der Expr-Stack ist nun nicht mehr notwendig
800 ClearExprStack();
802 // #56368 Kuenstliche Referenz fuer StepElem wieder freigeben,
803 // damit sie nicht ueber ein Statement hinaus erhalten bleibt
804 //refSaveObj = NULL;
805 // #74254 Jetzt per Liste
806 ClearRefs();
808 // Wir muessen hier hart abbrechen, da sonst Zeile und Spalte nicht mehr
809 // stimmen!
810 if( bFatalExpr)
812 StarBASIC::FatalError( SbERR_NO_METHOD, sUnknownMethodName );
813 return;
815 pStmnt = pCode - 9;
816 USHORT nOld = nLine;
817 nLine = static_cast<short>( nOp1 );
819 // #29955 & 0xFF, um for-Schleifen-Ebene wegzufiltern
820 nCol1 = static_cast<short>( nOp2 & 0xFF );
822 // Suchen des naechsten STMNT-Befehls,
823 // um die End-Spalte dieses Statements zu setzen
824 // Searches of the next STMNT instruction,
825 // around the final column of this statement to set
827 nCol2 = 0xffff;
828 USHORT n1, n2;
829 const BYTE* p = pMod->FindNextStmnt( pCode, n1, n2 );
830 if( p )
832 if( n1 == nOp1 )
834 // #29955 & 0xFF, um for-Schleifen-Ebene wegzufiltern
835 nCol2 = (n2 & 0xFF) - 1;
839 // #29955 for-Schleifen-Ebene korrigieren, #67452 NICHT im Error-Handler sonst Chaos
840 if( !bInError )
842 // (Bei Sprüngen aus Schleifen tritt hier eine Differenz auf)
843 USHORT nExspectedForLevel = static_cast<USHORT>( nOp2 / 0x100 );
844 if( pGosubStk )
845 nExspectedForLevel = nExspectedForLevel + pGosubStk->nStartForLvl;
847 // Wenn der tatsaechliche For-Level zu klein ist, wurde aus
848 // einer Schleife heraus gesprungen -> korrigieren
849 while( nForLvl > nExspectedForLevel )
850 PopFor();
853 // 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out
854 // Erklärung siehe bei _ImplGetBreakCallLevel.
855 if( pInst->nCallLvl <= pInst->nBreakCallLvl )
856 //if( nFlags & SbDEBUG_STEPINTO )
858 StarBASIC* pStepBasic = GetCurrentBasic( &rBasic );
859 USHORT nNewFlags = pStepBasic->StepPoint( nLine, nCol1, nCol2 );
861 // Neuen BreakCallLevel ermitteln
862 pInst->CalcBreakCallLevel( nNewFlags );
865 // Breakpoints nur bei STMNT-Befehlen in neuer Zeile!
866 else if( ( nOp1 != nOld )
867 && ( nFlags & SbDEBUG_BREAK )
868 && pMod->IsBP( static_cast<USHORT>( nOp1 ) ) )
870 StarBASIC* pBreakBasic = GetCurrentBasic( &rBasic );
871 USHORT nNewFlags = pBreakBasic->BreakPoint( nLine, nCol1, nCol2 );
873 // Neuen BreakCallLevel ermitteln
874 pInst->CalcBreakCallLevel( nNewFlags );
875 //16.10.96, ALT:
876 //if( nNewFlags != SbDEBUG_CONTINUE )
877 // nFlags = nNewFlags;
881 // (+SvStreamFlags+Flags)
882 // Stack: Blocklaenge
883 // Kanalnummer
884 // Dateiname
886 void SbiRuntime::StepOPEN( UINT32 nOp1, UINT32 nOp2 )
888 SbxVariableRef pName = PopVar();
889 SbxVariableRef pChan = PopVar();
890 SbxVariableRef pLen = PopVar();
891 short nBlkLen = pLen->GetInteger();
892 short nChan = pChan->GetInteger();
893 ByteString aName( pName->GetString(), gsl_getSystemTextEncoding() );
894 pIosys->Open( nChan, aName, static_cast<short>( nOp1 ),
895 static_cast<short>( nOp2 ), nBlkLen );
896 Error( pIosys->GetError() );
899 // Objekt kreieren (+StringID+StringID)
901 void SbiRuntime::StepCREATE( UINT32 nOp1, UINT32 nOp2 )
903 String aClass( pImg->GetString( static_cast<short>( nOp2 ) ) );
904 SbxObject *pObj = SbxBase::CreateObject( aClass );
905 if( !pObj )
906 Error( SbERR_INVALID_OBJECT );
907 else
909 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
910 pObj->SetName( aName );
911 // Das Objekt muss BASIC rufen koennen
912 pObj->SetParent( &rBasic );
913 SbxVariable* pNew = new SbxVariable;
914 pNew->PutObject( pObj );
915 PushVar( pNew );
919 void SbiRuntime::StepDCREATE( UINT32 nOp1, UINT32 nOp2 )
921 StepDCREATE_IMPL( nOp1, nOp2 );
924 void SbiRuntime::StepDCREATE_REDIMP( UINT32 nOp1, UINT32 nOp2 )
926 StepDCREATE_IMPL( nOp1, nOp2 );
930 // Helper function for StepDCREATE_IMPL / bRedimp = true
931 void implCopyDimArray_DCREATE( SbxDimArray* pNewArray, SbxDimArray* pOldArray, short nMaxDimIndex,
932 short nActualDim, sal_Int32* pActualIndices, sal_Int32* pLowerBounds, sal_Int32* pUpperBounds )
934 sal_Int32& ri = pActualIndices[nActualDim];
935 for( ri = pLowerBounds[nActualDim] ; ri <= pUpperBounds[nActualDim] ; ri++ )
937 if( nActualDim < nMaxDimIndex )
939 implCopyDimArray_DCREATE( pNewArray, pOldArray, nMaxDimIndex, nActualDim + 1,
940 pActualIndices, pLowerBounds, pUpperBounds );
942 else
944 SbxVariable* pSource = pOldArray->Get32( pActualIndices );
945 pNewArray->Put32( pSource, pActualIndices );
950 // #56204 Objekt-Array kreieren (+StringID+StringID), DCREATE == Dim-Create
951 void SbiRuntime::StepDCREATE_IMPL( UINT32 nOp1, UINT32 nOp2 )
953 SbxVariableRef refVar = PopVar();
955 DimImpl( refVar );
957 // Das Array mit Instanzen der geforderten Klasse fuellen
958 SbxBaseRef xObj = (SbxBase*)refVar->GetObject();
959 if( !xObj )
961 StarBASIC::Error( SbERR_INVALID_OBJECT );
962 return;
965 SbxDimArray* pArray = 0;
966 if( xObj->ISA(SbxDimArray) )
968 SbxBase* pObj = (SbxBase*)xObj;
969 pArray = (SbxDimArray*)pObj;
971 // Dimensionen auswerten
972 short nDims = pArray->GetDims();
973 INT32 nTotalSize = 0;
975 // es muss ein eindimensionales Array sein
976 INT32 nLower, nUpper, nSize;
977 INT32 i;
978 for( i = 0 ; i < nDims ; i++ )
980 pArray->GetDim32( i+1, nLower, nUpper );
981 nSize = nUpper - nLower + 1;
982 if( i == 0 )
983 nTotalSize = nSize;
984 else
985 nTotalSize *= nSize;
988 // Objekte anlegen und ins Array eintragen
989 String aClass( pImg->GetString( static_cast<short>( nOp2 ) ) );
990 for( i = 0 ; i < nTotalSize ; i++ )
992 SbxObject *pClassObj = SbxBase::CreateObject( aClass );
993 if( !pClassObj )
995 Error( SbERR_INVALID_OBJECT );
996 break;
998 else
1000 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
1001 pClassObj->SetName( aName );
1002 // Das Objekt muss BASIC rufen koennen
1003 pClassObj->SetParent( &rBasic );
1004 pArray->SbxArray::Put32( pClassObj, i );
1009 SbxDimArray* pOldArray = (SbxDimArray*)(SbxArray*)refRedimpArray;
1010 if( pArray && pOldArray )
1012 short nDimsNew = pArray->GetDims();
1013 short nDimsOld = pOldArray->GetDims();
1014 short nDims = nDimsNew;
1015 BOOL bRangeError = FALSE;
1017 // Store dims to use them for copying later
1018 sal_Int32* pLowerBounds = new sal_Int32[nDims];
1019 sal_Int32* pUpperBounds = new sal_Int32[nDims];
1020 sal_Int32* pActualIndices = new sal_Int32[nDims];
1021 if( nDimsOld != nDimsNew )
1023 bRangeError = TRUE;
1025 else
1027 // Compare bounds
1028 for( short i = 1 ; i <= nDims ; i++ )
1030 sal_Int32 lBoundNew, uBoundNew;
1031 sal_Int32 lBoundOld, uBoundOld;
1032 pArray->GetDim32( i, lBoundNew, uBoundNew );
1033 pOldArray->GetDim32( i, lBoundOld, uBoundOld );
1035 lBoundNew = std::max( lBoundNew, lBoundOld );
1036 uBoundNew = std::min( uBoundNew, uBoundOld );
1037 short j = i - 1;
1038 pActualIndices[j] = pLowerBounds[j] = lBoundNew;
1039 pUpperBounds[j] = uBoundNew;
1043 if( bRangeError )
1045 StarBASIC::Error( SbERR_OUT_OF_RANGE );
1047 else
1049 // Copy data from old array by going recursively through all dimensions
1050 // (It would be faster to work on the flat internal data array of an
1051 // SbyArray but this solution is clearer and easier)
1052 implCopyDimArray_DCREATE( pArray, pOldArray, nDims - 1,
1053 0, pActualIndices, pLowerBounds, pUpperBounds );
1055 delete [] pUpperBounds;
1056 delete [] pLowerBounds;
1057 delete [] pActualIndices;
1058 refRedimpArray = NULL;
1062 // Objekt aus User-Type kreieren (+StringID+StringID)
1064 SbxObject* createUserTypeImpl( const String& rClassName ); // sb.cxx
1066 void SbiRuntime::StepTCREATE( UINT32 nOp1, UINT32 nOp2 )
1068 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
1069 String aClass( pImg->GetString( static_cast<short>( nOp2 ) ) );
1071 SbxObject* pCopyObj = createUserTypeImpl( aClass );
1072 if( pCopyObj )
1073 pCopyObj->SetName( aName );
1074 SbxVariable* pNew = new SbxVariable;
1075 pNew->PutObject( pCopyObj );
1076 PushVar( pNew );
1080 // Einrichten einer lokalen Variablen (+StringID+Typ)
1082 void SbiRuntime::StepLOCAL( UINT32 nOp1, UINT32 nOp2 )
1084 if( !refLocals.Is() )
1085 refLocals = new SbxArray;
1086 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
1087 if( refLocals->Find( aName, SbxCLASS_DONTCARE ) == NULL )
1089 SbxDataType t = (SbxDataType) nOp2;
1090 SbxVariable* p = new SbxVariable( t );
1091 p->SetName( aName );
1092 refLocals->Put( p, refLocals->Count() );
1096 // Einrichten einer modulglobalen Variablen (+StringID+Typ)
1098 void SbiRuntime::StepPUBLIC_Impl( UINT32 nOp1, UINT32 nOp2, bool bUsedForClassModule )
1100 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
1101 SbxDataType t = (SbxDataType) nOp2;
1102 BOOL bFlag = pMod->IsSet( SBX_NO_MODIFY );
1103 pMod->SetFlag( SBX_NO_MODIFY );
1104 SbxVariableRef p = pMod->Find( aName, SbxCLASS_PROPERTY );
1105 if( p.Is() )
1106 pMod->Remove (p);
1107 SbProperty* pProp = pMod->GetProperty( aName, t );
1108 if( !bUsedForClassModule )
1109 pProp->SetFlag( SBX_PRIVATE );
1110 if( !bFlag )
1111 pMod->ResetFlag( SBX_NO_MODIFY );
1112 if( pProp )
1114 pProp->SetFlag( SBX_DONTSTORE );
1115 // AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden'
1116 pProp->SetFlag( SBX_NO_MODIFY);
1120 void SbiRuntime::StepPUBLIC( UINT32 nOp1, UINT32 nOp2 )
1122 StepPUBLIC_Impl( nOp1, nOp2, false );
1125 void SbiRuntime::StepPUBLIC_P( UINT32 nOp1, UINT32 nOp2 )
1127 // Creates module variable that isn't reinitialised when
1128 // between invocations ( for VBASupport & document basic only )
1129 if( pMod->pImage->bFirstInit )
1130 StepPUBLIC( nOp1, nOp2 );
1133 // Einrichten einer globalen Variablen (+StringID+Typ)
1135 void SbiRuntime::StepGLOBAL( UINT32 nOp1, UINT32 nOp2 )
1137 if( pImg->GetFlag( SBIMG_CLASSMODULE ) )
1138 StepPUBLIC_Impl( nOp1, nOp2, true );
1140 SbxObject* pStorage = &rBasic;
1141 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
1142 // Store module scope variables at module scope
1143 // in non vba mode these are stored at the library level :/
1144 // not sure if this really should not be enabled for ALL basic
1145 if ( SbiRuntime::isVBAEnabled() )
1147 pStorage = pMod;
1148 pMod->AddVarName( aName );
1151 SbxDataType t = (SbxDataType) nOp2;
1152 BOOL bFlag = pStorage->IsSet( SBX_NO_MODIFY );
1153 rBasic.SetFlag( SBX_NO_MODIFY );
1154 SbxVariableRef p = pStorage->Find( aName, SbxCLASS_PROPERTY );
1155 if( p.Is() )
1156 pStorage->Remove (p);
1157 p = pStorage->Make( aName, SbxCLASS_PROPERTY, t );
1158 if( !bFlag )
1159 pStorage->ResetFlag( SBX_NO_MODIFY );
1160 if( p )
1162 p->SetFlag( SBX_DONTSTORE );
1163 // AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden'
1164 p->SetFlag( SBX_NO_MODIFY);
1169 // Creates global variable that isn't reinitialised when
1170 // basic is restarted, P=PERSIST (+StringID+Typ)
1172 void SbiRuntime::StepGLOBAL_P( UINT32 nOp1, UINT32 nOp2 )
1174 if( pMod->pImage->bFirstInit )
1176 StepGLOBAL( nOp1, nOp2 );
1181 // Searches for global variable, behavior depends on the fact
1182 // if the variable is initialised for the first time
1184 void SbiRuntime::StepFIND_G( UINT32 nOp1, UINT32 nOp2 )
1186 if( pMod->pImage->bFirstInit )
1188 // Behave like always during first init
1189 StepFIND( nOp1, nOp2 );
1191 else
1193 // Return dummy variable
1194 SbxDataType t = (SbxDataType) nOp2;
1195 String aName( pImg->GetString( static_cast<short>( nOp1 & 0x7FFF ) ) );
1197 SbxVariable* pDummyVar = new SbxVariable( t );
1198 pDummyVar->SetName( aName );
1199 PushVar( pDummyVar );
1204 SbxVariable* SbiRuntime::StepSTATIC_Impl( String& aName, SbxDataType& t )
1206 SbxVariable* p = NULL;
1207 if ( pMeth )
1209 SbxArray* pStatics = pMeth->GetStatics();
1210 if( pStatics && ( pStatics->Find( aName, SbxCLASS_DONTCARE ) == NULL ) )
1212 p = new SbxVariable( t );
1213 if( t != SbxVARIANT )
1214 p->SetFlag( SBX_FIXED );
1215 p->SetName( aName );
1216 pStatics->Put( p, pStatics->Count() );
1219 return p;
1221 // Einrichten einer statischen Variablen (+StringID+Typ)
1222 void SbiRuntime::StepSTATIC( UINT32 nOp1, UINT32 nOp2 )
1224 String aName( pImg->GetString( static_cast<short>( nOp1 ) ) );
1225 SbxDataType t = (SbxDataType) nOp2;
1226 StepSTATIC_Impl( aName, t );