/************************************************************** * * Licensed to the Apache Software Foundation (ASF) under one * or more contributor license agreements. See the NOTICE file * distributed with this work for additional information * regarding copyright ownership. The ASF licenses this file * to you under the Apache License, Version 2.0 (the * "License"); you may not use this file except in compliance * with the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. * *************************************************************/ // MARKER(update_precomp.py): autogen include statement, do not remove #include "precompiled_basic.hxx" #include #include #include #include #include #include "runtime.hxx" #include "sbintern.hxx" #include "opcodes.hxx" #include "codegen.hxx" #include "iosys.hxx" #include "image.hxx" #include "ddectrl.hxx" #include "dllmgr.hxx" #include #include #include "sbunoobj.hxx" #include "errobject.hxx" #include "sbtrace.hxx" #include "comenumwrapper.hxx" using namespace ::com::sun::star; bool SbiRuntime::isVBAEnabled() { bool result = false; SbiInstance* pInst = pINST; if ( pInst && pINST->pRun ) result = pInst->pRun->bVBAEnabled; return result; } // #91147 Global reschedule flag static sal_Bool bStaticGlobalEnableReschedule = sal_True; void StarBASIC::StaticEnableReschedule( sal_Bool bReschedule ) { bStaticGlobalEnableReschedule = bReschedule; } void StarBASIC::SetVBAEnabled( sal_Bool bEnabled ) { if ( bDocBasic ) { bVBAEnabled = bEnabled; } } sal_Bool StarBASIC::isVBAEnabled() { if ( bDocBasic ) { if( SbiRuntime::isVBAEnabled() ) return sal_True; return bVBAEnabled; } return sal_False; } struct SbiArgvStack { // Argv stack: SbiArgvStack* pNext; // Stack Chain SbxArrayRef refArgv; // Argv short nArgc; // Argc }; SbiRuntime::pStep0 SbiRuntime::aStep0[] = { // Alle Opcodes ohne Operanden &SbiRuntime::StepNOP, &SbiRuntime::StepEXP, &SbiRuntime::StepMUL, &SbiRuntime::StepDIV, &SbiRuntime::StepMOD, &SbiRuntime::StepPLUS, &SbiRuntime::StepMINUS, &SbiRuntime::StepNEG, &SbiRuntime::StepEQ, &SbiRuntime::StepNE, &SbiRuntime::StepLT, &SbiRuntime::StepGT, &SbiRuntime::StepLE, &SbiRuntime::StepGE, &SbiRuntime::StepIDIV, &SbiRuntime::StepAND, &SbiRuntime::StepOR, &SbiRuntime::StepXOR, &SbiRuntime::StepEQV, &SbiRuntime::StepIMP, &SbiRuntime::StepNOT, &SbiRuntime::StepCAT, &SbiRuntime::StepLIKE, &SbiRuntime::StepIS, // Laden/speichern &SbiRuntime::StepARGC, // neuen Argv einrichten &SbiRuntime::StepARGV, // TOS ==> aktueller Argv &SbiRuntime::StepINPUT, // Input ==> TOS &SbiRuntime::StepLINPUT, // Line Input ==> TOS &SbiRuntime::StepGET, // TOS anfassen &SbiRuntime::StepSET, // Speichern Objekt TOS ==> TOS-1 &SbiRuntime::StepPUT, // TOS ==> TOS-1 &SbiRuntime::StepPUTC, // TOS ==> TOS-1, dann ReadOnly &SbiRuntime::StepDIM, // DIM &SbiRuntime::StepREDIM, // REDIM &SbiRuntime::StepREDIMP, // REDIM PRESERVE &SbiRuntime::StepERASE, // TOS loeschen // Verzweigen &SbiRuntime::StepSTOP, // Programmende &SbiRuntime::StepINITFOR, // FOR-Variable initialisieren &SbiRuntime::StepNEXT, // FOR-Variable inkrementieren &SbiRuntime::StepCASE, // Anfang CASE &SbiRuntime::StepENDCASE, // Ende CASE &SbiRuntime::StepSTDERROR, // Standard-Fehlerbehandlung &SbiRuntime::StepNOERROR, // keine Fehlerbehandlung &SbiRuntime::StepLEAVE, // UP verlassen // E/A &SbiRuntime::StepCHANNEL, // TOS = Kanalnummer &SbiRuntime::StepPRINT, // print TOS &SbiRuntime::StepPRINTF, // print TOS in field &SbiRuntime::StepWRITE, // write TOS &SbiRuntime::StepRENAME, // Rename Tos+1 to Tos &SbiRuntime::StepPROMPT, // Input Prompt aus TOS definieren &SbiRuntime::StepRESTART, // Set restart point &SbiRuntime::StepCHANNEL0, // E/A-Kanal 0 einstellen &SbiRuntime::StepEMPTY, // Leeren Ausdruck auf Stack &SbiRuntime::StepERROR, // TOS = Fehlercode &SbiRuntime::StepLSET, // Speichern Objekt TOS ==> TOS-1 &SbiRuntime::StepRSET, // Speichern Objekt TOS ==> TOS-1 &SbiRuntime::StepREDIMP_ERASE,// Copy array object for REDIMP &SbiRuntime::StepINITFOREACH,// Init for each loop &SbiRuntime::StepVBASET,// vba-like set statement &SbiRuntime::StepERASE_CLEAR,// vba-like set statement &SbiRuntime::StepARRAYACCESS,// access TOS as array &SbiRuntime::StepBYVAL, // access TOS as array }; SbiRuntime::pStep1 SbiRuntime::aStep1[] = { // Alle Opcodes mit einem Operanden &SbiRuntime::StepLOADNC, // Laden einer numerischen Konstanten (+ID) &SbiRuntime::StepLOADSC, // Laden einer Stringkonstanten (+ID) &SbiRuntime::StepLOADI, // Immediate Load (+Wert) &SbiRuntime::StepARGN, // Speichern eines named Args in Argv (+StringID) &SbiRuntime::StepPAD, // String auf feste Laenge bringen (+Laenge) // Verzweigungen &SbiRuntime::StepJUMP, // Sprung (+Target) &SbiRuntime::StepJUMPT, // TOS auswerten), bedingter Sprung (+Target) &SbiRuntime::StepJUMPF, // TOS auswerten), bedingter Sprung (+Target) &SbiRuntime::StepONJUMP, // TOS auswerten), Sprung in JUMP-Tabelle (+MaxVal) &SbiRuntime::StepGOSUB, // UP-Aufruf (+Target) &SbiRuntime::StepRETURN, // UP-Return (+0 oder Target) &SbiRuntime::StepTESTFOR, // FOR-Variable testen), inkrementieren (+Endlabel) &SbiRuntime::StepCASETO, // Tos+1 <= Case <= Tos), 2xremove (+Target) &SbiRuntime::StepERRHDL, // Fehler-Handler (+Offset) &SbiRuntime::StepRESUME, // Resume nach Fehlern (+0 or 1 or Label) // E/A &SbiRuntime::StepCLOSE, // (+Kanal/0) &SbiRuntime::StepPRCHAR, // (+char) // Verwaltung &SbiRuntime::StepSETCLASS, // Set + Klassennamen testen (+StringId) &SbiRuntime::StepTESTCLASS, // Check TOS class (+StringId) &SbiRuntime::StepLIB, // Lib fuer Declare-Call (+StringId) &SbiRuntime::StepBASED, // TOS wird um BASE erhoeht, BASE davor gepusht &SbiRuntime::StepARGTYP, // Letzten Parameter in Argv konvertieren (+Typ) &SbiRuntime::StepVBASETCLASS,// vba-like set statement }; SbiRuntime::pStep2 SbiRuntime::aStep2[] = {// Alle Opcodes mit zwei Operanden &SbiRuntime::StepRTL, // Laden aus RTL (+StringID+Typ) &SbiRuntime::StepFIND, // Laden (+StringID+Typ) &SbiRuntime::StepELEM, // Laden Element (+StringID+Typ) &SbiRuntime::StepPARAM, // Parameter (+Offset+Typ) // Verzweigen &SbiRuntime::StepCALL, // Declare-Call (+StringID+Typ) &SbiRuntime::StepCALLC, // CDecl-Declare-Call (+StringID+Typ) &SbiRuntime::StepCASEIS, // Case-Test (+Test-Opcode+False-Target) // Verwaltung &SbiRuntime::StepSTMNT, // Beginn eines Statements (+Line+Col) // E/A &SbiRuntime::StepOPEN, // (+SvStreamFlags+Flags) // Objekte &SbiRuntime::StepLOCAL, // Lokale Variable definieren (+StringId+Typ) &SbiRuntime::StepPUBLIC, // Modulglobale Variable (+StringID+Typ) &SbiRuntime::StepGLOBAL, // Globale Variable definieren (+StringID+Typ) &SbiRuntime::StepCREATE, // Objekt kreieren (+StringId+StringId) &SbiRuntime::StepSTATIC, // Statische Variable (+StringId+StringId) &SbiRuntime::StepTCREATE, // User Defined Objekte (+StringId+StringId) &SbiRuntime::StepDCREATE, // Objekt-Array kreieren (+StringID+StringID) &SbiRuntime::StepGLOBAL_P, // Globale Variable definieren, die beim Neustart // von Basic nicht ueberschrieben wird (+StringID+Typ) &SbiRuntime::StepFIND_G, // Sucht globale Variable mit Spezialbehandlung wegen _GLOBAL_P &SbiRuntime::StepDCREATE_REDIMP, // Objekt-Array redimensionieren (+StringID+StringID) &SbiRuntime::StepFIND_CM, // Search inside a class module (CM) to enable global search in time &SbiRuntime::StepPUBLIC_P, // Search inside a class module (CM) to enable global search in time &SbiRuntime::StepFIND_STATIC, // Search inside a class module (CM) to enable global search in time }; ////////////////////////////////////////////////////////////////////////// // SbiRTLData // ////////////////////////////////////////////////////////////////////////// SbiRTLData::SbiRTLData() { pDir = 0; nDirFlags = 0; nCurDirPos = 0; pWildCard = NULL; } SbiRTLData::~SbiRTLData() { delete pDir; pDir = 0; delete pWildCard; } ////////////////////////////////////////////////////////////////////////// // SbiInstance // ////////////////////////////////////////////////////////////////////////// // 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out // Die Entscheidung, ob StepPoint aufgerufen werden soll, wird anhand des // CallLevels getroffen. Angehalten wird, wenn der aktuelle CallLevel <= // nBreakCallLvl ist. Der aktuelle CallLevel kann niemals kleiner als 1 // sein, da er beim Aufruf einer Methode (auch main) inkrementiert wird. // Daher bedeutet ein BreakCallLvl von 0, dass das Programm gar nicht // angehalten wird. // (siehe auch step2.cxx, SbiRuntime::StepSTMNT() ) // Hilfsfunktion, um den BreakCallLevel gemaess der der Debug-Flags zu ermitteln void SbiInstance::CalcBreakCallLevel( sal_uInt16 nFlags ) { // Break-Flag wegfiltern nFlags &= ~((sal_uInt16)SbDEBUG_BREAK); sal_uInt16 nRet; switch( nFlags ) { case SbDEBUG_STEPINTO: nRet = nCallLvl + 1; // CallLevel+1 wird auch angehalten break; case SbDEBUG_STEPOVER | SbDEBUG_STEPINTO: nRet = nCallLvl; // Aktueller CallLevel wird angehalten break; case SbDEBUG_STEPOUT: nRet = nCallLvl - 1; // Kleinerer CallLevel wird angehalten break; case SbDEBUG_CONTINUE: // Basic-IDE liefert 0 statt SbDEBUG_CONTINUE, also auch default=continue default: nRet = 0; // CallLevel ist immer >0 -> kein StepPoint } nBreakCallLvl = nRet; // Ergebnis uebernehmen } SbiInstance::SbiInstance( StarBASIC* p ) { pBasic = p; pNext = NULL; pRun = NULL; pIosys = new SbiIoSystem; pDdeCtrl = new SbiDdeControl; pDllMgr = 0; // on demand pNumberFormatter = 0; // on demand nCallLvl = 0; nBreakCallLvl = 0; nErr = nErl = 0; bReschedule = sal_True; bCompatibility = sal_False; } SbiInstance::~SbiInstance() { while( pRun ) { SbiRuntime* p = pRun->pNext; delete pRun; pRun = p; } delete pIosys; delete pDdeCtrl; delete pDllMgr; delete pNumberFormatter; try { int nSize = ComponentVector.size(); if( nSize ) { for( int i = nSize - 1 ; i >= 0 ; --i ) { Reference< XComponent > xDlgComponent = ComponentVector[i]; if( xDlgComponent.is() ) xDlgComponent->dispose(); } } } catch( const Exception& ) { DBG_ERROR( "SbiInstance::~SbiInstance: caught an exception while disposing the components!" ); } ComponentVector.clear(); } SbiDllMgr* SbiInstance::GetDllMgr() { if( !pDllMgr ) pDllMgr = new SbiDllMgr; return pDllMgr; } // #39629 NumberFormatter jetzt ueber statische Methode anlegen SvNumberFormatter* SbiInstance::GetNumberFormatter() { LanguageType eLangType = GetpApp()->GetSettings().GetLanguage(); SvtSysLocale aSysLocale; DateFormat eDate = aSysLocale.GetLocaleData().getDateFormat(); if( pNumberFormatter ) { if( eLangType != meFormatterLangType || eDate != meFormatterDateFormat ) { delete pNumberFormatter; pNumberFormatter = NULL; } } meFormatterLangType = eLangType; meFormatterDateFormat = eDate; if( !pNumberFormatter ) PrepareNumberFormatter( pNumberFormatter, nStdDateIdx, nStdTimeIdx, nStdDateTimeIdx, &meFormatterLangType, &meFormatterDateFormat ); return pNumberFormatter; } // #39629 NumberFormatter auch statisch anbieten void SbiInstance::PrepareNumberFormatter( SvNumberFormatter*& rpNumberFormatter, sal_uInt32 &rnStdDateIdx, sal_uInt32 &rnStdTimeIdx, sal_uInt32 &rnStdDateTimeIdx, LanguageType* peFormatterLangType, DateFormat* peFormatterDateFormat ) { com::sun::star::uno::Reference< com::sun::star::lang::XMultiServiceFactory > xFactory = comphelper::getProcessServiceFactory(); LanguageType eLangType; if( peFormatterLangType ) eLangType = *peFormatterLangType; else eLangType = GetpApp()->GetSettings().GetLanguage(); DateFormat eDate; if( peFormatterDateFormat ) eDate = *peFormatterDateFormat; else { SvtSysLocale aSysLocale; eDate = aSysLocale.GetLocaleData().getDateFormat(); } rpNumberFormatter = new SvNumberFormatter( xFactory, eLangType ); xub_StrLen nCheckPos = 0; short nType; rnStdTimeIdx = rpNumberFormatter->GetStandardFormat( NUMBERFORMAT_TIME, eLangType ); // Standard-Vorlagen des Formatters haben nur zweistellige // Jahreszahl. Deshalb eigenes Format registrieren // HACK, da der Numberformatter in PutandConvertEntry die Platzhalter // fuer Monat, Tag, Jahr nicht entsprechend der Systemeinstellung // austauscht. Problem: Print Year(Date) unter engl. BS // siehe auch svtools\source\sbx\sbxdate.cxx String aDateStr; switch( eDate ) { case MDY: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("MM.TT.JJJJ") ); break; case DMY: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("TT.MM.JJJJ") ); break; case YMD: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("JJJJ.MM.TT") ); break; default: aDateStr = String( RTL_CONSTASCII_USTRINGPARAM("MM.TT.JJJJ") ); } String aStr( aDateStr ); rpNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, rnStdDateIdx, LANGUAGE_GERMAN, eLangType ); nCheckPos = 0; String aStrHHMMSS( RTL_CONSTASCII_USTRINGPARAM(" HH:MM:SS") ); aStr = aDateStr; aStr += aStrHHMMSS; rpNumberFormatter->PutandConvertEntry( aStr, nCheckPos, nType, rnStdDateTimeIdx, LANGUAGE_GERMAN, eLangType ); } // Engine laufenlassen. Falls Flags == SbDEBUG_CONTINUE, Flags uebernehmen void SbiInstance::Stop() { for( SbiRuntime* p = pRun; p; p = p->pNext ) p->Stop(); } // Allows Basic IDE to set watch mode to suppress errors static bool bWatchMode = false; void setBasicWatchMode( bool bOn ) { bWatchMode = bOn; } void SbiInstance::Error( SbError n ) { Error( n, String() ); } void SbiInstance::Error( SbError n, const String& rMsg ) { if( !bWatchMode ) { aErrorMsg = rMsg; pRun->Error( n ); } } void SbiInstance::ErrorVB( sal_Int32 nVBNumber, const String& rMsg ) { if( !bWatchMode ) { SbError n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) ); if ( !n ) n = nVBNumber; // force orig number, probably should have a specific table of vb ( localized ) errors aErrorMsg = rMsg; SbiRuntime::translateErrorToVba( n, aErrorMsg ); bool bVBATranslationAlreadyDone = true; pRun->Error( SbERR_BASIC_COMPAT, bVBATranslationAlreadyDone ); } } void SbiInstance::setErrorVB( sal_Int32 nVBNumber, const String& rMsg ) { SbError n = StarBASIC::GetSfxFromVBError( static_cast< sal_uInt16 >( nVBNumber ) ); if( !n ) n = nVBNumber; // force orig number, probably should have a specific table of vb ( localized ) errors aErrorMsg = rMsg; SbiRuntime::translateErrorToVba( n, aErrorMsg ); nErr = n; } void SbiInstance::FatalError( SbError n ) { pRun->FatalError( n ); } void SbiInstance::FatalError( SbError _errCode, const String& _details ) { pRun->FatalError( _errCode, _details ); } void SbiInstance::Abort() { // Basic suchen, in dem der Fehler auftrat StarBASIC* pErrBasic = GetCurrentBasic( pBasic ); pErrBasic->RTError( nErr, aErrorMsg, pRun->nLine, pRun->nCol1, pRun->nCol2 ); pBasic->Stop(); } // Hilfsfunktion, um aktives Basic zu finden, kann ungleich pRTBasic sein StarBASIC* GetCurrentBasic( StarBASIC* pRTBasic ) { StarBASIC* pCurBasic = pRTBasic; SbModule* pActiveModule = pRTBasic->GetActiveModule(); if( pActiveModule ) { SbxObject* pParent = pActiveModule->GetParent(); if( pParent && pParent->ISA(StarBASIC) ) pCurBasic = (StarBASIC*)pParent; } return pCurBasic; } SbModule* SbiInstance::GetActiveModule() { if( pRun ) return pRun->GetModule(); else return NULL; } SbMethod* SbiInstance::GetCaller( sal_uInt16 nLevel ) { SbiRuntime* p = pRun; while( nLevel-- && p ) p = p->pNext; if( p ) return p->GetCaller(); else return NULL; } SbxArray* SbiInstance::GetLocals( SbMethod* pMeth ) { SbiRuntime* p = pRun; while( p && p->GetMethod() != pMeth ) p = p->pNext; if( p ) return p->GetLocals(); else return NULL; } ////////////////////////////////////////////////////////////////////////// // SbiInstance // ////////////////////////////////////////////////////////////////////////// // Achtung: pMeth kann auch NULL sein (beim Aufruf des Init-Codes) SbiRuntime::SbiRuntime( SbModule* pm, SbMethod* pe, sal_uInt32 nStart ) : rBasic( *(StarBASIC*)pm->pParent ), pInst( pINST ), pMod( pm ), pMeth( pe ), pImg( pMod->pImage ), m_nLastTime(0) { nFlags = pe ? pe->GetDebugFlags() : 0; pIosys = pInst->pIosys; pArgvStk = NULL; pGosubStk = NULL; pForStk = NULL; pError = NULL; pErrCode = pErrStmnt = pRestart = NULL; pNext = NULL; pCode = pStmnt = (const sal_uInt8* ) pImg->GetCode() + nStart; bRun = bError = sal_True; bInError = sal_False; bBlocked = sal_False; nLine = 0; nCol1 = 0; nCol2 = 0; nExprLvl = 0; nArgc = 0; nError = 0; nGosubLvl = 0; nForLvl = 0; nOps = 0; refExprStk = new SbxArray; SetVBAEnabled( pMod->IsVBACompat() ); #if defined GCC SetParameters( pe ? pe->GetParameters() : (class SbxArray *)NULL ); #else SetParameters( pe ? pe->GetParameters() : NULL ); #endif pRefSaveList = NULL; pItemStoreList = NULL; } SbiRuntime::~SbiRuntime() { ClearGosubStack(); ClearArgvStack(); ClearForStack(); // #74254 Items zum Sichern temporaere Referenzen freigeben ClearRefs(); while( pItemStoreList ) { RefSaveItem* pToDeleteItem = pItemStoreList; pItemStoreList = pToDeleteItem->pNext; delete pToDeleteItem; } } void SbiRuntime::SetVBAEnabled(bool bEnabled ) { bVBAEnabled = bEnabled; } // Aufbau der Parameterliste. Alle ByRef-Parameter werden direkt // uebernommen; von ByVal-Parametern werden Kopien angelegt. Falls // ein bestimmter Datentyp verlangt wird, wird konvertiert. void SbiRuntime::SetParameters( SbxArray* pParams ) { refParams = new SbxArray; // fuer den Returnwert refParams->Put( pMeth, 0 ); SbxInfo* pInfo = pMeth ? pMeth->GetInfo() : NULL; sal_uInt16 nParamCount = pParams ? pParams->Count() : 1; if( nParamCount > 1 ) { for( sal_uInt16 i = 1 ; i < nParamCount ; i++ ) { const SbxParamInfo* p = pInfo ? pInfo->GetParam( i ) : NULL; // #111897 ParamArray if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) { SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); sal_uInt16 nParamArrayParamCount = nParamCount - i; pArray->unoAddDim( 0, nParamArrayParamCount - 1 ); for( sal_uInt16 j = i ; j < nParamCount ; j++ ) { SbxVariable* v = pParams->Get( j ); short nDimIndex = j - i; pArray->Put( v, &nDimIndex ); } SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); pArrayVar->SetFlag( SBX_READWRITE ); pArrayVar->PutObject( pArray ); refParams->Put( pArrayVar, i ); // Block ParamArray for missing parameter pInfo = NULL; break; } SbxVariable* v = pParams->Get( i ); // Methoden sind immer byval! sal_Bool bByVal = v->IsA( TYPE(SbxMethod) ); SbxDataType t = v->GetType(); bool bTargetTypeIsArray = false; if( p ) { bByVal |= sal_Bool( ( p->eType & SbxBYREF ) == 0 ); t = (SbxDataType) ( p->eType & 0x0FFF ); if( !bByVal && t != SbxVARIANT && (!v->IsFixed() || (SbxDataType)(v->GetType() & 0x0FFF ) != t) ) bByVal = sal_True; bTargetTypeIsArray = (p->nUserData & PARAM_INFO_WITHBRACKETS) != 0; } if( bByVal ) { if( bTargetTypeIsArray ) t = SbxOBJECT; SbxVariable* v2 = new SbxVariable( t ); v2->SetFlag( SBX_READWRITE ); *v2 = *v; refParams->Put( v2, i ); } else { if( t != SbxVARIANT && t != ( v->GetType() & 0x0FFF ) ) { // Array konvertieren?? if( p && (p->eType & SbxARRAY) ) Error( SbERR_CONVERSION ); else v->Convert( t ); } refParams->Put( v, i ); } if( p ) refParams->PutAlias( p->aName, i ); } } // ParamArray for missing parameter if( pInfo ) { // #111897 Check first missing parameter for ParamArray const SbxParamInfo* p = pInfo->GetParam( nParamCount ); if( p && (p->nUserData & PARAM_INFO_PARAMARRAY) != 0 ) { SbxDimArray* pArray = new SbxDimArray( SbxVARIANT ); pArray->unoAddDim( 0, -1 ); SbxVariable* pArrayVar = new SbxVariable( SbxVARIANT ); pArrayVar->SetFlag( SBX_READWRITE ); pArrayVar->PutObject( pArray ); refParams->Put( pArrayVar, nParamCount ); } } } // Einen P-Code ausfuehren sal_Bool SbiRuntime::Step() { if( bRun ) { // Unbedingt gelegentlich die Kontrolle abgeben! if( !( ++nOps & 0xF ) && pInst->IsReschedule() && bStaticGlobalEnableReschedule ) { sal_uInt32 nTime = osl_getGlobalTimer(); if (nTime - m_nLastTime > 5 ) // 20 ms { Application::Reschedule(); m_nLastTime = nTime; } } // #i48868 blocked by next call level? while( bBlocked ) { if( pInst->IsReschedule() && bStaticGlobalEnableReschedule ) Application::Reschedule(); } #ifdef DBG_TRACE_BASIC sal_uInt32 nPC = ( pCode - (const sal_uInt8* )pImg->GetCode() ); dbg_traceStep( pMod, nPC, pINST->nCallLvl ); #endif SbiOpcode eOp = (SbiOpcode ) ( *pCode++ ); sal_uInt32 nOp1, nOp2; if (eOp < SbOP0_END) { (this->*( aStep0[ eOp ] ) )(); } else if (eOp >= SbOP1_START && eOp < SbOP1_END) { nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; (this->*( aStep1[ eOp - SbOP1_START ] ) )( nOp1 ); } else if (eOp >= SbOP2_START && eOp < SbOP2_END) { nOp1 = *pCode++; nOp1 |= *pCode++ << 8; nOp1 |= *pCode++ << 16; nOp1 |= *pCode++ << 24; nOp2 = *pCode++; nOp2 |= *pCode++ << 8; nOp2 |= *pCode++ << 16; nOp2 |= *pCode++ << 24; (this->*( aStep2[ eOp - SbOP2_START ] ) )( nOp1, nOp2 ); } else StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); // SBX-Fehler aufgetreten? SbError nSbError = SbxBase::GetError(); Error( ERRCODE_TOERROR(nSbError) ); // Warnings rausfiltern // AB 13.2.1997, neues Error-Handling: // ACHTUNG: Hier kann nError auch dann gesetzt sein, wenn !nSbError, // da nError jetzt auch von anderen RT-Instanzen gesetzt werden kann if( nError ) SbxBase::ResetError(); // AB,15.3.96: Fehler nur anzeigen, wenn BASIC noch aktiv // (insbesondere nicht nach Compiler-Fehlern zur Laufzeit) if( nError && bRun ) { #ifdef DBG_TRACE_BASIC SbError nTraceErr = nError; String aTraceErrMsg = GetSbData()->aErrMsg; bool bTraceErrHandled = true; #endif SbError err = nError; ClearExprStack(); nError = 0; pInst->nErr = err; pInst->nErl = nLine; pErrCode = pCode; pErrStmnt = pStmnt; // An error occured in an error handler // force parent handler ( if there is one ) // to handle the error bool bLetParentHandleThis = false; // Im Error Handler? Dann Std-Error if ( !bInError ) { bInError = sal_True; if( !bError ) // On Error Resume Next StepRESUME( 1 ); else if( pError ) // On Error Goto ... pCode = pError; else bLetParentHandleThis = true; } else { bLetParentHandleThis = true; pError = NULL; //terminate the handler } if ( bLetParentHandleThis ) { // AB 13.2.1997, neues Error-Handling: // Uebergeordnete Error-Handler beruecksichtigen // Wir haben keinen Error-Handler -> weiter oben suchen SbiRuntime* pRtErrHdl = NULL; SbiRuntime* pRt = this; while( NULL != (pRt = pRt->pNext) ) { // Gibt es einen Error-Handler? if( pRt->bError == sal_False || pRt->pError != NULL ) { pRtErrHdl = pRt; break; } } // Error-Hdl gefunden? if( pRtErrHdl ) { // (Neuen) Error-Stack anlegen SbErrorStack*& rErrStack = GetSbData()->pErrStack; if( rErrStack ) delete rErrStack; rErrStack = new SbErrorStack(); // Alle im Call-Stack darunter stehenden RTs manipulieren pRt = this; do { // Fehler setzen pRt->nError = err; if( pRt != pRtErrHdl ) pRt->bRun = sal_False; // In Error-Stack eintragen SbErrorStackEntry *pEntry = new SbErrorStackEntry ( pRt->pMeth, pRt->nLine, pRt->nCol1, pRt->nCol2 ); rErrStack->C40_INSERT(SbErrorStackEntry, pEntry, rErrStack->Count() ); // Nach RT mit Error-Handler aufhoeren if( pRt == pRtErrHdl ) break; pRt = pRt->pNext; } while( pRt ); } // Kein Error-Hdl gefunden -> altes Vorgehen else { #ifdef DBG_TRACE_BASIC bTraceErrHandled = false; #endif pInst->Abort(); } // ALT: Nur // pInst->Abort(); } #ifdef DBG_TRACE_BASIC dbg_traceNotifyError( nTraceErr, aTraceErrMsg, bTraceErrHandled, pINST->nCallLvl ); #endif } } return bRun; } void SbiRuntime::Error( SbError n, bool bVBATranslationAlreadyDone ) { if( n ) { nError = n; if( isVBAEnabled() && !bVBATranslationAlreadyDone ) { String aMsg = pInst->GetErrorMsg(); sal_Int32 nVBAErrorNumber = translateErrorToVba( nError, aMsg ); SbxVariable* pSbxErrObjVar = SbxErrObject::getErrObject(); SbxErrObject* pGlobErr = static_cast< SbxErrObject* >( pSbxErrObjVar ); if( pGlobErr != NULL ) pGlobErr->setNumberAndDescription( nVBAErrorNumber, aMsg ); pInst->aErrorMsg = aMsg; nError = SbERR_BASIC_COMPAT; } } } void SbiRuntime::Error( SbError _errCode, const String& _details ) { if ( _errCode ) { // Not correct for class module usage, remove for now //OSL_ENSURE( pInst->pRun == this, "SbiRuntime::Error: can't propagate the error message details!" ); if ( pInst->pRun == this ) { pInst->Error( _errCode, _details ); //OSL_POSTCOND( nError == _errCode, "SbiRuntime::Error: the instance is expecte to propagate the error code back to me!" ); } else { nError = _errCode; } } } void SbiRuntime::FatalError( SbError n ) { StepSTDERROR(); Error( n ); } void SbiRuntime::FatalError( SbError _errCode, const String& _details ) { StepSTDERROR(); Error( _errCode, _details ); } sal_Int32 SbiRuntime::translateErrorToVba( SbError nError, String& rMsg ) { // If a message is defined use that ( in preference to // the defined one for the error ) NB #TODO // if there is an error defined it more than likely // is not the one you want ( some are the same though ) // we really need a new vba compatible error list if ( !rMsg.Len() ) { // TEST, has to be vb here always #ifdef DBG_UTIL SbError nTmp = StarBASIC::GetSfxFromVBError( (sal_uInt16)nError ); DBG_ASSERT( nTmp, "No VB error!" ); #endif StarBASIC::MakeErrorText( nError, rMsg ); rMsg = StarBASIC::GetErrorText(); if ( !rMsg.Len() ) // no message for err no, need localized resource here rMsg = String( RTL_CONSTASCII_USTRINGPARAM("Internal Object Error:") ); } // no num? most likely then it *is* really a vba err sal_uInt16 nVBErrorCode = StarBASIC::GetVBErrorCode( nError ); sal_Int32 nVBAErrorNumber = ( nVBErrorCode == 0 ) ? nError : nVBErrorCode; return nVBAErrorNumber; } ////////////////////////////////////////////////////////////////////////// // // Parameter, Locals, Caller // ////////////////////////////////////////////////////////////////////////// SbMethod* SbiRuntime::GetCaller() { return pMeth; } SbxArray* SbiRuntime::GetLocals() { return refLocals; } SbxArray* SbiRuntime::GetParams() { return refParams; } ////////////////////////////////////////////////////////////////////////// // // Stacks // ////////////////////////////////////////////////////////////////////////// // Der Expression-Stack steht fuer die laufende Auswertung von Expressions // zur Verfuegung. void SbiRuntime::PushVar( SbxVariable* pVar ) { if( pVar ) refExprStk->Put( pVar, nExprLvl++ ); } SbxVariableRef SbiRuntime::PopVar() { #ifdef DBG_UTIL if( !nExprLvl ) { StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); return new SbxVariable; } #endif SbxVariableRef xVar = refExprStk->Get( --nExprLvl ); #ifdef DBG_UTIL if ( xVar->GetName().EqualsAscii( "Cells" ) ) DBG_TRACE( "" ); #endif // Methods halten im 0.Parameter sich selbst, also weghauen if( xVar->IsA( TYPE(SbxMethod) ) ) xVar->SetParameters(0); return xVar; } sal_Bool SbiRuntime::ClearExprStack() { // Achtung: Clear() reicht nicht, da Methods geloescht werden muessen while ( nExprLvl ) { PopVar(); } refExprStk->Clear(); return sal_False; } // Variable auf dem Expression-Stack holen, ohne sie zu entfernen // n zaehlt ab 0. SbxVariable* SbiRuntime::GetTOS( short n ) { n = nExprLvl - n - 1; #ifdef DBG_UTIL if( n < 0 ) { StarBASIC::FatalError( SbERR_INTERNAL_ERROR ); return new SbxVariable; } #endif return refExprStk->Get( (sal_uInt16) n ); } // Sicherstellen, dass TOS eine temporaere Variable ist void SbiRuntime::TOSMakeTemp() { SbxVariable* p = refExprStk->Get( nExprLvl - 1 ); if( p->GetRefCount() != 1 ) { SbxVariable* pNew = new SbxVariable( *p ); pNew->SetFlag( SBX_READWRITE ); refExprStk->Put( pNew, nExprLvl - 1 ); } } // Der GOSUB-Stack nimmt Returnadressen fuer GOSUBs auf void SbiRuntime::PushGosub( const sal_uInt8* pc ) { if( ++nGosubLvl > MAXRECURSION ) StarBASIC::FatalError( SbERR_STACK_OVERFLOW ); SbiGosubStack* p = new SbiGosubStack; p->pCode = pc; p->pNext = pGosubStk; p->nStartForLvl = nForLvl; pGosubStk = p; } void SbiRuntime::PopGosub() { if( !pGosubStk ) Error( SbERR_NO_GOSUB ); else { SbiGosubStack* p = pGosubStk; pCode = p->pCode; pGosubStk = p->pNext; delete p; nGosubLvl--; } } // Entleeren des GOSUB-Stacks void SbiRuntime::ClearGosubStack() { SbiGosubStack* p; while(( p = pGosubStk ) != NULL ) pGosubStk = p->pNext, delete p; nGosubLvl = 0; } // Der Argv-Stack nimmt aktuelle Argument-Vektoren auf void SbiRuntime::PushArgv() { SbiArgvStack* p = new SbiArgvStack; p->refArgv = refArgv; p->nArgc = nArgc; nArgc = 1; refArgv.Clear(); p->pNext = pArgvStk; pArgvStk = p; } void SbiRuntime::PopArgv() { if( pArgvStk ) { SbiArgvStack* p = pArgvStk; pArgvStk = p->pNext; refArgv = p->refArgv; nArgc = p->nArgc; delete p; } } // Entleeren des Argv-Stacks void SbiRuntime::ClearArgvStack() { while( pArgvStk ) PopArgv(); } // Push des For-Stacks. Der Stack hat Inkrement, Ende, Beginn und Variable. // Nach Aufbau des Stack-Elements ist der Stack leer. void SbiRuntime::PushFor() { SbiForStack* p = new SbiForStack; p->eForType = FOR_TO; p->pNext = pForStk; pForStk = p; // Der Stack ist wie folgt aufgebaut: p->refInc = PopVar(); p->refEnd = PopVar(); SbxVariableRef xBgn = PopVar(); p->refVar = PopVar(); *(p->refVar) = *xBgn; nForLvl++; } void SbiRuntime::PushForEach() { SbiForStack* p = new SbiForStack; p->pNext = pForStk; pForStk = p; SbxVariableRef xObjVar = PopVar(); SbxBase* pObj = xObjVar.Is() ? xObjVar->GetObject() : NULL; if( pObj == NULL ) { Error( SbERR_NO_OBJECT ); return; } bool bError_ = false; BasicCollection* pCollection; SbxDimArray* pArray; SbUnoObject* pUnoObj; if( (pArray = PTR_CAST(SbxDimArray,pObj)) != NULL ) { p->eForType = FOR_EACH_ARRAY; p->refEnd = (SbxVariable*)pArray; short nDims = pArray->GetDims(); p->pArrayLowerBounds = new sal_Int32[nDims]; p->pArrayUpperBounds = new sal_Int32[nDims]; p->pArrayCurIndices = new sal_Int32[nDims]; sal_Int32 lBound, uBound; for( short i = 0 ; i < nDims ; i++ ) { pArray->GetDim32( i+1, lBound, uBound ); p->pArrayCurIndices[i] = p->pArrayLowerBounds[i] = lBound; p->pArrayUpperBounds[i] = uBound; } } else if( (pCollection = PTR_CAST(BasicCollection,pObj)) != NULL ) { p->eForType = FOR_EACH_COLLECTION; p->refEnd = pCollection; p->nCurCollectionIndex = 0; } else if( (pUnoObj = PTR_CAST(SbUnoObject,pObj)) != NULL ) { // XEnumerationAccess? Any aAny = pUnoObj->getUnoAny(); Reference< XEnumerationAccess > xEnumerationAccess; if( (aAny >>= xEnumerationAccess) ) { p->xEnumeration = xEnumerationAccess->createEnumeration(); p->eForType = FOR_EACH_XENUMERATION; } else if ( isVBAEnabled() && pUnoObj->isNativeCOMObject() ) { uno::Reference< script::XInvocation > xInvocation; if ( ( aAny >>= xInvocation ) && xInvocation.is() ) { try { p->xEnumeration = new ComEnumerationWrapper( xInvocation ); p->eForType = FOR_EACH_XENUMERATION; } catch( uno::Exception& ) {} } if ( !p->xEnumeration.is() ) bError_ = true; } else { bError_ = true; } } else { bError_ = true; } if( bError_ ) { Error( SbERR_CONVERSION ); return; } // Container variable p->refVar = PopVar(); nForLvl++; } // Poppen des FOR-Stacks void SbiRuntime::PopFor() { if( pForStk ) { SbiForStack* p = pForStk; pForStk = p->pNext; delete p; nForLvl--; } } // Entleeren des FOR-Stacks void SbiRuntime::ClearForStack() { while( pForStk ) PopFor(); } SbiForStack* SbiRuntime::FindForStackItemForCollection( class BasicCollection* pCollection ) { SbiForStack* pRet = NULL; SbiForStack* p = pForStk; while( p ) { SbxVariable* pVar = p->refEnd.Is() ? (SbxVariable*)p->refEnd : NULL; if( p->eForType == FOR_EACH_COLLECTION && pVar != NULL && (pCollection = PTR_CAST(BasicCollection,pVar)) == pCollection ) { pRet = p; break; } } return pRet; } ////////////////////////////////////////////////////////////////////////// // // DLL-Aufrufe // ////////////////////////////////////////////////////////////////////////// void SbiRuntime::DllCall ( const String& aFuncName, // Funktionsname const String& aDLLName, // Name der DLL SbxArray* pArgs, // Parameter (ab Index 1, kann NULL sein) SbxDataType eResType, // Returnwert sal_Bool bCDecl ) // sal_True: nach C-Konventionen { // No DllCall for "virtual" portal users if( needSecurityRestrictions() ) { StarBASIC::Error(SbERR_NOT_IMPLEMENTED); return; } // MUSS NOCH IMPLEMENTIERT WERDEN /* String aMsg; aMsg = "FUNC="; aMsg += pFunc; aMsg += " DLL="; aMsg += pDLL; MessBox( NULL, WB_OK, String( "DLL-CALL" ), aMsg ).Execute(); Error( SbERR_NOT_IMPLEMENTED ); */ SbxVariable* pRes = new SbxVariable( eResType ); SbiDllMgr* pDllMgr = pInst->GetDllMgr(); SbError nErr = pDllMgr->Call( aFuncName, aDLLName, pArgs, *pRes, bCDecl ); if( nErr ) Error( nErr ); PushVar( pRes ); } sal_uInt16 SbiRuntime::GetImageFlag( sal_uInt16 n ) const { return pImg->GetFlag( n ); } sal_uInt16 SbiRuntime::GetBase() { return pImg->GetBase(); }