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