xref: /AOO41X/main/basic/source/runtime/step1.cxx (revision e1f63238eb022c8a12b30d46a012444ff20e0951)
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 <stdlib.h>
28 #include <rtl/math.hxx>
29 #include <basic/sbuno.hxx>
30 #include "runtime.hxx"
31 #include "sbintern.hxx"
32 #include "iosys.hxx"
33 #include "image.hxx"
34 #include "sbunoobj.hxx"
35 #include "errobject.hxx"
36 
37 bool checkUnoObjectType( SbUnoObject* refVal, const ::rtl::OUString& aClass );
38 
39 // Laden einer numerischen Konstanten (+ID)
40 
StepLOADNC(sal_uInt32 nOp1)41 void SbiRuntime::StepLOADNC( sal_uInt32 nOp1 )
42 {
43     SbxVariable* p = new SbxVariable( SbxDOUBLE );
44 
45     // #57844 Lokalisierte Funktion benutzen
46     String aStr = pImg->GetString( static_cast<short>( nOp1 ) );
47     // Auch , zulassen !!!
48     sal_uInt16 iComma = aStr.Search( ',' );
49     if( iComma != STRING_NOTFOUND )
50     {
51         String aStr1 = aStr.Copy( 0, iComma );
52         String aStr2 = aStr.Copy( iComma + 1 );
53         aStr = aStr1;
54         aStr += '.';
55         aStr += aStr2;
56     }
57     double n = ::rtl::math::stringToDouble( aStr, '.', ',', NULL, NULL );
58 
59     p->PutDouble( n );
60     PushVar( p );
61 }
62 
63 // Laden einer Stringkonstanten (+ID)
64 
StepLOADSC(sal_uInt32 nOp1)65 void SbiRuntime::StepLOADSC( sal_uInt32 nOp1 )
66 {
67     SbxVariable* p = new SbxVariable;
68     p->PutString( pImg->GetString( static_cast<short>( nOp1 ) ) );
69     PushVar( p );
70 }
71 
72 // Immediate Load (+Wert)
73 
StepLOADI(sal_uInt32 nOp1)74 void SbiRuntime::StepLOADI( sal_uInt32 nOp1 )
75 {
76     SbxVariable* p = new SbxVariable;
77     p->PutInteger( static_cast<sal_Int16>( nOp1 ) );
78     PushVar( p );
79 }
80 
81 // Speichern eines named Arguments in Argv (+Arg-Nr ab 1!)
82 
StepARGN(sal_uInt32 nOp1)83 void SbiRuntime::StepARGN( sal_uInt32 nOp1 )
84 {
85     if( !refArgv )
86         StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
87     else
88     {
89         String aAlias( pImg->GetString( static_cast<short>( nOp1 ) ) );
90         SbxVariableRef pVal = PopVar();
91         refArgv->Put( pVal, nArgc );
92         refArgv->PutAlias( aAlias, nArgc++ );
93     }
94 }
95 
96 // Konvertierung des Typs eines Arguments in Argv fuer DECLARE-Fkt. (+Typ)
97 
StepARGTYP(sal_uInt32 nOp1)98 void SbiRuntime::StepARGTYP( sal_uInt32 nOp1 )
99 {
100     if( !refArgv )
101         StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
102     else
103     {
104         sal_Bool bByVal = (nOp1 & 0x8000) != 0;         // Ist BYVAL verlangt?
105         SbxDataType t = (SbxDataType) (nOp1 & 0x7FFF);
106         SbxVariable* pVar = refArgv->Get( refArgv->Count() - 1 );   // letztes Arg
107 
108         // BYVAL pr�fen
109         if( pVar->GetRefCount() > 2 )       // 2 ist normal f�r BYVAL
110         {
111             // Parameter ist eine Referenz
112             if( bByVal )
113             {
114                 // Call by Value ist verlangt -> Kopie anlegen
115                 pVar = new SbxVariable( *pVar );
116                 pVar->SetFlag( SBX_READWRITE );
117                 refExprStk->Put( pVar, refArgv->Count() - 1 );
118             }
119             else
120                 pVar->SetFlag( SBX_REFERENCE );     // Ref-Flag f�r DllMgr
121         }
122         else
123         {
124             // Parameter ist KEINE Referenz
125             if( bByVal )
126                 pVar->ResetFlag( SBX_REFERENCE );   // Keine Referenz -> OK
127             else
128                 Error( SbERR_BAD_PARAMETERS );      // Referenz verlangt
129         }
130 
131         if( pVar->GetType() != t )
132         {
133             // Variant, damit richtige Konvertierung
134             // Ausserdem Fehler, wenn SbxBYREF
135             pVar->Convert( SbxVARIANT );
136             pVar->Convert( t );
137         }
138     }
139 }
140 
141 // String auf feste Laenge bringen (+Laenge)
142 
StepPAD(sal_uInt32 nOp1)143 void SbiRuntime::StepPAD( sal_uInt32 nOp1 )
144 {
145     SbxVariable* p = GetTOS();
146     String& s = (String&)(const String&) *p;
147     if( s.Len() > nOp1 )
148         s.Erase( static_cast<xub_StrLen>( nOp1 ) );
149     else
150         s.Expand( static_cast<xub_StrLen>( nOp1 ), ' ' );
151 }
152 
153 // Sprung (+Target)
154 
StepJUMP(sal_uInt32 nOp1)155 void SbiRuntime::StepJUMP( sal_uInt32 nOp1 )
156 {
157 #ifdef DBG_UTIL
158     // #QUESTION shouln't this be
159     // if( (sal_uInt8*)( nOp1+pImagGetCode() ) >= pImg->GetCodeSize() )
160     if( nOp1 >= pImg->GetCodeSize() )
161         StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
162 #endif
163     pCode = (const sal_uInt8*) pImg->GetCode() + nOp1;
164 }
165 
166 // TOS auswerten, bedingter Sprung (+Target)
167 
StepJUMPT(sal_uInt32 nOp1)168 void SbiRuntime::StepJUMPT( sal_uInt32 nOp1 )
169 {
170     SbxVariableRef p = PopVar();
171     if( p->GetBool() )
172         StepJUMP( nOp1 );
173 }
174 
175 // TOS auswerten, bedingter Sprung (+Target)
176 
StepJUMPF(sal_uInt32 nOp1)177 void SbiRuntime::StepJUMPF( sal_uInt32 nOp1 )
178 {
179     SbxVariableRef p = PopVar();
180     if( !p->GetBool() )
181         StepJUMP( nOp1 );
182 }
183 
184 // TOS auswerten, Sprung in JUMP-Tabelle (+MaxVal)
185 // Sieht so aus:
186 // ONJUMP 2
187 // JUMP target1
188 // JUMP target2
189 // ...
190 //Falls im Operanden 0x8000 gesetzt ist, Returnadresse pushen (ON..GOSUB)
191 
StepONJUMP(sal_uInt32 nOp1)192 void SbiRuntime::StepONJUMP( sal_uInt32 nOp1 )
193 {
194     SbxVariableRef p = PopVar();
195     sal_Int16 n = p->GetInteger();
196     if( nOp1 & 0x8000 )
197     {
198         nOp1 &= 0x7FFF;
199         //PushGosub( pCode + 3 * nOp1 );
200         PushGosub( pCode + 5 * nOp1 );
201     }
202     if( n < 1 || static_cast<sal_uInt32>(n) > nOp1 )
203         n = static_cast<sal_Int16>( nOp1 + 1 );
204     //nOp1 = (sal_uInt32) ( (const char*) pCode - pImg->GetCode() ) + 3 * --n;
205     nOp1 = (sal_uInt32) ( (const char*) pCode - pImg->GetCode() ) + 5 * --n;
206     StepJUMP( nOp1 );
207 }
208 
209 // UP-Aufruf (+Target)
210 
StepGOSUB(sal_uInt32 nOp1)211 void SbiRuntime::StepGOSUB( sal_uInt32 nOp1 )
212 {
213     PushGosub( pCode );
214     if( nOp1 >= pImg->GetCodeSize() )
215         StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
216     pCode = (const sal_uInt8*) pImg->GetCode() + nOp1;
217 }
218 
219 // UP-Return (+0 oder Target)
220 
StepRETURN(sal_uInt32 nOp1)221 void SbiRuntime::StepRETURN( sal_uInt32 nOp1 )
222 {
223     PopGosub();
224     if( nOp1 )
225         StepJUMP( nOp1 );
226 }
227 
228 // FOR-Variable testen (+Endlabel)
229 
StepTESTFOR(sal_uInt32 nOp1)230 void SbiRuntime::StepTESTFOR( sal_uInt32 nOp1 )
231 {
232     if( !pForStk )
233     {
234         StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
235         return;
236     }
237 
238     bool bEndLoop = false;
239     switch( pForStk->eForType )
240     {
241         case FOR_TO:
242         {
243             SbxOperator eOp = ( pForStk->refInc->GetDouble() < 0 ) ? SbxLT : SbxGT;
244             if( pForStk->refVar->Compare( eOp, *pForStk->refEnd ) )
245                 bEndLoop = true;
246             break;
247         }
248         case FOR_EACH_ARRAY:
249         {
250             SbiForStack* p = pForStk;
251             if( p->pArrayCurIndices == NULL )
252             {
253                 bEndLoop = true;
254             }
255             else
256             {
257                 SbxDimArray* pArray = (SbxDimArray*)(SbxVariable*)p->refEnd;
258                 short nDims = pArray->GetDims();
259 
260                 // Empty array?
261                 if( nDims == 1 && p->pArrayLowerBounds[0] > p->pArrayUpperBounds[0] )
262                 {
263                     bEndLoop = true;
264                     break;
265                 }
266                 SbxVariable* pVal = pArray->Get32( p->pArrayCurIndices );
267                 *(p->refVar) = *pVal;
268 
269                 bool bFoundNext = false;
270                 for( short i = 0 ; i < nDims ; i++ )
271                 {
272                     if( p->pArrayCurIndices[i] < p->pArrayUpperBounds[i] )
273                     {
274                         bFoundNext = true;
275                         p->pArrayCurIndices[i]++;
276                         for( short j = i - 1 ; j >= 0 ; j-- )
277                             p->pArrayCurIndices[j] = p->pArrayLowerBounds[j];
278                         break;
279                     }
280                 }
281                 if( !bFoundNext )
282                 {
283                     delete[] p->pArrayCurIndices;
284                     p->pArrayCurIndices = NULL;
285                 }
286             }
287             break;
288         }
289         case FOR_EACH_COLLECTION:
290         {
291             BasicCollection* pCollection = (BasicCollection*)(SbxVariable*)pForStk->refEnd;
292             SbxArrayRef xItemArray = pCollection->xItemArray;
293             sal_Int32 nCount = xItemArray->Count32();
294             if( pForStk->nCurCollectionIndex < nCount )
295             {
296                 SbxVariable* pRes = xItemArray->Get32( pForStk->nCurCollectionIndex );
297                 pForStk->nCurCollectionIndex++;
298                 (*pForStk->refVar) = *pRes;
299             }
300             else
301             {
302                 bEndLoop = true;
303             }
304             break;
305         }
306         case FOR_EACH_XENUMERATION:
307         {
308             SbiForStack* p = pForStk;
309             if( p->xEnumeration->hasMoreElements() )
310             {
311                 Any aElem = p->xEnumeration->nextElement();
312                 SbxVariableRef xVar = new SbxVariable( SbxVARIANT );
313                 unoToSbxValue( (SbxVariable*)xVar, aElem );
314                 (*pForStk->refVar) = *xVar;
315             }
316             else
317             {
318                 bEndLoop = true;
319             }
320             break;
321         }
322     }
323     if( bEndLoop )
324     {
325         PopFor();
326         StepJUMP( nOp1 );
327     }
328 }
329 
330 // Tos+1 <= Tos+2 <= Tos, 2xremove (+Target)
331 
StepCASETO(sal_uInt32 nOp1)332 void SbiRuntime::StepCASETO( sal_uInt32 nOp1 )
333 {
334     if( !refCaseStk || !refCaseStk->Count() )
335         StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
336     else
337     {
338         SbxVariableRef xTo   = PopVar();
339         SbxVariableRef xFrom = PopVar();
340         SbxVariableRef xCase = refCaseStk->Get( refCaseStk->Count() - 1 );
341         if( *xCase >= *xFrom && *xCase <= *xTo )
342             StepJUMP( nOp1 );
343     }
344 }
345 
346 // Fehler-Handler
347 
StepERRHDL(sal_uInt32 nOp1)348 void SbiRuntime::StepERRHDL( sal_uInt32 nOp1 )
349 {
350     const sal_uInt8* p = pCode;
351     StepJUMP( nOp1 );
352     pError = pCode;
353     pCode = p;
354     pInst->aErrorMsg = String();
355     pInst->nErr = 0;
356     pInst->nErl = 0;
357     nError = 0;
358     SbxErrObject::getUnoErrObject()->Clear();
359 }
360 
361 // Resume nach Fehlern (+0=statement, 1=next or Label)
362 
StepRESUME(sal_uInt32 nOp1)363 void SbiRuntime::StepRESUME( sal_uInt32 nOp1 )
364 {
365     // AB #32714 Resume ohne Error? -> Fehler
366     if( !bInError )
367     {
368         Error( SbERR_BAD_RESUME );
369         return;
370     }
371     if( nOp1 )
372     {
373         // Code-Zeiger auf naechstes Statement setzen
374         sal_uInt16 n1, n2;
375         pCode = pMod->FindNextStmnt( pErrCode, n1, n2, sal_True, pImg );
376     }
377     else
378         pCode = pErrStmnt;
379     if ( pError ) // current in error handler ( and got a Resume Next statment )
380         SbxErrObject::getUnoErrObject()->Clear();
381 
382     if( nOp1 > 1 )
383         StepJUMP( nOp1 );
384     pInst->aErrorMsg = String();
385     pInst->nErr = 0;
386     pInst->nErl = 0;
387     nError = 0;
388     bInError = sal_False;
389 
390     // Error-Stack loeschen
391     SbErrorStack*& rErrStack = GetSbData()->pErrStack;
392     delete rErrStack;
393     rErrStack = NULL;
394 }
395 
396 // Kanal schliessen (+Kanal, 0=Alle)
StepCLOSE(sal_uInt32 nOp1)397 void SbiRuntime::StepCLOSE( sal_uInt32 nOp1 )
398 {
399     SbError err;
400     if( !nOp1 )
401         pIosys->Shutdown();
402     else
403     {
404         err = pIosys->GetError();
405         if( !err )
406         {
407             pIosys->Close();
408         }
409     }
410     err = pIosys->GetError();
411     Error( err );
412 }
413 
414 // Zeichen ausgeben (+char)
415 
StepPRCHAR(sal_uInt32 nOp1)416 void SbiRuntime::StepPRCHAR( sal_uInt32 nOp1 )
417 {
418     ByteString s( (char) nOp1 );
419     pIosys->Write( s );
420     Error( pIosys->GetError() );
421 }
422 
423 // Check, ob TOS eine bestimmte Objektklasse ist (+StringID)
424 
implIsClass(SbxObject * pObj,const String & aClass)425 bool SbiRuntime::implIsClass( SbxObject* pObj, const String& aClass )
426 {
427     bool bRet = true;
428 
429     if( aClass.Len() != 0 )
430     {
431         bRet = pObj->IsClass( aClass );
432         if( !bRet )
433             bRet = aClass.EqualsIgnoreCaseAscii( String( RTL_CONSTASCII_USTRINGPARAM("object") ) );
434         if( !bRet )
435         {
436             String aObjClass = pObj->GetClassName();
437             SbModule* pClassMod = pCLASSFAC->FindClass( aObjClass );
438             SbClassData* pClassData;
439             if( pClassMod && (pClassData=pClassMod->pClassData) != NULL )
440             {
441                 SbxVariable* pClassVar =
442                     pClassData->mxIfaces->Find( aClass, SbxCLASS_DONTCARE );
443                 bRet = (pClassVar != NULL);
444             }
445         }
446     }
447     return bRet;
448 }
449 
checkClass_Impl(const SbxVariableRef & refVal,const String & aClass,bool bRaiseErrors,bool bDefault)450 bool SbiRuntime::checkClass_Impl( const SbxVariableRef& refVal,
451     const String& aClass, bool bRaiseErrors, bool bDefault )
452 {
453     bool bOk = bDefault;
454 
455     SbxDataType t = refVal->GetType();
456     if( t == SbxOBJECT )
457     {
458         SbxObject* pObj;
459         SbxVariable* pVal = (SbxVariable*)refVal;
460         if( pVal->IsA( TYPE(SbxObject) ) )
461             pObj = (SbxObject*) pVal;
462         else
463         {
464             pObj = (SbxObject*) refVal->GetObject();
465             if( pObj && !pObj->IsA( TYPE(SbxObject) ) )
466                 pObj = NULL;
467         }
468         if( pObj )
469         {
470             if( !implIsClass( pObj, aClass ) )
471             {
472                 if ( bVBAEnabled && pObj->IsA( TYPE(SbUnoObject) ) )
473                 {
474                     SbUnoObject* pUnoObj = PTR_CAST(SbUnoObject,pObj);
475                     bOk = checkUnoObjectType( pUnoObj, aClass );
476                 }
477                 else
478                     bOk = false;
479                 if ( !bOk )
480                 {
481                     if( bRaiseErrors )
482                         Error( SbERR_INVALID_USAGE_OBJECT );
483                 }
484             }
485             else
486             {
487                 bOk = true;
488 
489                 SbClassModuleObject* pClassModuleObject = PTR_CAST(SbClassModuleObject,pObj);
490                 if( pClassModuleObject != NULL )
491                     pClassModuleObject->triggerInitializeEvent();
492             }
493         }
494     }
495     else
496     {
497         if ( !bVBAEnabled )
498         {
499             if( bRaiseErrors )
500                 Error( SbERR_NEEDS_OBJECT );
501             bOk = false;
502         }
503     }
504     return bOk;
505 }
506 
StepSETCLASS_impl(sal_uInt32 nOp1,bool bHandleDflt)507 void SbiRuntime::StepSETCLASS_impl( sal_uInt32 nOp1, bool bHandleDflt )
508 {
509     SbxVariableRef refVal = PopVar();
510     SbxVariableRef refVar = PopVar();
511     String aClass( pImg->GetString( static_cast<short>( nOp1 ) ) );
512 
513     bool bOk = checkClass_Impl( refVal, aClass, true );
514     if( bOk )
515         StepSET_Impl( refVal, refVar, bHandleDflt ); // don't do handle dflt prop for a "proper" set
516 }
517 
StepVBASETCLASS(sal_uInt32 nOp1)518 void SbiRuntime::StepVBASETCLASS( sal_uInt32 nOp1 )
519 {
520     StepSETCLASS_impl( nOp1, false );
521 }
522 
StepSETCLASS(sal_uInt32 nOp1)523 void SbiRuntime::StepSETCLASS( sal_uInt32 nOp1 )
524 {
525     StepSETCLASS_impl( nOp1, true );
526 }
527 
StepTESTCLASS(sal_uInt32 nOp1)528 void SbiRuntime::StepTESTCLASS( sal_uInt32 nOp1 )
529 {
530     SbxVariableRef xObjVal = PopVar();
531     String aClass( pImg->GetString( static_cast<short>( nOp1 ) ) );
532     bool bDefault = !bVBAEnabled;
533     bool bOk = checkClass_Impl( xObjVal, aClass, false, bDefault );
534 
535     SbxVariable* pRet = new SbxVariable;
536     pRet->PutBool( bOk );
537     PushVar( pRet );
538 }
539 
540 // Library fuer anschliessenden Declare-Call definieren
541 
StepLIB(sal_uInt32 nOp1)542 void SbiRuntime::StepLIB( sal_uInt32 nOp1 )
543 {
544     aLibName = pImg->GetString( static_cast<short>( nOp1 ) );
545 }
546 
547 // TOS wird um BASE erhoeht, BASE davor gepusht (+BASE)
548 // Dieser Opcode wird vor DIM/REDIM-Anweisungen gepusht,
549 // wenn nur ein Index angegeben wurde.
550 
StepBASED(sal_uInt32 nOp1)551 void SbiRuntime::StepBASED( sal_uInt32 nOp1 )
552 {
553     SbxVariable* p1 = new SbxVariable;
554     SbxVariableRef x2 = PopVar();
555 
556     // #109275 Check compatiblity mode
557     bool bCompatible = ((nOp1 & 0x8000) != 0);
558     sal_uInt16 uBase = static_cast<sal_uInt16>(nOp1 & 1);       // Can only be 0 or 1
559     p1->PutInteger( uBase );
560     if( !bCompatible )
561         x2->Compute( SbxPLUS, *p1 );
562     PushVar( x2 );  // erst die Expr
563     PushVar( p1 );  // dann die Base
564 }
565 
566 
567 
568 
569 
570