xref: /trunk/main/basic/source/classes/sb.cxx (revision f6c78b21b9451944eb43023c08ad1a3c8ad54ae4)
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 <unordered_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( "Scripting.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     else
453     if( rClass.EqualsIgnoreCaseAscii( "Scripting.Dictionary" ) )
454     {
455         try
456         {
457             Reference< XMultiServiceFactory > xFactory( comphelper::getProcessServiceFactory(), UNO_SET_THROW );
458             ::rtl::OUString aServiceName( RTL_CONSTASCII_USTRINGPARAM( "ooo.vba.scripting.Dictionary" ) );
459             Reference< XInterface > xInterface( xFactory->createInstance( aServiceName ), UNO_SET_THROW );
460             return new SbUnoObject( aServiceName, uno::makeAny( xInterface ) );
461         }
462         catch( Exception& )
463         {}
464     }
465 
466     return NULL;
467 }
468 
469 
470 // Factory class to create OLE objects
471 class SbOLEFactory : public SbxFactory
472 {
473 public:
474     virtual SbxBase* Create( sal_uInt16 nSbxId, sal_uInt32 = SBXCR_SBX );
475     virtual SbxObject* CreateObject( const String& );
476 };
477 
Create(sal_uInt16,sal_uInt32)478 SbxBase* SbOLEFactory::Create( sal_uInt16, sal_uInt32 )
479 {
480     // Not supported
481     return NULL;
482 }
483 
484 SbUnoObject* createOLEObject_Impl( const String& aType );   // sbunoobj.cxx
485 
CreateObject(const String & rClassName)486 SbxObject* SbOLEFactory::CreateObject( const String& rClassName )
487 {
488     SbxObject* pRet = createOLEObject_Impl( rClassName );
489     return pRet;
490 }
491 
492 
493 //========================================================================
494 // SbFormFactory, show user forms by: dim as new <user form name>
495 
496 class SbFormFactory : public SbxFactory
497 {
498 public:
499     virtual SbxBase* Create( sal_uInt16 nSbxId, sal_uInt32 = SBXCR_SBX );
500     virtual SbxObject* CreateObject( const String& );
501 };
502 
Create(sal_uInt16,sal_uInt32)503 SbxBase* SbFormFactory::Create( sal_uInt16, sal_uInt32 )
504 {
505     // Not supported
506     return NULL;
507 }
508 
CreateObject(const String & rClassName)509 SbxObject* SbFormFactory::CreateObject( const String& rClassName )
510 {
511     if( SbModule* pMod = pMOD )
512     {
513         if( SbxVariable* pVar = pMod->Find( rClassName, SbxCLASS_OBJECT ) )
514         {
515             if( SbUserFormModule* pFormModule = PTR_CAST( SbUserFormModule, pVar->GetObject() ) )
516             {
517                 bool bInitState = pFormModule->getInitState();
518                 if( bInitState )
519                 {
520                     // Not the first instantiate, reset
521                     bool bTriggerTerminateEvent = false;
522                     pFormModule->ResetApiObj( bTriggerTerminateEvent );
523                     pFormModule->setInitState( false );
524                 }
525                 else
526                 {
527                     pFormModule->Load();
528                 }
529                 return pFormModule->CreateInstance();
530             }
531         }
532     }
533     return 0;
534 }
535 
536 
537 //========================================================================
538 // SbTypeFactory
539 
cloneTypeObjectImpl(const SbxObject & rTypeObj)540 SbxObject* cloneTypeObjectImpl( const SbxObject& rTypeObj )
541 {
542     SbxObject* pRet = new SbxObject( rTypeObj );
543     pRet->PutObject( pRet );
544 
545     // Copy the properties, not only the reference to them
546     SbxArray* pProps = pRet->GetProperties();
547     sal_uInt32 nCount = pProps->Count32();
548     for( sal_uInt32 i = 0 ; i < nCount ; i++ )
549     {
550         SbxVariable* pVar = pProps->Get32( i );
551         SbxProperty* pProp = PTR_CAST( SbxProperty, pVar );
552         if( pProp )
553         {
554             SbxProperty* pNewProp = new SbxProperty( *pProp );
555             SbxDataType eVarType = pVar->GetType();
556             if( eVarType & SbxARRAY )
557             {
558                 SbxBase* pParObj = pVar->GetObject();
559                 SbxDimArray* pSource = PTR_CAST(SbxDimArray,pParObj);
560                 SbxDimArray* pDest = new SbxDimArray( pVar->GetType() );
561                 sal_Int32 lb = 0;
562                 sal_Int32 ub = 0;
563 
564                 pDest->setHasFixedSize( pSource->hasFixedSize() );
565                 if ( pSource->GetDims() && pSource->hasFixedSize() )
566                 {
567                     for ( sal_Int32 j = 1 ; j <= pSource->GetDims(); ++j )
568                     {
569                         pSource->GetDim32( (sal_Int32)j, lb, ub );
570                         pDest->AddDim32( lb, ub );
571                     }
572                 }
573                 else
574                     pDest->unoAddDim( 0, -1 ); // variant array
575 
576                 sal_uInt16 nSavFlags = pVar->GetFlags();
577                 pNewProp->ResetFlag( SBX_FIXED );
578                 // need to reset the FIXED flag
579                 // when calling PutObject ( because the type will not match Object )
580                 pNewProp->PutObject( pDest );
581                 pNewProp->SetFlags( nSavFlags );
582             }
583             if( eVarType == SbxOBJECT )
584             {
585                 SbxBase* pObjBase = pVar->GetObject();
586                 SbxObject* pSrcObj = PTR_CAST(SbxObject,pObjBase);
587                 SbxObject* pDestObj = NULL;
588                 if( pSrcObj != NULL )
589                     pDestObj = cloneTypeObjectImpl( *pSrcObj );
590                 pNewProp->PutObject( pDestObj );
591             }
592             pProps->PutDirect( pNewProp, i );
593         }
594     }
595     return pRet;
596 }
597 
598 // Factory class to create user defined objects (type command)
599 class SbTypeFactory : public SbxFactory
600 {
601 public:
602     virtual SbxBase* Create( sal_uInt16 nSbxId, sal_uInt32 = SBXCR_SBX );
603     virtual SbxObject* CreateObject( const String& );
604 };
605 
Create(sal_uInt16,sal_uInt32)606 SbxBase* SbTypeFactory::Create( sal_uInt16, sal_uInt32 )
607 {
608     // Not supported
609     return NULL;
610 }
611 
CreateObject(const String & rClassName)612 SbxObject* SbTypeFactory::CreateObject( const String& rClassName )
613 {
614     SbxObject* pRet = NULL;
615     SbModule* pMod = pMOD;
616     if( pMod )
617     {
618         const SbxObject* pObj = pMod->FindType( rClassName );
619         if( pObj )
620             pRet = cloneTypeObjectImpl( *pObj );
621     }
622     return pRet;
623 }
624 
createUserTypeImpl(const String & rClassName)625 SbxObject* createUserTypeImpl( const String& rClassName )
626 {
627     SbxObject* pRetObj = pTYPEFAC->CreateObject( rClassName );
628     return pRetObj;
629 }
630 
631 
TYPEINIT1(SbClassModuleObject,SbModule)632 TYPEINIT1(SbClassModuleObject,SbModule)
633 
634 SbClassModuleObject::SbClassModuleObject( SbModule* pClassModule )
635     : SbModule( pClassModule->GetName() )
636     , mpClassModule( pClassModule )
637     , mbInitializeEventDone( false )
638 {
639     aOUSource = pClassModule->aOUSource;
640     aComment = pClassModule->aComment;
641     pImage = pClassModule->pImage;
642     pBreaks = pClassModule->pBreaks;
643 
644     SetClassName( pClassModule->GetName() );
645 
646     // Allow search only internally
647     ResetFlag( SBX_GBLSEARCH );
648 
649     // Copy the methods from original class module
650     SbxArray* pClassMethods = pClassModule->GetMethods();
651     sal_uInt32 nMethodCount = pClassMethods->Count32();
652     sal_uInt32 i;
653     for( i = 0 ; i < nMethodCount ; i++ )
654     {
655         SbxVariable* pVar = pClassMethods->Get32( i );
656 
657         // Exclude SbIfaceMapperMethod to copy them in a second step
658         SbIfaceMapperMethod* pIfaceMethod = PTR_CAST( SbIfaceMapperMethod, pVar );
659         if( !pIfaceMethod )
660         {
661             SbMethod* pMethod = PTR_CAST(SbMethod, pVar );
662             if( pMethod )
663             {
664                 sal_uInt16 nFlags_ = pMethod->GetFlags();
665                 pMethod->SetFlag( SBX_NO_BROADCAST );
666                 SbMethod* pNewMethod = new SbMethod( *pMethod );
667                 pNewMethod->ResetFlag( SBX_NO_BROADCAST );
668                 pMethod->SetFlags( nFlags_ );
669                 pNewMethod->pMod = this;
670                 pNewMethod->SetParent( this );
671                 pMethods->PutDirect( pNewMethod, i );
672                 StartListening( pNewMethod->GetBroadcaster(), sal_True );
673             }
674         }
675     }
676 
677     // Copy SbIfaceMapperMethod in a second step to ensure that
678     // the corresponding base methods have already been copied
679     for( i = 0 ; i < nMethodCount ; i++ )
680     {
681         SbxVariable* pVar = pClassMethods->Get32( i );
682 
683         SbIfaceMapperMethod* pIfaceMethod = PTR_CAST( SbIfaceMapperMethod, pVar );
684         if( pIfaceMethod )
685         {
686             SbMethod* pImplMethod = pIfaceMethod->getImplMethod();
687             if( !pImplMethod )
688             {
689                 DBG_ERROR( "No ImplMethod" );
690                 continue;
691             }
692 
693             // Search for own copy of ImplMethod
694             String aImplMethodName = pImplMethod->GetName();
695             SbxVariable* p = pMethods->Find( aImplMethodName, SbxCLASS_METHOD );
696             SbMethod* pImplMethodCopy = p ? PTR_CAST(SbMethod,p) : NULL;
697             if( !pImplMethodCopy )
698             {
699                 DBG_ERROR( "Found no ImplMethod copy" );
700                 continue;
701             }
702             SbIfaceMapperMethod* pNewIfaceMethod =
703                 new SbIfaceMapperMethod( pIfaceMethod->GetName(), pImplMethodCopy );
704             pMethods->PutDirect( pNewIfaceMethod, i );
705         }
706     }
707 
708     // Copy the properties from original class module
709     SbxArray* pClassProps = pClassModule->GetProperties();
710     sal_uInt32 nPropertyCount = pClassProps->Count32();
711     for( i = 0 ; i < nPropertyCount ; i++ )
712     {
713         SbxVariable* pVar = pClassProps->Get32( i );
714         SbProcedureProperty* pProcedureProp = PTR_CAST( SbProcedureProperty, pVar );
715         if( pProcedureProp )
716         {
717             sal_uInt16 nFlags_ = pProcedureProp->GetFlags();
718             pProcedureProp->SetFlag( SBX_NO_BROADCAST );
719             SbProcedureProperty* pNewProp = new SbProcedureProperty
720                 ( pProcedureProp->GetName(), pProcedureProp->GetType() );
721                 // ( pProcedureProp->GetName(), pProcedureProp->GetType(), this );
722             pNewProp->SetFlags( nFlags_ ); // Copy flags
723             pNewProp->ResetFlag( SBX_NO_BROADCAST ); // except the Broadcast if it was set
724             pProcedureProp->SetFlags( nFlags_ );
725             pProps->PutDirect( pNewProp, i );
726             StartListening( pNewProp->GetBroadcaster(), sal_True );
727         }
728         else
729         {
730             SbxProperty* pProp = PTR_CAST( SbxProperty, pVar );
731             if( pProp )
732             {
733                 sal_uInt16 nFlags_ = pProp->GetFlags();
734                 pProp->SetFlag( SBX_NO_BROADCAST );
735                 SbxProperty* pNewProp = new SbxProperty( *pProp );
736 
737                 // Special handling for modules instances and collections, they need
738                 // to be instantiated, otherwise all refer to the same base object
739                 SbxDataType eVarType = pProp->GetType();
740                 if( eVarType == SbxOBJECT )
741                 {
742                     SbxBase* pObjBase = pProp->GetObject();
743                     SbxObject* pObj = PTR_CAST(SbxObject,pObjBase);
744                     if( pObj != NULL )
745                     {
746                         String aObjClass = pObj->GetClassName();
747 
748                         SbClassModuleObject* pClassModuleObj = PTR_CAST(SbClassModuleObject,pObjBase);
749                         if( pClassModuleObj != NULL )
750                         {
751                             SbModule* pLclClassModule = pClassModuleObj->getClassModule();
752                             SbClassModuleObject* pNewObj = new SbClassModuleObject( pLclClassModule );
753                             pNewObj->SetName( pProp->GetName() );
754                             pNewObj->SetParent( pLclClassModule->pParent );
755                             pNewProp->PutObject( pNewObj );
756                         }
757                         else if( aObjClass.EqualsIgnoreCaseAscii( "Collection" ) )
758                         {
759                             String aCollectionName( RTL_CONSTASCII_USTRINGPARAM("Collection") );
760                             BasicCollection* pNewCollection = new BasicCollection( aCollectionName );
761                             pNewCollection->SetName( pProp->GetName() );
762                             pNewCollection->SetParent( pClassModule->pParent );
763                             pNewProp->PutObject( pNewCollection );
764                         }
765                     }
766                 }
767 
768                 pNewProp->ResetFlag( SBX_NO_BROADCAST );
769                 pNewProp->SetParent( this );
770                 pProps->PutDirect( pNewProp, i );
771                 pProp->SetFlags( nFlags_ );
772             }
773         }
774     }
775     SetModuleType( ModuleType::CLASS );
776     mbVBACompat = pClassModule->mbVBACompat;
777 }
778 
~SbClassModuleObject()779 SbClassModuleObject::~SbClassModuleObject()
780 {
781     // do not trigger termination event when document is already closed
782     if( StarBASIC::IsRunning() )
783         if( StarBASIC* pDocBasic = lclGetDocBasicForModule( this ) )
784             if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) )
785                 if( !pDocBasicItem->isDocClosed() )
786                     triggerTerminateEvent();
787 
788     // Must be deleted by base class dtor because this data
789     // is not owned by the SbClassModuleObject object
790     pImage = NULL;
791     pBreaks = NULL;
792 }
793 
SFX_NOTIFY(SfxBroadcaster & rBC,const TypeId & rBCType,const SfxHint & rHint,const TypeId & rHintType)794 void SbClassModuleObject::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
795                            const SfxHint& rHint, const TypeId& rHintType )
796 {
797     handleProcedureProperties( rBC, rHint );
798 }
799 
Find(const XubString & rName,SbxClassType t)800 SbxVariable* SbClassModuleObject::Find( const XubString& rName, SbxClassType t )
801 {
802     SbxVariable* pRes = SbxObject::Find( rName, t );
803     if( pRes )
804     {
805         triggerInitializeEvent();
806 
807         SbIfaceMapperMethod* pIfaceMapperMethod = PTR_CAST(SbIfaceMapperMethod,pRes);
808         if( pIfaceMapperMethod )
809         {
810             pRes = pIfaceMapperMethod->getImplMethod();
811             pRes->SetFlag( SBX_EXTFOUND );
812         }
813     }
814     return pRes;
815 }
816 
triggerInitializeEvent(void)817 void SbClassModuleObject::triggerInitializeEvent( void )
818 {
819     static String aInitMethodName( RTL_CONSTASCII_USTRINGPARAM("Class_Initialize") );
820 
821     if( mbInitializeEventDone )
822         return;
823 
824     mbInitializeEventDone = true;
825 
826     // Search method
827     SbxVariable* pMeth = SbxObject::Find( aInitMethodName, SbxCLASS_METHOD );
828     if( pMeth )
829     {
830         SbxValues aVals;
831         pMeth->Get( aVals );
832     }
833 }
834 
triggerTerminateEvent(void)835 void SbClassModuleObject::triggerTerminateEvent( void )
836 {
837     static String aTermMethodName( RTL_CONSTASCII_USTRINGPARAM("Class_Terminate") );
838 
839     if( !mbInitializeEventDone || GetSbData()->bRunInit )
840         return;
841 
842     // Search method
843     SbxVariable* pMeth = SbxObject::Find( aTermMethodName, SbxCLASS_METHOD );
844     if( pMeth )
845     {
846         SbxValues aVals;
847         pMeth->Get( aVals );
848     }
849 }
850 
851 
SbClassData(void)852 SbClassData::SbClassData( void )
853 {
854     mxIfaces = new SbxArray();
855 }
856 
clear(void)857 void SbClassData::clear( void )
858 {
859     mxIfaces->Clear();
860     maRequiredTypes.clear();
861 }
862 
SbClassFactory(void)863 SbClassFactory::SbClassFactory( void )
864 {
865     String aDummyName;
866     xClassModules = new SbxObject( aDummyName );
867 }
868 
~SbClassFactory()869 SbClassFactory::~SbClassFactory()
870 {}
871 
AddClassModule(SbModule * pClassModule)872 void SbClassFactory::AddClassModule( SbModule* pClassModule )
873 {
874     SbxObjectRef xToUseClassModules = xClassModules;
875 
876     if( StarBASIC* pDocBasic = lclGetDocBasicForModule( pClassModule ) )
877         if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) )
878             xToUseClassModules = pDocBasicItem->getClassModules();
879 
880     SbxObject* pParent = pClassModule->GetParent();
881     xToUseClassModules->Insert( pClassModule );
882     pClassModule->SetParent( pParent );
883 }
884 
RemoveClassModule(SbModule * pClassModule)885 void SbClassFactory::RemoveClassModule( SbModule* pClassModule )
886 {
887     xClassModules->Remove( pClassModule );
888 }
889 
Create(sal_uInt16,sal_uInt32)890 SbxBase* SbClassFactory::Create( sal_uInt16, sal_uInt32 )
891 {
892     // Not supported
893     return NULL;
894 }
895 
CreateObject(const String & rClassName)896 SbxObject* SbClassFactory::CreateObject( const String& rClassName )
897 {
898     SbxObjectRef xToUseClassModules = xClassModules;
899 
900     if( SbModule* pMod = pMOD )
901         if( StarBASIC* pDocBasic = lclGetDocBasicForModule( pMod ) )
902             if( const DocBasicItem* pDocBasicItem = lclFindDocBasicItem( pDocBasic ) )
903                 xToUseClassModules = pDocBasicItem->getClassModules();
904 
905     SbxVariable* pVar = xToUseClassModules->Find( rClassName, SbxCLASS_OBJECT );
906     SbxObject* pRet = NULL;
907     if( pVar )
908     {
909         SbModule* pVarMod = (SbModule*)pVar;
910         pRet = new SbClassModuleObject( pVarMod );
911     }
912     return pRet;
913 }
914 
FindClass(const String & rClassName)915 SbModule* SbClassFactory::FindClass( const String& rClassName )
916 {
917     SbxVariable* pVar = xClassModules->Find( rClassName, SbxCLASS_DONTCARE );
918     SbModule* pMod = pVar ? (SbModule*)pVar : NULL;
919     return pMod;
920 }
921 
StarBASIC(StarBASIC * p,sal_Bool bIsDocBasic)922 StarBASIC::StarBASIC( StarBASIC* p, sal_Bool bIsDocBasic  )
923     : SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("StarBASIC") ) ), bDocBasic( bIsDocBasic )
924 {
925     SetParent( p );
926     pLibInfo = NULL;
927     bNoRtl = bBreak = sal_False;
928     bVBAEnabled = sal_False;
929     pModules = new SbxArray;
930 
931     if( !GetSbData()->nInst++ )
932     {
933         pSBFAC = new SbiFactory;
934         AddFactory( pSBFAC );
935         pTYPEFAC = new SbTypeFactory;
936         AddFactory( pTYPEFAC );
937         pCLASSFAC = new SbClassFactory;
938         AddFactory( pCLASSFAC );
939         pOLEFAC = new SbOLEFactory;
940         AddFactory( pOLEFAC );
941         pFORMFAC = new SbFormFactory;
942         AddFactory( pFORMFAC );
943         pUNOFAC = new SbUnoFactory;
944         AddFactory( pUNOFAC );
945     }
946     pRtl = new SbiStdObject( String( RTL_CONSTASCII_USTRINGPARAM(RTLNAME) ), this );
947     // Search via StarBasic is always global
948     SetFlag( SBX_GBLSEARCH );
949     pVBAGlobals = NULL;
950     bQuit = sal_False;
951 
952     if( bDocBasic )
953         lclInsertDocBasicItem( *this );
954 }
955 
956 // #51727 Override SetModified so that the modified state
957 // is not given to the parent
SetModified(sal_Bool b)958 void StarBASIC::SetModified( sal_Bool b )
959 {
960     SbxBase::SetModified( b );
961 }
962 
963 extern void lcl_closeTraceFile();
964 
~StarBASIC()965 StarBASIC::~StarBASIC()
966 {
967 #ifdef DBG_TRACE_BASIC
968     lcl_closeTraceFile();
969 #endif
970 
971     // Needs to be first action as it can trigger events
972     disposeComVariablesForBasic( this );
973 
974     if( !--GetSbData()->nInst )
975     {
976         RemoveFactory( pSBFAC );
977         delete pSBFAC; pSBFAC = NULL;
978         RemoveFactory( pUNOFAC );
979         delete pUNOFAC; pUNOFAC = NULL;
980         RemoveFactory( pTYPEFAC );
981         delete pTYPEFAC; pTYPEFAC = NULL;
982         RemoveFactory( pCLASSFAC );
983         delete pCLASSFAC; pCLASSFAC = NULL;
984         RemoveFactory( pOLEFAC );
985         delete pOLEFAC; pOLEFAC = NULL;
986         RemoveFactory( pFORMFAC );
987         delete pFORMFAC; pFORMFAC = NULL;
988 
989 #ifdef DBG_UTIL
990     // There is no need to clean SbiData at program end,
991     // but we dislike MLK's at Purify
992     // TODO: Where else???
993     SbiGlobals** pp = (SbiGlobals**) ::GetAppData( SHL_SBC );
994     SbiGlobals* p = *pp;
995     if( p )
996     {
997         delete p;
998         *pp = 0;
999     }
1000 #endif
1001     }
1002     else if( bDocBasic )
1003     {
1004         SbxError eOld = SbxBase::GetError();
1005 
1006         lclRemoveDocBasicItem( *this );
1007 
1008         SbxBase::ResetError();
1009         if( eOld != SbxERR_OK )
1010             SbxBase::SetError( eOld );
1011     }
1012 
1013     // #100326 Set Parent NULL in registered listeners
1014     if( xUnoListeners.Is() )
1015     {
1016         sal_uInt16 uCount = xUnoListeners->Count();
1017         for( sal_uInt16 i = 0 ; i < uCount ; i++ )
1018         {
1019             SbxVariable* pListenerObj = xUnoListeners->Get( i );
1020             pListenerObj->SetParent( NULL );
1021         }
1022         xUnoListeners = NULL;
1023     }
1024 
1025     clearUnoMethodsForBasic( this );
1026 }
1027 
1028 // Override new() operator, so that everyone can create a new instance
operator new(size_t n)1029 void* StarBASIC::operator new( size_t n )
1030 {
1031     if( n < sizeof( StarBASIC ) )
1032     {
1033 //      DBG_ASSERT( sal_False, "Warnung: inkompatibler BASIC-Stand!" );
1034         n = sizeof( StarBASIC );
1035     }
1036     return ::operator new( n );
1037 }
1038 
operator delete(void * p)1039 void StarBASIC::operator delete( void* p )
1040 {
1041     ::operator delete( p );
1042 }
1043 
implClearDependingVarsOnDelete(StarBASIC * pDeletedBasic)1044 void StarBASIC::implClearDependingVarsOnDelete( StarBASIC* pDeletedBasic )
1045 {
1046     if( this != pDeletedBasic )
1047     {
1048         for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1049         {
1050             SbModule* p = (SbModule*)pModules->Get( i );
1051             p->ClearVarsDependingOnDeletedBasic( pDeletedBasic );
1052         }
1053     }
1054 
1055     for( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ )
1056     {
1057         SbxVariable* pVar = pObjs->Get( nObj );
1058         StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
1059         if( pBasic && pBasic != pDeletedBasic )
1060             pBasic->implClearDependingVarsOnDelete( pDeletedBasic );
1061     }
1062 }
1063 
1064 
1065 /**************************************************************************
1066 *
1067 *    Creation/Management of modules
1068 *
1069 **************************************************************************/
1070 
MakeModule(const String & rName,const String & rSrc)1071 SbModule* StarBASIC::MakeModule( const String& rName, const String& rSrc )
1072 {
1073     return MakeModule32( rName, rSrc );
1074 }
1075 
MakeModule32(const String & rName,const::rtl::OUString & rSrc)1076 SbModule* StarBASIC::MakeModule32( const String& rName, const ::rtl::OUString& rSrc )
1077 {
1078     ModuleInfo mInfo;
1079     mInfo.ModuleType = ModuleType::NORMAL;
1080     return MakeModule32(  rName, mInfo, rSrc );
1081 }
MakeModule32(const String & rName,const ModuleInfo & mInfo,const rtl::OUString & rSrc)1082 SbModule* StarBASIC::MakeModule32( const String& rName, const ModuleInfo& mInfo, const rtl::OUString& rSrc )
1083 {
1084 
1085     OSL_TRACE("create module %s type mInfo %d", rtl::OUStringToOString( rName, RTL_TEXTENCODING_UTF8 ).getStr(), mInfo.ModuleType );
1086     SbModule* p = NULL;
1087     switch ( mInfo.ModuleType )
1088     {
1089         case ModuleType::DOCUMENT:
1090             // In theory we should be able to create Object modules
1091             // in ordinary basic ( in vba mode thought these are create
1092             // by the application/basic and not by the user )
1093             p = new SbObjModule( rName, mInfo, isVBAEnabled() );
1094             break;
1095         case ModuleType::CLASS:
1096             p = new SbModule( rName, isVBAEnabled() );
1097             p->SetModuleType( ModuleType::CLASS );
1098         break;
1099         case ModuleType::FORM:
1100             p = new SbUserFormModule( rName, mInfo, isVBAEnabled() );
1101         break;
1102         default:
1103             p = new SbModule( rName, isVBAEnabled() );
1104 
1105     }
1106     p->SetSource32( rSrc );
1107     p->SetParent( this );
1108     pModules->Insert( p, pModules->Count() );
1109     SetModified( sal_True );
1110     return p;
1111 }
1112 
Insert(SbxVariable * pVar)1113 void StarBASIC::Insert( SbxVariable* pVar )
1114 {
1115     if( pVar->IsA( TYPE(SbModule) ) )
1116     {
1117         pModules->Insert( pVar, pModules->Count() );
1118         pVar->SetParent( this );
1119         StartListening( pVar->GetBroadcaster(), sal_True );
1120     }
1121     else
1122     {
1123         sal_Bool bWasModified = IsModified();
1124         SbxObject::Insert( pVar );
1125         if( !bWasModified && pVar->IsSet( SBX_DONTSTORE ) )
1126             SetModified( sal_False );
1127     }
1128 }
1129 
Remove(SbxVariable * pVar)1130 void StarBASIC::Remove( SbxVariable* pVar )
1131 {
1132     if( pVar->IsA( TYPE(SbModule) ) )
1133     {
1134         // #87540 Can be last reference!
1135         SbxVariableRef xVar = pVar;
1136         pModules->Remove( pVar );
1137         pVar->SetParent( 0 );
1138         EndListening( pVar->GetBroadcaster() );
1139     }
1140     else
1141         SbxObject::Remove( pVar );
1142 }
1143 
Compile(SbModule * pMod)1144 sal_Bool StarBASIC::Compile( SbModule* pMod )
1145 {
1146     return pMod ? pMod->Compile() : sal_False;
1147 }
1148 
Disassemble(SbModule * pMod,String & rText)1149 sal_Bool StarBASIC::Disassemble( SbModule* pMod, String& rText )
1150 {
1151     rText.Erase();
1152     if( pMod )
1153         pMod->Disassemble( rText );
1154     return sal_Bool( rText.Len() != 0 );
1155 }
1156 
Clear()1157 void StarBASIC::Clear()
1158 {
1159     while( pModules->Count() )
1160         pModules->Remove( pModules->Count() - 1 );
1161 }
1162 
FindModule(const String & rName)1163 SbModule* StarBASIC::FindModule( const String& rName )
1164 {
1165     for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1166     {
1167         SbModule* p = (SbModule*) pModules->Get( i );
1168         if( p->GetName().EqualsIgnoreCaseAscii( rName ) )
1169             return p;
1170     }
1171     return NULL;
1172 }
1173 
1174 
1175 struct ClassModuleRunInitItem
1176 {
1177     SbModule*       m_pModule;
1178     bool            m_bProcessing;
1179     bool            m_bRunInitDone;
1180     //ModuleVector  m_vModulesDependingOnThisModule;
1181 
ClassModuleRunInitItemClassModuleRunInitItem1182     ClassModuleRunInitItem( void )
1183         : m_pModule( NULL )
1184         , m_bProcessing( false )
1185         , m_bRunInitDone( false )
1186     {}
ClassModuleRunInitItemClassModuleRunInitItem1187     ClassModuleRunInitItem( SbModule* pModule )
1188         : m_pModule( pModule )
1189         , m_bProcessing( false )
1190         , m_bRunInitDone( false )
1191     {}
1192 };
1193 
1194 // Derive from has_map type instead of typedef
1195 // to allow forward declaration in sbmod.hxx
1196 class ModuleInitDependencyMap : public
1197     std::unordered_map< ::rtl::OUString, ClassModuleRunInitItem,
1198         ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > >
1199 {};
1200 
implProcessModuleRunInit(ModuleInitDependencyMap & rMap,ClassModuleRunInitItem & rItem)1201 void SbModule::implProcessModuleRunInit( ModuleInitDependencyMap& rMap, ClassModuleRunInitItem& rItem )
1202 {
1203     rItem.m_bProcessing = true;
1204 
1205     //bool bAnyDependencies = true;
1206     SbModule* pModule = rItem.m_pModule;
1207     if( pModule->pClassData != NULL )
1208     {
1209         StringVector& rReqTypes = pModule->pClassData->maRequiredTypes;
1210         if( rReqTypes.size() > 0 )
1211         {
1212             for( StringVector::iterator it = rReqTypes.begin() ; it != rReqTypes.end() ; ++it )
1213             {
1214                 String& rStr = *it;
1215 
1216                 // Is required type a class module?
1217                 ModuleInitDependencyMap::iterator itFind = rMap.find( rStr );
1218                 if( itFind != rMap.end() )
1219                 {
1220                     ClassModuleRunInitItem& rParentItem = itFind->second;
1221                     if( rParentItem.m_bProcessing )
1222                     {
1223                         // TODO: raise error?
1224                         DBG_ERROR( "Cyclic module dependency detected" );
1225                         continue;
1226                     }
1227 
1228                     if( !rParentItem.m_bRunInitDone )
1229                         implProcessModuleRunInit( rMap, rParentItem );
1230                 }
1231             }
1232         }
1233     }
1234 
1235     pModule->RunInit();
1236     rItem.m_bRunInitDone = true;
1237     rItem.m_bProcessing = false;
1238 }
1239 
1240 // Run Init-Code of all modules (including inserted libraries)
InitAllModules(StarBASIC * pBasicNotToInit)1241 void StarBASIC::InitAllModules( StarBASIC* pBasicNotToInit )
1242 {
1243     ::vos::OGuard guard( Application::GetSolarMutex() );
1244 
1245     // Init own modules
1246     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1247     {
1248         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1249         if( !pModule->IsCompiled() )
1250             pModule->Compile();
1251     }
1252     // compile modules first then RunInit ( otherwise there is
1253     // can be order dependency, e.g. classmodule A has a member
1254     // of of type classmodule B and classmodule B hasn't been compiled yet )
1255 
1256     // Consider required types to init in right order. Class modules
1257     // that are required by other modules have to be initialized first.
1258     ModuleInitDependencyMap aMIDMap;
1259     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1260     {
1261         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1262         String aModuleName = pModule->GetName();
1263         if( pModule->isProxyModule() )
1264             aMIDMap[aModuleName] = ClassModuleRunInitItem( pModule );
1265     }
1266 
1267     ModuleInitDependencyMap::iterator it;
1268     for( it = aMIDMap.begin() ; it != aMIDMap.end(); ++it )
1269     {
1270         ClassModuleRunInitItem& rItem = it->second;
1271         SbModule::implProcessModuleRunInit( aMIDMap, rItem );
1272     }
1273 
1274     // Call RunInit on standard modules
1275     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1276     {
1277         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1278         if( !pModule->isProxyModule() )
1279             pModule->RunInit();
1280     }
1281 
1282     // Check all objects if they are BASIC,
1283     // if yes initialize
1284     for ( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ )
1285     {
1286         SbxVariable* pVar = pObjs->Get( nObj );
1287         StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
1288         if( pBasic && pBasic != pBasicNotToInit )
1289             pBasic->InitAllModules();
1290     }
1291 }
1292 
1293 // #88329 Put modules back to not initialised state to
1294 // force reinitialisation at next start
DeInitAllModules(void)1295 void StarBASIC::DeInitAllModules( void )
1296 {
1297     // Deinit own modules
1298     for ( sal_uInt16 nMod = 0; nMod < pModules->Count(); nMod++ )
1299     {
1300         SbModule* pModule = (SbModule*)pModules->Get( nMod );
1301         if( pModule->pImage && !pModule->isProxyModule() && !pModule->ISA(SbObjModule) )
1302             pModule->pImage->bInit = false;
1303     }
1304 
1305     for ( sal_uInt16 nObj = 0; nObj < pObjs->Count(); nObj++ )
1306     {
1307         SbxVariable* pVar = pObjs->Get( nObj );
1308         StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
1309         if( pBasic )
1310             pBasic->DeInitAllModules();
1311     }
1312 }
1313 
1314 // #43011 For TestTool, to delete global vars
ClearGlobalVars(void)1315 void StarBASIC::ClearGlobalVars( void )
1316 {
1317     SbxArrayRef xProps( GetProperties() );
1318     sal_uInt16 nPropCount = xProps->Count();
1319     for ( sal_uInt16 nProp = 0 ; nProp < nPropCount ; ++nProp )
1320     {
1321         SbxBase* pVar = xProps->Get( nProp );
1322         pVar->Clear();
1323     }
1324     SetModified( sal_True );
1325 }
1326 
1327 // This implementation at first searches within the runtime library,
1328 // then it looks for an element within one module. This moudle can be
1329 // a public var or an entrypoint. If it is not found and we look for a
1330 // method and a module with the given name is found the search continues
1331 // for entrypoint "Main".
1332 // If this fails again a conventional search over objects is performend.
Find(const String & rName,SbxClassType t)1333 SbxVariable* StarBASIC::Find( const String& rName, SbxClassType t )
1334 {
1335     static String aMainStr( RTL_CONSTASCII_USTRINGPARAM("Main") );
1336 
1337     SbxVariable* pRes = NULL;
1338     SbModule* pNamed = NULL;
1339     // "Extended" search in Runtime Lib
1340     // but only if SbiRuntime has not set the flag
1341     if( !bNoRtl )
1342     {
1343         if( t == SbxCLASS_DONTCARE || t == SbxCLASS_OBJECT )
1344         {
1345             if( rName.EqualsIgnoreCaseAscii( RTLNAME ) )
1346                 pRes = pRtl;
1347         }
1348         if( !pRes )
1349             pRes = ((SbiStdObject*) (SbxObject*) pRtl)->Find( rName, t );
1350         if( pRes )
1351             pRes->SetFlag( SBX_EXTFOUND );
1352     }
1353     // Search module
1354     if( !pRes )
1355       for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1356     {
1357         SbModule* p = (SbModule*) pModules->Get( i );
1358         if( p->IsVisible() )
1359         {
1360             // Remember modul fpr Main() call
1361             // or is the name equal?!?
1362             if( p->GetName().EqualsIgnoreCaseAscii( rName ) )
1363             {
1364                 if( t == SbxCLASS_OBJECT || t == SbxCLASS_DONTCARE )
1365                 {
1366                     pRes = p; break;
1367                 }
1368                 pNamed = p;
1369             }
1370             // Only variables qualified by the Module Name e.g. Sheet1.foo
1371             // should work for Documant && Class type Modules
1372             sal_Int32 nType = p->GetModuleType();
1373             if ( nType == ModuleType::DOCUMENT || nType == ModuleType::FORM )
1374                 continue;
1375 
1376             // otherwise check if the element is available
1377             // unset GBLSEARCH-Flag (due to Rekursion)
1378             sal_uInt16 nGblFlag = p->GetFlags() & SBX_GBLSEARCH;
1379             p->ResetFlag( SBX_GBLSEARCH );
1380             pRes = p->Find( rName, t );
1381             p->SetFlag( nGblFlag );
1382             if( pRes )
1383                 break;
1384         }
1385     }
1386     if( !pRes && pNamed && ( t == SbxCLASS_METHOD || t == SbxCLASS_DONTCARE ) &&
1387         !pNamed->GetName().EqualsIgnoreCaseAscii( aMainStr ) )
1388             pRes = pNamed->Find( aMainStr, SbxCLASS_METHOD );
1389     if( !pRes )
1390         pRes = SbxObject::Find( rName, t );
1391     return pRes;
1392 }
1393 
Call(const String & rName,SbxArray * pParam)1394 sal_Bool StarBASIC::Call( const String& rName, SbxArray* pParam )
1395 {
1396     sal_Bool bRes = SbxObject::Call( rName, pParam );
1397     if( !bRes )
1398     {
1399         SbxError eErr = SbxBase::GetError();
1400         SbxBase::ResetError();
1401         if( eErr != SbxERR_OK )
1402             RTError( (SbError)eErr, 0, 0, 0 );
1403     }
1404     return bRes;
1405 }
1406 
1407 // Find method via name (e.g. query via BASIC IDE)
FindSBXInCurrentScope(const String & rName)1408 SbxBase* StarBASIC::FindSBXInCurrentScope( const String& rName )
1409 {
1410     if( !pINST )
1411         return NULL;
1412     if( !pINST->pRun )
1413         return NULL;
1414     return pINST->pRun->FindElementExtern( rName );
1415 }
1416 
1417 // Preserve old interface
FindVarInCurrentScopy(const String & rName,sal_uInt16 & rStatus)1418 SbxVariable* StarBASIC::FindVarInCurrentScopy
1419 ( const String& rName, sal_uInt16& rStatus )
1420 {
1421     rStatus = 1;              // Presumption: nothing found
1422     SbxVariable* pVar = NULL;
1423     SbxBase* pSbx = FindSBXInCurrentScope( rName );
1424     if( pSbx )
1425     {
1426         if( !pSbx->ISA(SbxMethod) && !pSbx->ISA(SbxObject) )
1427             pVar = PTR_CAST(SbxVariable,pSbx);
1428     }
1429     if( pVar )
1430         rStatus = 0;      // We found something
1431     return pVar;
1432 }
1433 
QuitAndExitApplication()1434 void StarBASIC::QuitAndExitApplication()
1435 {
1436     Stop();
1437     bQuit = sal_True;
1438 }
1439 
Stop()1440 void StarBASIC::Stop()
1441 {
1442     SbiInstance* p = pINST;
1443     while( p )
1444     {
1445         p->Stop();
1446         p = p->pNext;
1447     }
1448 }
1449 
IsRunning()1450 sal_Bool StarBASIC::IsRunning()
1451 {
1452     return sal_Bool( pINST != NULL );
1453 }
1454 
1455 /**************************************************************************
1456 *
1457 *    Object factories and others
1458 *
1459 **************************************************************************/
1460 
1461 // Activation of an object. There is no need to access active objects
1462 // with name via BASIC. If NULL is given, everything is activated.
ActivateObject(const String * pName,sal_Bool bActivate)1463 void StarBASIC::ActivateObject( const String* pName, sal_Bool bActivate )
1464 {
1465     if( pName )
1466     {
1467         SbxObject* p = (SbxObject*) SbxObject::Find( *pName, SbxCLASS_OBJECT );
1468         if( p )
1469         {
1470             if( bActivate )
1471                 p->SetFlag( SBX_EXTSEARCH );
1472             else
1473                 p->ResetFlag( SBX_EXTSEARCH );
1474         }
1475     }
1476     else
1477     {
1478         for( sal_uInt16 i = 0; i < GetObjects()->Count(); i++ )
1479         {
1480             SbxObject* p = (SbxObject*) GetObjects()->Get( i );
1481             if( bActivate )
1482                 p->SetFlag( SBX_EXTSEARCH );
1483             else
1484                 p->ResetFlag( SBX_EXTSEARCH );
1485         }
1486     }
1487 }
1488 
1489 /**************************************************************************
1490 *
1491 *    Debugging and error handling
1492 *
1493 **************************************************************************/
1494 
GetActiveMethod(sal_uInt16 nLevel)1495 SbMethod* StarBASIC::GetActiveMethod( sal_uInt16 nLevel )
1496 {
1497     if( pINST )
1498         return pINST->GetCaller( nLevel );
1499     else
1500         return NULL;
1501 }
1502 
GetActiveModule()1503 SbModule* StarBASIC::GetActiveModule()
1504 {
1505     if( pINST && !IsCompilerError() )
1506         return pINST->GetActiveModule();
1507     else
1508         return pCMOD;
1509 }
1510 
BreakPoint(sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1511 sal_uInt16 StarBASIC::BreakPoint( sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1512 {
1513     SetErrorData( 0, l, c1, c2 );
1514     bBreak = sal_True;
1515     if( GetSbData()->aBreakHdl.IsSet() )
1516         return (sal_uInt16) GetSbData()->aBreakHdl.Call( this );
1517     else
1518         return BreakHdl();
1519 }
1520 
StepPoint(sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1521 sal_uInt16 StarBASIC::StepPoint( sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1522 {
1523     SetErrorData( 0, l, c1, c2 );
1524     bBreak = sal_False;
1525     if( GetSbData()->aBreakHdl.IsSet() )
1526         return (sal_uInt16) GetSbData()->aBreakHdl.Call( this );
1527     else
1528         return BreakHdl();
1529 }
1530 
BreakHdl()1531 sal_uInt16 __EXPORT StarBASIC::BreakHdl()
1532 {
1533     return (sal_uInt16) ( aBreakHdl.IsSet()
1534         ? aBreakHdl.Call( this ) : SbDEBUG_CONTINUE );
1535 }
1536 
1537 // Calls for error handler and break handler
GetLine()1538 sal_uInt16 StarBASIC::GetLine()     { return GetSbData()->nLine; }
GetCol1()1539 sal_uInt16 StarBASIC::GetCol1()     { return GetSbData()->nCol1; }
GetCol2()1540 sal_uInt16 StarBASIC::GetCol2()     { return GetSbData()->nCol2; }
1541 
1542 // Specific to error handler
GetErrorCode()1543 SbError StarBASIC::GetErrorCode()       { return GetSbData()->nCode; }
GetErrorText()1544 const String& StarBASIC::GetErrorText() { return GetSbData()->aErrMsg; }
IsCompilerError()1545 sal_Bool StarBASIC::IsCompilerError()       { return GetSbData()->bCompiler; }
SetGlobalLanguageMode(SbLanguageMode eLanguageMode)1546 void StarBASIC::SetGlobalLanguageMode( SbLanguageMode eLanguageMode )
1547 {
1548     GetSbData()->eLanguageMode = eLanguageMode;
1549 }
GetGlobalLanguageMode()1550 SbLanguageMode StarBASIC::GetGlobalLanguageMode()
1551 {
1552     return GetSbData()->eLanguageMode;
1553 }
1554 // Local settings
GetLanguageMode()1555 SbLanguageMode StarBASIC::GetLanguageMode()
1556 {
1557     // Use global settings?
1558     if( eLanguageMode == SB_LANG_GLOBAL )
1559         return GetSbData()->eLanguageMode;
1560     else
1561         return eLanguageMode;
1562 }
1563 
1564 // AB: 29.3.96
1565 // Das Mapping zwischen alten und neuen Fehlercodes erfolgt, indem die Tabelle
1566 // SFX_VB_ErrorTab[] durchsucht wird. Dies ist zwar nicht besonders performant,
1567 // verbraucht aber viel weniger Speicher als entsprechende switch-Bloecke.
1568 // Die Umrechnung von Fehlercodes muss nicht schnell sein, daher auch keine
1569 // binaere Suche bei VB-Error -> SFX-Error.
1570 
1571 // Neue Fehler-Codes auf alte, Sbx-Kompatible zurueckmappen
GetVBErrorCode(SbError nError)1572 sal_uInt16 StarBASIC::GetVBErrorCode( SbError nError )
1573 {
1574     sal_uInt16 nRet = 0;
1575 
1576     if( SbiRuntime::isVBAEnabled() )
1577     {
1578         switch( nError )
1579         {
1580             case SbERR_BASIC_ARRAY_FIX:
1581                 return 10;
1582             case SbERR_BASIC_STRING_OVERFLOW:
1583                 return 14;
1584             case SbERR_BASIC_EXPR_TOO_COMPLEX:
1585                 return 16;
1586             case SbERR_BASIC_OPER_NOT_PERFORM:
1587                 return 17;
1588             case SbERR_BASIC_TOO_MANY_DLL:
1589                 return 47;
1590             case SbERR_BASIC_LOOP_NOT_INIT:
1591                 return 92;
1592             default:
1593                 nRet = 0;
1594         }
1595     }
1596 
1597     // Suchschleife
1598     const SFX_VB_ErrorItem* pErrItem;
1599     sal_uInt16 nIndex = 0;
1600     do
1601     {
1602         pErrItem = SFX_VB_ErrorTab + nIndex;
1603         if( pErrItem->nErrorSFX == nError )
1604         {
1605             nRet = pErrItem->nErrorVB;
1606             break;
1607         }
1608         nIndex++;
1609     }
1610     while( pErrItem->nErrorVB != 0xFFFF );      // bis End-Marke
1611     return nRet;
1612 }
1613 
GetSfxFromVBError(sal_uInt16 nError)1614 SbError StarBASIC::GetSfxFromVBError( sal_uInt16 nError )
1615 {
1616     SbError nRet = 0L;
1617 
1618     if( SbiRuntime::isVBAEnabled() )
1619     {
1620         switch( nError )
1621         {
1622             case 1:
1623             case 2:
1624             case 4:
1625             case 8:
1626             case 12:
1627             case 73:
1628                 return 0L;
1629             case 10:
1630                 return SbERR_BASIC_ARRAY_FIX;
1631             case 14:
1632                 return SbERR_BASIC_STRING_OVERFLOW;
1633             case 16:
1634                 return SbERR_BASIC_EXPR_TOO_COMPLEX;
1635             case 17:
1636                 return SbERR_BASIC_OPER_NOT_PERFORM;
1637             case 47:
1638                 return SbERR_BASIC_TOO_MANY_DLL;
1639             case 92:
1640                 return SbERR_BASIC_LOOP_NOT_INIT;
1641             default:
1642                 nRet = 0L;
1643         }
1644     }
1645     const SFX_VB_ErrorItem* pErrItem;
1646     sal_uInt16 nIndex = 0;
1647     do
1648     {
1649         pErrItem = SFX_VB_ErrorTab + nIndex;
1650         if( pErrItem->nErrorVB == nError )
1651         {
1652             nRet = pErrItem->nErrorSFX;
1653             break;
1654         }
1655         else if( pErrItem->nErrorVB > nError )
1656             break;              // kann nicht mehr gefunden werden
1657 
1658         nIndex++;
1659     }
1660     while( pErrItem->nErrorVB != 0xFFFF );      // bis End-Marke
1661     return nRet;
1662 }
1663 
1664 // Error- / Break-Daten setzen
SetErrorData(SbError nCode,sal_uInt16 nLine,sal_uInt16 nCol1,sal_uInt16 nCol2)1665 void StarBASIC::SetErrorData
1666 ( SbError nCode, sal_uInt16 nLine, sal_uInt16 nCol1, sal_uInt16 nCol2 )
1667 {
1668     SbiGlobals& aGlobals = *GetSbData();
1669     aGlobals.nCode = nCode;
1670     aGlobals.nLine = nLine;
1671     aGlobals.nCol1 = nCol1;
1672     aGlobals.nCol2 = nCol2;
1673 }
1674 
1675 //----------------------------------------------------------------
1676 // Hilfsklasse zum Zugriff auf String SubResourcen einer Resource.
1677 // Quelle: sfx2\source\doc\docfile.cxx (TLX)
1678 struct BasicStringList_Impl : private Resource
1679 {
1680     ResId aResId;
1681 
BasicStringList_ImplBasicStringList_Impl1682     BasicStringList_Impl( ResId& rErrIdP,  sal_uInt16 nId)
1683         : Resource( rErrIdP ),aResId(nId, *rErrIdP.GetResMgr() ){}
~BasicStringList_ImplBasicStringList_Impl1684     ~BasicStringList_Impl() { FreeResource(); }
1685 
GetStringBasicStringList_Impl1686     String GetString(){ return String( aResId ); }
IsErrorTextAvailableBasicStringList_Impl1687     sal_Bool IsErrorTextAvailable( void )
1688         { return IsAvailableRes(aResId.SetRT(RSC_STRING)); }
1689 };
1690 //----------------------------------------------------------------
1691 
1692 // #60175 Flag, das bei Basic-Fehlern das Anziehen der SFX-Resourcen verhindert
1693 static sal_Bool bStaticSuppressSfxResource = sal_False;
1694 
StaticSuppressSfxResource(sal_Bool bSuppress)1695 void StarBASIC::StaticSuppressSfxResource( sal_Bool bSuppress )
1696 {
1697     bStaticSuppressSfxResource = bSuppress;
1698 }
1699 
1700 // Hack for #83750, use bStaticSuppressSfxResource as setup flag
runsInSetup(void)1701 sal_Bool runsInSetup( void )
1702 {
1703     return bStaticSuppressSfxResource;
1704 }
1705 
1706 
MakeErrorText(SbError nId,const String & aMsg)1707 void StarBASIC::MakeErrorText( SbError nId, const String& aMsg )
1708 {
1709     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1710 
1711     if( bStaticSuppressSfxResource )
1712     {
1713         GetSbData()->aErrMsg = String( RTL_CONSTASCII_USTRINGPARAM("No resource: Error message not available") );
1714         return;
1715     }
1716 
1717     sal_uInt16 nOldID = GetVBErrorCode( nId );
1718 
1719     // Hilfsklasse instanzieren
1720     BasResId aId( RID_BASIC_START );
1721     BasicStringList_Impl aMyStringList( aId, sal_uInt16(nId & ERRCODE_RES_MASK) );
1722 
1723     if( aMyStringList.IsErrorTextAvailable() )
1724     {
1725         // Merge Message mit Zusatztext
1726         String aMsg1 = aMyStringList.GetString();
1727         // Argument-Platzhalter durch %s ersetzen
1728         String aSrgStr( RTL_CONSTASCII_USTRINGPARAM("$(ARG1)") );
1729         sal_uInt16 nResult = aMsg1.Search( aSrgStr );
1730 
1731         if( nResult != STRING_NOTFOUND )
1732         {
1733             aMsg1.Erase( nResult, aSrgStr.Len() );
1734             aMsg1.Insert( aMsg, nResult );
1735         }
1736         GetSbData()->aErrMsg = aMsg1;
1737     }
1738     else if( nOldID != 0 )
1739     {
1740         String aStdMsg( RTL_CONSTASCII_USTRINGPARAM("Fehler ") );
1741         aStdMsg += String::CreateFromInt32( nOldID);
1742         aStdMsg += String( RTL_CONSTASCII_USTRINGPARAM(": Kein Fehlertext verfuegbar!") );
1743         GetSbData()->aErrMsg = aStdMsg;
1744     }
1745     else
1746         GetSbData()->aErrMsg = String::EmptyString();
1747 
1748 }
1749 
CError(SbError code,const String & rMsg,sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1750 sal_Bool StarBASIC::CError
1751     ( SbError code, const String& rMsg, sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1752 {
1753     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1754 
1755     // Compiler-Fehler waehrend der Laufzeit -> Programm anhalten
1756     if( IsRunning() )
1757     {
1758         // #109018 Check if running Basic is affected
1759         StarBASIC* pStartedBasic = pINST->GetBasic();
1760         if( pStartedBasic != this )
1761             return sal_False;
1762 
1763         Stop();
1764     }
1765 
1766     // Flag setzen, damit GlobalRunInit den Fehler mitbekommt
1767     GetSbData()->bGlobalInitErr = sal_True;
1768 
1769     // Fehlertext basteln
1770     MakeErrorText( code, rMsg );
1771 
1772     // Umsetzung des Codes fuer String-Transport in SFX-Error
1773     if( rMsg.Len() )
1774         code = (sal_uIntPtr)*new StringErrorInfo( code, String(rMsg) );
1775 
1776     SetErrorData( code, l, c1, c2 );
1777     GetSbData()->bCompiler = sal_True;
1778     sal_Bool bRet;
1779     if( GetSbData()->aErrHdl.IsSet() )
1780         bRet = (sal_Bool) GetSbData()->aErrHdl.Call( this );
1781     else
1782         bRet = ErrorHdl();
1783     GetSbData()->bCompiler = sal_False;     // nur sal_True fuer Error-Handler
1784     return bRet;
1785 }
1786 
RTError(SbError code,sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1787 sal_Bool StarBASIC::RTError
1788     ( SbError code, sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1789 {
1790     return RTError( code, String(), l, c1, c2 );
1791 }
1792 
RTError(SbError code,const String & rMsg,sal_uInt16 l,sal_uInt16 c1,sal_uInt16 c2)1793 sal_Bool StarBASIC::RTError( SbError code, const String& rMsg, sal_uInt16 l, sal_uInt16 c1, sal_uInt16 c2 )
1794 {
1795     vos::OGuard aSolarGuard( Application::GetSolarMutex() );
1796 
1797     SbError c = code;
1798     if( (c & ERRCODE_CLASS_MASK) == ERRCODE_CLASS_COMPILER )
1799         c = 0;
1800     MakeErrorText( c, rMsg );
1801 
1802     // Umsetzung des Codes fuer String-Transport in SFX-Error
1803     if( rMsg.Len() )
1804     {
1805         // very confusing, even though MakeErrorText sets up the error text
1806         // seems that this is not used ( if rMsg already has content )
1807         // In the case of VBA MakeErrorText also formats the error to be alittle more
1808         // like vba ( adds an error number etc )
1809         if ( SbiRuntime::isVBAEnabled() && ( code == SbERR_BASIC_COMPAT ) )
1810         {
1811             String aTmp = '\'';
1812             aTmp += String::CreateFromInt32( SbxErrObject::getUnoErrObject()->getNumber() );
1813             aTmp += String( RTL_CONSTASCII_USTRINGPARAM("\'\n") );
1814             aTmp +=  GetSbData()->aErrMsg.Len() ? GetSbData()->aErrMsg : rMsg;
1815             code = (sal_uIntPtr)*new StringErrorInfo( code, aTmp );
1816         }
1817         else
1818             code = (sal_uIntPtr)*new StringErrorInfo( code, String(rMsg) );
1819     }
1820 
1821     SetErrorData( code, l, c1, c2 );
1822     if( GetSbData()->aErrHdl.IsSet() )
1823         return (sal_Bool) GetSbData()->aErrHdl.Call( this );
1824     else
1825         return ErrorHdl();
1826 }
1827 
Error(SbError n)1828 void StarBASIC::Error( SbError n )
1829 {
1830     Error( n, String() );
1831 }
1832 
Error(SbError n,const String & rMsg)1833 void StarBASIC::Error( SbError n, const String& rMsg )
1834 {
1835     if( pINST )
1836         pINST->Error( n, rMsg );
1837 }
1838 
FatalError(SbError n)1839 void StarBASIC::FatalError( SbError n )
1840 {
1841     if( pINST )
1842         pINST->FatalError( n );
1843 }
1844 
FatalError(SbError _errCode,const String & _details)1845 void StarBASIC::FatalError( SbError _errCode, const String& _details )
1846 {
1847     if( pINST )
1848         pINST->FatalError( _errCode, _details );
1849 }
1850 
GetErrBasic()1851 SbError StarBASIC::GetErrBasic()
1852 {
1853     if( pINST )
1854         return pINST->GetErr();
1855     else
1856         return 0;
1857 }
1858 
1859 // #66536 Zusatz-Message fuer RTL-Funktion Error zugreifbar machen
GetErrorMsg()1860 String StarBASIC::GetErrorMsg()
1861 {
1862     if( pINST )
1863         return pINST->GetErrorMsg();
1864     else
1865         return String();
1866 }
1867 
GetErl()1868 sal_uInt16 StarBASIC::GetErl()
1869 {
1870     if( pINST )
1871         return pINST->GetErl();
1872     else
1873         return 0;
1874 }
1875 
ErrorHdl()1876 sal_Bool __EXPORT StarBASIC::ErrorHdl()
1877 {
1878     return (sal_Bool) ( aErrorHdl.IsSet()
1879         ? aErrorHdl.Call( this ) : sal_False );
1880 }
1881 
GetGlobalErrorHdl()1882 Link StarBASIC::GetGlobalErrorHdl()
1883 {
1884     return GetSbData()->aErrHdl;
1885 }
1886 
SetGlobalErrorHdl(const Link & rLink)1887 void StarBASIC::SetGlobalErrorHdl( const Link& rLink )
1888 {
1889     GetSbData()->aErrHdl = rLink;
1890 }
1891 
1892 
GetGlobalBreakHdl()1893 Link StarBASIC::GetGlobalBreakHdl()
1894 {
1895     return GetSbData()->aBreakHdl;
1896 }
1897 
SetGlobalBreakHdl(const Link & rLink)1898 void StarBASIC::SetGlobalBreakHdl( const Link& rLink )
1899 {
1900     GetSbData()->aBreakHdl = rLink;
1901 }
1902 
getUnoListeners(void)1903 SbxArrayRef StarBASIC::getUnoListeners( void )
1904 {
1905     if( !xUnoListeners.Is() )
1906         xUnoListeners = new SbxArray();
1907     return xUnoListeners;
1908 }
1909 
1910 
1911 /**************************************************************************
1912 *
1913 *   Laden und Speichern
1914 *
1915 **************************************************************************/
1916 
LoadData(SvStream & r,sal_uInt16 nVer)1917 sal_Bool StarBASIC::LoadData( SvStream& r, sal_uInt16 nVer )
1918 {
1919     if( !SbxObject::LoadData( r, nVer ) )
1920         return sal_False;
1921 
1922     // #95459 Delete dialogs, otherwise endless recursion
1923     // in SbxVarable::GetType() if dialogs are accessed
1924     sal_uInt16 nObjCount = pObjs->Count();
1925     SbxVariable** ppDeleteTab = new SbxVariable*[ nObjCount ];
1926     sal_uInt16 nObj;
1927 
1928     for( nObj = 0 ; nObj < nObjCount ; nObj++ )
1929     {
1930         SbxVariable* pVar = pObjs->Get( nObj );
1931         StarBASIC* pBasic = PTR_CAST( StarBASIC, pVar );
1932         ppDeleteTab[nObj] = pBasic ? NULL : pVar;
1933     }
1934     for( nObj = 0 ; nObj < nObjCount ; nObj++ )
1935     {
1936         SbxVariable* pVar = ppDeleteTab[nObj];
1937         if( pVar )
1938             pObjs->Remove( pVar );
1939     }
1940     delete[] ppDeleteTab;
1941 
1942     sal_uInt16 nMod;
1943     pModules->Clear();
1944     r >> nMod;
1945     for( sal_uInt16 i = 0; i < nMod; i++ )
1946     {
1947         SbModule* pMod = (SbModule*) SbxBase::Load( r );
1948         if( !pMod )
1949             return sal_False;
1950         else if( pMod->ISA(SbJScriptModule) )
1951         {
1952             // Ref zuweisen, damit pMod deleted wird
1953             SbModuleRef xRef = pMod;
1954         }
1955         else
1956         {
1957             pMod->SetParent( this );
1958             pModules->Put( pMod, i );
1959         }
1960     }
1961     // HACK fuer SFX-Mist!
1962     SbxVariable* p = Find( String( RTL_CONSTASCII_USTRINGPARAM("FALSE") ), SbxCLASS_PROPERTY );
1963     if( p )
1964         Remove( p );
1965     p = Find( String( RTL_CONSTASCII_USTRINGPARAM("TRUE") ), SbxCLASS_PROPERTY );
1966     if( p )
1967         Remove( p );
1968     // Ende des Hacks!
1969     // Suche ueber StarBASIC ist immer global
1970     DBG_ASSERT( IsSet( SBX_GBLSEARCH ), "Basic ohne GBLSEARCH geladen" );
1971     SetFlag( SBX_GBLSEARCH );
1972     return sal_True;
1973 }
1974 
StoreData(SvStream & r) const1975 sal_Bool StarBASIC::StoreData( SvStream& r ) const
1976 {
1977     if( !SbxObject::StoreData( r ) )
1978         return sal_False;
1979     r << (sal_uInt16) pModules->Count();
1980     for( sal_uInt16 i = 0; i < pModules->Count(); i++ )
1981     {
1982         SbModule* p = (SbModule*) pModules->Get( i );
1983         if( !p->Store( r ) )
1984             return sal_False;
1985     }
1986     return sal_True;
1987 }
1988 
LoadOldModules(SvStream &)1989 sal_Bool StarBASIC::LoadOldModules( SvStream& )
1990 {
1991     return sal_False;
1992 }
1993 
GetUNOConstant(const sal_Char * _pAsciiName,::com::sun::star::uno::Any & aOut)1994 bool StarBASIC::GetUNOConstant( const sal_Char* _pAsciiName, ::com::sun::star::uno::Any& aOut )
1995 {
1996     bool bRes = false;
1997     ::rtl::OUString sVarName( ::rtl::OUString::createFromAscii( _pAsciiName ) );
1998     SbUnoObject* pGlobs = dynamic_cast<SbUnoObject*>( Find( sVarName, SbxCLASS_DONTCARE ) );
1999     if ( pGlobs )
2000     {
2001         aOut = pGlobs->getUnoAny();
2002         bRes = true;
2003     }
2004     return bRes;
2005 }
2006 
GetModelFromBasic(SbxObject * pBasic)2007 Reference< frame::XModel > StarBASIC::GetModelFromBasic( SbxObject* pBasic )
2008 {
2009     OSL_PRECOND( pBasic != NULL, "getModelFromBasic: illegal call!" );
2010     if ( !pBasic )
2011         return NULL;
2012 
2013     // look for the ThisComponent variable, first in the parent (which
2014     // might be the document's Basic), then in the parent's parent (which might be
2015     // the application Basic)
2016     const ::rtl::OUString sThisComponent( RTL_CONSTASCII_USTRINGPARAM( "ThisComponent" ) );
2017     SbxVariable* pThisComponent = NULL;
2018 
2019     SbxObject* pLookup = pBasic->GetParent();
2020     while ( pLookup && !pThisComponent )
2021     {
2022         pThisComponent = pLookup->Find( sThisComponent, SbxCLASS_OBJECT );
2023         pLookup = pLookup->GetParent();
2024     }
2025     if ( !pThisComponent )
2026     {
2027         OSL_TRACE("Failed to get ThisComponent");
2028             // the application Basic, at the latest, should have this variable
2029         return NULL;
2030     }
2031 
2032     Any aThisComponentAny( sbxToUnoValue( pThisComponent ) );
2033     Reference< frame::XModel > xModel( aThisComponentAny, UNO_QUERY );
2034     if ( !xModel.is() )
2035     {
2036         // it's no XModel. Okay, ThisComponent nowadays is allowed to be a controller.
2037         Reference< frame::XController > xController( aThisComponentAny, UNO_QUERY );
2038         if ( xController.is() )
2039             xModel = xController->getModel();
2040     }
2041 
2042     if ( !xModel.is() )
2043         return NULL;
2044 
2045 #if OSL_DEBUG_LEVEL > 0
2046     OSL_TRACE("Have model ThisComponent points to url %s",
2047         ::rtl::OUStringToOString( xModel->getURL(),
2048             RTL_TEXTENCODING_ASCII_US ).pData->buffer );
2049 #endif
2050 
2051     return xModel;
2052 }
2053 
2054 
2055 //========================================================================
2056 // #118116 Implementation Collection object
2057 
2058 TYPEINIT1(BasicCollection,SbxObject)
2059 
2060 static const char pCountStr[]   = "Count";
2061 static const char pAddStr[]     = "Add";
2062 static const char pItemStr[]    = "Item";
2063 static const char pRemoveStr[]  = "Remove";
2064 static sal_uInt16 nCountHash = 0, nAddHash, nItemHash, nRemoveHash;
2065 
2066 SbxInfoRef BasicCollection::xAddInfo = NULL;
2067 SbxInfoRef BasicCollection::xItemInfo = NULL;
2068 
2069 // Items may share a name (an item added without a key keeps the name of the
2070 // variable it was copied from), so each name maps to all of its holders.
2071 class CollectionNameMap : public
2072     std::unordered_map< ::rtl::OUString, std::vector< SbxVariable* >,
2073         ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > >
2074 {};
2075 
2076 // Matches EqualsIgnoreCaseAscii: only ASCII letters are folded
lcl_foldCollectionName(const String & rName)2077 static ::rtl::OUString lcl_foldCollectionName( const String& rName )
2078 {
2079     return ::rtl::OUString( rName ).toAsciiUpperCase();
2080 }
2081 
BasicCollection(const XubString & rClass)2082 BasicCollection::BasicCollection( const XubString& rClass )
2083              : SbxObject( rClass ), mpNameMap( new CollectionNameMap )
2084 {
2085     if( !nCountHash )
2086     {
2087         nCountHash  = MakeHashCode( String::CreateFromAscii( pCountStr ) );
2088         nAddHash    = MakeHashCode( String::CreateFromAscii( pAddStr ) );
2089         nItemHash   = MakeHashCode( String::CreateFromAscii( pItemStr ) );
2090         nRemoveHash = MakeHashCode( String::CreateFromAscii( pRemoveStr ) );
2091     }
2092     Initialize();
2093 
2094 }
2095 
~BasicCollection()2096 BasicCollection::~BasicCollection()
2097 {
2098     delete mpNameMap;
2099 }
2100 
Clear()2101 void BasicCollection::Clear()
2102 {
2103     SbxObject::Clear();
2104     Initialize();
2105 }
2106 
Initialize()2107 void BasicCollection::Initialize()
2108 {
2109     xItemArray = new SbxArray();
2110     mpNameMap->clear();
2111     SetType( SbxOBJECT );
2112     SetFlag( SBX_FIXED );
2113     ResetFlag( SBX_WRITE );
2114     SbxVariable* p;
2115     p = Make( String::CreateFromAscii( pCountStr ), SbxCLASS_PROPERTY, SbxINTEGER );
2116     p->ResetFlag( SBX_WRITE );
2117     p->SetFlag( SBX_DONTSTORE );
2118     p = Make( String::CreateFromAscii( pAddStr ), SbxCLASS_METHOD, SbxEMPTY );
2119     p->SetFlag( SBX_DONTSTORE );
2120     p = Make( String::CreateFromAscii( pItemStr ), SbxCLASS_METHOD, SbxVARIANT );
2121     p->SetFlag( SBX_DONTSTORE );
2122     p = Make( String::CreateFromAscii( pRemoveStr ), SbxCLASS_METHOD, SbxEMPTY );
2123     p->SetFlag( SBX_DONTSTORE );
2124     if ( !xAddInfo.Is() )
2125     {
2126         xAddInfo = new SbxInfo;
2127         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Item") ), SbxVARIANT, SBX_READ );
2128         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Key") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL );
2129         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Before") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL );
2130         xAddInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("After") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL );
2131     }
2132     if ( !xItemInfo.Is() )
2133     {
2134         xItemInfo = new SbxInfo;
2135         xItemInfo->AddParam(  String( RTL_CONSTASCII_USTRINGPARAM("Index") ), SbxVARIANT, SBX_READ | SBX_OPTIONAL);
2136     }
2137 }
2138 
Find(const XubString & rName,SbxClassType t)2139 SbxVariable* BasicCollection::Find( const XubString& rName, SbxClassType t )
2140 {
2141     SbxVariable* pFind = SbxObject::Find( rName, t );
2142     return pFind;
2143 }
2144 
SFX_NOTIFY(SfxBroadcaster & rCst,const TypeId & rId1,const SfxHint & rHint,const TypeId & rId2)2145 void BasicCollection::SFX_NOTIFY( SfxBroadcaster& rCst, const TypeId& rId1,
2146                                 const SfxHint& rHint, const TypeId& rId2 )
2147 {
2148     const SbxHint* p = PTR_CAST(SbxHint,&rHint);
2149     if( p )
2150     {
2151         sal_uIntPtr nId = p->GetId();
2152         sal_Bool bRead  = sal_Bool( nId == SBX_HINT_DATAWANTED );
2153         sal_Bool bWrite = sal_Bool( nId == SBX_HINT_DATACHANGED );
2154         sal_Bool bRequestInfo = sal_Bool( nId == SBX_HINT_INFOWANTED );
2155         SbxVariable* pVar = p->GetVar();
2156         SbxArray* pArg = pVar->GetParameters();
2157         XubString aVarName( pVar->GetName() );
2158         if( bRead || bWrite )
2159         {
2160             if( pVar->GetHashCode() == nCountHash
2161                   && aVarName.EqualsIgnoreCaseAscii( pCountStr ) )
2162                 pVar->PutLong( xItemArray->Count32() );
2163             else if( pVar->GetHashCode() == nAddHash
2164                   && aVarName.EqualsIgnoreCaseAscii( pAddStr ) )
2165                 CollAdd( pArg );
2166             else if( pVar->GetHashCode() == nItemHash
2167                   && aVarName.EqualsIgnoreCaseAscii( pItemStr ) )
2168                 CollItem( pArg );
2169             else if( pVar->GetHashCode() == nRemoveHash
2170                   && aVarName.EqualsIgnoreCaseAscii( pRemoveStr ) )
2171                 CollRemove( pArg );
2172             else
2173                 SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
2174             return;
2175         }
2176         else if ( bRequestInfo )
2177         {
2178             if( pVar->GetHashCode() == nAddHash
2179                   && aVarName.EqualsIgnoreCaseAscii( pAddStr ) )
2180                 pVar->SetInfo( xAddInfo );
2181             else if( pVar->GetHashCode() == nItemHash
2182                   && aVarName.EqualsIgnoreCaseAscii( pItemStr ) )
2183                 pVar->SetInfo( xItemInfo );
2184         }
2185     }
2186     SbxObject::SFX_NOTIFY( rCst, rId1, rHint, rId2 );
2187 }
2188 
implGetIndex(SbxVariable * pIndexVar)2189 sal_Int32 BasicCollection::implGetIndex( SbxVariable* pIndexVar )
2190 {
2191     sal_Int32 nIndex = -1;
2192     if( pIndexVar->GetType() == SbxSTRING )
2193         nIndex = implGetIndexForName( pIndexVar->GetString() );
2194     else
2195         nIndex = pIndexVar->GetLong() - 1;
2196     return nIndex;
2197 }
2198 
implRegisterName(SbxVariable * pVar)2199 void BasicCollection::implRegisterName( SbxVariable* pVar )
2200 {
2201     // Nameless items are never found by name, see implFindByName
2202     if( pVar->GetName().Len() )
2203         (*mpNameMap)[ lcl_foldCollectionName( pVar->GetName() ) ].push_back( pVar );
2204 }
2205 
implUnregisterName(SbxVariable * pVar)2206 void BasicCollection::implUnregisterName( SbxVariable* pVar )
2207 {
2208     if( !pVar->GetName().Len() )
2209         return;
2210     CollectionNameMap::iterator it = mpNameMap->find( lcl_foldCollectionName( pVar->GetName() ) );
2211     if( it == mpNameMap->end() )
2212         return;
2213     std::vector< SbxVariable* >& rVars = it->second;
2214     rVars.erase( std::remove( rVars.begin(), rVars.end(), pVar ), rVars.end() );
2215     if( rVars.empty() )
2216         mpNameMap->erase( it );
2217 }
2218 
2219 // Returns the item with the lowest index that has the given name
implFindByName(const String & rName)2220 SbxVariable* BasicCollection::implFindByName( const String& rName )
2221 {
2222     sal_Int32 nCount = xItemArray->Count32();
2223     if( !rName.Len() )
2224     {
2225         // Nameless items are not indexed
2226         for( sal_Int32 i = 0 ; i < nCount ; i++ )
2227         {
2228             SbxVariable* pVar = xItemArray->Get32( i );
2229             if( !pVar->GetName().Len() )
2230                 return pVar;
2231         }
2232         return NULL;
2233     }
2234 
2235     CollectionNameMap::iterator it = mpNameMap->find( lcl_foldCollectionName( rName ) );
2236     if( it == mpNameMap->end() )
2237         return NULL;
2238     std::vector< SbxVariable* >& rVars = it->second;
2239     if( rVars.size() == 1 )
2240         return rVars[0];
2241     for( sal_Int32 i = 0 ; i < nCount ; i++ )
2242     {
2243         SbxVariable* pVar = xItemArray->Get32( i );
2244         if( std::find( rVars.begin(), rVars.end(), pVar ) != rVars.end() )
2245             return pVar;
2246     }
2247     return NULL;
2248 }
2249 
implGetIndexForName(const String & rName)2250 sal_Int32 BasicCollection::implGetIndexForName( const String& rName )
2251 {
2252     SbxVariable* pFound = implFindByName( rName );
2253     if( !pFound )
2254         return -1;
2255     sal_Int32 nCount = xItemArray->Count32();
2256     for( sal_Int32 i = 0 ; i < nCount ; i++ )
2257     {
2258         if( xItemArray->Get32( i ) == pFound )
2259             return i;
2260     }
2261     return -1;
2262 }
2263 
CollAdd(SbxArray * pPar_)2264 void BasicCollection::CollAdd( SbxArray* pPar_ )
2265 {
2266     sal_uInt16 nCount = pPar_->Count();
2267     if( nCount < 2 || nCount > 5 )
2268     {
2269         SetError( SbxERR_WRONG_ARGS );
2270         return;
2271     }
2272 
2273     SbxVariable* pItem = pPar_->Get(1);
2274     if( pItem )
2275     {
2276         int nNextIndex;
2277         if( nCount < 4 )
2278         {
2279             nNextIndex = xItemArray->Count();
2280         }
2281         else
2282         {
2283             SbxVariable* pBefore = pPar_->Get(3);
2284             if( nCount == 5 )
2285             {
2286                 if( !( pBefore->IsErr() || ( pBefore->GetType() == SbxEMPTY ) ) )
2287                 {
2288                     SetError( SbERR_BAD_ARGUMENT );
2289                     return;
2290                 }
2291                 SbxVariable* pAfter = pPar_->Get(4);
2292                 sal_Int32 nAfterIndex = implGetIndex( pAfter );
2293                 if( nAfterIndex == -1 )
2294                 {
2295                     SetError( SbERR_BAD_ARGUMENT );
2296                     return;
2297                 }
2298                 nNextIndex = nAfterIndex + 1;
2299             }
2300             else // if( nCount == 4 )
2301             {
2302                 sal_Int32 nBeforeIndex = implGetIndex( pBefore );
2303                 if( nBeforeIndex == -1 )
2304                 {
2305                     SetError( SbERR_BAD_ARGUMENT );
2306                     return;
2307                 }
2308                 nNextIndex = nBeforeIndex;
2309             }
2310         }
2311 
2312         SbxVariableRef pNewItem = new SbxVariable( *pItem );
2313         if( nCount >= 3 )
2314         {
2315             SbxVariable* pKey = pPar_->Get(2);
2316             if( !( pKey->IsErr() || ( pKey->GetType() == SbxEMPTY ) ) )
2317             {
2318                 if( pKey->GetType() != SbxSTRING )
2319                 {
2320                     SetError( SbERR_BAD_ARGUMENT );
2321                     return;
2322                 }
2323                 String aKey = pKey->GetString();
2324                 if( implGetIndexForName( aKey ) != -1 )
2325                 {
2326                     SetError( SbERR_BAD_ARGUMENT );
2327                     return;
2328                 }
2329                 pNewItem->SetName( aKey );
2330             }
2331         }
2332         pNewItem->SetFlag( SBX_READWRITE );
2333         xItemArray->Insert32( pNewItem, nNextIndex );
2334         implRegisterName( pNewItem );
2335     }
2336     else
2337     {
2338         SetError( SbERR_BAD_ARGUMENT );
2339         return;
2340     }
2341 }
2342 
CollItem(SbxArray * pPar_)2343 void BasicCollection::CollItem( SbxArray* pPar_ )
2344 {
2345     if( pPar_->Count() != 2 )
2346     {
2347         SetError( SbxERR_WRONG_ARGS );
2348         return;
2349     }
2350     SbxVariable* pRes = NULL;
2351     SbxVariable* p = pPar_->Get( 1 );
2352     if( p->GetType() == SbxSTRING )
2353     {
2354         pRes = implFindByName( p->GetString() );
2355     }
2356     else
2357     {
2358         sal_Int32 nIndex = implGetIndex( p );
2359         if( nIndex >= 0 && nIndex < (sal_Int32)xItemArray->Count32() )
2360             pRes = xItemArray->Get32( nIndex );
2361     }
2362     if( !pRes )
2363         SetError( SbERR_BAD_ARGUMENT );
2364     else
2365         *(pPar_->Get(0)) = *pRes;
2366 }
2367 
CollRemove(SbxArray * pPar_)2368 void BasicCollection::CollRemove( SbxArray* pPar_ )
2369 {
2370     if( pPar_ == NULL || pPar_->Count() != 2 )
2371     {
2372         SetError( SbxERR_WRONG_ARGS );
2373         return;
2374     }
2375 
2376     SbxVariable* p = pPar_->Get( 1 );
2377     sal_Int32 nIndex = implGetIndex( p );
2378     if( nIndex >= 0 && nIndex < (sal_Int32)xItemArray->Count32() )
2379     {
2380         implUnregisterName( xItemArray->Get32( nIndex ) );
2381         xItemArray->Remove32( nIndex );
2382 
2383         // Correct for stack if necessary
2384         SbiInstance* pInst = pINST;
2385         SbiRuntime* pRT = pInst ? pInst->pRun : NULL;
2386         if( pRT )
2387         {
2388             SbiForStack* pStack = pRT->FindForStackItemForCollection( this );
2389             if( pStack != NULL )
2390             {
2391                 if( pStack->nCurCollectionIndex >= nIndex )
2392                     --pStack->nCurCollectionIndex;
2393             }
2394         }
2395     }
2396     else
2397         SetError( SbERR_BAD_ARGUMENT );
2398 }
2399