diff options
author | Jens-Heiner Rechtien <hr@openoffice.org> | 2000-09-18 15:18:56 +0000 |
---|---|---|
committer | Jens-Heiner Rechtien <hr@openoffice.org> | 2000-09-18 15:18:56 +0000 |
commit | cb1a7c1869062c789c65bc55285e6b18fcf378e0 (patch) | |
tree | a084b702d7cce826b3b68cb69be833eeedd6bedb /basic/source/classes/sbxmod.cxx |
initial import
Diffstat (limited to 'basic/source/classes/sbxmod.cxx')
-rw-r--r-- | basic/source/classes/sbxmod.cxx | 1984 |
1 files changed, 1984 insertions, 0 deletions
diff --git a/basic/source/classes/sbxmod.cxx b/basic/source/classes/sbxmod.cxx new file mode 100644 index 0000000000..18e1783c42 --- /dev/null +++ b/basic/source/classes/sbxmod.cxx @@ -0,0 +1,1984 @@ +/************************************************************************* + * + * $RCSfile: sbxmod.cxx,v $ + * + * $Revision: 1.1.1.1 $ + * + * last change: $Author: hr $ $Date: 2000-09-18 16:12:10 $ + * + * The Contents of this file are made available subject to the terms of + * either of the following licenses + * + * - GNU Lesser General Public License Version 2.1 + * - Sun Industry Standards Source License Version 1.1 + * + * Sun Microsystems Inc., October, 2000 + * + * GNU Lesser General Public License Version 2.1 + * ============================================= + * Copyright 2000 by Sun Microsystems, Inc. + * 901 San Antonio Road, Palo Alto, CA 94303, USA + * + * 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. + * + * 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. + * + * 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 + * + * + * Sun Industry Standards Source License Version 1.1 + * ================================================= + * The contents of this file are subject to the Sun Industry Standards + * Source License Version 1.1 (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.openoffice.org/license.html. + * + * Software provided under this License is provided on an "AS IS" basis, + * WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, + * WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS, + * MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING. + * See the License for the specific provisions governing your rights and + * obligations concerning the Software. + * + * The Initial Developer of the Original Code is: Sun Microsystems, Inc. + * + * Copyright: 2000 by Sun Microsystems, Inc. + * + * All Rights Reserved. + * + * Contributor(s): _______________________________________ + * + * + ************************************************************************/ + +#if STLPORT_VERSION < 321 +#include <tools/presys.h> +#include <list> +#include <tools/postsys.h> +#else +#include <list> +#endif + +#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 <svtools/sbx.hxx> +#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> + + +// for the bsearch +#ifdef WNT +#define CDECL _cdecl +#endif +#ifdef OS2 +#define CDECL _Optlink +#endif +#if defined(UNX) || defined(MAC) +#define CDECL +#endif + + +// TEST +#include <stdio.h> + +#include "segmentc.hxx" +#pragma SW_SEGMENT_CLASS( SBASIC, SBASIC_CODE ) + +TYPEINIT1(SbModule,SbxObject) +TYPEINIT1(SbMethod,SbxMethod) +TYPEINIT1(SbProperty,SbxProperty) +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", + "byval", + "call", + "case", + "cdecl", + "close", + "compare", + "const", + "currency", + "date", + "declare", + "defbool", + "defcur", + "defdate", + "defdbl", + "deferr", + "defint", + "deflng", + "defobj", + "defsng", + "defstr", + "defvar", + "dim", + "do", + "double", + "each", + "else", + "elseif", + "end", + "end function", + "end if", + "end select", + "end sub", + "end type", + "endif", + "eqv", + "erase", + "error", + "exit", + "explicit", + "for", + "function", + "global", + "gosub", + "goto", + "if", + "imp", + "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", + "public", + "random", + "read", + "redim", + "rem", + "resume", + "return", + "rset", + "select", + "set", + "shared", + "single", + "static", + "step", + "stop", + "string", + "sub", + "system", + "text", + "then", + "to", + "type", + "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 ) +{ + SetName( rName ); + SetFlag( SBX_EXTSEARCH | SBX_GBLSEARCH ); +} + +SbModule::~SbModule() +{ + if( pImage ) + delete pImage; + if( pBreaks ) + delete pBreaks; +} + +BOOL SbModule::IsCompiled() const +{ + return BOOL( pImage != 0 ); +} + +// Aus dem Codegenerator: Loeschen des Images und Invalidieren der Entries + +void SbModule::StartDefinitions() +{ + delete pImage; pImage = NULL; + // 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; +} + +// 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++; + } + } + } + SetModified( TRUE ); +} + +void SbModule::Clear() +{ + delete pImage; pImage = NULL; + SbxObject::Clear(); +} + +const String& SbModule::GetSource() const +{ + return aSource; +} + +// Parent und BASIC sind eins! + +void SbModule::SetParent( SbxObject* p ) +{ + DBG_ASSERT( !p || p->IsA( TYPE(StarBASIC) ), "SbModules nur in BASIC eintragen" ); + 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 ) +{ + aSource = r; + 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; + } + } + 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(); + + // 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(); + + // Oberstes Basic suchen + SbxObject* p = pBasic; + while( p->GetParent() ) + p = p->GetParent(); + + // Rekursiven Loeschvorgang ausloesen + ClearUnoObjectsInRTL_Impl_Rek( (StarBASIC*)p ); +} + +// Ausfuehren eines BASIC-Unterprogramms +USHORT SbModule::Run( SbMethod* pMeth ) +{ + 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; + } + // Rekursion zu tief? + if( ++pINST->nCallLvl <= MAXRECURSION ) + { + // 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; + pINST->pRun = pRt; + while( pRt->Step() ) {} + + // #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; + SendHint( GetParent(), SBX_HINT_BASICSTOP, pMeth ); + } + } + } + else + StarBASIC::FatalError( SbERR_STACK_OVERFLOW ); + 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; + + // 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(); + } + // 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(); + } + +} + +// 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 ) + pBasic = PTR_CAST(StarBASIC,pParent); + if( pBasic ) + pBasic->InitAllModules(); + } +} + +// 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 +{ + USHORT nPC = (USHORT) ( p - (const BYTE*) pImage->GetCode() ); + while( nPC < pImage->GetCodeSize() ) + { + SbiOpcode eOp = (SbiOpcode ) ( *p++ ); + nPC++; + if( eOp >= SbOP1_START && eOp <= SbOP1_END ) + 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() ) + { + aSource = p->aSource; + // Alte Version: Image weg + if( nVer == 1 ) + { + SetSource( p->aSource ); + delete p; + } + else + pImage = p; + } + else + { + SetSource( p->aSource ); + delete p; + } + } + return TRUE; +} + +BOOL SbModule::StoreData( SvStream& rStrm ) const +{ + if( !SbxObject::StoreData( rStrm ) ) + return FALSE; + if( pImage ) + { + pImage->aSource = aSource; + pImage->aComment = aComment; + pImage->aName = GetName(); + rStrm << (BYTE) 1; + return pImage->Save( rStrm ); + } + else + { + SbiImage aImg; + aImg.aSource = aSource; + aImg.aComment = aComment; + aImg.aName = GetName(); + rStrm << (BYTE) 1; + return aImg.Save( rStrm ); + } +} + +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 + + +// Token-Typen TT_... + +//enum TokenType +//{ +// TT_UNKNOWN, +// TT_IDENTIFIER, +// TT_WHITESPACE, +// TT_NUMBER, +// TT_STRING, +//// TT_HTMLSTRING, +//// TT_LONG, +//// TT_DOUBLE, +//// TT_BOOLEAN, +//// TT_NULLOBJECT, +//// TT_CHAR, +// TT_EOL, +//// TT_LONG2DOUBLE, +// TT_COMMENT, +//// TT_SKIP, +// TT_ERROR, +// TT_OPERATOR, +// TT_KEYWORD +//}; + + +class SimpleTokenizer_Impl +{ + // Zeichen-Info-Tabelle + USHORT aCharTypeTab[256]; + + const char* mpStringBegin; + const char* mpActualPos; + + // Zeile und Spalte + UINT32 nLine; + UINT32 nCol; + + char peekChar( void ) { return *mpActualPos; } + char getChar( void ) { nCol++; return *mpActualPos++; } + + // Hilfsfunktion: Zeichen-Flag Testen + BOOL testCharFlags( unsigned char c, USHORT nTestFlags ); + + // Neues Token holen, Leerstring == nix mehr da + BOOL getNextToken( /*out*/TokenTypes& reType, + /*out*/const char*& rpStartPos, /*out*/const char*& rpEndPos ); + + String getTokStr( /*out*/const char* pStartPos, /*out*/const char* pEndPos ); + + // TEST: Token ausgeben + String getFullTokenStr( /*out*/TokenTypes eType, + /*out*/const char* pStartPos, /*out*/const char* pEndPos ); + + BOOL isBeginComment( UINT32 nLine ); + void setCommentState(UINT32 nLine, BOOL bCommentBegin, BOOL bCommentEnd); + + NAMESPACE_STD(list)<BOOL>* pCommentsBegin; + NAMESPACE_STD(list)<BOOL>* pCommentsEnd; + + char** ppListKeyWords; + UINT16 nKeyWordCount; + BOOL bStarScriptMode; + + BOOL bLineHasCommentBegin; + BOOL bLineHasCommentEnd; + +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 addLines(UINT32 nLine, INT32 nCount); + void outCommentList(); + void setKeyWords( char** ppKeyWords, UINT16 nCount ); +}; + +// Hilfsfunktion: Zeichen-Flag Testen +BOOL SimpleTokenizer_Impl::testCharFlags( unsigned char c, USHORT nTestFlags ) +{ + if( c != 0 ) + return ( (aCharTypeTab[c] & nTestFlags) != 0 ); + return FALSE; +} + +void SimpleTokenizer_Impl::setKeyWords( char** ppKeyWords, UINT16 nCount ) +{ + ppListKeyWords = ppKeyWords; + nKeyWordCount = nCount; +} + +// Neues Token holen +BOOL SimpleTokenizer_Impl::getNextToken( /*out*/TokenTypes& reType, + /*out*/const char*& rpStartPos, /*out*/const char*& rpEndPos ) +{ + reType = TT_UNKNOWN; + + // Position merken + rpStartPos = mpActualPos; + + // Zeichen untersuchen + char c = peekChar(); + if( c == CHAR_EOF ) + return FALSE; + + // Zeichen lesen + getChar(); + + //*** Alle Moeglichkeiten durchgehen *** + // Spce? + if ( (testCharFlags( c, CHAR_SPACE ) == TRUE) && (!bLineHasCommentBegin) ) + { + while( testCharFlags( peekChar(), CHAR_SPACE ) == TRUE ) + getChar(); + + reType = TT_WHITESPACE; + } + + // Identifier? + else if ( (testCharFlags( c, CHAR_START_IDENTIFIER ) == TRUE) && (!bLineHasCommentBegin) ) + { + 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) + { + ByteString aByteStr(rpStartPos, mpActualPos-rpStartPos); + if ( !bStarScriptMode ) + aByteStr.ToLowerAscii(); + + if ( bsearch( aByteStr.GetBuffer(), ppListKeyWords, nKeyWordCount, sizeof( char* ), + compare_strings ) ) + { + reType = TT_KEYWORD; + + if ( (!bStarScriptMode) && (aByteStr.Equals( "rem" )) ) + { + // Alle Zeichen bis Zeilen-Ende oder EOF entfernen + char cPeek = peekChar(); + while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE ) + { + c = getChar(); + cPeek = peekChar(); + } + + reType = TT_COMMENT; + } + } + } + } + + // Operator? + else if ( (testCharFlags( c, CHAR_OPERATOR ) == TRUE) || bLineHasCommentBegin + || ((!bStarScriptMode) && (c == '\'')) ) + { + // Kommentar ? + if ( (( c == '/' ) || bLineHasCommentBegin) || ((!bStarScriptMode) && (c == '\'')) ) + { + char cNext = peekChar(); + if ( cNext == '/' || ( bStarScriptMode && (cNext == '*' || bLineHasCommentBegin)) + || ((!bStarScriptMode) && (c == '\'')) ) // Kommentar + { + if ((c == '*') && (cNext == '/')) // Kommentarende am Zeilenanfang + { + getChar(); // Zeichen entfernen + + bLineHasCommentEnd = TRUE; + bLineHasCommentBegin = FALSE; + + reType = TT_COMMENT; + } + else if ( (cNext == '/' && (!bStarScriptMode || !bLineHasCommentBegin)) + || ((!bStarScriptMode) && (c == '\'')) )// C++ - Kommentar + { + c = getChar(); // '/' entfernen + + // Alle Zeichen bis Zeilen-Ende oder EOF entfernen + char cPeek = peekChar(); + while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE ) + { + c = getChar(); + cPeek = peekChar(); + + if (c == '*' && cPeek == '/') + { + bLineHasCommentEnd = TRUE; + } + } + + reType = TT_COMMENT; + } + else if (( cNext == '*' ) || bLineHasCommentBegin) // C -Kommentar + { + bLineHasCommentBegin = !bLineHasCommentBegin; + + // Alle Zeichen bis */ entfernen + do + { + c = getChar(); + cNext = peekChar(); + + // Zeilennummer auch im Kommentar pflegen + if( testCharFlags( c, CHAR_EOL ) == TRUE ) + { + // Doppelt-EOL rausschmeissen (CR/LF) + if( cNext != c && testCharFlags( cNext, CHAR_EOL ) == TRUE ) + { + c = getChar(); + cNext = peekChar(); + } + + setCommentState(nLine, bLineHasCommentBegin, bLineHasCommentEnd); + bLineHasCommentBegin = FALSE; + bLineHasCommentEnd = FALSE; + + // Positions-Daten auf Zeilen-Beginn setzen + nCol = 0; + nLine++; + } + else if (c == '*' && cNext == '/') // am Kommentarende + { + if (bLineHasCommentBegin) // das Ende ist in der gleichen Zeile + { // wie der Anfang des Kommentars + bLineHasCommentBegin = FALSE; // also zurücksetzen + } + else + { + bLineHasCommentEnd = TRUE; + } + } + } + while( cNext != CHAR_EOF && ( c != '*' || cNext != '/' ) ); + + // Alles ausser EOF lesen + if( cNext != CHAR_EOF ) + getChar(); + + reType = TT_COMMENT; + } + } + } + // HTML-Kommentar + else if( c == '<' ) + { + char cNext = peekChar(); + if( cNext == '!' ) + { + getChar(); // '!' ist verloren, wenn nicht wirklich Tag + + cNext = peekChar(); + if( cNext == '-' ) + { + getChar(); // '-' ist verloren, wenn nicht wirklich Tag + + cNext = peekChar(); + if( cNext == '-' ) + { + getChar(); + + // HTML-Kommentar: Alle Zeichen bis Zeilen-Ende oder EOF entfernen + char cPeek = peekChar(); + while( cPeek != CHAR_EOF && testCharFlags( cPeek, CHAR_EOL ) == FALSE ) + { + c = getChar(); + cPeek = peekChar(); + } + + reType = TT_COMMENT; + } + else + { + // Verlorene Zeichen nachliefern + mpActualPos -= 2; + } + } + else + { + // Verlorenes Zeichen nachliefern + mpActualPos--; + } + } + } + + // 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 + char cEndString = c; + + // 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; + } + // Escape-Character untersuchen + else if ( (c == '\\') && (bStarScriptMode) ) + { + // Kann hier ganz einfach gehandelt werden: + // Einfach ein weiteres Zeichen lesen + char cNext = getChar(); + } + } + + // 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 + char cNext = peekChar(); + if( cNext != c && testCharFlags( cNext, CHAR_EOL ) == TRUE ) + getChar(); + + setCommentState(nLine, bLineHasCommentBegin, bLineHasCommentEnd); + bLineHasCommentBegin = FALSE; + bLineHasCommentEnd = FALSE; + + // Positions-Daten auf Zeilen-Beginn setzen + nCol = 0; + nLine++; + + reType = TT_EOL; + } + + // Alles andere bleibt TT_UNKNOWN + + + // End-Position eintragen + rpEndPos = mpActualPos; + return TRUE; +} + +void SimpleTokenizer_Impl::setCommentState(UINT32 nLine, BOOL bCommentBegin, BOOL bCommentEnd) +{ + while (pCommentsBegin->size() <= nLine) + pCommentsBegin->push_back(FALSE); + + while (pCommentsEnd->size() <= nLine) + pCommentsEnd->push_back(FALSE); + + NAMESPACE_STD(list)<BOOL>::iterator posBegins, posEnds; + UINT32 nCounter = 0; + + posBegins = pCommentsBegin->begin(); + posEnds = pCommentsEnd->begin(); + + while (nCounter < nLine) + { + posBegins++; + posEnds++; + nCounter++; + } + + *posBegins = bCommentBegin; + *posEnds = bCommentEnd; +} + +void SimpleTokenizer_Impl::addLines(UINT32 nLine, INT32 nCount) +{ + NAMESPACE_STD(list)<BOOL>::iterator posBegins, posEnds; + UINT32 nCounter = 0; + + if (!pCommentsBegin->empty()) + { + posBegins = pCommentsBegin->begin(); + posEnds = pCommentsEnd->begin(); + + while (nCounter < nLine) + { + posBegins++; + posEnds++; + nCounter++; + } + + INT32 nDiff = nCount; + while (nDiff != 0) + { + if (nDiff > 0) + { + pCommentsBegin->insert(posBegins, FALSE); + pCommentsEnd->insert(posEnds, FALSE); + nDiff--; + } + else + { + pCommentsBegin->erase(posBegins++); + pCommentsEnd->erase(posEnds++); + UINT16 dummy = pCommentsBegin->size(); + + nDiff++; + } + } + } + else if (nCount > 0) + { + INT32 nDiff = nCount; + while (nDiff != 0) + { + pCommentsBegin->push_back(FALSE); + pCommentsEnd->push_back(FALSE); + nDiff--; + } + } +} + +String SimpleTokenizer_Impl::getTokStr + ( /*out*/const char* pStartPos, /*out*/const char* pEndPos ) +{ + return String( pStartPos, (USHORT)( pEndPos - pStartPos ) ); +} + +// TEST: Token ausgeben +String SimpleTokenizer_Impl::getFullTokenStr( /*out*/TokenTypes eType, + /*out*/const char* pStartPos, /*out*/const char* pEndPos ) +{ + 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; +} + +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; + + // fuer Syntax Highlighting + pCommentsBegin = new NAMESPACE_STD(list)<BOOL>(); + pCommentsEnd = new NAMESPACE_STD(list)<BOOL>(); + + bStarScriptMode = FALSE; + ppListKeyWords = NULL; +} + +SimpleTokenizer_Impl::~SimpleTokenizer_Impl( void ) +{ + delete(pCommentsBegin); + delete(pCommentsEnd); +} + +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 ) +{ + ByteString aByteSource( *aSource, gsl_getSystemTextEncoding() ); + + // Position auf den Anfang des Source-Strings setzen + mpStringBegin = mpActualPos = aByteSource.GetBuffer(); + bLineHasCommentBegin = isBeginComment( nParseLine ); + bLineHasCommentEnd = FALSE; + + // Zeile und Spalte initialisieren + nLine = nParseLine; + nCol = 0L; + + // Variablen fuer die Out-Parameter + TokenTypes eType; + const char* pStartPos; + const char* pEndPos; + + // Schleife ueber alle Tokens + UINT16 nTokenCount = 0; + while( getNextToken( eType, pStartPos, pEndPos ) ) + nTokenCount++; + + // die Endzustaende der Zeilen in die Listen eintragen + setCommentState(nParseLine, bLineHasCommentBegin, bLineHasCommentEnd); + + return nTokenCount; +} + +void SimpleTokenizer_Impl::getHighlightPortions( UINT32 nParseLine, const String& rLine, + /*out*/HighlightPortions& portions ) +{ + ByteString aByteLine( rLine, gsl_getSystemTextEncoding() ); + + // Position auf den Anfang des Source-Strings setzen + mpStringBegin = mpActualPos = aByteLine.GetBuffer(); + bLineHasCommentBegin = isBeginComment( nParseLine ); + bLineHasCommentEnd = FALSE; + + // Zeile und Spalte initialisieren + nLine = nParseLine; + nCol = 0L; + + // Variablen fuer die Out-Parameter + TokenTypes eType; + const char* pStartPos; + const char* pEndPos; + + // 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()); + } +} + +BOOL SimpleTokenizer_Impl::isBeginComment( UINT32 nLine ) +{ + NAMESPACE_STD(list)<BOOL>::const_iterator posBegin, posEnd; + BOOL bCommentStart = FALSE; + + UINT32 i = 0; + posBegin=pCommentsBegin->begin(); + posEnd=pCommentsEnd->begin(); + + while ((i < nLine) && (posBegin != pCommentsBegin->end()) && (posEnd != pCommentsEnd->end())) + { + if (bCommentStart && *posEnd) + bCommentStart = FALSE; + if ((!bCommentStart) && *posBegin) + bCommentStart = TRUE; + + posBegin++; + posEnd++; + i++; + } + + return bCommentStart; +} + +void SimpleTokenizer_Impl::outCommentList() +{ + NAMESPACE_STD(list)<BOOL>::const_iterator posBegin, posEnd; + BOOL bCommentStart = FALSE; + + UINT32 i = 0; + posBegin=pCommentsBegin->begin(); + posEnd=pCommentsEnd->begin(); + + printf("\nComments:\n"); + while (posBegin != pCommentsBegin->end()) + { + printf("line: %2d beginComment: %d endComment: %d\n", i, *posBegin, *posEnd); + + posBegin++; + posEnd++; + i++; + } + +} + +////////////////////////////////////////////////////////////////////////// +// 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) +{ + if (nLineCountDifference != 0) + m_pSimpleTokenizer->addLines(nLine, nLineCountDifference); + + 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 + rStrm.ReadByteString( aSource, gsl_getSystemTextEncoding() ); + //rStrm >> aSource; + return TRUE; +} + +BOOL SbJScriptModule::StoreData( SvStream& rStrm ) const +{ + if( !SbxObject::StoreData( rStrm ) ) + return FALSE; + + // Source-String schreiben + rStrm.WriteByteString( aSource, gsl_getSystemTextEncoding() ); + //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() +{} + +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; + 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; +} + +///////////////////////////////////////////////////////////////////////// + +// 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() +{} + + |