xref: /trunk/main/basic/source/classes/sb.cxx (revision b6be11d1285f1f5c601f8ae41773110c184dd1fb)
1 /**************************************************************
2  *
3  * Licensed to the Apache Software Foundation (ASF) under one
4  * or more contributor license agreements.  See the NOTICE file
5  * distributed with this work for additional information
6  * regarding copyright ownership.  The ASF licenses this file
7  * to you under the Apache License, Version 2.0 (the
8  * "License"); you may not use this file except in compliance
9  * with the License.  You may obtain a copy of the License at
10  *
11  *   http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing,
14  * software distributed under the License is distributed on an
15  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16  * KIND, either express or implied.  See the License for the
17  * specific language governing permissions and limitations
18  * under the License.
19  *
20  *************************************************************/
21 
22 
23 
24 // MARKER(update_precomp.py): autogen include statement, do not remove
25 #include "precompiled_basic.hxx"
26 
27 #include <stdio.h>
28 
29 #include "sb.hxx"
30 #include <tools/rcid.h>
31 #include <tools/config.hxx>
32 #include <tools/stream.hxx>
33 #ifndef __RSC //autogen
34 #include <tools/errinf.hxx>
35 #endif
36 #include <basic/sbx.hxx>
37 #include <tools/list.hxx>
38 #include <tools/shl.hxx>
39 #include <tools/rc.hxx>
40 #include <vcl/svapp.hxx>
41 #include <comphelper/processfactory.hxx>
42 #include "sbunoobj.hxx"
43 #include "sbjsmeth.hxx"
44 #include "sbjsmod.hxx"
45 #include "sbintern.hxx"
46 #include "disas.hxx"
47 #include "runtime.hxx"
48 #include <basic/sbuno.hxx>
49 #include <basic/sbobjmod.hxx>
50 #include "stdobj.hxx"
51 #include "filefmt.hxx"
52 #include "sb.hrc"
53 #include <basrid.hxx>
54 #include <vos/mutex.hxx>
55 #include <cppuhelper/implbase1.hxx>
56 #include <com/sun/star/lang/XMultiServiceFactory.hpp>
57 #include <com/sun/star/util/XCloseBroadcaster.hpp>
58 #include <com/sun/star/util/XCloseListener.hpp>
59 #include "errobject.hxx"
60 #include <map>
61 #include <hash_map>
62 #include <vector>
63 #include <algorithm>
64 
65 #include <com/sun/star/script/ModuleType.hpp>
66 #include <com/sun/star/script/ModuleInfo.hpp>
67 using namespace ::com::sun::star::script;
68 
69 // #pragma SW_SEGMENT_CLASS( SBASIC, SBASIC_CODE )
70 
71 SV_IMPL_VARARR(SbTextPortions,SbTextPortion)
72 
73 TYPEINIT1(StarBASIC,SbxObject)
74 
75 #define RTLNAME "@SBRTL"
76 //  i#i68894#
77 using namespace ::com::sun::star;
78 using com::sun::star::uno::Reference;
79 using com::sun::star::uno::Any;
80 using com::sun::star::uno::UNO_QUERY;
81 using com::sun::star::lang::XMultiServiceFactory;
82 
83 const static String aThisComponent( RTL_CONSTASCII_USTRINGPARAM("ThisComponent") );
84 const static String aVBAHook( RTL_CONSTASCII_USTRINGPARAM( "VBAGlobals" ) );
85 
86 // ============================================================================
87 
88 class DocBasicItem : public ::cppu::WeakImplHelper1< util::XCloseListener >
89 {
90 public:
91     explicit DocBasicItem( StarBASIC& rDocBasic );
92     virtual ~DocBasicItem();
93 
getClassModules() const94     inline const SbxObjectRef& getClassModules() const { return mxClassModules; }
isDocClosed() const95     inline bool isDocClosed() const { return mbDocClosed; }
96 
97     void clearDependingVarsOnDelete( StarBASIC& rDeletedBasic );
98 
99     void startListening();
100     void stopListening();
101 
102     virtual void SAL_CALL queryClosing( const lang::EventObject& rSource, sal_Bool bGetsOwnership );
103     virtual void SAL_CALL notifyClosing( const lang::EventObject& rSource );
104     virtual void SAL_CALL disposing( const lang::EventObject& rSource );
105 
106 private:
107     StarBASIC&      mrDocBasic;
108     SbxObjectRef    mxClassModules;
109     bool            mbDocClosed;
110     bool            mbDisposed;
111 };
112 
113 // ----------------------------------------------------------------------------
114 
DocBasicItem(StarBASIC & rDocBasic)115 DocBasicItem::DocBasicItem( StarBASIC& rDocBasic ) :
116     mrDocBasic( rDocBasic ),
117     mxClassModules( new SbxObject( String() ) ),
118     mbDocClosed( false ),
119     mbDisposed( false )
120 {
121 }
122 
~DocBasicItem()123 DocBasicItem::~DocBasicItem()
124 {
125     stopListening();
126 }
127 
clearDependingVarsOnDelete(StarBASIC & rDeletedBasic)128 void DocBasicItem::clearDependingVarsOnDelete( StarBASIC& rDeletedBasic )
129 {
130     mrDocBasic.implClearDependingVarsOnDelete( &rDeletedBasic );
131 }
132 
startListening()133 void DocBasicItem::startListening()
134 {
135     Any aThisComp;
136     mrDocBasic.GetUNOConstant( "ThisComponent", aThisComp );
137     Reference< util::XCloseBroadcaster > xCloseBC( aThisComp, UNO_QUERY );
138     mbDisposed = !xCloseBC.is();
139     if( xCloseBC.is() )
140         try { xCloseBC->addCloseListener( this ); } catch( uno::Exception& ) {}
141 }
142 
stopListening()143 void DocBasicItem::stopListening()
144 {
145     if( mbDisposed ) return;
146     mbDisposed = true;
147     Any aThisComp;
148     mrDocBasic.GetUNOConstant( "ThisComponent", aThisComp );
149     Reference< util::XCloseBroadcaster > xCloseBC( aThisComp, UNO_QUERY );
150     if( xCloseBC.is() )
151         try { xCloseBC->removeCloseListener( this ); } catch( uno::Exception& ) {}
152 }
153 
queryClosing(const lang::EventObject &,sal_Bool)154 void SAL_CALL DocBasicItem::queryClosing( const lang::EventObject& /*rSource*/, sal_Bool /*bGetsOwnership*/ )
155 {
156 }
157 
notifyClosing(const lang::EventObject &)158 void SAL_CALL DocBasicItem::notifyClosing( const lang::EventObject& /*rEvent*/ )
159 {
160     stopListening();
161     mbDocClosed = true;
162 }
163 
disposing(const lang::EventObject &)164 void SAL_CALL DocBasicItem::disposing( const lang::EventObject& /*rEvent*/ )
165 {
166     stopListening();
167 }
168 
169 // ----------------------------------------------------------------------------
170 
171 namespace {
172 
173 typedef ::rtl::Reference< DocBasicItem > DocBasicItemRef;
174 typedef std::map< const StarBASIC*, DocBasicItemRef > DocBasicItemMap;
175 static DocBasicItemMap GaDocBasicItems;
176 
lclFindDocBasicItem(const StarBASIC * pDocBasic)177 const DocBasicItem* lclFindDocBasicItem( const StarBASIC* pDocBasic )
178 {
179     DocBasicItemMap::iterator it = GaDocBasicItems.find( pDocBasic );
180     return (it != GaDocBasicItems.end()) ? it->second.get() : 0;
181 }
182 
lclInsertDocBasicItem(StarBASIC & rDocBasic)183 void lclInsertDocBasicItem( StarBASIC& rDocBasic )
184 {
185     DocBasicItemRef& rxDocBasicItem = GaDocBasicItems[ &rDocBasic ];
186     rxDocBasicItem.set( new DocBasicItem( rDocBasic ) );
187     rxDocBasicItem->startListening();
188 }
189 
lclRemoveDocBasicItem(StarBASIC & rDocBasic)190 void lclRemoveDocBasicItem( StarBASIC& rDocBasic )
191 {
192     DocBasicItemMap::iterator it = GaDocBasicItems.find( &rDocBasic );
193     if( it != GaDocBasicItems.end() )
194     {
195         it->second->stopListening();
196         GaDocBasicItems.erase( it );
197     }
198     DocBasicItemMap::iterator it_end = GaDocBasicItems.end();
199     for( it = GaDocBasicItems.begin(); it != it_end; ++it )
200         it->second->clearDependingVarsOnDelete( rDocBasic );
201 }
202 
lclGetDocBasicForModule(SbModule * pModule)203 StarBASIC* lclGetDocBasicForModule( SbModule* pModule )
204 {
205     StarBASIC* pRetBasic = NULL;
206     SbxObject* pCurParent = pModule;
207     while( pCurParent->GetParent() != NULL )
208     {
209         pCurParent = pCurParent->GetParent();
210         StarBASIC* pDocBasic = PTR_CAST( StarBASIC, pCurParent );
211         if( pDocBasic != NULL && pDocBasic->IsDocBasic() )
212         {
213             pRetBasic = pDocBasic;
214             break;
215         }
216     }
217     return pRetBasic;
218 }
219 
220 } // namespace
221 
222 // ============================================================================
223 
getVBAGlobals()224 SbxObject* StarBASIC::getVBAGlobals( )
225 {
226     if ( !pVBAGlobals )
227     {
228         Any aThisDoc;
229         if ( GetUNOConstant("ThisComponent", aThisDoc) )
230         {
231             Reference< XMultiServiceFactory > xDocFac( aThisDoc, UNO_QUERY );
232                         if ( xDocFac.is() )
233             {
234                 try
235                 {
236                     xDocFac->createInstance( rtl::OUString( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.VBAGlobals" ) ) );
237                 }
238                 catch( Exception& )
239                 {
240                     // Ignore
241                 }
242             }
243         }
244         pVBAGlobals = (SbUnoObject*)Find( aVBAHook , SbxCLASS_DONTCARE );
245     }
246     return pVBAGlobals;
247 }
248 
249 //  i#i68894#
VBAFind(const String & rName,SbxClassType t)250 SbxVariable* StarBASIC::VBAFind( const String& rName, SbxClassType t )
251 {
252     if( rName == aThisComponent )
253         return NULL;
254     // rename to init globals
255     if ( getVBAGlobals( ) )
256         return pVBAGlobals->Find( rName, t );
257     return NULL;
258 
259 }
260 // Create array for conversion SFX <-> VB error code
261 struct SFX_VB_ErrorItem
262 {
263     sal_uInt16  nErrorVB;
264     SbError nErrorSFX;
265 };
266 
267 const SFX_VB_ErrorItem __FAR_DATA SFX_VB_ErrorTab[] =
268 {
269     { 1, SbERR_BASIC_EXCEPTION },  // #87844 Map exception to error code 1
270     { 2, SbERR_SYNTAX },
271     { 3, SbERR_NO_GOSUB },
272     { 4, SbERR_REDO_FROM_START },
273     { 5, SbERR_BAD_ARGUMENT },
274     { 6, SbERR_MATH_OVERFLOW },
275     { 7, SbERR_NO_MEMORY },
276     { 8, SbERR_ALREADY_DIM },
277     { 9, SbERR_OUT_OF_RANGE },
278     { 10, SbERR_DUPLICATE_DEF },
279     { 11, SbERR_ZERODIV },
280     { 12, SbERR_VAR_UNDEFINED },
281     { 13, SbERR_CONVERSION },
282     { 14, SbERR_BAD_PARAMETER },
283     { 18, SbERR_USER_ABORT },
284     { 20, SbERR_BAD_RESUME },
285     { 28, SbERR_STACK_OVERFLOW },
286     { 35, SbERR_PROC_UNDEFINED },
287     { 48, SbERR_BAD_DLL_LOAD },
288     { 49, SbERR_BAD_DLL_CALL },
289     { 51, SbERR_INTERNAL_ERROR },
290     { 52, SbERR_BAD_CHANNEL },
291     { 53, SbERR_FILE_NOT_FOUND },
292     { 54, SbERR_BAD_FILE_MODE },
293     { 55, SbERR_FILE_ALREADY_OPEN },
294     { 57, SbERR_IO_ERROR },
295     { 58, SbERR_FILE_EXISTS },
296     { 59, SbERR_BAD_RECORD_LENGTH },
297     { 61, SbERR_DISK_FULL },
298     { 62, SbERR_READ_PAST_EOF },
299     { 63, SbERR_BAD_RECORD_NUMBER },
300     { 67, SbERR_TOO_MANY_FILES },
301     { 68, SbERR_NO_DEVICE },
302     { 70, SbERR_ACCESS_DENIED },
303     { 71, SbERR_NOT_READY },
304     { 73, SbERR_NOT_IMPLEMENTED },
305     { 74, SbERR_DIFFERENT_DRIVE },
306     { 75, SbERR_ACCESS_ERROR },
307     { 76, SbERR_PATH_NOT_FOUND },
308     { 91, SbERR_NO_OBJECT },
309     { 93, SbERR_BAD_PATTERN },
310     { 94, SBERR_IS_NULL },
311     { 250, SbERR_DDE_ERROR },
312     { 280, SbERR_DDE_WAITINGACK },
313     { 281, SbERR_DDE_OUTOFCHANNELS },
314     { 282, SbERR_DDE_NO_RESPONSE },
315     { 283, SbERR_DDE_MULT_RESPONSES },
316     { 284, SbERR_DDE_CHANNEL_LOCKED },
317     { 285, SbERR_DDE_NOTPROCESSED },
318     { 286, SbERR_DDE_TIMEOUT },
319     { 287, SbERR_DDE_USER_INTERRUPT },
320     { 288, SbERR_DDE_BUSY },
321     { 289, SbERR_DDE_NO_DATA },
322     { 290, SbERR_DDE_WRONG_DATA_FORMAT },
323     { 291, SbERR_DDE_PARTNER_QUIT },
324     { 292, SbERR_DDE_CONV_CLOSED },
325     { 293, SbERR_DDE_NO_CHANNEL },
326     { 294, SbERR_DDE_INVALID_LINK },
327     { 295, SbERR_DDE_QUEUE_OVERFLOW },
328     { 296, SbERR_DDE_LINK_ALREADY_EST },
329     { 297, SbERR_DDE_LINK_INV_TOPIC },
330     { 298, SbERR_DDE_DLL_NOT_FOUND },
331     { 323, SbERR_CANNOT_LOAD },
332     { 341, SbERR_BAD_INDEX },
333     { 366, SbERR_NO_ACTIVE_OBJECT },
334     { 380, SbERR_BAD_PROP_VALUE },
335     { 382, SbERR_PROP_READONLY },
336     { 394, SbERR_PROP_WRITEONLY },
337     { 420, SbERR_INVALID_OBJECT },
338     { 423, SbERR_NO_METHOD },
339     { 424, SbERR_NEEDS_OBJECT },
340     { 425, SbERR_INVALID_USAGE_OBJECT },
341     { 430, SbERR_NO_OLE },
342     { 438, SbERR_BAD_METHOD },
343     { 440, SbERR_OLE_ERROR },
344     { 445, SbERR_BAD_ACTION },
345     { 446, SbERR_NO_NAMED_ARGS },
346     { 447, SbERR_BAD_LOCALE },
347     { 448, SbERR_NAMED_NOT_FOUND },
348     { 449, SbERR_NOT_OPTIONAL },
349     { 450, SbERR_WRONG_ARGS },
350     { 451, SbERR_NOT_A_COLL },
351     { 452, SbERR_BAD_ORDINAL },
352     { 453, SbERR_DLLPROC_NOT_FOUND },
353     { 460, SbERR_BAD_CLIPBD_FORMAT },
354     { 951, SbERR_UNEXPECTED },
355     { 952, SbERR_EXPECTED },
356     { 953, SbERR_SYMBOL_EXPECTED },
357     { 954, SbERR_VAR_EXPECTED },
358     { 955, SbERR_LABEL_EXPECTED },
359     { 956, SbERR_LVALUE_EXPECTED },
360     { 957, SbERR_VAR_DEFINED },
361     { 958, SbERR_PROC_DEFINED },
362     { 959, SbERR_LABEL_DEFINED },
363     { 960, SbERR_UNDEF_VAR },
364     { 961, SbERR_UNDEF_ARRAY },
365     { 962, SbERR_UNDEF_PROC },
366     { 963, SbERR_UNDEF_LABEL },
367     { 964, SbERR_UNDEF_TYPE },
368     { 965, SbERR_BAD_EXIT },
369     { 966, SbERR_BAD_BLOCK },
370     { 967, SbERR_BAD_BRACKETS },
371     { 968, SbERR_BAD_DECLARATION },
372     { 969, SbERR_BAD_PARAMETERS },
373     { 970, SbERR_BAD_CHAR_IN_NUMBER },
374     { 971, SbERR_MUST_HAVE_DIMS },
375     { 972, SbERR_NO_IF },
376     { 973, SbERR_NOT_IN_SUBR },
377     { 974, SbERR_NOT_IN_MAIN },
378     { 975, SbERR_WRONG_DIMS },
379     { 976, SbERR_BAD_OPTION },
380     { 977, SbERR_CONSTANT_REDECLARED },
381     { 978, SbERR_PROG_TOO_LARGE },
382     { 979, SbERR_NO_STRINGS_ARRAYS },
383     { 1000, SbERR_PROPERTY_NOT_FOUND },
384     { 1001, SbERR_METHOD_NOT_FOUND },
385     { 1002, SbERR_ARG_MISSING },
386     { 1003, SbERR_BAD_NUMBER_OF_ARGS },
387     { 1004, SbERR_METHOD_FAILED },
388     { 1005, SbERR_SETPROP_FAILED },
389     { 1006, SbERR_GETPROP_FAILED },
390     { 1007, SbERR_BASIC_COMPAT },
391     { 0xFFFF, 0xFFFFFFFFL }     // End mark
392 };
393 
394 // The StarBASIC factory is a hack. When a SbModule is created, its pointer
395 // is saved and given to the following SbProperties/SbMethods. This restores
396 // the Modul-relationshop. But it works only when a modul is loaded.
397 // Can cause troubles with separately loaded properties!
398 
Create(sal_uInt16 nSbxId,sal_uInt32 nCreator)399 SbxBase* SbiFactory::Create( sal_uInt16 nSbxId, sal_uInt32 nCreator )
400 {
401     if( nCreator ==  SBXCR_SBX )
402     {
403         String aEmpty;
404         switch( nSbxId )
405         {
406             case SBXID_BASIC:
407                 return new StarBASIC( NULL );
408             case SBXID_BASICMOD:
409                 return new SbModule( aEmpty );
410             case SBXID_BASICPROP:
411                 return new SbProperty( aEmpty, SbxVARIANT, NULL );
412             case SBXID_BASICMETHOD:
413                 return new SbMethod( aEmpty, SbxVARIANT, NULL );
414             case SBXID_JSCRIPTMOD:
415                 return new SbJScriptModule( aEmpty );
416             case SBXID_JSCRIPTMETH:
417                 return new SbJScriptMethod( aEmpty, SbxVARIANT, NULL );
418         }
419     }
420     return NULL;
421 }
422 
CreateObject(const String & rClass)423 SbxObject* SbiFactory::CreateObject( const String& rClass )
424 {
425     if( rClass.EqualsIgnoreCaseAscii( "StarBASIC" ) )
426         return new StarBASIC( NULL );
427     else
428     if( rClass.EqualsIgnoreCaseAscii( "StarBASICModule" ) )
429     {
430         String aEmpty;
431         return new SbModule( aEmpty );
432     }
433     else
434     if( rClass.EqualsIgnoreCaseAscii( "Collection" ) )
435     {
436         String aCollectionName( RTL_CONSTASCII_USTRINGPARAM("Collection") );
437         return new BasicCollection( aCollectionName );
438     }
439     else
440     if( rClass.EqualsIgnoreCaseAscii( "FileSystemObject" ) )
441     {
442         try
443         {
444             Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory(), UNO_SET_THROW );
445             ::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.FileSystemObject" ) );
446             Reference< XInterface > xInterface( xFactory->createInstance( aServiceName ), UNO_SET_THROW );
447             return new SbUnoObject( aServiceName, uno::makeAny( xInterface ) );
448         }
449         catch( Exception& )
450         {}
451     }
452 
453     return NULL;
454 }
455 
456 
457 // Factory class to create OLE objects
458 class SbOLEFactory : public SbxFactory
459 {
460 public:
461     virtual SbxBase* Create( sal_uInt16 nSbxId, sal_uInt32 = SBXCR_SBX );
462     virtual SbxObject* CreateObject( const String& );
463 };
464 
Create(sal_uInt16,sal_uInt32)465 SbxBase* SbOLEFactory::Create( sal_uInt16, sal_uInt32 )
466 {
467     // Not supported
468     return NULL;
469 }
470 
471 SbUnoObject* createOLEObject_Impl( const String& aType );   // sbunoobj.cxx
472 
CreateObject(const String & rClassName)473 SbxObject* SbOLEFactory::CreateObject( const String& rClassName )
474 {
475     SbxObject* pRet = createOLEObject_Impl( rClassName );
476     return pRet;
477 }
478 
479 
480 //========================================================================
481 // SbFormFactory, show user forms by: dim as new <user form name>
482 
483 class SbFormFactory : public SbxFactory
484 {
485 public:
486     virtual SbxBase* Create( sal_uInt16 nSbxId, sal_uInt32 = SBXCR_SBX );
487     virtual SbxObject* CreateObject( const String& );
488 };
489 
Create(sal_uInt16,sal_uInt32)490 SbxBase* SbFormFactory::Create( sal_uInt16, sal_uInt32 )
491 {
492     // Not supported
493     return NULL;
494 }
495 
CreateObject(const String & rClassName)496 SbxObject* SbFormFactory::CreateObject( const String& rClassName )
497 {
498     if( SbModule* pMod = pMOD )
499     {
500         if( SbxVariable* pVar = pMod->Find( rClassName, SbxCLASS_OBJECT ) )
501         {
502             if( SbUserFormModule* pFormModule = PTR_CAST( SbUserFormModule, pVar->GetObject() ) )
503             {
504                 bool bInitState = pFormModule->getInitState();
505                 if( bInitState )
506                 {
507                     // Not the first instantiate, reset
508                     bool bTriggerTerminateEvent = false;
509                     pFormModule->ResetApiObj( bTriggerTerminateEvent );
510                     pFormModule->setInitState( false );
511                 }
512                 else
513                 {
514                     pFormModule->Load();
515                 }
516                 return pFormModule->CreateInstance();
517             }
518         }
519     }
520     return 0;
521 }
522 
523 
524 //========================================================================
525 // SbTypeFactory
526 
cloneTypeObjectImpl(const SbxObject & rTypeObj)527 SbxObject* cloneTypeObjectImpl( const SbxObject& rTypeObj )
528 {
529     SbxObject* pRet = new SbxObject( rTypeObj );
530     pRet->PutObject( pRet );
531 
532     // Copy the properties, not only the reference to them
533     SbxArray* pProps = pRet->GetProperties();
534     sal_uInt32 nCount = pProps->Count32();
535     for( sal_uInt32 i = 0 ; i < nCount ; i++ )
536     {
537         SbxVariable* pVar = pProps->Get32( i );
538         SbxProperty* pProp = PTR_CAST( SbxProperty, pVar );
539         if( pProp )
540         {
541             SbxProperty* pNewProp = new SbxProperty( *pProp );
542             SbxDataType eVarType = pVar->GetType();
543             if( eVarType & SbxARRAY )
544             {
545                 SbxBase* pParObj = pVar->GetObject();
546                 SbxDimArray* pSource = PTR_CAST(SbxDimArray,pParObj);
547                 SbxDimArray* pDest = new SbxDimArray( pVar->GetType() );
548                 sal_Int32 lb = 0;
549                 sal_Int32 ub = 0;
550 
551                 pDest->setHasFixedSize( pSource->hasFixedSize() );
552                 if ( pSource->GetDims() && pSource->hasFixedSize() )
553                 {
554                     for ( sal_Int32 j = 1 ; j <= pSource->GetDims(); ++j )
555                     {
556                         pSource->GetDim32( (sal_Int32)j, lb, ub );
557                         pDest->AddDim32( lb, ub );
558                     }
559                 }
560                 else
561                     pDest->unoAddDim( 0, -1 ); // variant array
562 
563                 sal_uInt16 nSavFlags = pVar->GetFlags();
564                 pNewProp->ResetFlag( SBX_FIXED );
565                 // need to reset the FIXED flag
566                 // when calling PutObject ( because the type will not match Object )
567                 pNewProp->PutObject( pDest );
568                 pNewProp->SetFlags( nSavFlags );
569             }
570             if( eVarType == SbxOBJECT )
571             {
572                 SbxBase* pObjBase = pVar->GetObject();
573                 SbxObject* pSrcObj = PTR_CAST(SbxObject,pObjBase);
574                 SbxObject* pDestObj = NULL;
575                 if( pSrcObj != NULL )
576                     pDestObj = cloneTypeObjectImpl( *pSrcObj );
577                 pNewProp->PutObject( pDestObj );
578             }
579             pProps->PutDirect( pNewProp, i );
580         }
581     }
582     return pRet;
583 }
584 
585 // Factory class to create user defined objects (type command)
586 class SbTypeFactory : public SbxFactory
587 {
588 public:
589     virtual SbxBase* Create( sal_uInt16 nSbxId, sal_uInt32 = SBXCR_SBX );
590     virtual SbxObject* CreateObject( const String& );
591 };
592 
Create(sal_uInt16,sal_uInt32)593 SbxBase* SbTypeFactory::Create( sal_uInt16, sal_uInt32 )
594 {
595     // Not supported
596     return NULL;
597 }
598 
CreateObject(const String & rClassName)599 SbxObject* SbTypeFactory::CreateObject( const String& rClassName )
600 {
601     SbxObject* pRet = NULL;
602     SbModule* pMod = pMOD;
603     if( pMod )
604     {
605         const SbxObject* pObj = pMod->FindType( rClassName );
606         if( pObj )
607             pRet = cloneTypeObjectImpl( *pObj );
608     }
609     return pRet;
610 }
611 
createUserTypeImpl(const String & rClassName)612 SbxObject* createUserTypeImpl( const String& rClassName )
613 {
614     SbxObject* pRetObj = pTYPEFAC->CreateObject( rClassName );
615     return pRetObj;
616 }
617 
618 
TYPEINIT1(SbClassModuleObject,SbModule)619 TYPEINIT1(SbClassModuleObject,SbModule)
620 
621 SbClassModuleObject::SbClassModuleObject( SbModule* pClassModule )
622     : SbModule( pClassModule->GetName() )
623     , mpClassModule( pClassModule )
624     , mbInitializeEventDone( false )
625 {
626     aOUSource = pClassModule->aOUSource;
627     aComment = pClassModule->aComment;
628     pImage = pClassModule->pImage;
629     pBreaks = pClassModule->pBreaks;
630 
631     SetClassName( pClassModule->GetName() );
632 
633     // Allow search only internally
634     ResetFlag( SBX_GBLSEARCH );
635 
636     // Copy the methods from original class module
637     SbxArray* pClassMethods = pClassModule->GetMethods();
638     sal_uInt32 nMethodCount = pClassMethods->Count32();
639     sal_uInt32 i;
640     for( i = 0 ; i < nMethodCount ; i++ )
641     {
642         SbxVariable* pVar = pClassMethods->Get32( i );
643 
644         // Exclude SbIfaceMapperMethod to copy them in a second step
645         SbIfaceMapperMethod* pIfaceMethod = PTR_CAST( SbIfaceMapperMethod, pVar );
646         if( !pIfaceMethod )
647         {
648             SbMethod* pMethod = PTR_CAST(SbMethod, pVar );
649             if( pMethod )
650             {
651                 sal_uInt16 nFlags_ = pMethod->GetFlags();
652                 pMethod->SetFlag( SBX_NO_BROADCAST );
653                 SbMethod* pNewMethod = new SbMethod( *pMethod );
654                 pNewMethod->ResetFlag( SBX_NO_BROADCAST );
655                 pMethod->SetFlags( nFlags_ );
656                 pNewMethod->pMod = this;
657                 pNewMethod->SetParent( this );
658                 pMethods->PutDirect( pNewMethod, i );
659                 StartListening( pNewMethod->GetBroadcaster(), sal_True );
660             }
661         }
662     }
663 
664     // Copy SbIfaceMapperMethod in a second step to ensure that
665     // the corresponding base methods have already been copied
666     for( i = 0 ; i < nMethodCount ; i++ )
667     {
668         SbxVariable* pVar = pClassMethods->Get32( i );
669 
670         SbIfaceMapperMethod* pIfaceMethod = PTR_CAST( SbIfaceMapperMethod, pVar );
671         if( pIfaceMethod )
672         {
673             SbMethod* pImplMethod = pIfaceMethod->getImplMethod();
674             if( !pImplMethod )
675             {
676                 DBG_ERROR( "No ImplMethod" );
677                 continue;
678             }
679 
680             // Search for own copy of ImplMethod
681             String aImplMethodName = pImplMethod->GetName();
682             SbxVariable* p = pMethods->Find( aImplMethodName, SbxCLASS_METHOD );
683             SbMethod* pImplMethodCopy = p ? PTR_CAST(SbMethod,p) : NULL;
684             if( !pImplMethodCopy )
685             {
686                 DBG_ERROR( "Found no ImplMethod copy" );
687                 continue;
688             }
689             SbIfaceMapperMethod* pNewIfaceMethod =
690                 new SbIfaceMapperMethod( pIfaceMethod->GetName(), pImplMethodCopy );
691             pMethods->PutDirect( pNewIfaceMethod, i );
692         }
693     }
694 
695     // Copy the properties from original class module
696     SbxArray* pClassProps = pClassModule->GetProperties();
697     sal_uInt32 nPropertyCount = pClassProps->Count32();
698     for( i = 0 ; i < nPropertyCount ; i++ )
699     {
700         SbxVariable* pVar = pClassProps->Get32( i );
701         SbProcedureProperty* pProcedureProp = PTR_CAST( SbProcedureProperty, pVar );
702         if( pProcedureProp )
703         {
704             sal_uInt16 nFlags_ = pProcedureProp->GetFlags();
705             pProcedureProp->SetFlag( SBX_NO_BROADCAST );
706             SbProcedureProperty* pNewProp = new SbProcedureProperty
707                 ( pProcedureProp->GetName(), pProcedureProp->GetType() );
708                 // ( pProcedureProp->GetName(), pProcedureProp->GetType(), this );
709             pNewProp->SetFlags( nFlags_ ); // Copy flags
710             pNewProp->ResetFlag( SBX_NO_BROADCAST ); // except the Broadcast if it was set
711             pProcedureProp->SetFlags( nFlags_ );
712             pProps->PutDirect( pNewProp, i );
713             StartListening( pNewProp->GetBroadcaster(), sal_True );
714         }
715         else
716         {
717             SbxProperty* pProp = PTR_CAST( SbxProperty, pVar );
718             if( pProp )
719             {
720                 sal_uInt16 nFlags_ = pProp->GetFlags();
721                 pProp->SetFlag( SBX_NO_BROADCAST );
722                 SbxProperty* pNewProp = new SbxProperty( *pProp );
723 
724                 // Special handling for modules instances and collections, they need
725                 // to be instantiated, otherwise all refer to the same base object
726                 SbxDataType eVarType = pProp->GetType();
727                 if( eVarType == SbxOBJECT )
728                 {
729                     SbxBase* pObjBase = pProp->GetObject();
730                     SbxObject* pObj = PTR_CAST(SbxObject,pObjBase);
731                     if( pObj != NULL )
732                     {
733                         String aObjClass = pObj->GetClassName();
734 
735                         SbClassModuleObject* pClassModuleObj = PTR_CAST(SbClassModuleObject,pObjBase);
736                         if( pClassModuleObj != NULL )
737                         {
738                             SbModule* pLclClassModule = pClassModuleObj->getClassModule();
739                             SbClassModuleObject* pNewObj = new SbClassModuleObject( pLclClassModule );
740                             pNewObj->SetName( pProp->GetName() );
741                             pNewObj->SetParent( pLclClassModule->pParent );
742                             pNewProp->PutObject( pNewObj );
743                         }
744                         else if( aObjClass.EqualsIgnoreCaseAscii( "Collection" ) )
745                         {
746                             String aCollectionName( RTL_CONSTASCII_USTRINGPARAM("Collection") );
747                             BasicCollection* pNewCollection = new BasicCollection( aCollectionName );
748                             pNewCollection->SetName( pProp->GetName() );
749                             pNewCollection->SetParent( pClassModule->pParent );
750                             pNewProp->PutObject( pNewCollection );
751                         }
752                     }
753                 }
754 
755                 pNewProp->ResetFlag( SBX_NO_BROADCAST );
756                 pNewProp->SetParent( this );
757                 pProps->PutDirect( pNewProp, i );
758                 pProp->SetFlags( nFlags_ );
759             }
760         }
761     }
762     SetModuleType( ModuleType::CLASS );
763     mbVBACompat = pClassModule->mbVBACompat;
764 }
765 
~SbClassModuleObject()766 SbClassModuleObject::~SbClassModuleObject()
767 {
768     // do not trigger termination event when document is already closed
769     if( StarBASIC::IsRunning() )
770         if( StarBASIC* pDocBasic = lclGetDocBasicForModule( this ) )
771             if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) )
772                 if( !pDocBasicItem->isDocClosed() )
773                     triggerTerminateEvent();
774 
775     // Must be deleted by base class dtor because this data
776     // is not owned by the SbClassModuleObject object
777     pImage = NULL;
778     pBreaks = NULL;
779 }
780 
SFX_NOTIFY(SfxBroadcaster & rBC,const TypeId & rBCType,const SfxHint & rHint,const TypeId & rHintType)781 void SbClassModuleObject::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
782                            const SfxHint& rHint, const TypeId& rHintType )
783 {
784     handleProcedureProperties( rBC, rHint );
785 }
786 
Find(const XubString & rName,SbxClassType t)787 SbxVariable* SbClassModuleObject::Find( const XubString& rName, SbxClassType t )
788 {
789     SbxVariable* pRes = SbxObject::Find( rName, t );
790     if( pRes )
791     {
792         triggerInitializeEvent();
793 
794         SbIfaceMapperMethod* pIfaceMapperMethod = PTR_CAST(SbIfaceMapperMethod,pRes);
795         if( pIfaceMapperMethod )
796         {
797             pRes = pIfaceMapperMethod->getImplMethod();
798             pRes->SetFlag( SBX_EXTFOUND );
799         }
800     }
801     return pRes;
802 }
803 
triggerInitializeEvent(void)804 void SbClassModuleObject::triggerInitializeEvent( void )
805 {
806     static String aInitMethodName( RTL_CONSTASCII_USTRINGPARAM("Class_Initialize") );
807 
808     if( mbInitializeEventDone )
809         return;
810 
811     mbInitializeEventDone = true;
812 
813     // Search method
814     SbxVariable* pMeth = SbxObject::Find( aInitMethodName, SbxCLASS_METHOD );
815     if( pMeth )
816     {
817         SbxValues aVals;
818         pMeth->Get( aVals );
819     }
820 }
821 
triggerTerminateEvent(void)822 void SbClassModuleObject::triggerTerminateEvent( void )
823 {
824     static String aTermMethodName( RTL_CONSTASCII_USTRINGPARAM("Class_Terminate") );
825 
826     if( !mbInitializeEventDone || GetSbData()->bRunInit )
827         return;
828 
829     // Search method
830     SbxVariable* pMeth = SbxObject::Find( aTermMethodName, SbxCLASS_METHOD );
831     if( pMeth )
832     {
833         SbxValues aVals;
834         pMeth->Get( aVals );
835     }
836 }
837 
838 
SbClassData(void)839 SbClassData::SbClassData( void )
840 {
841     mxIfaces = new SbxArray();
842 }
843 
clear(void)844 void SbClassData::clear( void )
845 {
846     mxIfaces->Clear();
847     maRequiredTypes.clear();
848 }
849 
SbClassFactory(void)850 SbClassFactory::SbClassFactory( void )
851 {
852     String aDummyName;
853     xClassModules = new SbxObject( aDummyName );
854 }
855 
~SbClassFactory()856 SbClassFactory::~SbClassFactory()
857 {}
858 
AddClassModule(SbModule * pClassModule)859 void SbClassFactory::AddClassModule( SbModule* pClassModule )
860 {
861     SbxObjectRef xToUseClassModules = xClassModules;
862 
863     if( StarBASIC* pDocBasic = lclGetDocBasicForModule( pClassModule ) )
864         if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) )
865             xToUseClassModules = pDocBasicItem->getClassModules();
866 
867     SbxObject* pParent = pClassModule->GetParent();
868     xToUseClassModules->Insert( pClassModule );
869     pClassModule->SetParent( pParent );
870 }
871 
RemoveClassModule(SbModule * pClassModule)872 void SbClassFactory::RemoveClassModule( SbModule* pClassModule )
873 {
874     xClassModules->Remove( pClassModule );
875 }
876 
Create(sal_uInt16,sal_uInt32)877 SbxBase* SbClassFactory::Create( sal_uInt16, sal_uInt32 )
878 {
879     // Not supported
880     return NULL;
881 }
882 
CreateObject(const String & rClassName)883 SbxObject* SbClassFactory::CreateObject( const String& rClassName )
884 {
885     SbxObjectRef xToUseClassModules = xClassModules;
886 
887     if( SbModule* pMod = pMOD )
888         if( StarBASIC* pDocBasic = lclGetDocBasicForModule( pMod ) )
889             if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) )
890                 xToUseClassModules = pDocBasicItem->getClassModules();
891 
892     SbxVariable* pVar = xToUseClassModules->Find( rClassName, SbxCLASS_OBJECT );
893     SbxObject* pRet = NULL;
894     if( pVar )
895     {
896         SbModule* pVarMod = (SbModule*)pVar;
897         pRet = new SbClassModuleObject( pVarMod );
898     }
899     return pRet;
900 }
901 
FindClass(const String & rClassName)902 SbModule* SbClassFactory::FindClass( const String& rClassName )
903 {
904     SbxVariable* pVar = xClassModules->Find( rClassName, SbxCLASS_DONTCARE );
905     SbModule* pMod = pVar ? (SbModule*)pVar : NULL;
906     return pMod;
907 }
908 
StarBASIC(StarBASIC * p,sal_Bool bIsDocBasic)909 StarBASIC::StarBASIC( StarBASIC* p, sal_Bool bIsDocBasic  )
910     : SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("StarBASIC") ) ), bDocBasic( bIsDocBasic )
911 {
912     SetParent( p );
913     pLibInfo = NULL;
914     bNoRtl = bBreak = sal_False;
915     bVBAEnabled = sal_False;
916     pModules = new SbxArray;
917 
918     if( !GetSbData()->nInst++ )
919     {
920         pSBFAC = new SbiFactory;
921         AddFactory( pSBFAC );
922         pTYPEFAC = new SbTypeFactory;
923         AddFactory( pTYPEFAC );
924         pCLASSFAC = new SbClassFactory;
925         AddFactory( pCLASSFAC );
926         pOLEFAC = new SbOLEFactory;
927         AddFactory( pOLEFAC );
928         pFORMFAC = new SbFormFactory;
929         AddFactory( pFORMFAC );
930         pUNOFAC = new SbUnoFactory;
931         AddFactory( pUNOFAC );
932     }
933     pRtl = new SbiStdObject( String( RTL_CONSTASCII_USTRINGPARAM(RTLNAME) ), this );
934     // Search via StarBasic is always global
935     SetFlag( SBX_GBLSEARCH );
936     pVBAGlobals = NULL;
937     bQuit = sal_False;
938 
939     if( bDocBasic )
940         lclInsertDocBasicItem( *this );
941 }
942 
943 // #51727 Override SetModified so that the modified state
944 // is not given to the parent
SetModified(sal_Bool b)945 void StarBASIC::SetModified( sal_Bool b )
946 {
947     SbxBase::SetModified( b );
948 }
949 
950 extern void lcl_closeTraceFile();
951 
~StarBASIC()952 StarBASIC::~StarBASIC()
953 {
954 #ifdef DBG_TRACE_BASIC
955     lcl_closeTraceFile();
956 #endif
957 
958     // Needs to be first action as it can trigger events
959     disposeComVariablesForBasic( this );
960 
961     if( !--GetSbData()->nInst )
962     {
963         RemoveFactory( pSBFAC );
964         delete pSBFAC; pSBFAC = NULL;
965         RemoveFactory( pUNOFAC );
966         delete pUNOFAC; pUNOFAC = NULL;
967         RemoveFactory( pTYPEFAC );
968         delete pTYPEFAC; pTYPEFAC = NULL;
969         RemoveFactory( pCLASSFAC );
970         delete pCLASSFAC; pCLASSFAC = NULL;
971         RemoveFactory( pOLEFAC );
972         delete pOLEFAC; pOLEFAC = NULL;
973         RemoveFactory( pFORMFAC );
974         delete pFORMFAC; pFORMFAC = NULL;
975 
976 #ifdef DBG_UTIL
977     // There is no need to clean SbiData at program end,
978     // but we dislike MLK's at Purify
979     // TODO: Where else???
980     SbiGlobals** pp = (SbiGlobals**) ::GetAppData( SHL_SBC );
981     SbiGlobals* p = *pp;
982     if( p )
983     {
984         delete p;
985         *pp = 0;
986     }
987 #endif
988     }
989     else if( bDocBasic )
990     {
991         SbxError eOld = SbxBase::GetError();
992 
993         lclRemoveDocBasicItem( *this );
994 
995         SbxBase::ResetError();
996         if( eOld != SbxERR_OK )
997             SbxBase::SetError( eOld );
998     }
999 
1000     // #100326 Set Parent NULL in registered listeners
1001     if( xUnoListeners.Is() )
1002     {
1003         sal_uInt16 uCount = xUnoListeners->Count();
1004         for( sal_uInt16 i = 0 ; i < uCount ; i++ )
1005         {
1006             SbxVariable* pListenerObj = xUnoListeners->Get( i );
1007             pListenerObj->SetParent( NULL );
1008         }
1009         xUnoListeners = NULL;
1010     }
1011 
1012     clearUnoMethodsForBasic( this );
1013 }
1014 
1015 // Override new() operator, so that everyone can create a new instance
operator new(size_t n)1016 void* StarBASIC::operator new( size_t n )
1017 {
1018     if( n < sizeof( StarBASIC ) )
1019     {
1020 //      DBG_ASSERT( sal_False, "Warnung: inkompatibler BASIC-Stand!" );
1021         n = sizeof( StarBASIC );
1022     }
1023     return ::operator new( n );
1024 }
1025 
operator delete(void * p)1026 void StarBASIC::operator delete( void* p )
1027 {
1028     ::operator delete( p );
1029 }
1030 
implClearDependingVarsOnDelete(StarBASIC * pDeletedBasic)1031 void StarBASIC::implClearDependingVarsOnDelete( StarBASIC* pDeletedBasic )
1032 {
1033     if( this != pDeletedBasic )
1034     {
1035         for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1036         {
1037             SbModule* p = (SbModule*)pModules->Get( i );
1038             p->ClearVarsDependingOnDeletedBasic( pDeletedBasic );
1039         }
1040     }
1041 
1042     for( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ )
1043     {
1044         SbxVariable* pVar = pObjs->Get( nObj );
1045         StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
1046         if( pBasic && pBasic != pDeletedBasic )
1047             pBasic->implClearDependingVarsOnDelete( pDeletedBasic );
1048     }
1049 }
1050 
1051 
1052 /**************************************************************************
1053 *
1054 *    Creation/Management of modules
1055 *
1056 **************************************************************************/
1057 
MakeModule(const String & rName,const String & rSrc)1058 SbModule* StarBASIC::MakeModule( const String& rName, const String& rSrc )
1059 {
1060     return MakeModule32( rName, rSrc );
1061 }
1062 
MakeModule32(const String & rName,const::rtl::OUString & rSrc)1063 SbModule* StarBASIC::MakeModule32( const String& rName, const ::rtl::OUString& rSrc )
1064 {
1065     ModuleInfo mInfo;
1066     mInfo.ModuleType = ModuleType::NORMAL;
1067     return MakeModule32(  rName, mInfo, rSrc );
1068 }
MakeModule32(const String & rName,const ModuleInfo & mInfo,const rtl::OUString & rSrc)1069 SbModule* StarBASIC::MakeModule32( const String& rName, const ModuleInfo& mInfo, const rtl::OUString& rSrc )
1070 {
1071 
1072     OSL_TRACE("create module %s type mInfo %d", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(), mInfo.ModuleType );
1073     SbModule* p = NULL;
1074     switch ( mInfo.ModuleType )
1075     {
1076         case ModuleType::DOCUMENT:
1077             // In theory we should be able to create Object modules
1078             // in ordinary basic ( in vba mode thought these are create
1079             // by the application/basic and not by the user )
1080             p = new SbObjModule( rName, mInfo, isVBAEnabled() );
1081             break;
1082         case ModuleType::CLASS:
1083             p = new SbModule( rName, isVBAEnabled() );
1084             p->SetModuleType( ModuleType::CLASS );
1085         break;
1086         case ModuleType::FORM:
1087             p = new SbUserFormModule( rName, mInfo, isVBAEnabled() );
1088         break;
1089         default:
1090             p = new SbModule( rName, isVBAEnabled() );
1091 
1092     }
1093     p->SetSource32( rSrc );
1094     p->SetParent( this );
1095     pModules->Insert( p, pModules->Count() );
1096     SetModified( sal_True );
1097     return p;
1098 }
1099 
Insert(SbxVariable * pVar)1100 void StarBASIC::Insert( SbxVariable* pVar )
1101 {
1102     if( pVar->IsA( TYPE(SbModule) ) )
1103     {
1104         pModules->Insert( pVar, pModules->Count() );
1105         pVar->SetParent( this );
1106         StartListening( pVar->GetBroadcaster(), sal_True );
1107     }
1108     else
1109     {
1110         sal_Bool bWasModified = IsModified();
1111         SbxObject::Insert( pVar );
1112         if( !bWasModified && pVar->IsSet( SBX_DONTSTORE ) )
1113             SetModified( sal_False );
1114     }
1115 }
1116 
Remove(SbxVariable * pVar)1117 void StarBASIC::Remove( SbxVariable* pVar )
1118 {
1119     if( pVar->IsA( TYPE(SbModule) ) )
1120     {
1121         // #87540 Can be last reference!
1122         SbxVariableRef xVar = pVar;
1123         pModules->Remove( pVar );
1124         pVar->SetParent( 0 );
1125         EndListening( pVar->GetBroadcaster() );
1126     }
1127     else
1128         SbxObject::Remove( pVar );
1129 }
1130 
Compile(SbModule * pMod)1131 sal_Bool StarBASIC::Compile( SbModule* pMod )
1132 {
1133     return pMod ? pMod->Compile() : sal_False;
1134 }
1135 
Disassemble(SbModule * pMod,String & rText)1136 sal_Bool StarBASIC::Disassemble( SbModule* pMod, String& rText )
1137 {
1138     rText.Erase();
1139     if( pMod )
1140         pMod->Disassemble( rText );
1141     return sal_Bool( rText.Len() != 0 );
1142 }
1143 
Clear()1144 void StarBASIC::Clear()
1145 {
1146     while( pModules->Count() )
1147         pModules->Remove( pModules->Count() - 1 );
1148 }
1149 
FindModule(const String & rName)1150 SbModule* StarBASIC::FindModule( const String& rName )
1151 {
1152     for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1153     {
1154         SbModule* p = (SbModule*) pModules->Get( i );
1155         if( p->GetName().EqualsIgnoreCaseAscii( rName ) )
1156             return p;
1157     }
1158     return NULL;
1159 }
1160 
1161 
1162 struct ClassModuleRunInitItem
1163 {
1164     SbModule*       m_pModule;
1165     bool            m_bProcessing;
1166     bool            m_bRunInitDone;
1167     //ModuleVector  m_vModulesDependingOnThisModule;
1168 
ClassModuleRunInitItemClassModuleRunInitItem1169     ClassModuleRunInitItem( void )
1170         : m_pModule( NULL )
1171         , m_bProcessing( false )
1172         , m_bRunInitDone( false )
1173     {}
ClassModuleRunInitItemClassModuleRunInitItem1174     ClassModuleRunInitItem( SbModule* pModule )
1175         : m_pModule( pModule )
1176         , m_bProcessing( false )
1177         , m_bRunInitDone( false )
1178     {}
1179 };
1180 
1181 // Derive from has_map type instead of typedef
1182 // to allow forward declaration in sbmod.hxx
1183 class ModuleInitDependencyMap : public
1184     std::hash_map< ::rtl::OUString, ClassModuleRunInitItem,
1185         ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > >
1186 {};
1187 
implProcessModuleRunInit(ModuleInitDependencyMap & rMap,ClassModuleRunInitItem & rItem)1188 void SbModule::implProcessModuleRunInit( ModuleInitDependencyMap& rMap, ClassModuleRunInitItem& rItem )
1189 {
1190     rItem.m_bProcessing = true;
1191 
1192     //bool bAnyDependencies = true;
1193     SbModule* pModule = rItem.m_pModule;
1194     if( pModule->pClassData != NULL )
1195     {
1196         StringVector& rReqTypes = pModule->pClassData->maRequiredTypes;
1197         if( rReqTypes.size() > 0 )
1198         {
1199             for( StringVector::iterator it = rReqTypes.begin() ; it != rReqTypes.end() ; ++it )
1200             {
1201                 String& rStr = *it;
1202 
1203                 // Is required type a class module?
1204                 ModuleInitDependencyMap::iterator itFind = rMap.find( rStr );
1205                 if( itFind != rMap.end() )
1206                 {
1207                     ClassModuleRunInitItem& rParentItem = itFind->second;
1208                     if( rParentItem.m_bProcessing )
1209                     {
1210                         // TODO: raise error?
1211                         DBG_ERROR( "Cyclic module dependency detected" );
1212                         continue;
1213                     }
1214 
1215                     if( !rParentItem.m_bRunInitDone )
1216                         implProcessModuleRunInit( rMap, rParentItem );
1217                 }
1218             }
1219         }
1220     }
1221 
1222     pModule->RunInit();
1223     rItem.m_bRunInitDone = true;
1224     rItem.m_bProcessing = false;
1225 }
1226 
1227 // Run Init-Code of all modules (including inserted libraries)
InitAllModules(StarBASIC * pBasicNotToInit)1228 void StarBASIC::InitAllModules( StarBASIC* pBasicNotToInit )
1229 {
1230     ::vos::OGuard guard( Application::GetSolarMutex() );
1231 
1232     // Init own modules
1233     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1234     {
1235         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1236         if( !pModule->IsCompiled() )
1237             pModule->Compile();
1238     }
1239     // compile modules first then RunInit ( otherwise there is
1240     // can be order dependency, e.g. classmodule A has a member
1241     // of of type classmodule B and classmodule B hasn't been compiled yet )
1242 
1243     // Consider required types to init in right order. Class modules
1244     // that are required by other modules have to be initialized first.
1245     ModuleInitDependencyMap aMIDMap;
1246     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1247     {
1248         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1249         String aModuleName = pModule->GetName();
1250         if( pModule->isProxyModule() )
1251             aMIDMap[aModuleName] = ClassModuleRunInitItem( pModule );
1252     }
1253 
1254     ModuleInitDependencyMap::iterator it;
1255     for( it = aMIDMap.begin() ; it != aMIDMap.end(); ++it )
1256     {
1257         ClassModuleRunInitItem& rItem = it->second;
1258         SbModule::implProcessModuleRunInit( aMIDMap, rItem );
1259     }
1260 
1261     // Call RunInit on standard modules
1262     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1263     {
1264         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1265         if( !pModule->isProxyModule() )
1266             pModule->RunInit();
1267     }
1268 
1269     // Check all objects if they are BASIC,
1270     // if yes initialize
1271     for ( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ )
1272     {
1273         SbxVariable* pVar = pObjs->Get( nObj );
1274         StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
1275         if( pBasic && pBasic != pBasicNotToInit )
1276             pBasic->InitAllModules();
1277     }
1278 }
1279 
1280 // #88329 Put modules back to not initialised state to
1281 // force reinitialisation at next start
DeInitAllModules(void)1282 void StarBASIC::DeInitAllModules( void )
1283 {
1284     // Deinit own modules
1285     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1286     {
1287         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1288         if( pModule->pImage && !pModule->isProxyModule() && !pModule->ISA(SbObjModule) )
1289             pModule->pImage->bInit = false;
1290     }
1291 
1292     for ( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ )
1293     {
1294         SbxVariable* pVar = pObjs->Get( nObj );
1295         StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
1296         if( pBasic )
1297             pBasic->DeInitAllModules();
1298     }
1299 }
1300 
1301 // #43011 For TestTool, to delete global vars
ClearGlobalVars(void)1302 void StarBASIC::ClearGlobalVars( void )
1303 {
1304     SbxArrayRef xProps( GetProperties() );
1305     sal_uInt16 nPropCount = xProps->Count();
1306     for ( sal_uInt16 nProp = 0 ; nProp < nPropCount ; ++nProp )
1307     {
1308         SbxBase* pVar = xProps->Get( nProp );
1309         pVar->Clear();
1310     }
1311     SetModified( sal_True );
1312 }
1313 
1314 // This implementation at first searches within the runtime library,
1315 // then it looks for an element within one module. This moudle can be
1316 // a public var or an entrypoint. If it is not found and we look for a
1317 // method and a module with the given name is found the search continues
1318 // for entrypoint "Main".
1319 // If this fails again a conventional search over objects is performend.
Find(const String & rName,SbxClassType t)1320 SbxVariable* StarBASIC::Find( const String& rName, SbxClassType t )
1321 {
1322     static String aMainStr( RTL_CONSTASCII_USTRINGPARAM("Main") );
1323 
1324     SbxVariable* pRes = NULL;
1325     SbModule* pNamed = NULL;
1326     // "Extended" search in Runtime Lib
1327     // but only if SbiRuntime has not set the flag
1328     if( !bNoRtl )
1329     {
1330         if( t == SbxCLASS_DONTCARE || t == SbxCLASS_OBJECT )
1331         {
1332             if( rName.EqualsIgnoreCaseAscii( RTLNAME ) )
1333                 pRes = pRtl;
1334         }
1335         if( !pRes )
1336             pRes = ((SbiStdObject*) (SbxObject*) pRtl)->Find( rName, t );
1337         if( pRes )
1338             pRes->SetFlag( SBX_EXTFOUND );
1339     }
1340     // Search module
1341     if( !pRes )
1342       for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1343     {
1344         SbModule* p = (SbModule*) pModules->Get( i );
1345         if( p->IsVisible() )
1346         {
1347             // Remember modul fpr Main() call
1348             // or is the name equal?!?
1349             if( p->GetName().EqualsIgnoreCaseAscii( rName ) )
1350             {
1351                 if( t == SbxCLASS_OBJECT || t == SbxCLASS_DONTCARE )
1352                 {
1353                     pRes = p; break;
1354                 }
1355                 pNamed = p;
1356             }
1357             // Only variables qualified by the Module Name e.g. Sheet1.foo
1358             // should work for Documant && Class type Modules
1359             sal_Int32 nType = p->GetModuleType();
1360             if ( nType == ModuleType::DOCUMENT || nType == ModuleType::FORM )
1361                 continue;
1362 
1363             // otherwise check if the element is available
1364             // unset GBLSEARCH-Flag (due to Rekursion)
1365             sal_uInt16 nGblFlag = p->GetFlags() & SBX_GBLSEARCH;
1366             p->ResetFlag( SBX_GBLSEARCH );
1367             pRes = p->Find( rName, t );
1368             p->SetFlag( nGblFlag );
1369             if( pRes )
1370                 break;
1371         }
1372     }
1373     if( !pRes && pNamed && ( t == SbxCLASS_METHOD || t == SbxCLASS_DONTCARE ) &&
1374         !pNamed->GetName().EqualsIgnoreCaseAscii( aMainStr ) )
1375             pRes = pNamed->Find( aMainStr, SbxCLASS_METHOD );
1376     if( !pRes )
1377         pRes = SbxObject::Find( rName, t );
1378     return pRes;
1379 }
1380 
Call(const String & rName,SbxArray * pParam)1381 sal_Bool StarBASIC::Call( const String& rName, SbxArray* pParam )
1382 {
1383     sal_Bool bRes = SbxObject::Call( rName, pParam );
1384     if( !bRes )
1385     {
1386         SbxError eErr = SbxBase::GetError();
1387         SbxBase::ResetError();
1388         if( eErr != SbxERR_OK )
1389             RTError( (SbError)eErr, 0, 0, 0 );
1390     }
1391     return bRes;
1392 }
1393 
1394 // Find method via name (e.g. query via BASIC IDE)
FindSBXInCurrentScope(const String & rName)1395 SbxBase* StarBASIC::FindSBXInCurrentScope( const String& rName )
1396 {
1397     if( !pINST )
1398         return NULL;
1399     if( !pINST->pRun )
1400         return NULL;
1401     return pINST->pRun->FindElementExtern( rName );
1402 }
1403 
1404 // Preserve old interface
FindVarInCurrentScopy(const String & rName,sal_uInt16 & rStatus)1405 SbxVariable* StarBASIC::FindVarInCurrentScopy
1406 ( const String& rName, sal_uInt16& rStatus )
1407 {
1408     rStatus = 1;              // Presumption: nothing found
1409     SbxVariable* pVar = NULL;
1410     SbxBase* pSbx = FindSBXInCurrentScope( rName );
1411     if( pSbx )
1412     {
1413         if( !pSbx->ISA(SbxMethod) && !pSbx->ISA(SbxObject) )
1414             pVar = PTR_CAST(SbxVariable,pSbx);
1415     }
1416     if( pVar )
1417         rStatus = 0;      // We found something
1418     return pVar;
1419 }
1420 
QuitAndExitApplication()1421 void StarBASIC::QuitAndExitApplication()
1422 {
1423     Stop();
1424     bQuit = sal_True;
1425 }
1426 
Stop()1427 void StarBASIC::Stop()
1428 {
1429     SbiInstance* p = pINST;
1430     while( p )
1431     {
1432         p->Stop();
1433         p = p->pNext;
1434     }
1435 }
1436 
IsRunning()1437 sal_Bool StarBASIC::IsRunning()
1438 {
1439     return sal_Bool( pINST != NULL );
1440 }
1441 
1442 /**************************************************************************
1443 *
1444 *    Object factories and others
1445 *
1446 **************************************************************************/
1447 
1448 // Activation of an object. There is no need to access active objects
1449 // with name via BASIC. If NULL is given, everything is activated.
ActivateObject(const String * pName,sal_Bool bActivate)1450 void StarBASIC::ActivateObject( const String* pName, sal_Bool bActivate )
1451 {
1452     if( pName )
1453     {
1454         SbxObject* p = (SbxObject*) SbxObject::Find( *pName, SbxCLASS_OBJECT );
1455         if( p )
1456         {
1457             if( bActivate )
1458                 p->SetFlag( SBX_EXTSEARCH );
1459             else
1460                 p->ResetFlag( SBX_EXTSEARCH );
1461         }
1462     }
1463     else
1464     {
1465         for( sal_uInt16 i = 0; i < GetObjects()->Count(); i++ )
1466         {
1467             SbxObject* p = (SbxObject*) GetObjects()->Get( i );
1468             if( bActivate )
1469                 p->SetFlag( SBX_EXTSEARCH );
1470             else
1471                 p->ResetFlag( SBX_EXTSEARCH );
1472         }
1473     }
1474 }
1475 
1476 /**************************************************************************
1477 *
1478 *    Debugging and error handling
1479 *
1480 **************************************************************************/
1481 
GetActiveMethod(sal_uInt16 nLevel)1482 SbMethod* StarBASIC::GetActiveMethod( sal_uInt16 nLevel )
1483 {
1484     if( pINST )
1485         return pINST->GetCaller( nLevel );
1486     else
1487         return NULL;
1488 }
1489 
GetActiveModule()1490 SbModule* StarBASIC::GetActiveModule()
1491 {
1492     if( pINST && !IsCompilerError() )
1493         return pINST->GetActiveModule();
1494     else
1495         return pCMOD;
1496 }
1497 
BreakPoint(sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1498 sal_uInt16 StarBASIC::BreakPoint( sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1499 {
1500     SetErrorData( 0, l, c1, c2 );
1501     bBreak = sal_True;
1502     if( GetSbData()->aBreakHdl.IsSet() )
1503         return (sal_uInt16) GetSbData()->aBreakHdl.Call( this );
1504     else
1505         return BreakHdl();
1506 }
1507 
StepPoint(sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1508 sal_uInt16 StarBASIC::StepPoint( sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1509 {
1510     SetErrorData( 0, l, c1, c2 );
1511     bBreak = sal_False;
1512     if( GetSbData()->aBreakHdl.IsSet() )
1513         return (sal_uInt16) GetSbData()->aBreakHdl.Call( this );
1514     else
1515         return BreakHdl();
1516 }
1517 
BreakHdl()1518 sal_uInt16 __EXPORT StarBASIC::BreakHdl()
1519 {
1520     return (sal_uInt16) ( aBreakHdl.IsSet()
1521         ? aBreakHdl.Call( this ) : SbDEBUG_CONTINUE );
1522 }
1523 
1524 // Calls for error handler and break handler
GetLine()1525 sal_uInt16 StarBASIC::GetLine()     { return GetSbData()->nLine; }
GetCol1()1526 sal_uInt16 StarBASIC::GetCol1()     { return GetSbData()->nCol1; }
GetCol2()1527 sal_uInt16 StarBASIC::GetCol2()     { return GetSbData()->nCol2; }
1528 
1529 // Specific to error handler
GetErrorCode()1530 SbError StarBASIC::GetErrorCode()       { return GetSbData()->nCode; }
GetErrorText()1531 const String& StarBASIC::GetErrorText() { return GetSbData()->aErrMsg; }
IsCompilerError()1532 sal_Bool StarBASIC::IsCompilerError()       { return GetSbData()->bCompiler; }
SetGlobalLanguageMode(SbLanguageMode eLanguageMode)1533 void StarBASIC::SetGlobalLanguageMode( SbLanguageMode eLanguageMode )
1534 {
1535     GetSbData()->eLanguageMode = eLanguageMode;
1536 }
GetGlobalLanguageMode()1537 SbLanguageMode StarBASIC::GetGlobalLanguageMode()
1538 {
1539     return GetSbData()->eLanguageMode;
1540 }
1541 // Local settings
GetLanguageMode()1542 SbLanguageMode StarBASIC::GetLanguageMode()
1543 {
1544     // Use global settings?
1545     if( eLanguageMode == SB_LANG_GLOBAL )
1546         return GetSbData()->eLanguageMode;
1547     else
1548         return eLanguageMode;
1549 }
1550 
1551 // AB: 29.3.96
1552 // Das Mapping zwischen alten und neuen Fehlercodes erfolgt, indem die Tabelle
1553 // SFX_VB_ErrorTab[] durchsucht wird. Dies ist zwar nicht besonders performant,
1554 // verbraucht aber viel weniger Speicher als entsprechende switch-Bloecke.
1555 // Die Umrechnung von Fehlercodes muss nicht schnell sein, daher auch keine
1556 // binaere Suche bei VB-Error -> SFX-Error.
1557 
1558 // Neue Fehler-Codes auf alte, Sbx-Kompatible zurueckmappen
GetVBErrorCode(SbError nError)1559 sal_uInt16 StarBASIC::GetVBErrorCode( SbError nError )
1560 {
1561     sal_uInt16 nRet = 0;
1562 
1563     if( SbiRuntime::isVBAEnabled() )
1564     {
1565         switch( nError )
1566         {
1567             case SbERR_BASIC_ARRAY_FIX:
1568                 return 10;
1569             case SbERR_BASIC_STRING_OVERFLOW:
1570                 return 14;
1571             case SbERR_BASIC_EXPR_TOO_COMPLEX:
1572                 return 16;
1573             case SbERR_BASIC_OPER_NOT_PERFORM:
1574                 return 17;
1575             case SbERR_BASIC_TOO_MANY_DLL:
1576                 return 47;
1577             case SbERR_BASIC_LOOP_NOT_INIT:
1578                 return 92;
1579             default:
1580                 nRet = 0;
1581         }
1582     }
1583 
1584     // Suchschleife
1585     const SFX_VB_ErrorItem* pErrItem;
1586     sal_uInt16 nIndex = 0;
1587     do
1588     {
1589         pErrItem = SFX_VB_ErrorTab + nIndex;
1590         if( pErrItem->nErrorSFX == nError )
1591         {
1592             nRet = pErrItem->nErrorVB;
1593             break;
1594         }
1595         nIndex++;
1596     }
1597     while( pErrItem->nErrorVB != 0xFFFF );      // bis End-Marke
1598     return nRet;
1599 }
1600 
GetSfxFromVBError(sal_uInt16 nError)1601 SbError StarBASIC::GetSfxFromVBError( sal_uInt16 nError )
1602 {
1603     SbError nRet = 0L;
1604 
1605     if( SbiRuntime::isVBAEnabled() )
1606     {
1607         switch( nError )
1608         {
1609             case 1:
1610             case 2:
1611             case 4:
1612             case 8:
1613             case 12:
1614             case 73:
1615                 return 0L;
1616             case 10:
1617                 return SbERR_BASIC_ARRAY_FIX;
1618             case 14:
1619                 return SbERR_BASIC_STRING_OVERFLOW;
1620             case 16:
1621                 return SbERR_BASIC_EXPR_TOO_COMPLEX;
1622             case 17:
1623                 return SbERR_BASIC_OPER_NOT_PERFORM;
1624             case 47:
1625                 return SbERR_BASIC_TOO_MANY_DLL;
1626             case 92:
1627                 return SbERR_BASIC_LOOP_NOT_INIT;
1628             default:
1629                 nRet = 0L;
1630         }
1631     }
1632     const SFX_VB_ErrorItem* pErrItem;
1633     sal_uInt16 nIndex = 0;
1634     do
1635     {
1636         pErrItem = SFX_VB_ErrorTab + nIndex;
1637         if( pErrItem->nErrorVB == nError )
1638         {
1639             nRet = pErrItem->nErrorSFX;
1640             break;
1641         }
1642         else if( pErrItem->nErrorVB > nError )
1643             break;              // kann nicht mehr gefunden werden
1644 
1645         nIndex++;
1646     }
1647     while( pErrItem->nErrorVB != 0xFFFF );      // bis End-Marke
1648     return nRet;
1649 }
1650 
1651 // Error- / Break-Daten setzen
SetErrorData(SbError nCode,sal_uInt16 nLine,sal_uInt16 nCol1,sal_uInt16 nCol2)1652 void StarBASIC::SetErrorData
1653 ( SbError nCode, sal_uInt16 nLine, sal_uInt16 nCol1, sal_uInt16 nCol2 )
1654 {
1655     SbiGlobals& aGlobals = *GetSbData();
1656     aGlobals.nCode = nCode;
1657     aGlobals.nLine = nLine;
1658     aGlobals.nCol1 = nCol1;
1659     aGlobals.nCol2 = nCol2;
1660 }
1661 
1662 //----------------------------------------------------------------
1663 // Hilfsklasse zum Zugriff auf String SubResourcen einer Resource.
1664 // Quelle: sfx2\source\doc\docfile.cxx (TLX)
1665 struct BasicStringList_Impl : private Resource
1666 {
1667     ResId aResId;
1668 
BasicStringList_ImplBasicStringList_Impl1669     BasicStringList_Impl( ResId& rErrIdP,  sal_uInt16 nId)
1670         : Resource( rErrIdP ),aResId(nId, *rErrIdP.GetResMgr() ){}
~BasicStringList_ImplBasicStringList_Impl1671     ~BasicStringList_Impl() { FreeResource(); }
1672 
GetStringBasicStringList_Impl1673     String GetString(){ return String( aResId ); }
IsErrorTextAvailableBasicStringList_Impl1674     sal_Bool IsErrorTextAvailable( void )
1675         { return IsAvailableRes(aResId.SetRT(RSC_STRING)); }
1676 };
1677 //----------------------------------------------------------------
1678 
1679 // #60175 Flag, das bei Basic-Fehlern das Anziehen der SFX-Resourcen verhindert
1680 static sal_Bool bStaticSuppressSfxResource = sal_False;
1681 
StaticSuppressSfxResource(sal_Bool bSuppress)1682 void StarBASIC::StaticSuppressSfxResource( sal_Bool bSuppress )
1683 {
1684     bStaticSuppressSfxResource = bSuppress;
1685 }
1686 
1687 // Hack for #83750, use bStaticSuppressSfxResource as setup flag
runsInSetup(void)1688 sal_Bool runsInSetup( void )
1689 {
1690     return bStaticSuppressSfxResource;
1691 }
1692 
1693 
MakeErrorText(SbError nId,const String & aMsg)1694 void StarBASIC::MakeErrorText( SbError nId, const String& aMsg )
1695 {
1696     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1697 
1698     if( bStaticSuppressSfxResource )
1699     {
1700         GetSbData()->aErrMsg = String( RTL_CONSTASCII_USTRINGPARAM("No resource: Error message not available") );
1701         return;
1702     }
1703 
1704     sal_uInt16 nOldID = GetVBErrorCode( nId );
1705 
1706     // Hilfsklasse instanzieren
1707     BasResId aId( RID_BASIC_START );
1708     BasicStringList_Impl aMyStringList( aId, sal_uInt16(nId & ERRCODE_RES_MASK) );
1709 
1710     if( aMyStringList.IsErrorTextAvailable() )
1711     {
1712         // Merge Message mit Zusatztext
1713         String aMsg1 = aMyStringList.GetString();
1714         // Argument-Platzhalter durch %s ersetzen
1715         String aSrgStr( RTL_CONSTASCII_USTRINGPARAM("$(ARG1)") );
1716         sal_uInt16 nResult = aMsg1.Search( aSrgStr );
1717 
1718         if( nResult != STRING_NOTFOUND )
1719         {
1720             aMsg1.Erase( nResult, aSrgStr.Len() );
1721             aMsg1.Insert( aMsg, nResult );
1722         }
1723         GetSbData()->aErrMsg = aMsg1;
1724     }
1725     else if( nOldID != 0 )
1726     {
1727         String aStdMsg( RTL_CONSTASCII_USTRINGPARAM("Fehler ") );
1728         aStdMsg += String::CreateFromInt32( nOldID);
1729         aStdMsg += String( RTL_CONSTASCII_USTRINGPARAM(": Kein Fehlertext verfuegbar!") );
1730         GetSbData()->aErrMsg = aStdMsg;
1731     }
1732     else
1733         GetSbData()->aErrMsg = String::EmptyString();
1734 
1735 }
1736 
CError(SbError code,const String & rMsg,sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1737 sal_Bool StarBASIC::CError
1738     ( SbError code, const String& rMsg, sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1739 {
1740     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1741 
1742     // Compiler-Fehler waehrend der Laufzeit -> Programm anhalten
1743     if( IsRunning() )
1744     {
1745         // #109018 Check if running Basic is affected
1746         StarBASIC* pStartedBasic = pINST->GetBasic();
1747         if( pStartedBasic != this )
1748             return sal_False;
1749 
1750         Stop();
1751     }
1752 
1753     // Flag setzen, damit GlobalRunInit den Fehler mitbekommt
1754     GetSbData()->bGlobalInitErr = sal_True;
1755 
1756     // Fehlertext basteln
1757     MakeErrorText( code, rMsg );
1758 
1759     // Umsetzung des Codes fuer String-Transport in SFX-Error
1760     if( rMsg.Len() )
1761         code = (sal_uIntPtr)*new StringErrorInfo( code, String(rMsg) );
1762 
1763     SetErrorData( code, l, c1, c2 );
1764     GetSbData()->bCompiler = sal_True;
1765     sal_Bool bRet;
1766     if( GetSbData()->aErrHdl.IsSet() )
1767         bRet = (sal_Bool) GetSbData()->aErrHdl.Call( this );
1768     else
1769         bRet = ErrorHdl();
1770     GetSbData()->bCompiler = sal_False;     // nur sal_True fuer Error-Handler
1771     return bRet;
1772 }
1773 
RTError(SbError code,sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1774 sal_Bool StarBASIC::RTError
1775     ( SbError code, sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1776 {
1777     return RTError( code, String(), l, c1, c2 );
1778 }
1779 
RTError(SbError code,const String & rMsg,sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1780 sal_Bool StarBASIC::RTError( SbError code, const String& rMsg, sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1781 {
1782     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1783 
1784     SbError c = code;
1785     if( (c & ERRCODE_CLASS_MASK) == ERRCODE_CLASS_COMPILER )
1786         c = 0;
1787     MakeErrorText( c, rMsg );
1788 
1789     // Umsetzung des Codes fuer String-Transport in SFX-Error
1790     if( rMsg.Len() )
1791     {
1792         // very confusing, even though MakeErrorText sets up the error text
1793         // seems that this is not used ( if rMsg already has content )
1794         // In the case of VBA MakeErrorText also formats the error to be alittle more
1795         // like vba ( adds an error number etc )
1796         if ( SbiRuntime::isVBAEnabled() && ( code == SbERR_BASIC_COMPAT ) )
1797         {
1798             String aTmp = '\'';
1799             aTmp += String::CreateFromInt32( SbxErrObject::getUnoErrObject()->getNumber() );
1800             aTmp += String( RTL_CONSTASCII_USTRINGPARAM("\'\n") );
1801             aTmp +=  GetSbData()->aErrMsg.Len() ? GetSbData()->aErrMsg : rMsg;
1802             code = (sal_uIntPtr)*new StringErrorInfo( code, aTmp );
1803         }
1804         else
1805             code = (sal_uIntPtr)*new StringErrorInfo( code, String(rMsg) );
1806     }
1807 
1808     SetErrorData( code, l, c1, c2 );
1809     if( GetSbData()->aErrHdl.IsSet() )
1810         return (sal_Bool) GetSbData()->aErrHdl.Call( this );
1811     else
1812         return ErrorHdl();
1813 }
1814 
Error(SbError n)1815 void StarBASIC::Error( SbError n )
1816 {
1817     Error( n, String() );
1818 }
1819 
Error(SbError n,const String & rMsg)1820 void StarBASIC::Error( SbError n, const String& rMsg )
1821 {
1822     if( pINST )
1823         pINST->Error( n, rMsg );
1824 }
1825 
FatalError(SbError n)1826 void StarBASIC::FatalError( SbError n )
1827 {
1828     if( pINST )
1829         pINST->FatalError( n );
1830 }
1831 
FatalError(SbError _errCode,const String & _details)1832 void StarBASIC::FatalError( SbError _errCode, const String& _details )
1833 {
1834     if( pINST )
1835         pINST->FatalError( _errCode, _details );
1836 }
1837 
GetErrBasic()1838 SbError StarBASIC::GetErrBasic()
1839 {
1840     if( pINST )
1841         return pINST->GetErr();
1842     else
1843         return 0;
1844 }
1845 
1846 // #66536 Zusatz-Message fuer RTL-Funktion Error zugreifbar machen
GetErrorMsg()1847 String StarBASIC::GetErrorMsg()
1848 {
1849     if( pINST )
1850         return pINST->GetErrorMsg();
1851     else
1852         return String();
1853 }
1854 
GetErl()1855 sal_uInt16 StarBASIC::GetErl()
1856 {
1857     if( pINST )
1858         return pINST->GetErl();
1859     else
1860         return 0;
1861 }
1862 
ErrorHdl()1863 sal_Bool __EXPORT StarBASIC::ErrorHdl()
1864 {
1865     return (sal_Bool) ( aErrorHdl.IsSet()
1866         ? aErrorHdl.Call( this ) : sal_False );
1867 }
1868 
GetGlobalErrorHdl()1869 Link StarBASIC::GetGlobalErrorHdl()
1870 {
1871     return GetSbData()->aErrHdl;
1872 }
1873 
SetGlobalErrorHdl(const Link & rLink)1874 void StarBASIC::SetGlobalErrorHdl( const Link& rLink )
1875 {
1876     GetSbData()->aErrHdl = rLink;
1877 }
1878 
1879 
GetGlobalBreakHdl()1880 Link StarBASIC::GetGlobalBreakHdl()
1881 {
1882     return GetSbData()->aBreakHdl;
1883 }
1884 
SetGlobalBreakHdl(const Link & rLink)1885 void StarBASIC::SetGlobalBreakHdl( const Link& rLink )
1886 {
1887     GetSbData()->aBreakHdl = rLink;
1888 }
1889 
getUnoListeners(void)1890 SbxArrayRef StarBASIC::getUnoListeners( void )
1891 {
1892     if( !xUnoListeners.Is() )
1893         xUnoListeners = new SbxArray();
1894     return xUnoListeners;
1895 }
1896 
1897 
1898 /**************************************************************************
1899 *
1900 *   Laden und Speichern
1901 *
1902 **************************************************************************/
1903 
LoadData(SvStream & r,sal_uInt16 nVer)1904 sal_Bool StarBASIC::LoadData( SvStream& r, sal_uInt16 nVer )
1905 {
1906     if( !SbxObject::LoadData( r, nVer ) )
1907         return sal_False;
1908 
1909     // #95459 Delete dialogs, otherwise endless recursion
1910     // in SbxVarable::GetType() if dialogs are accessed
1911     sal_uInt16 nObjCount = pObjs->Count();
1912     SbxVariable** ppDeleteTab = new SbxVariable*[ nObjCount ];
1913     sal_uInt16 nObj;
1914 
1915     for( nObj = 0 ; nObj < nObjCount ; nObj++ )
1916     {
1917         SbxVariable* pVar = pObjs->Get( nObj );
1918         StarBASIC* pBasic = PTR_CAST( StarBASIC, pVar );
1919         ppDeleteTab[nObj] = pBasic ? NULL : pVar;
1920     }
1921     for( nObj = 0 ; nObj < nObjCount ; nObj++ )
1922     {
1923         SbxVariable* pVar = ppDeleteTab[nObj];
1924         if( pVar )
1925             pObjs->Remove( pVar );
1926     }
1927     delete[] ppDeleteTab;
1928 
1929     sal_uInt16 nMod;
1930     pModules->Clear();
1931     r >> nMod;
1932     for( sal_uInt16 i = 0; i < nMod; i++ )
1933     {
1934         SbModule* pMod = (SbModule*) SbxBase::Load( r );
1935         if( !pMod )
1936             return sal_False;
1937         else if( pMod->ISA(SbJScriptModule) )
1938         {
1939             // Ref zuweisen, damit pMod deleted wird
1940             SbModuleRef xRef = pMod;
1941         }
1942         else
1943         {
1944             pMod->SetParent( this );
1945             pModules->Put( pMod, i );
1946         }
1947     }
1948     // HACK fuer SFX-Mist!
1949     SbxVariable* p = Find( String( RTL_CONSTASCII_USTRINGPARAM("FALSE") ), SbxCLASS_PROPERTY );
1950     if( p )
1951         Remove( p );
1952     p = Find( String( RTL_CONSTASCII_USTRINGPARAM("TRUE") ), SbxCLASS_PROPERTY );
1953     if( p )
1954         Remove( p );
1955     // Ende des Hacks!
1956     // Suche ueber StarBASIC ist immer global
1957     DBG_ASSERT( IsSet( SBX_GBLSEARCH ), "Basic ohne GBLSEARCH geladen" );
1958     SetFlag( SBX_GBLSEARCH );
1959     return sal_True;
1960 }
1961 
StoreData(SvStream & r) const1962 sal_Bool StarBASIC::StoreData( SvStream& r ) const
1963 {
1964     if( !SbxObject::StoreData( r ) )
1965         return sal_False;
1966     r << (sal_uInt16) pModules->Count();
1967     for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1968     {
1969         SbModule* p = (SbModule*) pModules->Get( i );
1970         if( !p->Store( r ) )
1971             return sal_False;
1972     }
1973     return sal_True;
1974 }
1975 
LoadOldModules(SvStream &)1976 sal_Bool StarBASIC::LoadOldModules( SvStream& )
1977 {
1978     return sal_False;
1979 }
1980 
GetUNOConstant(const sal_Char * _pAsciiName,::com::sun::star::uno::Any & aOut)1981 bool StarBASIC::GetUNOConstant( const sal_Char* _pAsciiName, ::com::sun::star::uno::Any& aOut )
1982 {
1983     bool bRes = false;
1984     ::rtl::OUString sVarName( ::rtl::OUString::createFromAscii( _pAsciiName ) );
1985     SbUnoObject* pGlobs = dynamic_cast<SbUnoObject*>( Find( sVarName, SbxCLASS_DONTCARE ) );
1986     if ( pGlobs )
1987     {
1988         aOut = pGlobs->getUnoAny();
1989         bRes = true;
1990     }
1991     return bRes;
1992 }
1993 
GetModelFromBasic(SbxObject * pBasic)1994 Reference< frame::XModel > StarBASIC::GetModelFromBasic( SbxObject* pBasic )
1995 {
1996     OSL_PRECOND( pBasic != NULL, "getModelFromBasic: illegal call!" );
1997     if ( !pBasic )
1998         return NULL;
1999 
2000     // look for the ThisComponent variable, first in the parent (which
2001     // might be the document's Basic), then in the parent's parent (which might be
2002     // the application Basic)
2003     const ::rtl::OUString sThisComponent( RTL_CONSTASCII_USTRINGPARAM( "ThisComponent" ) );
2004     SbxVariable* pThisComponent = NULL;
2005 
2006     SbxObject* pLookup = pBasic->GetParent();
2007     while ( pLookup && !pThisComponent )
2008     {
2009         pThisComponent = pLookup->Find( sThisComponent, SbxCLASS_OBJECT );
2010         pLookup = pLookup->GetParent();
2011     }
2012     if ( !pThisComponent )
2013     {
2014         OSL_TRACE("Failed to get ThisComponent");
2015             // the application Basic, at the latest, should have this variable
2016         return NULL;
2017     }
2018 
2019     Any aThisComponentAny( sbxToUnoValue( pThisComponent ) );
2020     Reference< frame::XModel > xModel( aThisComponentAny, UNO_QUERY );
2021     if ( !xModel.is() )
2022     {
2023         // it's no XModel. Okay, ThisComponent nowadays is allowed to be a controller.
2024         Reference< frame::XController > xController( aThisComponentAny, UNO_QUERY );
2025         if ( xController.is() )
2026             xModel = xController->getModel();
2027     }
2028 
2029     if ( !xModel.is() )
2030         return NULL;
2031 
2032 #if OSL_DEBUG_LEVEL > 0
2033     OSL_TRACE("Have model ThisComponent points to url %s",
2034         ::rtl::OUStringToOString( xModel->getURL(),
2035             RTL_TEXTENCODING_ASCII_US ).pData->buffer );
2036 #endif
2037 
2038     return xModel;
2039 }
2040 
2041 
2042 //========================================================================
2043 // #118116 Implementation Collection object
2044 
2045 TYPEINIT1(BasicCollection,SbxObject)
2046 
2047 static const char pCountStr[]   = "Count";
2048 static const char pAddStr[]     = "Add";
2049 static const char pItemStr[]    = "Item";
2050 static const char pRemoveStr[]  = "Remove";
2051 static sal_uInt16 nCountHash = 0, nAddHash, nItemHash, nRemoveHash;
2052 
2053 SbxInfoRef BasicCollection::xAddInfo = NULL;
2054 SbxInfoRef BasicCollection::xItemInfo = NULL;
2055 
2056 // Items may share a name (an item added without a key keeps the name of the
2057 // variable it was copied from), so each name maps to all of its holders.
2058 class CollectionNameMap : public
2059     std::hash_map< ::rtl::OUString, std::vector< SbxVariable* >,
2060         ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > >
2061 {};
2062 
2063 // Matches EqualsIgnoreCaseAscii: only ASCII letters are folded
lcl_foldCollectionName(const String & rName)2064 static ::rtl::OUString lcl_foldCollectionName( const String& rName )
2065 {
2066     return ::rtl::OUString( rName ).toAsciiUpperCase();
2067 }
2068 
BasicCollection(const XubString & rClass)2069 BasicCollection::BasicCollection( const XubString& rClass )
2070              : SbxObject( rClass ), mpNameMap( new CollectionNameMap )
2071 {
2072     if( !nCountHash )
2073     {
2074         nCountHash  = MakeHashCode( String::CreateFromAscii( pCountStr ) );
2075         nAddHash    = MakeHashCode( String::CreateFromAscii( pAddStr ) );
2076         nItemHash   = MakeHashCode( String::CreateFromAscii( pItemStr ) );
2077         nRemoveHash = MakeHashCode( String::CreateFromAscii( pRemoveStr ) );
2078     }
2079     Initialize();
2080 
2081 }
2082 
~BasicCollection()2083 BasicCollection::~BasicCollection()
2084 {
2085     delete mpNameMap;
2086 }
2087 
Clear()2088 void BasicCollection::Clear()
2089 {
2090     SbxObject::Clear();
2091     Initialize();
2092 }
2093 
Initialize()2094 void BasicCollection::Initialize()
2095 {
2096     xItemArray = new SbxArray();
2097     mpNameMap->clear();
2098     SetType( SbxOBJECT );
2099     SetFlag( SBX_FIXED );
2100     ResetFlag( SBX_WRITE );
2101     SbxVariable* p;
2102     p = Make( String::CreateFromAscii( pCountStr ), SbxCLASS_PROPERTY, SbxINTEGER );
2103     p->ResetFlag( SBX_WRITE );
2104     p->SetFlag( SBX_DONTSTORE );
2105     p = Make( String::CreateFromAscii( pAddStr ), SbxCLASS_METHOD, SbxEMPTY );
2106     p->SetFlag( SBX_DONTSTORE );
2107     p = Make( String::CreateFromAscii( pItemStr ), SbxCLASS_METHOD, SbxVARIANT );
2108     p->SetFlag( SBX_DONTSTORE );
2109     p = Make( String::CreateFromAscii( pRemoveStr ), SbxCLASS_METHOD, SbxEMPTY );
2110     p->SetFlag( SBX_DONTSTORE );
2111     if ( !xAddInfo.Is() )
2112     {
2113         xAddInfo = new SbxInfo;
2114         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Item") ), SbxVARIANT, SBX_READ );
2115         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Key") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL );
2116         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Before") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL );
2117         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("After") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL );
2118     }
2119     if ( !xItemInfo.Is() )
2120     {
2121         xItemInfo = new SbxInfo;
2122         xItemInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Index") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL);
2123     }
2124 }
2125 
Find(const XubString & rName,SbxClassType t)2126 SbxVariable* BasicCollection::Find( const XubString& rName, SbxClassType t )
2127 {
2128     SbxVariable* pFind = SbxObject::Find( rName, t );
2129     return pFind;
2130 }
2131 
SFX_NOTIFY(SfxBroadcaster & rCst,const TypeId & rId1,const SfxHint & rHint,const TypeId & rId2)2132 void BasicCollection::SFX_NOTIFY( SfxBroadcaster& rCst, const TypeId& rId1,
2133                                 const SfxHint& rHint, const TypeId& rId2 )
2134 {
2135     const SbxHint* p = PTR_CAST(SbxHint,&rHint);
2136     if( p )
2137     {
2138         sal_uIntPtr nId = p->GetId();
2139         sal_Bool bRead  = sal_Bool( nId == SBX_HINT_DATAWANTED );
2140         sal_Bool bWrite = sal_Bool( nId == SBX_HINT_DATACHANGED );
2141         sal_Bool bRequestInfo = sal_Bool( nId == SBX_HINT_INFOWANTED );
2142         SbxVariable* pVar = p->GetVar();
2143         SbxArray* pArg = pVar->GetParameters();
2144         XubString aVarName( pVar->GetName() );
2145         if( bRead || bWrite )
2146         {
2147             if( pVar->GetHashCode() == nCountHash
2148                   && aVarName.EqualsIgnoreCaseAscii( pCountStr ) )
2149                 pVar->PutLong( xItemArray->Count32() );
2150             else if( pVar->GetHashCode() == nAddHash
2151                   && aVarName.EqualsIgnoreCaseAscii( pAddStr ) )
2152                 CollAdd( pArg );
2153             else if( pVar->GetHashCode() == nItemHash
2154                   && aVarName.EqualsIgnoreCaseAscii( pItemStr ) )
2155                 CollItem( pArg );
2156             else if( pVar->GetHashCode() == nRemoveHash
2157                   && aVarName.EqualsIgnoreCaseAscii( pRemoveStr ) )
2158                 CollRemove( pArg );
2159             else
2160                 SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
2161             return;
2162         }
2163         else if ( bRequestInfo )
2164         {
2165             if( pVar->GetHashCode() == nAddHash
2166                   && aVarName.EqualsIgnoreCaseAscii( pAddStr ) )
2167                 pVar->SetInfo( xAddInfo );
2168             else if( pVar->GetHashCode() == nItemHash
2169                   && aVarName.EqualsIgnoreCaseAscii( pItemStr ) )
2170                 pVar->SetInfo( xItemInfo );
2171         }
2172     }
2173     SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
2174 }
2175 
implGetIndex(SbxVariable * pIndexVar)2176 sal_Int32 BasicCollection::implGetIndex( SbxVariable* pIndexVar )
2177 {
2178     sal_Int32 nIndex = -1;
2179     if( pIndexVar->GetType() == SbxSTRING )
2180         nIndex = implGetIndexForName( pIndexVar->GetString() );
2181     else
2182         nIndex = pIndexVar->GetLong() - 1;
2183     return nIndex;
2184 }
2185 
implRegisterName(SbxVariable * pVar)2186 void BasicCollection::implRegisterName( SbxVariable* pVar )
2187 {
2188     // Nameless items are never found by name, see implFindByName
2189     if( pVar->GetName().Len() )
2190         (*mpNameMap)[ lcl_foldCollectionName( pVar->GetName() ) ].push_back( pVar );
2191 }
2192 
implUnregisterName(SbxVariable * pVar)2193 void BasicCollection::implUnregisterName( SbxVariable* pVar )
2194 {
2195     if( !pVar->GetName().Len() )
2196         return;
2197     CollectionNameMap::iterator it = mpNameMap->find( lcl_foldCollectionName( pVar->GetName() ) );
2198     if( it == mpNameMap->end() )
2199         return;
2200     std::vector< SbxVariable* >& rVars = it->second;
2201     rVars.erase( std::remove( rVars.begin(), rVars.end(), pVar ), rVars.end() );
2202     if( rVars.empty() )
2203         mpNameMap->erase( it );
2204 }
2205 
2206 // Returns the item with the lowest index that has the given name
implFindByName(const String & rName)2207 SbxVariable* BasicCollection::implFindByName( const String& rName )
2208 {
2209     sal_Int32 nCount = xItemArray->Count32();
2210     if( !rName.Len() )
2211     {
2212         // Nameless items are not indexed
2213         for( sal_Int32 i = 0 ; i < nCount ; i++ )
2214         {
2215             SbxVariable* pVar = xItemArray->Get32( i );
2216             if( !pVar->GetName().Len() )
2217                 return pVar;
2218         }
2219         return NULL;
2220     }
2221 
2222     CollectionNameMap::iterator it = mpNameMap->find( lcl_foldCollectionName( rName ) );
2223     if( it == mpNameMap->end() )
2224         return NULL;
2225     std::vector< SbxVariable* >& rVars = it->second;
2226     if( rVars.size() == 1 )
2227         return rVars[0];
2228     for( sal_Int32 i = 0 ; i < nCount ; i++ )
2229     {
2230         SbxVariable* pVar = xItemArray->Get32( i );
2231         if( std::find( rVars.begin(), rVars.end(), pVar ) != rVars.end() )
2232             return pVar;
2233     }
2234     return NULL;
2235 }
2236 
implGetIndexForName(const String & rName)2237 sal_Int32 BasicCollection::implGetIndexForName( const String& rName )
2238 {
2239     SbxVariable* pFound = implFindByName( rName );
2240     if( !pFound )
2241         return -1;
2242     sal_Int32 nCount = xItemArray->Count32();
2243     for( sal_Int32 i = 0 ; i < nCount ; i++ )
2244     {
2245         if( xItemArray->Get32( i ) == pFound )
2246             return i;
2247     }
2248     return -1;
2249 }
2250 
CollAdd(SbxArray * pPar_)2251 void BasicCollection::CollAdd( SbxArray* pPar_ )
2252 {
2253     sal_uInt16 nCount = pPar_->Count();
2254     if( nCount < 2 || nCount > 5 )
2255     {
2256         SetError( SbxERR_WRONG_ARGS );
2257         return;
2258     }
2259 
2260     SbxVariable* pItem = pPar_->Get(1);
2261     if( pItem )
2262     {
2263         int nNextIndex;
2264         if( nCount < 4 )
2265         {
2266             nNextIndex = xItemArray->Count();
2267         }
2268         else
2269         {
2270             SbxVariable* pBefore = pPar_->Get(3);
2271             if( nCount == 5 )
2272             {
2273                 if( !( pBefore->IsErr() || ( pBefore->GetType() == SbxEMPTY ) ) )
2274                 {
2275                     SetError( SbERR_BAD_ARGUMENT );
2276                     return;
2277                 }
2278                 SbxVariable* pAfter = pPar_->Get(4);
2279                 sal_Int32 nAfterIndex = implGetIndex( pAfter );
2280                 if( nAfterIndex == -1 )
2281                 {
2282                     SetError( SbERR_BAD_ARGUMENT );
2283                     return;
2284                 }
2285                 nNextIndex = nAfterIndex + 1;
2286             }
2287             else // if( nCount == 4 )
2288             {
2289                 sal_Int32 nBeforeIndex = implGetIndex( pBefore );
2290                 if( nBeforeIndex == -1 )
2291                 {
2292                     SetError( SbERR_BAD_ARGUMENT );
2293                     return;
2294                 }
2295                 nNextIndex = nBeforeIndex;
2296             }
2297         }
2298 
2299         SbxVariableRef pNewItem = new SbxVariable( *pItem );
2300         if( nCount >= 3 )
2301         {
2302             SbxVariable* pKey = pPar_->Get(2);
2303             if( !( pKey->IsErr() || ( pKey->GetType() == SbxEMPTY ) ) )
2304             {
2305                 if( pKey->GetType() != SbxSTRING )
2306                 {
2307                     SetError( SbERR_BAD_ARGUMENT );
2308                     return;
2309                 }
2310                 String aKey = pKey->GetString();
2311                 if( implGetIndexForName( aKey ) != -1 )
2312                 {
2313                     SetError( SbERR_BAD_ARGUMENT );
2314                     return;
2315                 }
2316                 pNewItem->SetName( aKey );
2317             }
2318         }
2319         pNewItem->SetFlag( SBX_READWRITE );
2320         xItemArray->Insert32( pNewItem, nNextIndex );
2321         implRegisterName( pNewItem );
2322     }
2323     else
2324     {
2325         SetError( SbERR_BAD_ARGUMENT );
2326         return;
2327     }
2328 }
2329 
CollItem(SbxArray * pPar_)2330 void BasicCollection::CollItem( SbxArray* pPar_ )
2331 {
2332     if( pPar_->Count() != 2 )
2333     {
2334         SetError( SbxERR_WRONG_ARGS );
2335         return;
2336     }
2337     SbxVariable* pRes = NULL;
2338     SbxVariable* p = pPar_->Get( 1 );
2339     if( p->GetType() == SbxSTRING )
2340     {
2341         pRes = implFindByName( p->GetString() );
2342     }
2343     else
2344     {
2345         sal_Int32 nIndex = implGetIndex( p );
2346         if( nIndex >= 0 && nIndex < (sal_Int32)xItemArray->Count32() )
2347             pRes = xItemArray->Get32( nIndex );
2348     }
2349     if( !pRes )
2350         SetError( SbERR_BAD_ARGUMENT );
2351     else
2352         *(pPar_->Get(0)) = *pRes;
2353 }
2354 
CollRemove(SbxArray * pPar_)2355 void BasicCollection::CollRemove( SbxArray* pPar_ )
2356 {
2357     if( pPar_ == NULL || pPar_->Count() != 2 )
2358     {
2359         SetError( SbxERR_WRONG_ARGS );
2360         return;
2361     }
2362 
2363     SbxVariable* p = pPar_->Get( 1 );
2364     sal_Int32 nIndex = implGetIndex( p );
2365     if( nIndex >= 0 && nIndex < (sal_Int32)xItemArray->Count32() )
2366     {
2367         implUnregisterName( xItemArray->Get32( nIndex ) );
2368         xItemArray->Remove32( nIndex );
2369 
2370         // Correct for stack if necessary
2371         SbiInstance* pInst = pINST;
2372         SbiRuntime* pRT = pInst ? pInst->pRun : NULL;
2373         if( pRT )
2374         {
2375             SbiForStack* pStack = pRT->FindForStackItemForCollection( this );
2376             if( pStack != NULL )
2377             {
2378                 if( pStack->nCurCollectionIndex >= nIndex )
2379                     --pStack->nCurCollectionIndex;
2380             }
2381         }
2382     }
2383     else
2384         SetError( SbERR_BAD_ARGUMENT );
2385 }
2386