Files
libreoffice/basic/source/classes/sbxmod.cxx

2004 lines
54 KiB
C++
Raw Normal View History

2000-09-18 15:18:56 +00:00
/*************************************************************************
*
* OpenOffice.org - a multi-platform office productivity suite
*
* $RCSfile: sbxmod.cxx,v $
*
* $Revision: 1.27 $
2000-09-18 15:18:56 +00:00
*
* last change: $Author: hr $ $Date: 2005-09-29 18:38:55 $
2000-09-18 15:18:56 +00:00
*
* The Contents of this file are made available subject to
* the terms of GNU Lesser General Public License Version 2.1.
2000-09-18 15:18:56 +00:00
*
*
* GNU Lesser General Public License Version 2.1
* =============================================
* Copyright 2005 by Sun Microsystems, Inc.
* 901 San Antonio Road, Palo Alto, CA 94303, USA
2000-09-18 15:18:56 +00:00
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License version 2.1, as published by the Free Software Foundation.
2000-09-18 15:18:56 +00:00
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
2000-09-18 15:18:56 +00:00
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
2000-09-18 15:18:56 +00:00
*
************************************************************************/
#include <list>
#include <vos/macros.hxx>
#include <vcl/svapp.hxx>
#ifndef _STREAM_HXX //autogen
#include <tools/stream.hxx>
#endif
#ifndef _SFXBRDCST_HXX //autogen
#include <svtools/brdcst.hxx>
#endif
#ifndef _SHL_HXX //autogen
#include <tools/shl.hxx>
#endif
#pragma hdrstop
#include <sbx.hxx>
2000-09-18 15:18:56 +00:00
#include "sb.hxx"
#include <sbjsmeth.hxx>
#include "sbjsmod.hxx"
#include "sbintern.hxx"
#include "image.hxx"
#include "opcodes.hxx"
#include "runtime.hxx"
#include "token.hxx"
#include "sbunoobj.hxx"
#include <hilight.hxx>
#include <basrdll.hxx>
#ifndef _VOS_MUTEX_HXX_
#include <vos/mutex.hxx>
#endif
2000-09-18 15:18:56 +00:00
// for the bsearch
#ifdef WNT
#define CDECL _cdecl
#endif
#ifdef OS2
#define CDECL _Optlink
#endif
#if defined(UNX) || defined(MAC)
#define CDECL
#endif
#ifdef UNX
#include <sys/resource.h>
#endif
2000-09-18 15:18:56 +00:00
#include <stdio.h>
TYPEINIT1(SbModule,SbxObject)
TYPEINIT1(SbMethod,SbxMethod)
TYPEINIT1(SbProperty,SbxProperty)
TYPEINIT1(SbProcedureProperty,SbxProperty)
2000-09-18 15:18:56 +00:00
TYPEINIT1(SbJScriptModule,SbModule)
TYPEINIT1(SbJScriptMethod,SbMethod)
SV_DECL_VARARR(SbiBreakpoints,USHORT,4,4)
SV_IMPL_VARARR(SbiBreakpoints,USHORT)
SV_IMPL_VARARR(HighlightPortions, HighlightPortion)
// ##########################################################################
// ACHTUNG!!! Alle Woerter dieser Tabelle m<>ssen KLEIN geschrieben werden!!!
// ##########################################################################
static char* strListBasicKeyWords[] = {
"access",
"alias",
"and",
"any",
"append",
"as",
"base",
"binary",
"boolean",
"byref",
2000-09-18 15:18:56 +00:00
"byval",
"call",
"case",
"cdecl",
"classmodule",
2000-09-18 15:18:56 +00:00
"close",
"compare",
"compatible",
2000-09-18 15:18:56 +00:00
"const",
"currency",
"date",
"declare",
"defbool",
"defcur",
"defdate",
"defdbl",
"deferr",
"defint",
"deflng",
"defobj",
"defsng",
"defstr",
"defvar",
"dim",
"do",
"double",
"each",
"else",
"elseif",
"end",
"end enum",
2000-09-18 15:18:56 +00:00
"end function",
"end if",
"end select",
"end sub",
"end type",
"endif",
"enum",
2000-09-18 15:18:56 +00:00
"eqv",
"erase",
"error",
"exit",
"explicit",
"for",
"function",
"get",
2000-09-18 15:18:56 +00:00
"global",
"gosub",
"goto",
"if",
"imp",
"implements",
2000-09-18 15:18:56 +00:00
"in",
"input",
"integer",
"is",
"let",
"lib"
"line",
"line input",
"local",
"lock",
"long",
"loop",
"lprint",
"lset",
"mod",
"name",
"new",
"next",
"not",
"object",
"on",
"open",
"option",
"optional",
"or",
"output",
"preserve",
"print",
"private",
"property",
2000-09-18 15:18:56 +00:00
"public",
"random",
"read",
"redim",
"rem",
"resume",
"return",
"rset",
"select",
"set",
"shared",
"single",
"static",
"step",
"stop",
"string",
"sub",
"system",
"text",
"then",
"to",
"type",
"typeof",
2000-09-18 15:18:56 +00:00
"until",
"variant",
"wend",
"while",
"with",
"write",
"xor"
};
int CDECL compare_strings( const void *arg1, const void *arg2 )
{
char* pCh = *(char**)arg2;
return strcmp( (char *)arg1, *(char **)arg2 );
}
/////////////////////////////////////////////////////////////////////////////
// Ein BASIC-Modul hat EXTSEARCH gesetzt, damit die im Modul enthaltenen
// Elemente von anderen Modulen aus gefunden werden koennen.
SbModule::SbModule( const String& rName )
: SbxObject( String( RTL_CONSTASCII_USTRINGPARAM("StarBASICModule") ) ),
pImage( NULL ), pBreaks( NULL ), pClassData( NULL )
2000-09-18 15:18:56 +00:00
{
SetName( rName );
SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH );
}
SbModule::~SbModule()
{
if( pImage )
delete pImage;
if( pBreaks )
delete pBreaks;
if( pClassData )
delete pClassData;
2000-09-18 15:18:56 +00:00
}
BOOL SbModule::IsCompiled() const
{
return BOOL( pImage != 0 );
}
const SbxObject* SbModule::FindType( String aTypeName ) const
{
return pImage ? pImage->FindType( aTypeName ) : NULL;
}
2000-09-18 15:18:56 +00:00
// Aus dem Codegenerator: Loeschen des Images und Invalidieren der Entries
void SbModule::StartDefinitions()
{
delete pImage; pImage = NULL;
if( pClassData )
pClassData->clear();
2000-09-18 15:18:56 +00:00
// Methoden und Properties bleiben erhalten, sind jedoch ungueltig
// schliesslich sind ja u.U. die Infos belegt
USHORT i;
for( i = 0; i < pMethods->Count(); i++ )
{
SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
if( p )
p->bInvalid = TRUE;
}
for( i = 0; i < pProps->Count(); )
{
SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
if( p )
pProps->Remove( i );
else
i++;
}
}
// Methode anfordern/anlegen
SbMethod* SbModule::GetMethod( const String& rName, SbxDataType t )
{
SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD );
SbMethod* pMeth = p ? PTR_CAST(SbMethod,p) : NULL;
if( p && !pMeth )
pMethods->Remove( p );
if( !pMeth )
{
pMeth = new SbMethod( rName, t, this );
pMeth->SetParent( this );
pMeth->SetFlags( SBX_READ );
pMethods->Put( pMeth, pMethods->Count() );
StartListening( pMeth->GetBroadcaster(), TRUE );
}
// Per Default ist die Methode GUELTIG, da sie auch vom Compiler
// (Codegenerator) erzeugt werden kann
pMeth->bInvalid = FALSE;
pMeth->ResetFlag( SBX_FIXED );
pMeth->SetFlag( SBX_WRITE );
pMeth->SetType( t );
pMeth->ResetFlag( SBX_WRITE );
if( t != SbxVARIANT )
pMeth->SetFlag( SBX_FIXED );
return pMeth;
}
// Property anfordern/anlegen
SbProperty* SbModule::GetProperty( const String& rName, SbxDataType t )
{
SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY );
SbProperty* pProp = p ? PTR_CAST(SbProperty,p) : NULL;
if( p && !pProp )
pProps->Remove( p );
if( !pProp )
{
pProp = new SbProperty( rName, t, this );
pProp->SetFlag( SBX_READWRITE );
pProp->SetParent( this );
pProps->Put( pProp, pProps->Count() );
StartListening( pProp->GetBroadcaster(), TRUE );
}
return pProp;
}
SbProcedureProperty* SbModule::GetProcedureProperty
( const String& rName, SbxDataType t )
{
SbxVariable* p = pProps->Find( rName, SbxCLASS_PROPERTY );
SbProcedureProperty* pProp = p ? PTR_CAST(SbProcedureProperty,p) : NULL;
if( p && !pProp )
pProps->Remove( p );
if( !pProp )
{
pProp = new SbProcedureProperty( rName, t );
pProp->SetFlag( SBX_READWRITE );
pProp->SetParent( this );
pProps->Put( pProp, pProps->Count() );
StartListening( pProp->GetBroadcaster(), TRUE );
}
return pProp;
}
SbIfaceMapperMethod* SbModule::GetIfaceMapperMethod
( const String& rName, SbMethod* pImplMeth )
{
SbxVariable* p = pMethods->Find( rName, SbxCLASS_METHOD );
SbIfaceMapperMethod* pMapperMethod = p ? PTR_CAST(SbIfaceMapperMethod,p) : NULL;
if( p && !pMapperMethod )
pMethods->Remove( p );
if( !pMapperMethod )
{
pMapperMethod = new SbIfaceMapperMethod( rName, pImplMeth );
pMapperMethod->SetParent( this );
pMapperMethod->SetFlags( SBX_READ );
pMethods->Put( pMapperMethod, pMethods->Count() );
}
pMapperMethod->bInvalid = FALSE;
return pMapperMethod;
}
SbIfaceMapperMethod::~SbIfaceMapperMethod()
{
}
TYPEINIT1(SbIfaceMapperMethod,SbMethod)
2000-09-18 15:18:56 +00:00
// Aus dem Codegenerator: Ungueltige Eintraege entfernen
void SbModule::EndDefinitions( BOOL bNewState )
{
for( USHORT i = 0; i < pMethods->Count(); )
{
SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
if( p )
{
if( p->bInvalid )
pMethods->Remove( p );
else
{
p->bInvalid = bNewState;
i++;
}
}
else
i++;
2000-09-18 15:18:56 +00:00
}
SetModified( TRUE );
}
void SbModule::Clear()
{
delete pImage; pImage = NULL;
if( pClassData )
pClassData->clear();
2000-09-18 15:18:56 +00:00
SbxObject::Clear();
}
SbxVariable* SbModule::Find( const XubString& rName, SbxClassType t )
{
SbxVariable* pRes = SbxObject::Find( rName, t );
if( !pRes && pImage )
{
SbiInstance* pInst = pINST;
if( pInst && pInst->IsCompatibility() )
{
// Put enum types as objects into module,
// allows MyEnum.First notation
SbxArrayRef xArray = pImage->GetEnums();
if( xArray.Is() )
{
SbxVariable* pEnumVar = xArray->Find( rName, SbxCLASS_DONTCARE );
SbxObject* pEnumObject = PTR_CAST( SbxObject, pEnumVar );
if( pEnumObject )
{
bool bPrivate = pEnumObject->IsSet( SBX_PRIVATE );
String aEnumName = pEnumObject->GetName();
pRes = new SbxVariable( SbxOBJECT );
pRes->SetName( aEnumName );
pRes->SetParent( this );
pRes->SetFlag( SBX_READ );
if( bPrivate )
pRes->SetFlag( SBX_PRIVATE );
pRes->PutObject( pEnumObject );
}
}
}
}
return pRes;
}
const ::rtl::OUString& SbModule::GetSource32() const
{
return aOUSource;
}
2000-09-18 15:18:56 +00:00
const String& SbModule::GetSource() const
{
static String aRetStr;
aRetStr = aOUSource;
return aRetStr;
2000-09-18 15:18:56 +00:00
}
// Parent und BASIC sind eins!
void SbModule::SetParent( SbxObject* p )
{
// #118083: Assertion is not valid any more
// DBG_ASSERT( !p || p->IsA( TYPE(StarBASIC) ), "SbModules nur in BASIC eintragen" );
2000-09-18 15:18:56 +00:00
pParent = p;
}
void SbModule::SFX_NOTIFY( SfxBroadcaster& rBC, const TypeId& rBCType,
const SfxHint& rHint, const TypeId& rHintType )
{
const SbxHint* pHint = PTR_CAST(SbxHint,&rHint);
if( pHint )
{
SbxVariable* pVar = pHint->GetVar();
SbProperty* pProp = PTR_CAST(SbProperty,pVar);
SbMethod* pMeth = PTR_CAST(SbMethod,pVar);
if( pProp )
{
if( pProp->GetModule() != this )
SetError( SbxERR_BAD_ACTION );
}
else if( pMeth )
{
if( pHint->GetId() == SBX_HINT_DATAWANTED )
{
if( pMeth->bInvalid && !Compile() )
// Auto-Compile hat nicht geklappt!
StarBASIC::Error( SbERR_BAD_PROP_VALUE );
else
{
// Aufruf eines Unterprogramms
SbModule* pOld = pMOD;
pMOD = this;
Run( (SbMethod*) pVar );
pMOD = pOld;
}
}
}
else
SbxObject::SFX_NOTIFY( rBC, rBCType, rHint, rHintType );
}
}
// Das Setzen der Source macht das Image ungueltig
// und scant die Methoden-Definitionen neu ein
void SbModule::SetSource( const String& r )
{
SetSource32( r );
}
void SbModule::SetSource32( const ::rtl::OUString& r )
{
aOUSource = r;
2000-09-18 15:18:56 +00:00
StartDefinitions();
SbiTokenizer aTok( r );
while( !aTok.IsEof() )
{
SbiToken eEndTok = NIL;
// Suchen nach SUB oder FUNCTION
SbiToken eLastTok = NIL;
while( !aTok.IsEof() )
{
// #32385: Nicht bei declare
SbiToken eCurTok = aTok.Next();
if( eLastTok != DECLARE )
{
if( eCurTok == SUB )
{
eEndTok = ENDSUB; break;
}
if( eCurTok == FUNCTION )
{
eEndTok = ENDFUNC; break;
}
if( eCurTok == PROPERTY )
{
eEndTok = ENDPROPERTY; break;
}
if( eCurTok == OPTION )
{
eCurTok = aTok.Next();
if( eCurTok == COMPATIBLE )
aTok.SetCompatible( true );
}
2000-09-18 15:18:56 +00:00
}
eLastTok = eCurTok;
}
// Definition der Methode
SbMethod* pMeth;
if( eEndTok != NIL )
{
USHORT nLine1 = aTok.GetLine();
if( aTok.Next() == SYMBOL )
{
String aName( aTok.GetSym() );
SbxDataType t = aTok.GetType();
if( t == SbxVARIANT && eEndTok == ENDSUB )
t = SbxVOID;
pMeth = GetMethod( aName, t );
pMeth->nLine1 = pMeth->nLine2 = nLine1;
// Die Methode ist erst mal GUELTIG
pMeth->bInvalid = FALSE;
}
else
eEndTok = NIL;
}
// Skip bis END SUB/END FUNCTION
if( eEndTok != NIL )
{
while( !aTok.IsEof() )
{
if( aTok.Next() == eEndTok )
{
pMeth->nLine2 = aTok.GetLine();
break;
}
}
if( aTok.IsEof() )
pMeth->nLine2 = aTok.GetLine();
}
}
EndDefinitions( TRUE );
}
void SbModule::SetComment( const String& r )
{
aComment = r;
SetModified( TRUE );
}
SbMethod* SbModule::GetFunctionForLine( USHORT nLine )
{
for( USHORT i = 0; i < pMethods->Count(); i++ )
{
SbMethod* p = (SbMethod*) pMethods->Get( i );
if( p->GetSbxId() == SBXID_BASICMETHOD )
{
if( nLine >= p->nLine1 && nLine <= p->nLine2 )
return p;
}
}
return NULL;
}
// Ausstrahlen eines Hints an alle Basics
static void _SendHint( SbxObject* pObj, ULONG nId, SbMethod* p )
{
// Selbst ein BASIC?
if( pObj->IsA( TYPE(StarBASIC) ) && pObj->IsBroadcaster() )
pObj->GetBroadcaster().Broadcast( SbxHint( nId, p ) );
// Dann die Unterobjekte fragen
SbxArray* pObjs = pObj->GetObjects();
for( USHORT i = 0; i < pObjs->Count(); i++ )
{
SbxVariable* pVar = pObjs->Get( i );
if( pVar->IsA( TYPE(SbxObject) ) )
_SendHint( PTR_CAST(SbxObject,pVar), nId, p );
}
}
static void SendHint( SbxObject* pObj, ULONG nId, SbMethod* p )
{
while( pObj->GetParent() )
pObj = pObj->GetParent();
_SendHint( pObj, nId, p );
}
// #57841 Uno-Objekte, die in RTL-Funktionen gehalten werden,
// beim Programm-Ende freigeben, damit nichts gehalten wird.
void ClearUnoObjectsInRTL_Impl_Rek( StarBASIC* pBasic )
{
// return-Wert von CreateUnoService loeschen
static String aName( RTL_CONSTASCII_USTRINGPARAM("CreateUnoService") );
SbxVariable* pVar = pBasic->GetRtl()->Find( aName, SbxCLASS_METHOD );
if( pVar )
pVar->SbxValue::Clear();
// return-Wert von CreateUnoDialog loeschen
static String aName2( RTL_CONSTASCII_USTRINGPARAM("CreateUnoDialog") );
pVar = pBasic->GetRtl()->Find( aName2, SbxCLASS_METHOD );
if( pVar )
pVar->SbxValue::Clear();
// return-Wert von CreateUnoDialog loeschen
static String aName3( RTL_CONSTASCII_USTRINGPARAM("CDec") );
pVar = pBasic->GetRtl()->Find( aName3, SbxCLASS_METHOD );
if( pVar )
pVar->SbxValue::Clear();
2000-09-18 15:18:56 +00:00
// Ueber alle Sub-Basics gehen
SbxArray* pObjs = pBasic->GetObjects();
USHORT nCount = pObjs->Count();
for( USHORT i = 0 ; i < nCount ; i++ )
{
SbxVariable* pObjVar = pObjs->Get( i );
StarBASIC* pSubBasic = PTR_CAST( StarBASIC, pObjVar );
if( pSubBasic )
ClearUnoObjectsInRTL_Impl_Rek( pSubBasic );
}
}
void ClearUnoObjectsInRTL_Impl( StarBASIC* pBasic )
{
// #67781 Rueckgabewerte der Uno-Methoden loeschen
clearUnoMethods();
ClearUnoObjectsInRTL_Impl_Rek( pBasic );
2000-09-18 15:18:56 +00:00
// Oberstes Basic suchen
SbxObject* p = pBasic;
while( p->GetParent() )
p = p->GetParent();
if( ((StarBASIC*)p) != pBasic )
ClearUnoObjectsInRTL_Impl_Rek( (StarBASIC*)p );
2000-09-18 15:18:56 +00:00
}
// Ausfuehren eines BASIC-Unterprogramms
USHORT SbModule::Run( SbMethod* pMeth )
{
static USHORT nMaxCallLevel = 0;
2000-09-18 15:18:56 +00:00
USHORT nRes = 0;
BOOL bDelInst = BOOL( pINST == NULL );
StarBASICRef xBasic;
if( bDelInst )
{
// #32779: Basic waehrend der Ausfuehrung festhalten
xBasic = (StarBASIC*) GetParent();
pINST = new SbiInstance( (StarBASIC*) GetParent() );
// Error-Stack loeschen
SbErrorStack*& rErrStack = GetSbData()->pErrStack;
delete rErrStack;
rErrStack = NULL;
if( nMaxCallLevel == 0 )
{
#ifdef UNX
struct rlimit rl;
getrlimit ( RLIMIT_STACK, &rl );
// printf( "RLIMIT_STACK = %ld\n", rl.rlim_cur );
#endif
#ifdef LINUX
// Empiric value, 900 = needed bytes/Basic call level
// for Linux including 10% safety margin
nMaxCallLevel = rl.rlim_cur / 900;
#elif SOLARIS
// Empiric value, 1650 = needed bytes/Basic call level
// for Solaris including 10% safety margin
nMaxCallLevel = rl.rlim_cur / 1650;
#elif WIN32
nMaxCallLevel = 5800;
#else
nMaxCallLevel = MAXRECURSION;
#endif
}
2000-09-18 15:18:56 +00:00
}
2000-09-18 15:18:56 +00:00
// Rekursion zu tief?
if( ++pINST->nCallLvl <= nMaxCallLevel )
2000-09-18 15:18:56 +00:00
{
// Globale Variable in allen Mods definieren
GlobalRunInit( /* bBasicStart = */ bDelInst );
// Trat ein Compiler-Fehler auf? Dann starten wir nicht
if( GetSbData()->bGlobalInitErr == FALSE )
{
if( bDelInst )
{
SendHint( GetParent(), SBX_HINT_BASICSTART, pMeth );
// 16.10.96: #31460 Neues Konzept fuer StepInto/Over/Out
// Erklaerung siehe runtime.cxx bei SbiInstance::CalcBreakCallLevel()
// BreakCallLevel ermitteln
pINST->CalcBreakCallLevel( pMeth->GetDebugFlags() );
}
SbModule* pOldMod = pMOD;
pMOD = this;
SbiRuntime* pRt = new SbiRuntime( this, pMeth, pMeth->nStart );
pRt->pNext = pINST->pRun;
if( pRt->pNext )
pRt->pNext->block();
2000-09-18 15:18:56 +00:00
pINST->pRun = pRt;
while( pRt->Step() ) {}
if( pRt->pNext )
pRt->pNext->unblock();
2000-09-18 15:18:56 +00:00
// #63710 Durch ein anderes Thread-Handling bei Events kann es passieren,
// dass show-Aufruf an einem Dialog zurueckkehrt (durch schliessen des
// Dialogs per UI), BEVOR ein per Event ausgeloester weitergehender Call,
// der in Basic weiter oben im Stack steht und auf einen Basic-Breakpoint
// gelaufen ist, zurueckkehrt. Dann wird unten die Instanz zerstoert und
// wenn das noch im Call stehende Basic weiterlaeuft, gibt es einen GPF.
// Daher muss hier gewartet werden, bis andere Call zurueckkehrt.
if( bDelInst )
{
// Hier mit 1 statt 0 vergleichen, da vor nCallLvl--
while( pINST->nCallLvl != 1 )
GetpApp()->Yield();
}
nRes = TRUE;
pINST->pRun = pRt->pNext;
pINST->nCallLvl--; // Call-Level wieder runter
// Gibt es eine uebergeordnete Runtime-Instanz?
// Dann SbDEBUG_BREAK uebernehmen, wenn gesetzt
SbiRuntime* pRtNext = pRt->pNext;
if( pRtNext && (pRt->GetDebugFlags() & SbDEBUG_BREAK) )
pRtNext->SetDebugFlags( SbDEBUG_BREAK );
delete pRt;
pMOD = pOldMod;
if( bDelInst )
{
// #57841 Uno-Objekte, die in RTL-Funktionen gehalten werden,
// beim Programm-Ende freigeben, damit nichts gehalten wird.
ClearUnoObjectsInRTL_Impl( xBasic );
DBG_ASSERT(pINST->nCallLvl==0,"BASIC-Call-Level > 0")
delete pINST, pINST = NULL, bDelInst = FALSE;
// #i30690
vos::OGuard aSolarGuard( Application::GetSolarMutex() );
2000-09-18 15:18:56 +00:00
SendHint( GetParent(), SBX_HINT_BASICSTOP, pMeth );
GlobalRunDeInit();
2000-09-18 15:18:56 +00:00
}
}
else
pINST->nCallLvl--; // Call-Level wieder runter
2000-09-18 15:18:56 +00:00
}
else
{
pINST->nCallLvl--; // Call-Level wieder runter
2000-09-18 15:18:56 +00:00
StarBASIC::FatalError( SbERR_STACK_OVERFLOW );
}
2000-09-18 15:18:56 +00:00
if( bDelInst )
{
// #57841 Uno-Objekte, die in RTL-Funktionen gehalten werden,
// beim Programm-Ende freigeben, damit nichts gehalten wird.
ClearUnoObjectsInRTL_Impl( xBasic );
delete pINST;
pINST = NULL;
}
return nRes;
}
// Ausfuehren der Init-Methode eines Moduls nach dem Laden
// oder der Compilation
void SbModule::RunInit()
{
if( pImage
&& !pImage->bInit
&& pImage->GetFlag( SBIMG_INITCODE ) )
{
// Flag setzen, dass RunInit aktiv ist (Testtool)
GetSbData()->bRunInit = TRUE;
// BOOL bDelInst = BOOL( pINST == NULL );
// if( bDelInst )
// pINST = new SbiInstance( (StarBASIC*) GetParent() );
SbModule* pOldMod = pMOD;
pMOD = this;
// Der Init-Code beginnt immer hier
SbiRuntime* pRt = new SbiRuntime( this, NULL, 0 );
pRt->pNext = pINST->pRun;
pINST->pRun = pRt;
while( pRt->Step() ) {}
pINST->pRun = pRt->pNext;
delete pRt;
pMOD = pOldMod;
// if( bDelInst )
// delete pINST, pINST = NULL;
pImage->bInit = TRUE;
pImage->bFirstInit = FALSE;
2000-09-18 15:18:56 +00:00
// RunInit ist nicht mehr aktiv
GetSbData()->bRunInit = FALSE;
}
}
// Mit private/dim deklarierte Variablen loeschen
void SbModule::ClearPrivateVars()
{
for( int i = 0 ; i < pProps->Count() ; i++ )
{
SbProperty* p = PTR_CAST(SbProperty,pProps->Get( i ) );
if( p )
{
// Arrays nicht loeschen, sondern nur deren Inhalt
if( p->GetType() & SbxARRAY )
{
SbxArray* pArray = PTR_CAST(SbxArray,p->GetObject());
if( pArray )
{
for( int j = 0 ; j < pArray->Count() ; j++ )
{
SbxVariable* pj = PTR_CAST(SbxVariable,pArray->Get( j ));
pj->SbxValue::Clear();
/*
USHORT nFlags = pj->GetFlags();
pj->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) );
pj->PutEmpty();
pj->SetFlags( nFlags );
*/
}
}
}
else
{
p->SbxValue::Clear();
/*
USHORT nFlags = p->GetFlags();
p->SetFlags( (nFlags | SBX_WRITE) & (~SBX_FIXED) );
p->PutEmpty();
p->SetFlags( nFlags );
*/
}
}
}
}
// Zunaechst in dieses Modul, um 358-faehig zu bleiben
// (Branch in sb.cxx vermeiden)
void StarBASIC::ClearAllModuleVars( void )
{
// Eigene Module initialisieren
for ( USHORT nMod = 0; nMod < pModules->Count(); nMod++ )
{
SbModule* pModule = (SbModule*)pModules->Get( nMod );
// Nur initialisieren, wenn der Startcode schon ausgefuehrt wurde
if( pModule->pImage && pModule->pImage->bInit )
pModule->ClearPrivateVars();
}
/* #88042 This code can delete already used public vars during runtime!
2000-09-18 15:18:56 +00:00
// Alle Objekte ueberpruefen, ob es sich um ein Basic handelt
// Wenn ja, auch dort initialisieren
for ( USHORT nObj = 0; nObj < pObjs->Count(); nObj++ )
{
SbxVariable* pVar = pObjs->Get( nObj );
StarBASIC* pBasic = PTR_CAST(StarBASIC,pVar);
if( pBasic )
pBasic->ClearAllModuleVars();
}
*/
2000-09-18 15:18:56 +00:00
}
// Ausfuehren des Init-Codes aller Module
void SbModule::GlobalRunInit( BOOL bBasicStart )
{
// Wenn kein Basic-Start, nur initialisieren, wenn Modul uninitialisiert
if( !bBasicStart )
if( !(pImage && !pImage->bInit) )
return;
// GlobalInitErr-Flag fuer Compiler-Error initialisieren
// Anhand dieses Flags kann in SbModule::Run() nach dem Aufruf
// von GlobalRunInit festgestellt werden, ob beim initialisieren
// der Module ein Fehler auftrat. Dann wird nicht gestartet.
GetSbData()->bGlobalInitErr = FALSE;
// Parent vom Modul ist ein Basic
StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent());
if( pBasic )
{
pBasic->InitAllModules();
SbxObject* pParent = pBasic->GetParent();
if( pParent )
{
StarBASIC * pParentBasic = PTR_CAST(StarBASIC,pParent);
if( pParentBasic )
{
pParentBasic->InitAllModules( pBasic );
// #109018 Parent can also have a parent (library in doc)
SbxObject* pParentParent = pParentBasic->GetParent();
if( pParentParent )
{
StarBASIC * pParentParentBasic = PTR_CAST(StarBASIC,pParentParent);
if( pParentParentBasic )
pParentParentBasic->InitAllModules( pParentBasic );
}
}
}
2000-09-18 15:18:56 +00:00
}
}
void SbModule::GlobalRunDeInit( void )
{
StarBASIC *pBasic = PTR_CAST(StarBASIC,GetParent());
if( pBasic )
{
pBasic->DeInitAllModules();
SbxObject* pParent = pBasic->GetParent();
if( pParent )
pBasic = PTR_CAST(StarBASIC,pParent);
if( pBasic )
pBasic->DeInitAllModules();
}
}
2000-09-18 15:18:56 +00:00
// Suche nach dem naechsten STMNT-Befehl im Code. Wird vom STMNT-
// Opcode verwendet, um die Endspalte zu setzen.
const BYTE* SbModule::FindNextStmnt( const BYTE* p, USHORT& nLine, USHORT& nCol ) const
{
return FindNextStmnt( p, nLine, nCol, FALSE );
}
const BYTE* SbModule::FindNextStmnt( const BYTE* p, USHORT& nLine, USHORT& nCol,
BOOL bFollowJumps, const SbiImage* pImg ) const
2000-09-18 15:18:56 +00:00
{
USHORT nPC = (USHORT) ( p - (const BYTE*) pImage->GetCode() );
while( nPC < pImage->GetCodeSize() )
{
SbiOpcode eOp = (SbiOpcode ) ( *p++ );
nPC++;
if( bFollowJumps && eOp == _JUMP && pImg )
{
DBG_ASSERT( pImg, "FindNextStmnt: pImg==NULL with FollowJumps option" );
USHORT nOp1 = *p++; nOp1 |= *p++ << 8;
p = (const BYTE*) pImg->GetCode() + nOp1;
}
else if( eOp >= SbOP1_START && eOp <= SbOP1_END )
2000-09-18 15:18:56 +00:00
p += 2, nPC += 2;
else if( eOp == _STMNT )
{
USHORT nl, nc;
nl = *p++; nl |= *p++ << 8;
nc = *p++; nc |= *p++ << 8;
nLine = nl; nCol = nc;
return p;
}
else if( eOp >= SbOP2_START && eOp <= SbOP2_END )
p += 4, nPC += 4;
else if( !( eOp >= SbOP0_START && eOp <= SbOP0_END ) )
{
StarBASIC::FatalError( SbERR_INTERNAL_ERROR );
break;
}
}
return NULL;
}
// Testen, ob eine Zeile STMNT-Opcodes enthaelt
BOOL SbModule::IsBreakable( USHORT nLine ) const
{
if( !pImage )
return FALSE;
const BYTE* p = (const BYTE* ) pImage->GetCode();
USHORT nl, nc;
while( ( p = FindNextStmnt( p, nl, nc ) ) != NULL )
if( nl == nLine )
return TRUE;
return FALSE;
}
USHORT SbModule::GetBPCount() const
{
return pBreaks ? pBreaks->Count() : 0;
}
USHORT SbModule::GetBP( USHORT n ) const
{
if( pBreaks && n < pBreaks->Count() )
return pBreaks->GetObject( n );
else
return 0;
}
BOOL SbModule::IsBP( USHORT nLine ) const
{
if( pBreaks )
{
const USHORT* p = pBreaks->GetData();
USHORT n = pBreaks->Count();
for( USHORT i = 0; i < n; i++, p++ )
{
USHORT b = *p;
if( b == nLine )
return TRUE;
if( b < nLine )
break;
}
}
return FALSE;
}
BOOL SbModule::SetBP( USHORT nLine )
{
if( !IsBreakable( nLine ) )
return FALSE;
if( !pBreaks )
pBreaks = new SbiBreakpoints;
const USHORT* p = pBreaks->GetData();
USHORT n = pBreaks->Count();
USHORT i;
for( i = 0; i < n; i++, p++ )
{
USHORT b = *p;
if( b == nLine )
return TRUE;
if( b < nLine )
break;
}
pBreaks->Insert( &nLine, 1, i );
// #38568: Zur Laufzeit auch hier SbDEBUG_BREAK setzen
if( pINST && pINST->pRun )
pINST->pRun->SetDebugFlags( SbDEBUG_BREAK );
return IsBreakable( nLine );
}
BOOL SbModule::ClearBP( USHORT nLine )
{
BOOL bRes = FALSE;
if( pBreaks )
{
const USHORT* p = pBreaks->GetData();
USHORT n = pBreaks->Count();
for( USHORT i = 0; i < n; i++, p++ )
{
USHORT b = *p;
if( b == nLine )
{
pBreaks->Remove( i, 1 ); bRes = TRUE; break;
}
if( b < nLine )
break;
}
if( !pBreaks->Count() )
delete pBreaks, pBreaks = NULL;
}
return bRes;
}
void SbModule::ClearAllBP()
{
delete pBreaks; pBreaks = NULL;
}
BOOL SbModule::LoadData( SvStream& rStrm, USHORT nVer )
{
Clear();
if( !SbxObject::LoadData( rStrm, 1 ) )
return FALSE;
// Sicherheitshalber...
SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH );
BYTE bImage;
rStrm >> bImage;
if( bImage )
{
SbiImage* p = new SbiImage;
if( !p->Load( rStrm ) )
{
delete p;
return FALSE;
}
aComment = p->aComment;
SetName( p->aName );
// Ist Code vorhanden?
if( p->GetCodeSize() )
{
aOUSource = p->aOUSource;
2000-09-18 15:18:56 +00:00
// Alte Version: Image weg
if( nVer == 1 )
{
SetSource32( p->aOUSource );
2000-09-18 15:18:56 +00:00
delete p;
}
else
pImage = p;
}
else
{
SetSource32( p->aOUSource );
2000-09-18 15:18:56 +00:00
delete p;
}
}
return TRUE;
}
BOOL SbModule::StoreData( SvStream& rStrm ) const
{
if( !SbxObject::StoreData( rStrm ) )
return FALSE;
if( pImage )
{
pImage->aOUSource = aOUSource;
2000-09-18 15:18:56 +00:00
pImage->aComment = aComment;
pImage->aName = GetName();
rStrm << (BYTE) 1;
return pImage->Save( rStrm );
}
else
{
SbiImage aImg;
aImg.aOUSource = aOUSource;
2000-09-18 15:18:56 +00:00
aImg.aComment = aComment;
aImg.aName = GetName();
rStrm << (BYTE) 1;
return aImg.Save( rStrm );
}
}
// Store only image, no source
BOOL SbModule::StoreBinaryData( SvStream& rStrm )
{
2001-11-14 10:11:32 +00:00
BOOL bRet = Compile();
if( bRet )
{
2001-11-14 10:11:32 +00:00
bRet = SbxObject::StoreData( rStrm );
if( bRet )
{
pImage->aOUSource = OUString();
pImage->aComment = aComment;
pImage->aName = GetName();
rStrm << (BYTE) 1;
bRet = pImage->Save( rStrm );
pImage->aOUSource = aOUSource;
}
}
return bRet;
}
BOOL SbModule::LoadBinaryData( SvStream& rStrm )
{
OUString aKeepSource = aOUSource;
bool bRet = LoadData( rStrm, 2 );
LoadCompleted();
aOUSource = aKeepSource;
return bRet;
}
2000-09-18 15:18:56 +00:00
BOOL SbModule::LoadCompleted()
{
SbxArray* p = GetMethods();
USHORT i;
for( i = 0; i < p->Count(); i++ )
{
SbMethod* q = PTR_CAST(SbMethod,p->Get( i ) );
if( q )
q->pMod = this;
}
p = GetProperties();
for( i = 0; i < p->Count(); i++ )
{
SbProperty* q = PTR_CAST(SbProperty,p->Get( i ) );
if( q )
q->pMod = this;
}
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
// Hilfsklasse zur Untersuchung von JavaScript-Modulen, zunaechst zum
// Heraussuchen der Funktionen, spaeter auch zum Syntax-Highlighting verwenden
// Flags fuer Zeichen-Eigenschaften
#define CHAR_START_IDENTIFIER 0x0001
#define CHAR_IN_IDENTIFIER 0x0002
#define CHAR_START_NUMBER 0x0004
#define CHAR_IN_NUMBER 0x0008
#define CHAR_IN_HEX_NUMBER 0x0010
#define CHAR_IN_OCT_NUMBER 0x0020
#define CHAR_START_STRING 0x0040
#define CHAR_OPERATOR 0x0080
#define CHAR_SPACE 0x0100
#define CHAR_EOL 0x0200
#define CHAR_EOF 0x00
class SimpleTokenizer_Impl
{
// Zeichen-Info-Tabelle
USHORT aCharTypeTab[256];
const sal_Unicode* mpStringBegin;
const sal_Unicode* mpActualPos;
2000-09-18 15:18:56 +00:00
// Zeile und Spalte
UINT32 nLine;
UINT32 nCol;
sal_Unicode peekChar( void ) { return *mpActualPos; }
sal_Unicode getChar( void ) { nCol++; return *mpActualPos++; }
2000-09-18 15:18:56 +00:00
// Hilfsfunktion: Zeichen-Flag Testen
BOOL testCharFlags( sal_Unicode c, USHORT nTestFlags );
2000-09-18 15:18:56 +00:00
// Neues Token holen, Leerstring == nix mehr da
BOOL getNextToken( /*out*/TokenTypes& reType,
/*out*/const sal_Unicode*& rpStartPos, /*out*/const sal_Unicode*& rpEndPos );
2000-09-18 15:18:56 +00:00
String getTokStr( /*out*/const sal_Unicode* pStartPos, /*out*/const sal_Unicode* pEndPos );
2000-09-18 15:18:56 +00:00
#ifndef PRODUCT
2000-09-18 15:18:56 +00:00
// TEST: Token ausgeben
String getFullTokenStr( /*out*/TokenTypes eType,
/*out*/const sal_Unicode* pStartPos, /*out*/const sal_Unicode* pEndPos );
#endif
2000-09-18 15:18:56 +00:00
char** ppListKeyWords;
UINT16 nKeyWordCount;
public:
SimpleTokenizer_Impl( void );
~SimpleTokenizer_Impl( void );
UINT16 parseLine( UINT32 nLine, const String* aSource );
void getHighlightPortions( UINT32 nParseLine, const String& rLine,
/*out*/HighlightPortions& portions );
void setKeyWords( char** ppKeyWords, UINT16 nCount );
};
// Hilfsfunktion: Zeichen-Flag Testen
BOOL SimpleTokenizer_Impl::testCharFlags( sal_Unicode c, USHORT nTestFlags )
2000-09-18 15:18:56 +00:00
{
bool bRet = false;
if( c != 0 && c <= 255 )
{
bRet = ( (aCharTypeTab[c] & nTestFlags) != 0 );
}
else if( c > 255 )
{
bRet = (( CHAR_START_IDENTIFIER | CHAR_IN_IDENTIFIER ) & nTestFlags) != 0
? BasicSimpleCharClass::isAlpha( c, true ) : false;
}
return bRet;
2000-09-18 15:18:56 +00:00
}
void SimpleTokenizer_Impl::setKeyWords( char** ppKeyWords, UINT16 nCount )
{
ppListKeyWords = ppKeyWords;
nKeyWordCount = nCount;
}
// Neues Token holen
BOOL SimpleTokenizer_Impl::getNextToken( /*out*/TokenTypes& reType,
/*out*/const sal_Unicode*& rpStartPos, /*out*/const sal_Unicode*& rpEndPos )
2000-09-18 15:18:56 +00:00
{
reType = TT_UNKNOWN;
// Position merken
rpStartPos = mpActualPos;
// Zeichen untersuchen
sal_Unicode c = peekChar();
2000-09-18 15:18:56 +00:00
if( c == CHAR_EOF )
return FALSE;
// Zeichen lesen
getChar();
//*** Alle Moeglichkeiten durchgehen ***
// Space?
if ( (testCharFlags( c, CHAR_SPACE ) == TRUE) )
2000-09-18 15:18:56 +00:00
{
while( testCharFlags( peekChar(), CHAR_SPACE ) == TRUE )
getChar();
reType = TT_WHITESPACE;
}
// Identifier?
else if ( (testCharFlags( c, CHAR_START_IDENTIFIER ) == TRUE) )
2000-09-18 15:18:56 +00:00
{
BOOL bIdentifierChar;
int nPos = 0;
do
{
// Naechstes Zeichen holen
c = peekChar();
bIdentifierChar = testCharFlags( c, CHAR_IN_IDENTIFIER );
if( bIdentifierChar )
getChar();
}
while( bIdentifierChar );
reType = TT_IDENTIFIER;
// Schluesselwort-Tabelle
if (ppListKeyWords != NULL)
{
int nCount = mpActualPos - rpStartPos;
2000-09-18 15:18:56 +00:00
// No keyword if string contains char > 255
bool bCanBeKeyword = true;
for( int i = 0 ; i < nCount ; i++ )
2000-09-18 15:18:56 +00:00
{
if( rpStartPos[i] > 255 )
2000-09-18 15:18:56 +00:00
{
bCanBeKeyword = false;
break;
2000-09-18 15:18:56 +00:00
}
}
if( bCanBeKeyword )
2000-09-18 15:18:56 +00:00
{
String aKWString( rpStartPos, nCount );
ByteString aByteStr( aKWString, RTL_TEXTENCODING_ASCII_US );
aByteStr.ToLowerAscii();
if ( bsearch( aByteStr.GetBuffer(), ppListKeyWords, nKeyWordCount, sizeof( char* ),
compare_strings ) )
2000-09-18 15:18:56 +00:00
{
reType = TT_KEYWORD;
2000-09-18 15:18:56 +00:00
if ( aByteStr.Equals( "rem" ) )
2000-09-18 15:18:56 +00:00
{
// Alle Zeichen bis Zeilen-Ende oder EOF entfernen
sal_Unicode cPeek = peekChar();
2000-09-18 15:18:56 +00:00
while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE )
{
c = getChar();
cPeek = peekChar();
}
reType = TT_COMMENT;
}
}
}
}
}
// Operator?
else if ( testCharFlags( c, CHAR_OPERATOR ) == TRUE || c == '\'' )
{
// Kommentar ?
if ( c == '\'' )
{
c = getChar(); // '/' entfernen
// Alle Zeichen bis Zeilen-Ende oder EOF entfernen
sal_Unicode cPeek = peekChar();
while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE )
{
getChar();
cPeek = peekChar();
}
reType = TT_COMMENT;
}
2000-09-18 15:18:56 +00:00
// Echter Operator, kann hier einfach behandelt werden,
// da nicht der wirkliche Operator, wie z.B. += interessiert,
// sondern nur die Tatsache, dass es sich um einen handelt.
if( reType != TT_COMMENT )
{
reType = TT_OPERATOR;
}
}
// Objekt-Trenner? Muss vor Number abgehandelt werden
else if( c == '.' && ( peekChar() < '0' || peekChar() > '9' ) )
{
reType = TT_OPERATOR;
}
// Zahl?
else if( testCharFlags( c, CHAR_START_NUMBER ) == TRUE )
{
// Buffer-Position initialisieren
int nPos = 0;
// Zahlensystem, 10 = normal, wird bei Oct/Hex geaendert
int nRadix = 10;
// Ist es eine Hex- oder Oct-Zahl?
if( c == '0' )
{
// Octal?
// Java-Script geht von einem Octal-Wert aus, wenn nach 0 eine
// Ziffer im oktalen Ziffernbereich folgt
if( testCharFlags( peekChar(), CHAR_IN_OCT_NUMBER ) )
{
nRadix = 8; // Octal-Basis
// Alle Ziffern einlesen
while( testCharFlags( peekChar(), CHAR_IN_OCT_NUMBER ) )
c = getChar();
}
// Dementsprechend wird bei 0x Hex geparsed
else if( peekChar() == 'x' || peekChar() == 'X' )
{
// x entfernen
getChar();
nRadix = 16; // Hex-Basis
// Alle Ziffern einlesen und puffern
while( testCharFlags( peekChar(), CHAR_IN_HEX_NUMBER ) )
c = getChar();
}
}
// Wenn nicht Oct oder Hex als double ansehen
if( nRadix == 10 )
{
// Flag, ob das letzte Zeichen ein Exponent war
BOOL bAfterExpChar = FALSE;
// Alle Ziffern einlesen
while( testCharFlags( peekChar(), CHAR_IN_NUMBER ) ||
(bAfterExpChar && peekChar() == '+' ) ||
(bAfterExpChar && peekChar() == '-' ) )
// Nach Exponent auch +/- OK
{
c = getChar(); // Zeichen lesen
bAfterExpChar = ( c == 'e' || c == 'E' );
}
}
reType = TT_NUMBER;
}
// String?
else if( testCharFlags( c, CHAR_START_STRING ) == TRUE )
{
// Merken, welches Zeichen den String eroeffnet hat
sal_Unicode cEndString = c;
2000-09-18 15:18:56 +00:00
// Alle Ziffern einlesen und puffern
while( peekChar() != cEndString )
{
// #58846 EOF vor getChar() abfangen, damit EOF micht verloren geht
if( peekChar() == CHAR_EOF )
{
// ERROR: unterminated string literal
reType = TT_ERROR;
break;
}
c = getChar();
if( testCharFlags( c, CHAR_EOL ) == TRUE )
{
// ERROR: unterminated string literal
reType = TT_ERROR;
break;
}
}
// Zeichen lesen
if( reType != TT_ERROR )
{
getChar();
reType = TT_STRING;
}
}
// Zeilenende?
else if( testCharFlags( c, CHAR_EOL ) == TRUE )
{
// Falls ein weiteres anderes EOL-Char folgt, weg damit
sal_Unicode cNext = peekChar();
2000-09-18 15:18:56 +00:00
if( cNext != c && testCharFlags( cNext, CHAR_EOL ) == TRUE )
getChar();
// Positions-Daten auf Zeilen-Beginn setzen
nCol = 0;
nLine++;
reType = TT_EOL;
}
// Alles andere bleibt TT_UNKNOWN
// End-Position eintragen
rpEndPos = mpActualPos;
return TRUE;
}
String SimpleTokenizer_Impl::getTokStr
( /*out*/const sal_Unicode* pStartPos, /*out*/const sal_Unicode* pEndPos )
2000-09-18 15:18:56 +00:00
{
return String( pStartPos, (USHORT)( pEndPos - pStartPos ) );
}
#ifndef PRODUCT
2000-09-18 15:18:56 +00:00
// TEST: Token ausgeben
String SimpleTokenizer_Impl::getFullTokenStr( /*out*/TokenTypes eType,
/*out*/const sal_Unicode* pStartPos, /*out*/const sal_Unicode* pEndPos )
2000-09-18 15:18:56 +00:00
{
String aOut;
switch( eType )
{
case TT_UNKNOWN: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_UNKNOWN:") ); break;
case TT_IDENTIFIER: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_IDENTIFIER:") ); break;
case TT_WHITESPACE: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_WHITESPACE:") ); break;
case TT_NUMBER: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_NUMBER:") ); break;
case TT_STRING: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_STRING:") ); break;
case TT_EOL: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_EOL:") ); break;
case TT_COMMENT: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_COMMENT:") ); break;
case TT_ERROR: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_ERROR:") ); break;
case TT_OPERATOR: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_OPERATOR:") ); break;
case TT_KEYWORD: aOut = String( RTL_CONSTASCII_USTRINGPARAM("TT_KEYWORD:") ); break;
}
if( eType != TT_EOL )
{
aOut += String( pStartPos, (USHORT)( pEndPos - pStartPos ) );
}
aOut += String( RTL_CONSTASCII_USTRINGPARAM("\n") );
return aOut;
}
#endif
2000-09-18 15:18:56 +00:00
SimpleTokenizer_Impl::SimpleTokenizer_Impl( void )
{
memset( aCharTypeTab, 0, sizeof( aCharTypeTab ) );
// Zeichen-Tabelle fuellen
USHORT i;
// Zulaessige Zeichen fuer Identifier
USHORT nHelpMask = (USHORT)( CHAR_START_IDENTIFIER | CHAR_IN_IDENTIFIER );
for( i = 'a' ; i <= 'z' ; i++ )
aCharTypeTab[i] |= nHelpMask;
for( i = 'A' ; i <= 'Z' ; i++ )
aCharTypeTab[i] |= nHelpMask;
// '_' extra eintragen
aCharTypeTab['_'] |= nHelpMask;
// AB 23.6.97: '$' ist auch erlaubt
aCharTypeTab['$'] |= nHelpMask;
// Ziffern (Identifier und Number ist moeglich)
nHelpMask = (USHORT)( CHAR_IN_IDENTIFIER | CHAR_START_NUMBER |
CHAR_IN_NUMBER | CHAR_IN_HEX_NUMBER );
for( i = '0' ; i <= '9' ; i++ )
aCharTypeTab[i] |= nHelpMask;
// e und E sowie . von Hand ergaenzen
aCharTypeTab['e'] |= CHAR_IN_NUMBER;
aCharTypeTab['E'] |= CHAR_IN_NUMBER;
aCharTypeTab['.'] |= (USHORT)( CHAR_IN_NUMBER | CHAR_START_NUMBER );
// Hex-Ziffern
for( i = 'a' ; i <= 'f' ; i++ )
aCharTypeTab[i] |= CHAR_IN_HEX_NUMBER;
for( i = 'A' ; i <= 'F' ; i++ )
aCharTypeTab[i] |= CHAR_IN_HEX_NUMBER;
// Oct-Ziffern
for( i = '0' ; i <= '7' ; i++ )
aCharTypeTab[i] |= CHAR_IN_OCT_NUMBER;
// String-Beginn/End-Zeichen
aCharTypeTab['\''] |= CHAR_START_STRING;
aCharTypeTab['\"'] |= CHAR_START_STRING;
// Operator-Zeichen
aCharTypeTab['!'] |= CHAR_OPERATOR;
aCharTypeTab['%'] |= CHAR_OPERATOR;
aCharTypeTab['&'] |= CHAR_OPERATOR;
aCharTypeTab['('] |= CHAR_OPERATOR;
aCharTypeTab[')'] |= CHAR_OPERATOR;
aCharTypeTab['*'] |= CHAR_OPERATOR;
aCharTypeTab['+'] |= CHAR_OPERATOR;
aCharTypeTab[','] |= CHAR_OPERATOR;
aCharTypeTab['-'] |= CHAR_OPERATOR;
aCharTypeTab['/'] |= CHAR_OPERATOR;
aCharTypeTab[':'] |= CHAR_OPERATOR;
aCharTypeTab['<'] |= CHAR_OPERATOR;
aCharTypeTab['='] |= CHAR_OPERATOR;
aCharTypeTab['>'] |= CHAR_OPERATOR;
aCharTypeTab['?'] |= CHAR_OPERATOR;
aCharTypeTab['^'] |= CHAR_OPERATOR;
aCharTypeTab['|'] |= CHAR_OPERATOR;
aCharTypeTab['~'] |= CHAR_OPERATOR;
aCharTypeTab['{'] |= CHAR_OPERATOR;
aCharTypeTab['}'] |= CHAR_OPERATOR;
aCharTypeTab['['] |= CHAR_OPERATOR;
aCharTypeTab[']'] |= CHAR_OPERATOR;
aCharTypeTab[';'] |= CHAR_OPERATOR;
// Space
aCharTypeTab[' ' ] |= CHAR_SPACE;
aCharTypeTab['\t'] |= CHAR_SPACE;
// Zeilen-Ende-Zeichen
aCharTypeTab['\r'] |= CHAR_EOL;
aCharTypeTab['\n'] |= CHAR_EOL;
ppListKeyWords = NULL;
}
SimpleTokenizer_Impl::~SimpleTokenizer_Impl( void )
{
}
SimpleTokenizer_Impl* getSimpleTokenizer( void )
{
static SimpleTokenizer_Impl* pSimpleTokenizer = NULL;
if( !pSimpleTokenizer )
pSimpleTokenizer = new SimpleTokenizer_Impl();
return pSimpleTokenizer;
}
// Heraussuchen der jeweils naechsten Funktion aus einem JavaScript-Modul
UINT16 SimpleTokenizer_Impl::parseLine( UINT32 nParseLine, const String* aSource )
{
// Position auf den Anfang des Source-Strings setzen
mpStringBegin = mpActualPos = aSource->GetBuffer();
2000-09-18 15:18:56 +00:00
// Zeile und Spalte initialisieren
nLine = nParseLine;
nCol = 0L;
// Variablen fuer die Out-Parameter
TokenTypes eType;
const sal_Unicode* pStartPos;
const sal_Unicode* pEndPos;
2000-09-18 15:18:56 +00:00
// Schleife ueber alle Tokens
UINT16 nTokenCount = 0;
while( getNextToken( eType, pStartPos, pEndPos ) )
nTokenCount++;
return nTokenCount;
}
void SimpleTokenizer_Impl::getHighlightPortions( UINT32 nParseLine, const String& rLine,
/*out*/HighlightPortions& portions )
{
// Position auf den Anfang des Source-Strings setzen
mpStringBegin = mpActualPos = rLine.GetBuffer();
2000-09-18 15:18:56 +00:00
// Zeile und Spalte initialisieren
nLine = nParseLine;
nCol = 0L;
// Variablen fuer die Out-Parameter
TokenTypes eType;
const sal_Unicode* pStartPos;
const sal_Unicode* pEndPos;
2000-09-18 15:18:56 +00:00
// Schleife ueber alle Tokens
while( getNextToken( eType, pStartPos, pEndPos ) )
{
HighlightPortion portion;
portion.nBegin = (UINT16)(pStartPos - mpStringBegin);
portion.nEnd = (UINT16)(pEndPos - mpStringBegin);
portion.tokenType = eType;
portions.Insert(portion, portions.Count());
}
}
//////////////////////////////////////////////////////////////////////////
// Implementierung des SyntaxHighlighter
SyntaxHighlighter::SyntaxHighlighter()
{
m_pSimpleTokenizer = new SimpleTokenizer_Impl();
m_pKeyWords = NULL;
m_nKeyWordCount = 0;
}
SyntaxHighlighter::~SyntaxHighlighter()
{
delete(m_pSimpleTokenizer);
delete(m_pKeyWords);
}
void SyntaxHighlighter::initialize( HighlighterLanguage eLanguage_ )
{
eLanguage = eLanguage_;
delete(m_pSimpleTokenizer);
m_pSimpleTokenizer = new SimpleTokenizer_Impl();
if (eLanguage == HIGHLIGHT_BASIC)
{
m_pSimpleTokenizer->setKeyWords( strListBasicKeyWords,
sizeof( strListBasicKeyWords ) / sizeof( char* ));
}
else
{
m_pSimpleTokenizer->setKeyWords( NULL, 0 );
}
}
const Range SyntaxHighlighter::notifyChange( UINT32 nLine, INT32 nLineCountDifference,
const String* pChangedLines, UINT32 nArrayLength)
{
for (INT32 i=0; i<nArrayLength; i++)
m_pSimpleTokenizer->parseLine(nLine+i, &pChangedLines[i]);
return Range(nLine, nLine+nArrayLength-1);
}
void SyntaxHighlighter::getHighlightPortions( UINT32 nLine, const String& rLine,
/*out*/HighlightPortions& portions )
{
m_pSimpleTokenizer->getHighlightPortions( nLine, rLine, portions );
}
/////////////////////////////////////////////////////////////////////////
// Implementation SbJScriptModule (Basic-Modul fuer JavaScript-Sourcen)
SbJScriptModule::SbJScriptModule( const String& rName )
:SbModule( rName )
{
}
BOOL SbJScriptModule::LoadData( SvStream& rStrm, USHORT nVer )
{
Clear();
if( !SbxObject::LoadData( rStrm, 1 ) )
return FALSE;
// Source-String holen
String aTmp;
rStrm.ReadByteString( aTmp, gsl_getSystemTextEncoding() );
aOUSource = aTmp;
2000-09-18 15:18:56 +00:00
//rStrm >> aSource;
return TRUE;
}
BOOL SbJScriptModule::StoreData( SvStream& rStrm ) const
{
if( !SbxObject::StoreData( rStrm ) )
return FALSE;
// Source-String schreiben
String aTmp = aOUSource;
rStrm.WriteByteString( aTmp, gsl_getSystemTextEncoding() );
2000-09-18 15:18:56 +00:00
//rStrm << aSource;
return TRUE;
}
/////////////////////////////////////////////////////////////////////////
SbMethod::SbMethod( const String& r, SbxDataType t, SbModule* p )
: SbxMethod( r, t ), pMod( p )
{
bInvalid = TRUE;
nStart =
nDebugFlags =
nLine1 =
nLine2 = 0;
// AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden'
SetFlag( SBX_NO_MODIFY );
}
SbMethod::SbMethod( const SbMethod& r )
: SbxMethod( r )
{
pMod = r.pMod;
bInvalid = r.bInvalid;
nStart = r.nStart;
nDebugFlags = r.nDebugFlags;
nLine1 = r.nLine1;
nLine2 = r.nLine2;
SetFlag( SBX_NO_MODIFY );
}
2000-09-18 15:18:56 +00:00
SbMethod::~SbMethod()
{
}
2000-09-18 15:18:56 +00:00
SbxArray* SbMethod::GetLocals()
{
if( pINST )
return pINST->GetLocals( this );
else
return NULL;
}
SbxArray* SbMethod::GetStatics()
{
DBG_ERROR( "SbMethod::GetStatics() invalid, AB fragen" )
return NULL;
}
BOOL SbMethod::LoadData( SvStream& rStrm, USHORT nVer )
{
if( !SbxMethod::LoadData( rStrm, 1 ) )
return FALSE;
INT16 n;
rStrm >> n;
// nDebugFlags = n; // AB 16.1.96: Nicht mehr uebernehmen
if( nVer == 2 )
rStrm >> nLine1 >> nLine2 >> nStart >> bInvalid;
// AB: 2.7.1996: HACK wegen 'Referenz kann nicht gesichert werden'
SetFlag( SBX_NO_MODIFY );
return TRUE;
}
BOOL SbMethod::StoreData( SvStream& rStrm ) const
{
if( !SbxMethod::StoreData( rStrm ) )
return FALSE;
rStrm << (INT16) nDebugFlags
<< (INT16) nLine1
<< (INT16) nLine2
<< (INT16) nStart
<< (BYTE) bInvalid;
return TRUE;
}
void SbMethod::GetLineRange( USHORT& l1, USHORT& l2 )
{
l1 = nLine1; l2 = nLine2;
}
// Kann spaeter mal weg
SbxInfo* SbMethod::GetInfo()
{
return pInfo;
}
// Schnittstelle zum Ausfuehren einer Methode aus den Applikationen
// #34191# Mit speziellem RefCounting, damit das Basic nicht durch CloseDocument()
// abgeschossen werden kann. Rueckgabewert wird als String geliefert.
ErrCode SbMethod::Call( SbxValue* pRet )
{
// RefCount vom Modul hochzaehlen
SbModule* pMod = (SbModule*)GetParent();
pMod->AddRef();
// RefCount vom Basic hochzaehlen
StarBASIC* pBasic = (StarBASIC*)pMod->GetParent();
pBasic->AddRef();
// Values anlegen, um Return-Wert zu erhalten
SbxValues aVals;
aVals.eType = SbxVARIANT;
// #104083: Compile BEFORE get
if( bInvalid && !pMod->Compile() )
StarBASIC::Error( SbERR_BAD_PROP_VALUE );
2000-09-18 15:18:56 +00:00
Get( aVals );
if ( pRet )
pRet->Put( aVals );
// Gab es einen Error
ErrCode nErr = SbxBase::GetError();
SbxBase::ResetError();
// Objekte freigeben
pMod->ReleaseRef();
pBasic->ReleaseRef();
return nErr;
}
// #100883 Own Broadcast for SbMethod
void SbMethod::Broadcast( ULONG nHintId )
{
if( pCst && !IsSet( SBX_NO_BROADCAST ) && StaticIsEnabledBroadcasting() )
{
// Da die Methode von aussen aufrufbar ist, hier noch einmal
// die Berechtigung testen
if( nHintId & SBX_HINT_DATAWANTED )
if( !CanRead() )
return;
if( nHintId & SBX_HINT_DATACHANGED )
if( !CanWrite() )
return;
if( pMod && !pMod->IsCompiled() )
pMod->Compile();
// Block broadcasts while creating new method
SfxBroadcaster* pSave = pCst;
pCst = NULL;
SbMethod* pThisCopy = new SbMethod( *this );
SbMethodRef xHolder = pThisCopy;
if( pPar.Is() )
{
// this, als Element 0 eintragen, aber den Parent nicht umsetzen!
pPar->PutDirect( pThisCopy, 0 );
SetParameters( NULL );
}
pCst = pSave;
pSave->Broadcast( SbxHint( nHintId, pThisCopy ) );
USHORT nSaveFlags = GetFlags();
SetFlag( SBX_READWRITE );
pCst = NULL;
Put( pThisCopy->GetValues_Impl() );
pCst = pSave;
SetFlags( nSaveFlags );
}
}
2000-09-18 15:18:56 +00:00
/////////////////////////////////////////////////////////////////////////
// Implementation SbJScriptMethod (Method-Klasse als Wrapper fuer JavaScript-Funktionen)
SbJScriptMethod::SbJScriptMethod( const String& r, SbxDataType t, SbModule* p )
: SbMethod( r, t, p )
{
}
SbJScriptMethod::~SbJScriptMethod()
{}
/////////////////////////////////////////////////////////////////////////
SbProperty::SbProperty( const String& r, SbxDataType t, SbModule* p )
: SbxProperty( r, t ), pMod( p )
{
bInvalid = FALSE;
}
SbProperty::~SbProperty()
{}
/////////////////////////////////////////////////////////////////////////
SbProcedureProperty::~SbProcedureProperty()
{}
2000-09-18 15:18:56 +00:00