xref: /aoo41x/main/basic/source/comp/sbcomp.cxx (revision 0848378b)
1e1f63238SAndrew Rist /**************************************************************
2cdf0e10cSrcweir  *
3e1f63238SAndrew Rist  * Licensed to the Apache Software Foundation (ASF) under one
4e1f63238SAndrew Rist  * or more contributor license agreements.  See the NOTICE file
5e1f63238SAndrew Rist  * distributed with this work for additional information
6e1f63238SAndrew Rist  * regarding copyright ownership.  The ASF licenses this file
7e1f63238SAndrew Rist  * to you under the Apache License, Version 2.0 (the
8e1f63238SAndrew Rist  * "License"); you may not use this file except in compliance
9e1f63238SAndrew Rist  * with the License.  You may obtain a copy of the License at
10e1f63238SAndrew Rist  *
11e1f63238SAndrew Rist  *   http://www.apache.org/licenses/LICENSE-2.0
12e1f63238SAndrew Rist  *
13e1f63238SAndrew Rist  * Unless required by applicable law or agreed to in writing,
14e1f63238SAndrew Rist  * software distributed under the License is distributed on an
15e1f63238SAndrew Rist  * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
16e1f63238SAndrew Rist  * KIND, either express or implied.  See the License for the
17e1f63238SAndrew Rist  * specific language governing permissions and limitations
18e1f63238SAndrew Rist  * under the License.
19e1f63238SAndrew Rist  *
20e1f63238SAndrew Rist  *************************************************************/
21e1f63238SAndrew Rist 
22e1f63238SAndrew Rist 
23cdf0e10cSrcweir 
24cdf0e10cSrcweir // MARKER(update_precomp.py): autogen include statement, do not remove
25cdf0e10cSrcweir #include "precompiled_basic.hxx"
26cdf0e10cSrcweir 
27cdf0e10cSrcweir #include <basic/sbx.hxx>
28cdf0e10cSrcweir #include "sbcomp.hxx"
29cdf0e10cSrcweir #include "image.hxx"
30cdf0e10cSrcweir #include "sbtrace.hxx"
31cdf0e10cSrcweir #include <basic/sbobjmod.hxx>
32cdf0e10cSrcweir #include <stdio.h>
33cdf0e10cSrcweir 
34cdf0e10cSrcweir //==========================================================================
35cdf0e10cSrcweir // Tracing, for debugging only
36cdf0e10cSrcweir 
37cdf0e10cSrcweir // To activate tracing enable in sbtrace.hxx
38cdf0e10cSrcweir #ifdef DBG_TRACE_BASIC
39cdf0e10cSrcweir 
40cdf0e10cSrcweir #include <hash_map>
41cdf0e10cSrcweir 
42cdf0e10cSrcweir // Trace ini file (set NULL to ignore)
43cdf0e10cSrcweir // can be overridden with the environment variable OOO_BASICTRACEINI
44cdf0e10cSrcweir static char		GpTraceIniFile[] = "~/BasicTrace.ini";
45cdf0e10cSrcweir //static char*	GpTraceIniFile = NULL;
46cdf0e10cSrcweir 
47cdf0e10cSrcweir 
48cdf0e10cSrcweir // Trace Settings, used if no ini file / not found in ini file
49cdf0e10cSrcweir static char		GpTraceFileNameDefault[] = "~/BasicTrace.txt";
50cdf0e10cSrcweir static char*	GpTraceFileName = GpTraceFileNameDefault;
51cdf0e10cSrcweir 
52cdf0e10cSrcweir // GbTraceOn:
53cdf0e10cSrcweir // true = tracing is active, false = tracing is disabled, default = true
54cdf0e10cSrcweir // Set to false initially if you want to activate tracing on demand with
55cdf0e10cSrcweir // TraceCommand( "TraceOn" ), see below
56cdf0e10cSrcweir static bool	GbTraceOn = true;
57cdf0e10cSrcweir 
58cdf0e10cSrcweir // GbIncludePCodes:
59cdf0e10cSrcweir // true = PCodes are written to trace, default = false, correspondents
60cdf0e10cSrcweir // with TraceCommand( "PCodeOn" / "PCodeOff" ), see below
61cdf0e10cSrcweir static bool	GbIncludePCodes = false;
62cdf0e10cSrcweir 
63cdf0e10cSrcweir // GbInitOnlyAtOfficeStart:
64cdf0e10cSrcweir // true = Tracing is only intialized onces after Office start when
65cdf0e10cSrcweir // Basic runs the first time. Further calls to Basic, e.g. via events
66cdf0e10cSrcweir // use the same output file. The trace ini file is not read again.
67cdf0e10cSrcweir static bool	GbInitOnlyAtOfficeStart = false;
68cdf0e10cSrcweir 
69cdf0e10cSrcweir static int	GnIndentPerCallLevel = 4;
70cdf0e10cSrcweir static int	GnIndentForPCode = 2;
71cdf0e10cSrcweir 
72cdf0e10cSrcweir /*
73cdf0e10cSrcweir 	With trace enabled the runtime function TraceCommand
74cdf0e10cSrcweir 	can be used to influence the trace functionality
75cdf0e10cSrcweir 	from within the running Basic macro.
76cdf0e10cSrcweir 
77cdf0e10cSrcweir 	Format: TraceCommand( command as String [, param as Variant] )
78cdf0e10cSrcweir 
79cdf0e10cSrcweir 	Supported commands (command is NOT case sensitive):
80cdf0e10cSrcweir 	TraceCommand "TraceOn"			sets GbTraceOn = true
81cdf0e10cSrcweir 	TraceCommand "TraceOff"			sets GbTraceOn = false
82cdf0e10cSrcweir 
83cdf0e10cSrcweir 	TraceCommand "PCodeOn"			sets GbIncludePCodes = true
84cdf0e10cSrcweir 	TraceCommand "PCodeOff"			sets GbIncludePCodes = false
85cdf0e10cSrcweir 
86cdf0e10cSrcweir 	TraceCommand "Print", aVal		writes aVal into the trace file as
87cdf0e10cSrcweir 									long as it can be converted to string
88cdf0e10cSrcweir */
89cdf0e10cSrcweir 
90cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
91cdf0e10cSrcweir 
92cdf0e10cSrcweir #include <algorithm>
93cdf0e10cSrcweir #include <stack>
94cdf0e10cSrcweir #include "canvas/elapsedtime.hxx"
95cdf0e10cSrcweir 
96cdf0e10cSrcweir //*** Profiling ***
97cdf0e10cSrcweir // GbTimerOn:
98cdf0e10cSrcweir // true = including time stamps
99cdf0e10cSrcweir static bool	GbTimerOn = true;
100cdf0e10cSrcweir 
101cdf0e10cSrcweir // GbTimeStampForEachStep:
102cdf0e10cSrcweir // true = prints time stamp after each command / pcode (very slow)
103cdf0e10cSrcweir static bool	GbTimeStampForEachStep = false;
104cdf0e10cSrcweir 
105cdf0e10cSrcweir // GbBlockAllAfterFirstFunctionUsage:
106cdf0e10cSrcweir // true = everything (commands, pcodes, functions) is only printed
107cdf0e10cSrcweir // for the first usage (improves performance when tracing / pro-
108cdf0e10cSrcweir // filing large macros)
109cdf0e10cSrcweir static bool	GbBlockAllAfterFirstFunctionUsage = false;
110cdf0e10cSrcweir 
111cdf0e10cSrcweir // GbBlockStepsAfterFirstFunctionUsage:
112cdf0e10cSrcweir // true = commands / pcodes are only printed for the first time
113cdf0e10cSrcweir // a function is executed. Afterwards only the entering/leaving
114cdf0e10cSrcweir // messages are logged (improves performance when tracing / pro-
115cdf0e10cSrcweir // filing large macros)
116cdf0e10cSrcweir static bool	GbBlockStepsAfterFirstFunctionUsage = false;
117cdf0e10cSrcweir 
118cdf0e10cSrcweir #endif
119cdf0e10cSrcweir 
120cdf0e10cSrcweir 
lcl_skipWhites(char * & rpc)121cdf0e10cSrcweir static void lcl_skipWhites( char*& rpc )
122cdf0e10cSrcweir {
123cdf0e10cSrcweir 	while( *rpc == ' ' || *rpc == '\t' )
124cdf0e10cSrcweir 		++rpc;
125cdf0e10cSrcweir }
126cdf0e10cSrcweir 
lcl_findNextLine(char * & rpc,char * pe)127cdf0e10cSrcweir inline void lcl_findNextLine( char*& rpc, char* pe )
128cdf0e10cSrcweir {
129cdf0e10cSrcweir 	// Find line end
130cdf0e10cSrcweir 	while( rpc < pe && *rpc != 13 && *rpc != 10 )
131cdf0e10cSrcweir 		++rpc;
132cdf0e10cSrcweir 
133cdf0e10cSrcweir 	// Read all
134cdf0e10cSrcweir 	while( rpc < pe && (*rpc == 13 || *rpc == 10) )
135cdf0e10cSrcweir 		++rpc;
136cdf0e10cSrcweir }
137cdf0e10cSrcweir 
lcl_isAlpha(char c)138cdf0e10cSrcweir inline bool lcl_isAlpha( char c )
139cdf0e10cSrcweir {
140cdf0e10cSrcweir 	bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
141cdf0e10cSrcweir 	return bRet;
142cdf0e10cSrcweir }
143cdf0e10cSrcweir 
lcl_ReadIniFile(const char * pIniFileName)144cdf0e10cSrcweir static void lcl_ReadIniFile( const char* pIniFileName )
145cdf0e10cSrcweir {
146cdf0e10cSrcweir 	const int BUF_SIZE = 1000;
147cdf0e10cSrcweir 	static sal_Char TraceFileNameBuffer[BUF_SIZE];
148cdf0e10cSrcweir 	sal_Char Buffer[BUF_SIZE];
149cdf0e10cSrcweir 	sal_Char VarNameBuffer[BUF_SIZE];
150cdf0e10cSrcweir 	sal_Char ValBuffer[BUF_SIZE];
151cdf0e10cSrcweir 
152cdf0e10cSrcweir 	FILE* pFile = fopen( pIniFileName ,"rb" );
153cdf0e10cSrcweir 	if( pFile == NULL )
154cdf0e10cSrcweir 		return;
155cdf0e10cSrcweir 
156cdf0e10cSrcweir 	size_t nRead = fread( Buffer, 1, BUF_SIZE, pFile );
157cdf0e10cSrcweir 
158cdf0e10cSrcweir 	// Scan
159cdf0e10cSrcweir 	char* pc = Buffer;
160cdf0e10cSrcweir 	char* pe = Buffer + nRead;
161cdf0e10cSrcweir 	while( pc < pe )
162cdf0e10cSrcweir 	{
163cdf0e10cSrcweir 		lcl_skipWhites( pc ); if( pc == pe ) break;
164cdf0e10cSrcweir 
165cdf0e10cSrcweir 		// Read variable
166cdf0e10cSrcweir 		char* pVarStart = pc;
167cdf0e10cSrcweir 		while( pc < pe && lcl_isAlpha( *pc ) )
168cdf0e10cSrcweir 			++pc;
169cdf0e10cSrcweir 		int nVarLen = pc - pVarStart;
170cdf0e10cSrcweir 		if( nVarLen == 0 )
171cdf0e10cSrcweir 		{
172cdf0e10cSrcweir 			lcl_findNextLine( pc, pe );
173cdf0e10cSrcweir 			continue;
174cdf0e10cSrcweir 		}
175cdf0e10cSrcweir 		strncpy( VarNameBuffer, pVarStart, nVarLen );
176cdf0e10cSrcweir 		VarNameBuffer[nVarLen] = '\0';
177cdf0e10cSrcweir 
178cdf0e10cSrcweir 		// Check =
179cdf0e10cSrcweir 		lcl_skipWhites( pc ); if( pc == pe ) break;
180cdf0e10cSrcweir 		if( *pc != '=' )
181cdf0e10cSrcweir 			continue;
182cdf0e10cSrcweir 		++pc;
183cdf0e10cSrcweir 		lcl_skipWhites( pc ); if( pc == pe ) break;
184cdf0e10cSrcweir 
185cdf0e10cSrcweir 		// Read value
186cdf0e10cSrcweir 		char* pValStart = pc;
187cdf0e10cSrcweir 		while( pc < pe && *pc != 13 && *pc != 10 )
188cdf0e10cSrcweir 			++pc;
189cdf0e10cSrcweir 		int nValLen = pc - pValStart;
190cdf0e10cSrcweir 		if( nValLen == 0 )
191cdf0e10cSrcweir 		{
192cdf0e10cSrcweir 			lcl_findNextLine( pc, pe );
193cdf0e10cSrcweir 			continue;
194cdf0e10cSrcweir 		}
195cdf0e10cSrcweir 		strncpy( ValBuffer, pValStart, nValLen );
196cdf0e10cSrcweir 		ValBuffer[nValLen] = '\0';
197cdf0e10cSrcweir 
198cdf0e10cSrcweir 		// Match variables
199cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GpTraceFileName") == 0 )
200cdf0e10cSrcweir 		{
201cdf0e10cSrcweir 			strcpy( TraceFileNameBuffer, ValBuffer );
202cdf0e10cSrcweir 			GpTraceFileName = TraceFileNameBuffer;
203cdf0e10cSrcweir 		}
204cdf0e10cSrcweir 		else
205cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbTraceOn") == 0 )
206cdf0e10cSrcweir 			GbTraceOn = (strcmp( ValBuffer, "true" ) == 0);
207cdf0e10cSrcweir 		else
208cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbIncludePCodes") == 0 )
209cdf0e10cSrcweir 			GbIncludePCodes = (strcmp( ValBuffer, "true" ) == 0);
210cdf0e10cSrcweir 		else
211cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbInitOnlyAtOfficeStart") == 0 )
212cdf0e10cSrcweir 			GbInitOnlyAtOfficeStart = (strcmp( ValBuffer, "true" ) == 0);
213cdf0e10cSrcweir 		else
214cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GnIndentPerCallLevel") == 0 )
215cdf0e10cSrcweir 			GnIndentPerCallLevel = strtol( ValBuffer, NULL, 10 );
216cdf0e10cSrcweir 		else
217cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GnIndentForPCode") == 0 )
218cdf0e10cSrcweir 			GnIndentForPCode = strtol( ValBuffer, NULL, 10 );
219cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
220cdf0e10cSrcweir 		else
221cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbTimerOn") == 0 )
222cdf0e10cSrcweir 			GbTimerOn = (strcmp( ValBuffer, "true" ) == 0);
223cdf0e10cSrcweir 		else
224cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbTimeStampForEachStep") == 0 )
225cdf0e10cSrcweir 			GbTimeStampForEachStep = (strcmp( ValBuffer, "true" ) == 0);
226cdf0e10cSrcweir 		else
227cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbBlockAllAfterFirstFunctionUsage") == 0 )
228cdf0e10cSrcweir 			GbBlockAllAfterFirstFunctionUsage = (strcmp( ValBuffer, "true" ) == 0);
229cdf0e10cSrcweir 		else
230cdf0e10cSrcweir 		if( strcmp( VarNameBuffer, "GbBlockStepsAfterFirstFunctionUsage") == 0 )
231cdf0e10cSrcweir 			GbBlockStepsAfterFirstFunctionUsage = (strcmp( ValBuffer, "true" ) == 0);
232cdf0e10cSrcweir #endif
233cdf0e10cSrcweir 	}
234cdf0e10cSrcweir 	fclose( pFile );
235cdf0e10cSrcweir }
236cdf0e10cSrcweir 
237cdf0e10cSrcweir struct TraceTextData
238cdf0e10cSrcweir {
239cdf0e10cSrcweir 	rtl::OString m_aTraceStr_STMNT;
240cdf0e10cSrcweir 	rtl::OString m_aTraceStr_PCode;
241cdf0e10cSrcweir };
242cdf0e10cSrcweir typedef std::hash_map< sal_Int32, TraceTextData > PCToTextDataMap;
243cdf0e10cSrcweir typedef std::hash_map< ::rtl::OUString, PCToTextDataMap*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > ModuleTraceMap;
244cdf0e10cSrcweir 
245cdf0e10cSrcweir ModuleTraceMap		GaModuleTraceMap;
246cdf0e10cSrcweir ModuleTraceMap&		rModuleTraceMap = GaModuleTraceMap;
247cdf0e10cSrcweir 
lcl_PrepareTraceForModule(SbModule * pModule)248cdf0e10cSrcweir static void lcl_PrepareTraceForModule( SbModule* pModule )
249cdf0e10cSrcweir {
250cdf0e10cSrcweir 	String aModuleName = pModule->GetName();
251cdf0e10cSrcweir     ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
252cdf0e10cSrcweir     if( it != rModuleTraceMap.end() )
253cdf0e10cSrcweir 	{
254cdf0e10cSrcweir 		PCToTextDataMap* pInnerMap = it->second;
255cdf0e10cSrcweir 		delete pInnerMap;
256cdf0e10cSrcweir 		rModuleTraceMap.erase( it );
257cdf0e10cSrcweir 	}
258cdf0e10cSrcweir 
259cdf0e10cSrcweir 	String aDisassemblyStr;
260cdf0e10cSrcweir 	pModule->Disassemble( aDisassemblyStr );
261cdf0e10cSrcweir }
262cdf0e10cSrcweir 
263cdf0e10cSrcweir static FILE* GpGlobalFile = NULL;
264cdf0e10cSrcweir 
lcl_lineOut(const char * pStr,const char * pPreStr=NULL,const char * pPostStr=NULL)265cdf0e10cSrcweir static void lcl_lineOut( const char* pStr, const char* pPreStr = NULL, const char* pPostStr = NULL )
266cdf0e10cSrcweir {
267cdf0e10cSrcweir 	if( GpGlobalFile != NULL )
268cdf0e10cSrcweir 	{
269cdf0e10cSrcweir 		fprintf( GpGlobalFile, "%s%s%s\n", pPreStr ? pPreStr : "", pStr, pPostStr ? pPostStr : "" );
270cdf0e10cSrcweir         fflush( GpGlobalFile );
271cdf0e10cSrcweir 	}
272cdf0e10cSrcweir }
273cdf0e10cSrcweir 
lcl_getSpaces(int nSpaceCount)274cdf0e10cSrcweir const char* lcl_getSpaces( int nSpaceCount )
275cdf0e10cSrcweir {
276cdf0e10cSrcweir 	static sal_Char Spaces[] = "                                                                                                    "
277cdf0e10cSrcweir 		"                                                                                                    "
278cdf0e10cSrcweir 		"                                                                                                    ";
279cdf0e10cSrcweir 	static int nAvailableSpaceCount = strlen( Spaces );
280cdf0e10cSrcweir 	static sal_Char* pSpacesEnd = Spaces + nAvailableSpaceCount;
281cdf0e10cSrcweir 
282cdf0e10cSrcweir 	if( nSpaceCount > nAvailableSpaceCount )
283cdf0e10cSrcweir 		nSpaceCount = nAvailableSpaceCount;
284cdf0e10cSrcweir 
285cdf0e10cSrcweir 	return pSpacesEnd - nSpaceCount;
286cdf0e10cSrcweir }
287cdf0e10cSrcweir 
lcl_toOStringSkipLeadingWhites(const String & aStr)288cdf0e10cSrcweir static rtl::OString lcl_toOStringSkipLeadingWhites( const String& aStr )
289cdf0e10cSrcweir {
290cdf0e10cSrcweir 	static sal_Char Buffer[1000];
291cdf0e10cSrcweir 
292cdf0e10cSrcweir 	rtl::OString aOStr = OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US );
293cdf0e10cSrcweir 	const sal_Char* pStr = aOStr.getStr();
294cdf0e10cSrcweir 
295cdf0e10cSrcweir 	// Skip whitespace
296cdf0e10cSrcweir 	sal_Char c = *pStr;
297cdf0e10cSrcweir 	while( c == ' ' || c == '\t' )
298cdf0e10cSrcweir 	{
299cdf0e10cSrcweir 		pStr++;
300cdf0e10cSrcweir 		c = *pStr;
301cdf0e10cSrcweir 	}
302cdf0e10cSrcweir 
303cdf0e10cSrcweir 	int nLen = strlen( pStr );
304cdf0e10cSrcweir 	strncpy( Buffer, pStr, nLen );
305cdf0e10cSrcweir 	Buffer[nLen] = 0;
306cdf0e10cSrcweir 
307cdf0e10cSrcweir 	rtl::OString aORetStr( Buffer );
308cdf0e10cSrcweir 	return aORetStr;
309cdf0e10cSrcweir }
310cdf0e10cSrcweir 
lcl_dumpMethodParameters(SbMethod * pMethod)311cdf0e10cSrcweir String lcl_dumpMethodParameters( SbMethod* pMethod )
312cdf0e10cSrcweir {
313cdf0e10cSrcweir 	String aStr;
314cdf0e10cSrcweir     if( pMethod == NULL )
315cdf0e10cSrcweir 		return aStr;
316cdf0e10cSrcweir 
317cdf0e10cSrcweir     SbxError eOld = SbxBase::GetError();
318cdf0e10cSrcweir 
319cdf0e10cSrcweir     SbxArray* pParams = pMethod->GetParameters();
320cdf0e10cSrcweir     SbxInfo* pInfo = pMethod->GetInfo();
321cdf0e10cSrcweir     if ( pParams )
322cdf0e10cSrcweir     {
323cdf0e10cSrcweir 	    aStr += '(';
324cdf0e10cSrcweir 	    // 0 is sub itself
325cdf0e10cSrcweir 	    for ( sal_uInt16 nParam = 1; nParam < pParams->Count(); nParam++ )
326cdf0e10cSrcweir 	    {
327cdf0e10cSrcweir 		    SbxVariable* pVar = pParams->Get( nParam );
328cdf0e10cSrcweir 		    DBG_ASSERT( pVar, "Parameter?!" );
329cdf0e10cSrcweir 		    if ( pVar->GetName().Len() )
330cdf0e10cSrcweir 			    aStr += pVar->GetName();
331cdf0e10cSrcweir 		    else if ( pInfo )
332cdf0e10cSrcweir 		    {
333cdf0e10cSrcweir 			    const SbxParamInfo* pParam = pInfo->GetParam( nParam );
334cdf0e10cSrcweir 			    if ( pParam )
335cdf0e10cSrcweir 				    aStr += pParam->aName;
336cdf0e10cSrcweir 		    }
337cdf0e10cSrcweir 		    aStr += '=';
338cdf0e10cSrcweir 			SbxDataType eType = pVar->GetType();
339cdf0e10cSrcweir 			if( eType & SbxARRAY )
340cdf0e10cSrcweir 			    aStr += String( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
341cdf0e10cSrcweir 		    else if( eType != SbxOBJECT )
342cdf0e10cSrcweir 			    aStr += pVar->GetString();
343cdf0e10cSrcweir 		    if ( nParam < ( pParams->Count() - 1 ) )
344cdf0e10cSrcweir 			    aStr += String( RTL_CONSTASCII_USTRINGPARAM( ", " ) );
345cdf0e10cSrcweir 	    }
346cdf0e10cSrcweir 	    aStr += ')';
347cdf0e10cSrcweir     }
348cdf0e10cSrcweir 
349cdf0e10cSrcweir     SbxBase::ResetError();
350cdf0e10cSrcweir     if( eOld != SbxERR_OK )
351cdf0e10cSrcweir 	    SbxBase::SetError( eOld );
352cdf0e10cSrcweir 
353cdf0e10cSrcweir 	return aStr;
354cdf0e10cSrcweir }
355cdf0e10cSrcweir 
356cdf0e10cSrcweir 
357cdf0e10cSrcweir // Public functions
358cdf0e10cSrcweir static bool	GbSavTraceOn = false;
359cdf0e10cSrcweir 
360cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
361cdf0e10cSrcweir static canvas::tools::ElapsedTime* GpTimer = NULL;
362cdf0e10cSrcweir static double GdStartTime = 0.0;
363cdf0e10cSrcweir static double GdLastTime = 0.0;
364cdf0e10cSrcweir static bool GbBlockSteps = false;
365cdf0e10cSrcweir static bool GbBlockAll = false;
366cdf0e10cSrcweir 
367cdf0e10cSrcweir struct FunctionItem
368cdf0e10cSrcweir {
369cdf0e10cSrcweir 	String		m_aCompleteFunctionName;
370cdf0e10cSrcweir 	double		m_dTotalTime;
371cdf0e10cSrcweir 	double		m_dNetTime;
372cdf0e10cSrcweir 	int			m_nCallCount;
373cdf0e10cSrcweir 	bool		m_bBlockAll;
374cdf0e10cSrcweir 	bool		m_bBlockSteps;
375cdf0e10cSrcweir 
FunctionItemFunctionItem376cdf0e10cSrcweir 	FunctionItem( void )
377cdf0e10cSrcweir 		: m_dTotalTime( 0.0 )
378cdf0e10cSrcweir 		, m_dNetTime( 0.0 )
379cdf0e10cSrcweir 		, m_nCallCount( 0 )
380cdf0e10cSrcweir 		, m_bBlockAll( false )
381cdf0e10cSrcweir 		, m_bBlockSteps( false )
382cdf0e10cSrcweir 	{}
383cdf0e10cSrcweir };
384cdf0e10cSrcweir typedef std::hash_map< ::rtl::OUString, FunctionItem*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > FunctionItemMap;
385cdf0e10cSrcweir 
386cdf0e10cSrcweir static std::stack< double >				GaCallEnterTimeStack;
387cdf0e10cSrcweir static std::stack< FunctionItem* >		GaFunctionItemStack;
388cdf0e10cSrcweir static FunctionItemMap					GaFunctionItemMap;
389cdf0e10cSrcweir 
compareFunctionNetTime(FunctionItem * p1,FunctionItem * p2)390cdf0e10cSrcweir bool compareFunctionNetTime( FunctionItem* p1, FunctionItem* p2 )
391cdf0e10cSrcweir {
392cdf0e10cSrcweir 	return (p1->m_dNetTime > p2->m_dNetTime);
393cdf0e10cSrcweir }
394cdf0e10cSrcweir 
lcl_printTimeOutput(void)395cdf0e10cSrcweir void lcl_printTimeOutput( void )
396cdf0e10cSrcweir {
397cdf0e10cSrcweir 	// Overall time output
398cdf0e10cSrcweir 	lcl_lineOut( "" );
399cdf0e10cSrcweir 	lcl_lineOut( "***** Time Output *****" );
400cdf0e10cSrcweir 	char TimeBuffer[500];
401cdf0e10cSrcweir 	double dTotalTime = GpTimer->getElapsedTime() - GdStartTime;
402cdf0e10cSrcweir 	sprintf( TimeBuffer, "Total execution time = %f ms", dTotalTime*1000.0 );
403cdf0e10cSrcweir 	lcl_lineOut( TimeBuffer );
404cdf0e10cSrcweir 	lcl_lineOut( "" );
405cdf0e10cSrcweir 
406cdf0e10cSrcweir 	if( GbTimerOn )
407cdf0e10cSrcweir 	{
408cdf0e10cSrcweir 		lcl_lineOut( "Functions:" );
409cdf0e10cSrcweir 
410cdf0e10cSrcweir 		std::vector<FunctionItem*> avFunctionItems;
411cdf0e10cSrcweir 
412cdf0e10cSrcweir 		FunctionItemMap::iterator it;
413cdf0e10cSrcweir 		for( it = GaFunctionItemMap.begin() ; it != GaFunctionItemMap.end() ; ++it )
414cdf0e10cSrcweir 		{
415cdf0e10cSrcweir 			FunctionItem* pFunctionItem = it->second;
416cdf0e10cSrcweir 			if( pFunctionItem != NULL )
417cdf0e10cSrcweir 				avFunctionItems.push_back( pFunctionItem );
418cdf0e10cSrcweir 		}
419cdf0e10cSrcweir 
420cdf0e10cSrcweir 		std::sort( avFunctionItems.begin(), avFunctionItems.end(), compareFunctionNetTime );
421cdf0e10cSrcweir 
422cdf0e10cSrcweir 		std::vector<FunctionItem*>::iterator itv;
423cdf0e10cSrcweir 		for( itv = avFunctionItems.begin() ; itv != avFunctionItems.end() ; ++itv )
424cdf0e10cSrcweir 		{
425cdf0e10cSrcweir 			FunctionItem* pFunctionItem = *itv;
426cdf0e10cSrcweir 			if( pFunctionItem != NULL )
427cdf0e10cSrcweir 			{
428cdf0e10cSrcweir 				rtl::OUString aCompleteFunctionName = pFunctionItem->m_aCompleteFunctionName;
429cdf0e10cSrcweir 				const char* pName = OUStringToOString( aCompleteFunctionName, RTL_TEXTENCODING_ASCII_US ).getStr();
430cdf0e10cSrcweir 				int nNameLen = aCompleteFunctionName.getLength();
431cdf0e10cSrcweir 
432cdf0e10cSrcweir 				double dFctTotalTime = pFunctionItem->m_dTotalTime;
433cdf0e10cSrcweir 				double dFctNetTime = pFunctionItem->m_dNetTime;
434cdf0e10cSrcweir 				double dFctTotalTimePercent = 100.0 * dFctTotalTime / dTotalTime;
435cdf0e10cSrcweir 				double dFctNetTimePercent = 100.0 * dFctNetTime / dTotalTime;
436cdf0e10cSrcweir 				int nSpaceCount = 30 - nNameLen;
437cdf0e10cSrcweir 				if( nSpaceCount < 0 )
438cdf0e10cSrcweir 					nSpaceCount = 2;
439cdf0e10cSrcweir 				sprintf( TimeBuffer, "%s:%sCalled %d times\t%f ms (%f%%) / net %f (%f%%) ms",
440cdf0e10cSrcweir 					pName, lcl_getSpaces( nSpaceCount ), pFunctionItem->m_nCallCount,
441cdf0e10cSrcweir 					dFctTotalTime*1000.0, dFctTotalTimePercent, dFctNetTime*1000.0, dFctNetTimePercent );
442cdf0e10cSrcweir 				lcl_lineOut( TimeBuffer );
443cdf0e10cSrcweir 			}
444cdf0e10cSrcweir 		}
445cdf0e10cSrcweir 	}
446cdf0e10cSrcweir }
447cdf0e10cSrcweir #endif
448cdf0e10cSrcweir 
449cdf0e10cSrcweir 
450cdf0e10cSrcweir static bool GbInitTraceAlreadyCalled = false;
451cdf0e10cSrcweir 
dbg_InitTrace(void)452cdf0e10cSrcweir void dbg_InitTrace( void )
453cdf0e10cSrcweir {
454cdf0e10cSrcweir 	if( GbInitOnlyAtOfficeStart && GbInitTraceAlreadyCalled )
455cdf0e10cSrcweir 	{
456cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
457cdf0e10cSrcweir 		if( GbTimerOn )
458cdf0e10cSrcweir 			GpTimer->continueTimer();
459cdf0e10cSrcweir #endif
460cdf0e10cSrcweir 		GpGlobalFile = fopen( GpTraceFileName, "a+" );
461cdf0e10cSrcweir 		return;
462cdf0e10cSrcweir 	}
463cdf0e10cSrcweir 	GbInitTraceAlreadyCalled = true;
464cdf0e10cSrcweir 
465cdf0e10cSrcweir     if( const sal_Char* pcIniFileName = ::getenv( "OOO_BASICTRACEINI" ) )
466cdf0e10cSrcweir 		lcl_ReadIniFile( pcIniFileName );
467cdf0e10cSrcweir 	else if( GpTraceIniFile != NULL )
468cdf0e10cSrcweir 		lcl_ReadIniFile( GpTraceIniFile );
469cdf0e10cSrcweir 
470cdf0e10cSrcweir 	GpGlobalFile = fopen( GpTraceFileName, "w" );
471cdf0e10cSrcweir 	GbSavTraceOn = GbTraceOn;
472cdf0e10cSrcweir 	if( !GbTraceOn )
473cdf0e10cSrcweir 		lcl_lineOut( "### Program started with trace off ###" );
474cdf0e10cSrcweir 
475cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
476cdf0e10cSrcweir 	GpTimer = new canvas::tools::ElapsedTime();
477cdf0e10cSrcweir 	GdStartTime = GpTimer->getElapsedTime();
478cdf0e10cSrcweir 	GdLastTime = GdStartTime;
479cdf0e10cSrcweir 	GbBlockSteps = false;
480cdf0e10cSrcweir 	GbBlockAll = false;
481cdf0e10cSrcweir #endif
482cdf0e10cSrcweir }
483cdf0e10cSrcweir 
dbg_DeInitTrace(void)484cdf0e10cSrcweir void dbg_DeInitTrace( void )
485cdf0e10cSrcweir {
486cdf0e10cSrcweir 	GbTraceOn = GbSavTraceOn;
487cdf0e10cSrcweir 
488cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
489cdf0e10cSrcweir 	while( !GaCallEnterTimeStack.empty() )
490cdf0e10cSrcweir 		GaCallEnterTimeStack.pop();
491cdf0e10cSrcweir 	while( !GaFunctionItemStack.empty() )
492cdf0e10cSrcweir 		GaFunctionItemStack.pop();
493cdf0e10cSrcweir 
494cdf0e10cSrcweir 	lcl_printTimeOutput();
495cdf0e10cSrcweir 
496cdf0e10cSrcweir 	for( FunctionItemMap::iterator it = GaFunctionItemMap.begin() ; it != GaFunctionItemMap.end() ; ++it )
497cdf0e10cSrcweir 		delete it->second;
498cdf0e10cSrcweir 	GaFunctionItemMap.clear();
499cdf0e10cSrcweir 
500cdf0e10cSrcweir 	if( GpGlobalFile )
501cdf0e10cSrcweir 	{
502cdf0e10cSrcweir 		fclose( GpGlobalFile );
503cdf0e10cSrcweir 		GpGlobalFile = NULL;
504cdf0e10cSrcweir 	}
505cdf0e10cSrcweir 
506cdf0e10cSrcweir 	if( GbInitOnlyAtOfficeStart )
507cdf0e10cSrcweir 	{
508cdf0e10cSrcweir 		if( GbTimerOn )
509cdf0e10cSrcweir 			GpTimer->pauseTimer();
510cdf0e10cSrcweir 	}
511cdf0e10cSrcweir 	else
512cdf0e10cSrcweir 	{
513cdf0e10cSrcweir 		delete GpTimer;
514cdf0e10cSrcweir 	}
515cdf0e10cSrcweir #endif
516cdf0e10cSrcweir }
517cdf0e10cSrcweir 
518cdf0e10cSrcweir static sal_Int32 GnLastCallLvl = 0;
519cdf0e10cSrcweir 
dbg_tracePrint(const String & aStr,sal_Int32 nCallLvl,bool bCallLvlRelativeToCurrent)520cdf0e10cSrcweir void dbg_tracePrint( const String& aStr, sal_Int32 nCallLvl, bool bCallLvlRelativeToCurrent )
521cdf0e10cSrcweir {
522cdf0e10cSrcweir 	if( bCallLvlRelativeToCurrent )
523cdf0e10cSrcweir 		nCallLvl += GnLastCallLvl;
524cdf0e10cSrcweir 
525cdf0e10cSrcweir 	int nIndent = nCallLvl * GnIndentPerCallLevel;
526cdf0e10cSrcweir 	lcl_lineOut( OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr(), lcl_getSpaces( nIndent ) );
527cdf0e10cSrcweir }
528cdf0e10cSrcweir 
dbg_traceStep(SbModule * pModule,sal_uInt32 nPC,sal_Int32 nCallLvl)529cdf0e10cSrcweir void dbg_traceStep( SbModule* pModule, sal_uInt32 nPC, sal_Int32 nCallLvl )
530cdf0e10cSrcweir {
531cdf0e10cSrcweir 	if( !GbTraceOn )
532cdf0e10cSrcweir 		return;
533cdf0e10cSrcweir 
534cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
535cdf0e10cSrcweir 	if( GbBlockSteps || GbBlockAll )
536cdf0e10cSrcweir 		return;
537cdf0e10cSrcweir 
538cdf0e10cSrcweir 	double dCurTime = 0.0;
539cdf0e10cSrcweir 	bool bPrintTimeStamp = false;
540cdf0e10cSrcweir 	if( GbTimerOn )
541cdf0e10cSrcweir 	{
542cdf0e10cSrcweir 		GpTimer->pauseTimer();
543cdf0e10cSrcweir 		dCurTime = GpTimer->getElapsedTime();
544cdf0e10cSrcweir 		bPrintTimeStamp = GbTimeStampForEachStep;
545cdf0e10cSrcweir 	}
546cdf0e10cSrcweir #else
547cdf0e10cSrcweir 	bool bPrintTimeStamp = false;
548cdf0e10cSrcweir #endif
549cdf0e10cSrcweir 
550cdf0e10cSrcweir 	GnLastCallLvl = nCallLvl;
551cdf0e10cSrcweir 
552cdf0e10cSrcweir 	SbModule* pTraceMod = pModule;
553cdf0e10cSrcweir 	if( pTraceMod->ISA(SbClassModuleObject) )
554cdf0e10cSrcweir 	{
555cdf0e10cSrcweir 		SbClassModuleObject* pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
556cdf0e10cSrcweir 		pTraceMod = pClassModuleObj->getClassModule();
557cdf0e10cSrcweir 	}
558cdf0e10cSrcweir 
559cdf0e10cSrcweir 	String aModuleName = pTraceMod->GetName();
560cdf0e10cSrcweir     ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
561cdf0e10cSrcweir     if( it == rModuleTraceMap.end() )
562cdf0e10cSrcweir 	{
563cdf0e10cSrcweir 		const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
564cdf0e10cSrcweir 		char Buffer[200];
565cdf0e10cSrcweir 		sprintf( Buffer, "TRACE ERROR: Unknown module \"%s\"", pModuleNameStr );
566cdf0e10cSrcweir 		lcl_lineOut( Buffer );
567cdf0e10cSrcweir 		return;
568cdf0e10cSrcweir 	}
569cdf0e10cSrcweir 
570cdf0e10cSrcweir 	PCToTextDataMap* pInnerMap = it->second;
571cdf0e10cSrcweir 	if( pInnerMap == NULL )
572cdf0e10cSrcweir 	{
573cdf0e10cSrcweir 		lcl_lineOut( "TRACE INTERNAL ERROR: No inner map" );
574cdf0e10cSrcweir 		return;
575cdf0e10cSrcweir 	}
576cdf0e10cSrcweir 
577cdf0e10cSrcweir 	PCToTextDataMap::iterator itInner = pInnerMap->find( nPC );
578cdf0e10cSrcweir     if( itInner == pInnerMap->end() )
579cdf0e10cSrcweir 	{
580cdf0e10cSrcweir 		const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
581cdf0e10cSrcweir 		char Buffer[200];
582cdf0e10cSrcweir 		sprintf( Buffer, "TRACE ERROR: No info for PC = %d in module \"%s\"", (int)nPC, pModuleNameStr );
583cdf0e10cSrcweir 		lcl_lineOut( Buffer );
584cdf0e10cSrcweir 		return;
585cdf0e10cSrcweir 	}
586cdf0e10cSrcweir 
587cdf0e10cSrcweir 	int nIndent = nCallLvl * GnIndentPerCallLevel;
588cdf0e10cSrcweir 
589cdf0e10cSrcweir 	const TraceTextData& rTraceTextData = itInner->second;
590cdf0e10cSrcweir 	const rtl::OString& rStr_STMNT = rTraceTextData.m_aTraceStr_STMNT;
591cdf0e10cSrcweir 	bool bSTMT = false;
592*0848378bSHerbert Dürr 	if( !rStr_STMNT.isEmpty() )
593cdf0e10cSrcweir 		bSTMT = true;
594cdf0e10cSrcweir 
595cdf0e10cSrcweir 	char TimeBuffer[200];
596cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
597cdf0e10cSrcweir 	if( bPrintTimeStamp )
598cdf0e10cSrcweir 	{
599cdf0e10cSrcweir 		double dDiffTime = dCurTime - GdLastTime;
600cdf0e10cSrcweir 		GdLastTime = dCurTime;
601cdf0e10cSrcweir 		sprintf( TimeBuffer, "\t\t// Time = %f ms / += %f ms", dCurTime*1000.0, dDiffTime*1000.0 );
602cdf0e10cSrcweir 	}
603cdf0e10cSrcweir #endif
604cdf0e10cSrcweir 
605cdf0e10cSrcweir 	if( bSTMT )
606cdf0e10cSrcweir 	{
607cdf0e10cSrcweir 		lcl_lineOut( rStr_STMNT.getStr(), lcl_getSpaces( nIndent ),
608cdf0e10cSrcweir 			(bPrintTimeStamp && !GbIncludePCodes) ? TimeBuffer : NULL );
609cdf0e10cSrcweir 	}
610cdf0e10cSrcweir 
611cdf0e10cSrcweir 	if( !GbIncludePCodes )
612cdf0e10cSrcweir 	{
613cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
614cdf0e10cSrcweir 		if( GbTimerOn )
615cdf0e10cSrcweir 			GpTimer->continueTimer();
616cdf0e10cSrcweir #endif
617cdf0e10cSrcweir 		return;
618cdf0e10cSrcweir 	}
619cdf0e10cSrcweir 
620cdf0e10cSrcweir 	nIndent += GnIndentForPCode;
621cdf0e10cSrcweir 	const rtl::OString& rStr_PCode = rTraceTextData.m_aTraceStr_PCode;
622*0848378bSHerbert Dürr 	if( !rStr_PCode.isEmpty() )
623cdf0e10cSrcweir 	{
624cdf0e10cSrcweir 		lcl_lineOut( rStr_PCode.getStr(), lcl_getSpaces( nIndent ),
625cdf0e10cSrcweir 			bPrintTimeStamp ? TimeBuffer : NULL );
626cdf0e10cSrcweir 	}
627cdf0e10cSrcweir 
628cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
629cdf0e10cSrcweir 	if( GbTimerOn )
630cdf0e10cSrcweir 		GpTimer->continueTimer();
631cdf0e10cSrcweir #endif
632cdf0e10cSrcweir }
633cdf0e10cSrcweir 
634cdf0e10cSrcweir 
dbg_traceNotifyCall(SbModule * pModule,SbMethod * pMethod,sal_Int32 nCallLvl,bool bLeave)635cdf0e10cSrcweir void dbg_traceNotifyCall( SbModule* pModule, SbMethod* pMethod, sal_Int32 nCallLvl, bool bLeave )
636cdf0e10cSrcweir {
637cdf0e10cSrcweir 	static const char* pSeparator = "' ================================================================================";
638cdf0e10cSrcweir 
639cdf0e10cSrcweir 	if( !GbTraceOn )
640cdf0e10cSrcweir 		return;
641cdf0e10cSrcweir 
642cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
643cdf0e10cSrcweir 	double dCurTime = 0.0;
644cdf0e10cSrcweir 	double dExecutionTime = 0.0;
645cdf0e10cSrcweir 	if( GbTimerOn )
646cdf0e10cSrcweir 	{
647cdf0e10cSrcweir 		dCurTime = GpTimer->getElapsedTime();
648cdf0e10cSrcweir 		GpTimer->pauseTimer();
649cdf0e10cSrcweir 	}
650cdf0e10cSrcweir #endif
651cdf0e10cSrcweir 
652cdf0e10cSrcweir 	GnLastCallLvl = nCallLvl;
653cdf0e10cSrcweir 
654cdf0e10cSrcweir 	SbModule* pTraceMod = pModule;
655cdf0e10cSrcweir 	SbClassModuleObject* pClassModuleObj = NULL;
656cdf0e10cSrcweir 	if( pTraceMod->ISA(SbClassModuleObject) )
657cdf0e10cSrcweir 	{
658cdf0e10cSrcweir 		pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
659cdf0e10cSrcweir 		pTraceMod = pClassModuleObj->getClassModule();
660cdf0e10cSrcweir 	}
661cdf0e10cSrcweir 
662cdf0e10cSrcweir 	String aCompleteFunctionName = pTraceMod->GetName();
663cdf0e10cSrcweir 	if( pMethod != NULL )
664cdf0e10cSrcweir 	{
665cdf0e10cSrcweir 		aCompleteFunctionName.AppendAscii( "::" );
666cdf0e10cSrcweir 		String aMethodName = pMethod->GetName();
667cdf0e10cSrcweir 		aCompleteFunctionName += aMethodName;
668cdf0e10cSrcweir 	}
669cdf0e10cSrcweir 	else
670cdf0e10cSrcweir 	{
671cdf0e10cSrcweir 		aCompleteFunctionName.AppendAscii( "/RunInit" );
672cdf0e10cSrcweir 	}
673cdf0e10cSrcweir 
674cdf0e10cSrcweir 	bool bOwnBlockSteps = false;
675cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
676cdf0e10cSrcweir 	bool bOwnBlockAll = false;
677cdf0e10cSrcweir 	FunctionItem* pFunctionItem = NULL;
678cdf0e10cSrcweir 	if( GbTimerOn )
679cdf0e10cSrcweir 	{
680cdf0e10cSrcweir 		FunctionItemMap::iterator itFunctionItem = GaFunctionItemMap.find( aCompleteFunctionName );
681cdf0e10cSrcweir 		if( itFunctionItem != GaFunctionItemMap.end() )
682cdf0e10cSrcweir 			pFunctionItem = itFunctionItem->second;
683cdf0e10cSrcweir 
684cdf0e10cSrcweir 		if( pFunctionItem == NULL )
685cdf0e10cSrcweir 		{
686cdf0e10cSrcweir 			DBG_ASSERT( !bLeave, "No FunctionItem in leave!" );
687cdf0e10cSrcweir 
688cdf0e10cSrcweir 			pFunctionItem = new FunctionItem();
689cdf0e10cSrcweir 			pFunctionItem->m_aCompleteFunctionName = aCompleteFunctionName;
690cdf0e10cSrcweir 			GaFunctionItemMap[ aCompleteFunctionName ] = pFunctionItem;
691cdf0e10cSrcweir 		}
692cdf0e10cSrcweir 		else if( GbBlockAllAfterFirstFunctionUsage && !bLeave )
693cdf0e10cSrcweir 		{
694cdf0e10cSrcweir 			pFunctionItem->m_bBlockAll = true;
695cdf0e10cSrcweir 		}
696cdf0e10cSrcweir 		else if( GbBlockStepsAfterFirstFunctionUsage && !bLeave )
697cdf0e10cSrcweir 		{
698cdf0e10cSrcweir 			pFunctionItem->m_bBlockSteps = true;
699cdf0e10cSrcweir 		}
700cdf0e10cSrcweir 
701cdf0e10cSrcweir 		if( bLeave )
702cdf0e10cSrcweir 		{
703cdf0e10cSrcweir 			bOwnBlockAll = GbBlockAll;
704cdf0e10cSrcweir 			bOwnBlockSteps = GbBlockSteps;
705cdf0e10cSrcweir 			GbBlockAll = false;
706cdf0e10cSrcweir 			GbBlockSteps = false;
707cdf0e10cSrcweir 
708cdf0e10cSrcweir 			dExecutionTime = dCurTime - GaCallEnterTimeStack.top();
709cdf0e10cSrcweir 			GaCallEnterTimeStack.pop();
710cdf0e10cSrcweir 
711cdf0e10cSrcweir 			pFunctionItem->m_dTotalTime += dExecutionTime;
712cdf0e10cSrcweir 			pFunctionItem->m_dNetTime += dExecutionTime;
713cdf0e10cSrcweir 			pFunctionItem->m_nCallCount++;
714cdf0e10cSrcweir 
715cdf0e10cSrcweir 			GaFunctionItemStack.pop();
716cdf0e10cSrcweir 			if( !GaFunctionItemStack.empty() )
717cdf0e10cSrcweir 			{
718cdf0e10cSrcweir 				FunctionItem* pParentItem = GaFunctionItemStack.top();
719cdf0e10cSrcweir 				if( pParentItem != NULL )
720cdf0e10cSrcweir 				{
721cdf0e10cSrcweir 					pParentItem->m_dNetTime -= dExecutionTime;
722cdf0e10cSrcweir 
723cdf0e10cSrcweir 					GbBlockSteps = pParentItem->m_bBlockSteps;
724cdf0e10cSrcweir 					GbBlockAll = pParentItem->m_bBlockAll;
725cdf0e10cSrcweir 				}
726cdf0e10cSrcweir 			}
727cdf0e10cSrcweir 		}
728cdf0e10cSrcweir 		else
729cdf0e10cSrcweir 		{
730cdf0e10cSrcweir 			GbBlockSteps = bOwnBlockSteps = pFunctionItem->m_bBlockSteps;
731cdf0e10cSrcweir 			GbBlockAll = bOwnBlockAll = pFunctionItem->m_bBlockAll;
732cdf0e10cSrcweir 
733cdf0e10cSrcweir 			GaCallEnterTimeStack.push( dCurTime );
734cdf0e10cSrcweir 			GaFunctionItemStack.push( pFunctionItem );
735cdf0e10cSrcweir 		}
736cdf0e10cSrcweir 	}
737cdf0e10cSrcweir 
738cdf0e10cSrcweir 	if( bOwnBlockAll )
739cdf0e10cSrcweir 	{
740cdf0e10cSrcweir 		if( GbTimerOn )
741cdf0e10cSrcweir 			GpTimer->continueTimer();
742cdf0e10cSrcweir 		return;
743cdf0e10cSrcweir 	}
744cdf0e10cSrcweir #endif
745cdf0e10cSrcweir 
746cdf0e10cSrcweir 	if( nCallLvl > 0 )
747cdf0e10cSrcweir 		nCallLvl--;
748cdf0e10cSrcweir 	int nIndent = nCallLvl * GnIndentPerCallLevel;
749cdf0e10cSrcweir 	if( !bLeave && !bOwnBlockSteps )
750cdf0e10cSrcweir 	{
751cdf0e10cSrcweir 		lcl_lineOut( "" );
752cdf0e10cSrcweir 		lcl_lineOut( pSeparator, lcl_getSpaces( nIndent ) );
753cdf0e10cSrcweir 	}
754cdf0e10cSrcweir 
755cdf0e10cSrcweir 	String aStr;
756cdf0e10cSrcweir 	if( bLeave )
757cdf0e10cSrcweir 	{
758cdf0e10cSrcweir 		if( !bOwnBlockSteps )
759cdf0e10cSrcweir 		{
760cdf0e10cSrcweir 			lcl_lineOut( "}", lcl_getSpaces( nIndent ) );
761cdf0e10cSrcweir 			aStr.AppendAscii( "' Leaving " );
762cdf0e10cSrcweir 		}
763cdf0e10cSrcweir 	}
764cdf0e10cSrcweir 	else
765cdf0e10cSrcweir 	{
766cdf0e10cSrcweir 		aStr.AppendAscii( "Entering " );
767cdf0e10cSrcweir 	}
768cdf0e10cSrcweir 	if( !bLeave || !bOwnBlockSteps )
769cdf0e10cSrcweir 		aStr += aCompleteFunctionName;
770cdf0e10cSrcweir 
771cdf0e10cSrcweir 	if( !bOwnBlockSteps && pClassModuleObj != NULL )
772cdf0e10cSrcweir 	{
773cdf0e10cSrcweir 		aStr.AppendAscii( "[this=" );
774cdf0e10cSrcweir 		aStr += pClassModuleObj->GetName();
775cdf0e10cSrcweir 		aStr.AppendAscii( "]" );
776cdf0e10cSrcweir 	}
777cdf0e10cSrcweir 	if( !bLeave )
778cdf0e10cSrcweir 		aStr += lcl_dumpMethodParameters( pMethod );
779cdf0e10cSrcweir 
780cdf0e10cSrcweir 	const char* pPostStr = NULL;
781cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
782cdf0e10cSrcweir 	char TimeBuffer[200];
783cdf0e10cSrcweir 	if( GbTimerOn && bLeave )
784cdf0e10cSrcweir 	{
785cdf0e10cSrcweir 		sprintf( TimeBuffer, "    // Execution Time = %f ms", dExecutionTime*1000.0 );
786cdf0e10cSrcweir 		pPostStr = TimeBuffer;
787cdf0e10cSrcweir 	}
788cdf0e10cSrcweir #endif
789cdf0e10cSrcweir 	lcl_lineOut( (!bLeave || !bOwnBlockSteps) ? OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr() : "}",
790cdf0e10cSrcweir 		lcl_getSpaces( nIndent ), pPostStr );
791cdf0e10cSrcweir 	if( !bLeave )
792cdf0e10cSrcweir 		lcl_lineOut( "{", lcl_getSpaces( nIndent ) );
793cdf0e10cSrcweir 
794cdf0e10cSrcweir 	if( bLeave && !bOwnBlockSteps )
795cdf0e10cSrcweir 		lcl_lineOut( "" );
796cdf0e10cSrcweir 
797cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
798cdf0e10cSrcweir 	if( GbTimerOn )
799cdf0e10cSrcweir 		GpTimer->continueTimer();
800cdf0e10cSrcweir #endif
801cdf0e10cSrcweir }
802cdf0e10cSrcweir 
dbg_traceNotifyError(SbError nTraceErr,const String & aTraceErrMsg,bool bTraceErrHandled,sal_Int32 nCallLvl)803cdf0e10cSrcweir void dbg_traceNotifyError( SbError nTraceErr, const String& aTraceErrMsg, bool bTraceErrHandled, sal_Int32 nCallLvl )
804cdf0e10cSrcweir {
805cdf0e10cSrcweir 	if( !GbTraceOn )
806cdf0e10cSrcweir 		return;
807cdf0e10cSrcweir #ifdef DBG_TRACE_PROFILING
808cdf0e10cSrcweir 	if( GbBlockSteps || GbBlockAll )
809cdf0e10cSrcweir 		return;
810cdf0e10cSrcweir #endif
811cdf0e10cSrcweir 	GnLastCallLvl = nCallLvl;
812cdf0e10cSrcweir 
813cdf0e10cSrcweir 	rtl::OString aOTraceErrMsg = OUStringToOString( rtl::OUString( aTraceErrMsg ), RTL_TEXTENCODING_ASCII_US );
814cdf0e10cSrcweir 
815cdf0e10cSrcweir 	char Buffer[200];
816cdf0e10cSrcweir 	const char* pHandledStr = bTraceErrHandled ? " / HANDLED" : "";
817cdf0e10cSrcweir 	sprintf( Buffer, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr, (int)nTraceErr, aOTraceErrMsg.getStr() );
818cdf0e10cSrcweir 	int nIndent = nCallLvl * GnIndentPerCallLevel;
819cdf0e10cSrcweir 	lcl_lineOut( Buffer, lcl_getSpaces( nIndent ) );
820cdf0e10cSrcweir }
821cdf0e10cSrcweir 
dbg_RegisterTraceTextForPC(SbModule * pModule,sal_uInt32 nPC,const String & aTraceStr_STMNT,const String & aTraceStr_PCode)822cdf0e10cSrcweir void dbg_RegisterTraceTextForPC( SbModule* pModule, sal_uInt32 nPC,
823cdf0e10cSrcweir 	const String& aTraceStr_STMNT, const String& aTraceStr_PCode )
824cdf0e10cSrcweir {
825cdf0e10cSrcweir 	String aModuleName = pModule->GetName();
826cdf0e10cSrcweir     ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
827cdf0e10cSrcweir 	PCToTextDataMap* pInnerMap;
828cdf0e10cSrcweir     if( it == rModuleTraceMap.end() )
829cdf0e10cSrcweir 	{
830cdf0e10cSrcweir 		pInnerMap = new PCToTextDataMap();
831cdf0e10cSrcweir 		rModuleTraceMap[ aModuleName ] = pInnerMap;
832cdf0e10cSrcweir 	}
833cdf0e10cSrcweir 	else
834cdf0e10cSrcweir 	{
835cdf0e10cSrcweir 		pInnerMap = it->second;
836cdf0e10cSrcweir 	}
837cdf0e10cSrcweir 
838cdf0e10cSrcweir 	TraceTextData aData;
839cdf0e10cSrcweir 
840cdf0e10cSrcweir 	rtl::OString aOTraceStr_STMNT = lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT );
841cdf0e10cSrcweir 	aData.m_aTraceStr_STMNT = aOTraceStr_STMNT;
842cdf0e10cSrcweir 
843cdf0e10cSrcweir 	rtl::OString aOTraceStr_PCode = lcl_toOStringSkipLeadingWhites( aTraceStr_PCode );
844cdf0e10cSrcweir 	aData.m_aTraceStr_PCode = aOTraceStr_PCode;
845cdf0e10cSrcweir 
846cdf0e10cSrcweir 	(*pInnerMap)[nPC] = aData;
847cdf0e10cSrcweir }
848cdf0e10cSrcweir 
RTL_Impl_TraceCommand(StarBASIC * pBasic,SbxArray & rPar,sal_Bool bWrite)849cdf0e10cSrcweir void RTL_Impl_TraceCommand( StarBASIC* pBasic, SbxArray& rPar, sal_Bool bWrite )
850cdf0e10cSrcweir {
851cdf0e10cSrcweir     (void)pBasic;
852cdf0e10cSrcweir     (void)bWrite;
853cdf0e10cSrcweir 
854cdf0e10cSrcweir 	if ( rPar.Count() < 2 )
855cdf0e10cSrcweir 	{
856cdf0e10cSrcweir 		StarBASIC::Error( SbERR_BAD_ARGUMENT );
857cdf0e10cSrcweir 		return;
858cdf0e10cSrcweir 	}
859cdf0e10cSrcweir 
860cdf0e10cSrcweir 	String aCommand = rPar.Get(1)->GetString();
861cdf0e10cSrcweir 
862cdf0e10cSrcweir 	if( aCommand.EqualsIgnoreCaseAscii( "TraceOn" ) )
863cdf0e10cSrcweir 		GbTraceOn = true;
864cdf0e10cSrcweir 	else
865cdf0e10cSrcweir 	if( aCommand.EqualsIgnoreCaseAscii( "TraceOff" ) )
866cdf0e10cSrcweir 		GbTraceOn = false;
867cdf0e10cSrcweir 	else
868cdf0e10cSrcweir 	if( aCommand.EqualsIgnoreCaseAscii( "PCodeOn" ) )
869cdf0e10cSrcweir 		GbIncludePCodes = true;
870cdf0e10cSrcweir 	else
871cdf0e10cSrcweir 	if( aCommand.EqualsIgnoreCaseAscii( "PCodeOff" ) )
872cdf0e10cSrcweir 		GbIncludePCodes = false;
873cdf0e10cSrcweir 	else
874cdf0e10cSrcweir 	if( aCommand.EqualsIgnoreCaseAscii( "Print" ) )
875cdf0e10cSrcweir 	{
876cdf0e10cSrcweir 		if ( rPar.Count() < 3 )
877cdf0e10cSrcweir 		{
878cdf0e10cSrcweir 			StarBASIC::Error( SbERR_BAD_ARGUMENT );
879cdf0e10cSrcweir 			return;
880cdf0e10cSrcweir 		}
881cdf0e10cSrcweir 
882cdf0e10cSrcweir 		SbxError eOld = SbxBase::GetError();
883cdf0e10cSrcweir 		if( eOld != SbxERR_OK )
884cdf0e10cSrcweir 			SbxBase::ResetError();
885cdf0e10cSrcweir 
886cdf0e10cSrcweir 		String aValStr = rPar.Get(2)->GetString();
887cdf0e10cSrcweir 		SbxError eErr = SbxBase::GetError();
888cdf0e10cSrcweir 		if( eErr != SbxERR_OK )
889cdf0e10cSrcweir 		{
890cdf0e10cSrcweir 			aValStr = String( RTL_CONSTASCII_USTRINGPARAM( "<ERROR converting value to String>" ) );
891cdf0e10cSrcweir 			SbxBase::ResetError();
892cdf0e10cSrcweir 		}
893cdf0e10cSrcweir 
894cdf0e10cSrcweir 		char Buffer[500];
895cdf0e10cSrcweir 		const char* pValStr = OUStringToOString( rtl::OUString( aValStr ), RTL_TEXTENCODING_ASCII_US ).getStr();
896cdf0e10cSrcweir 
897cdf0e10cSrcweir 		sprintf( Buffer, "### TRACE_PRINT: %s ###", pValStr );
898cdf0e10cSrcweir 		int nIndent = GnLastCallLvl * GnIndentPerCallLevel;
899cdf0e10cSrcweir 		lcl_lineOut( Buffer, lcl_getSpaces( nIndent ) );
900cdf0e10cSrcweir 
901cdf0e10cSrcweir 		if( eOld != SbxERR_OK )
902cdf0e10cSrcweir 			SbxBase::SetError( eOld );
903cdf0e10cSrcweir 	}
904cdf0e10cSrcweir }
905cdf0e10cSrcweir 
906cdf0e10cSrcweir #endif
907cdf0e10cSrcweir 
908cdf0e10cSrcweir 
909cdf0e10cSrcweir //==========================================================================
910cdf0e10cSrcweir // For debugging only
911cdf0e10cSrcweir //#define DBG_SAVE_DISASSEMBLY
912cdf0e10cSrcweir 
913cdf0e10cSrcweir #ifdef DBG_SAVE_DISASSEMBLY
914cdf0e10cSrcweir static bool dbg_bDisassemble = true;
915cdf0e10cSrcweir #include <comphelper/processfactory.hxx>
916cdf0e10cSrcweir 
917cdf0e10cSrcweir #include <com/sun/star/lang/XMultiServiceFactory.hpp>
918cdf0e10cSrcweir #include <com/sun/star/ucb/XSimpleFileAccess3.hpp>
919cdf0e10cSrcweir #include <com/sun/star/io/XTextOutputStream.hpp>
920cdf0e10cSrcweir #include <com/sun/star/io/XActiveDataSource.hpp>
921cdf0e10cSrcweir 
922cdf0e10cSrcweir using namespace comphelper;
923cdf0e10cSrcweir using namespace rtl;
924cdf0e10cSrcweir using namespace com::sun::star::uno;
925cdf0e10cSrcweir using namespace com::sun::star::lang;
926cdf0e10cSrcweir using namespace com::sun::star::ucb;
927cdf0e10cSrcweir using namespace com::sun::star::io;
928cdf0e10cSrcweir 
dbg_SaveDisassembly(SbModule * pModule)929cdf0e10cSrcweir void dbg_SaveDisassembly( SbModule* pModule )
930cdf0e10cSrcweir {
931cdf0e10cSrcweir     bool bDisassemble = dbg_bDisassemble;
932cdf0e10cSrcweir     if( bDisassemble )
933cdf0e10cSrcweir 	{
934cdf0e10cSrcweir 		Reference< XSimpleFileAccess3 > xSFI;
935cdf0e10cSrcweir 		Reference< XTextOutputStream > xTextOut;
936cdf0e10cSrcweir 		Reference< XOutputStream > xOut;
937cdf0e10cSrcweir 		Reference< XMultiServiceFactory > xSMgr = getProcessServiceFactory();
938cdf0e10cSrcweir 		if( xSMgr.is() )
939cdf0e10cSrcweir 		{
940cdf0e10cSrcweir 			Reference< XSimpleFileAccess3 > xSFI = Reference< XSimpleFileAccess3 >( xSMgr->createInstance
941cdf0e10cSrcweir 				( OUString::createFromAscii( "com.sun.star.ucb.SimpleFileAccess" ) ), UNO_QUERY );
942cdf0e10cSrcweir 			if( xSFI.is() )
943cdf0e10cSrcweir 			{
944cdf0e10cSrcweir 				String aFile( RTL_CONSTASCII_USTRINGPARAM("file:///d:/zBasic.Asm/Asm_") );
945cdf0e10cSrcweir 				StarBASIC* pBasic = (StarBASIC*)pModule->GetParent();
946cdf0e10cSrcweir 				if( pBasic )
947cdf0e10cSrcweir 				{
948cdf0e10cSrcweir 					aFile += pBasic->GetName();
949cdf0e10cSrcweir 					aFile.AppendAscii( "_" );
950cdf0e10cSrcweir 				}
951cdf0e10cSrcweir 				aFile += pModule->GetName();
952cdf0e10cSrcweir 				aFile.AppendAscii( ".txt" );
953cdf0e10cSrcweir 
954cdf0e10cSrcweir 				// String aFile( RTL_CONSTASCII_USTRINGPARAM("file:///d:/BasicAsm.txt") );
955cdf0e10cSrcweir 				if( xSFI->exists( aFile ) )
956cdf0e10cSrcweir 					xSFI->kill( aFile );
957cdf0e10cSrcweir 				xOut = xSFI->openFileWrite( aFile );
958cdf0e10cSrcweir 				Reference< XInterface > x = xSMgr->createInstance( OUString::createFromAscii( "com.sun.star.io.TextOutputStream" ) );
959cdf0e10cSrcweir 				Reference< XActiveDataSource > xADS( x, UNO_QUERY );
960cdf0e10cSrcweir 				xADS->setOutputStream( xOut );
961cdf0e10cSrcweir 				xTextOut = Reference< XTextOutputStream >( x, UNO_QUERY );
962cdf0e10cSrcweir 			}
963cdf0e10cSrcweir 		}
964cdf0e10cSrcweir 
965cdf0e10cSrcweir 		if( xTextOut.is() )
966cdf0e10cSrcweir 		{
967cdf0e10cSrcweir 			String aDisassemblyStr;
968cdf0e10cSrcweir 			pModule->Disassemble( aDisassemblyStr );
969cdf0e10cSrcweir 			xTextOut->writeString( aDisassemblyStr );
970cdf0e10cSrcweir 		}
971cdf0e10cSrcweir 		xOut->closeOutput();
972cdf0e10cSrcweir 	}
973cdf0e10cSrcweir }
974cdf0e10cSrcweir #endif
975cdf0e10cSrcweir 
976cdf0e10cSrcweir 
977cdf0e10cSrcweir // Diese Routine ist hier definiert, damit der Compiler als eigenes Segment
978cdf0e10cSrcweir // geladen werden kann.
979cdf0e10cSrcweir 
Compile()980cdf0e10cSrcweir sal_Bool SbModule::Compile()
981cdf0e10cSrcweir {
982cdf0e10cSrcweir 	if( pImage )
983cdf0e10cSrcweir 		return sal_True;
984cdf0e10cSrcweir 	StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
985cdf0e10cSrcweir 	if( !pBasic )
986cdf0e10cSrcweir 		return sal_False;
987cdf0e10cSrcweir 	SbxBase::ResetError();
988cdf0e10cSrcweir 	// Aktuelles Modul!
989cdf0e10cSrcweir 	SbModule* pOld = pCMOD;
990cdf0e10cSrcweir 	pCMOD = this;
991cdf0e10cSrcweir 
992cdf0e10cSrcweir 	SbiParser* pParser = new SbiParser( (StarBASIC*) GetParent(), this );
993cdf0e10cSrcweir 	while( pParser->Parse() ) {}
994cdf0e10cSrcweir 	if( !pParser->GetErrors() )
995cdf0e10cSrcweir 		pParser->aGen.Save();
996cdf0e10cSrcweir 	delete pParser;
997cdf0e10cSrcweir 	// fuer den Disassembler
998cdf0e10cSrcweir 	if( pImage )
999cdf0e10cSrcweir 		pImage->aOUSource = aOUSource;
1000cdf0e10cSrcweir 
1001cdf0e10cSrcweir 	pCMOD = pOld;
1002cdf0e10cSrcweir 
1003cdf0e10cSrcweir 	// Beim Compilieren eines Moduls werden die Modul-globalen
1004cdf0e10cSrcweir 	// Variablen aller Module ungueltig
1005cdf0e10cSrcweir 	sal_Bool bRet = IsCompiled();
1006cdf0e10cSrcweir 	if( bRet )
1007cdf0e10cSrcweir 	{
1008cdf0e10cSrcweir 		if( !this->ISA(SbObjModule) )
1009cdf0e10cSrcweir 			pBasic->ClearAllModuleVars();
1010cdf0e10cSrcweir         RemoveVars(); // remove 'this' Modules variables
1011cdf0e10cSrcweir 		// clear all method statics
1012cdf0e10cSrcweir 		for( sal_uInt16 i = 0; i < pMethods->Count(); i++ )
1013cdf0e10cSrcweir 		{
1014cdf0e10cSrcweir 			SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
1015cdf0e10cSrcweir 			if( p )
1016cdf0e10cSrcweir 				p->ClearStatics();
1017cdf0e10cSrcweir 		}
1018cdf0e10cSrcweir 
1019cdf0e10cSrcweir 		// #i31510 Init other libs only if Basic isn't running
1020cdf0e10cSrcweir 		if( pINST == NULL )
1021cdf0e10cSrcweir 		{
1022cdf0e10cSrcweir 			SbxObject* pParent_ = pBasic->GetParent();
1023cdf0e10cSrcweir 			if( pParent_ )
1024cdf0e10cSrcweir 				pBasic = PTR_CAST(StarBASIC,pParent_);
1025cdf0e10cSrcweir 			if( pBasic )
1026cdf0e10cSrcweir 				pBasic->ClearAllModuleVars();
1027cdf0e10cSrcweir 		}
1028cdf0e10cSrcweir 	}
1029cdf0e10cSrcweir 
1030cdf0e10cSrcweir #ifdef DBG_SAVE_DISASSEMBLY
1031cdf0e10cSrcweir 	dbg_SaveDisassembly( this );
1032cdf0e10cSrcweir #endif
1033cdf0e10cSrcweir 
1034cdf0e10cSrcweir #ifdef DBG_TRACE_BASIC
1035cdf0e10cSrcweir 	lcl_PrepareTraceForModule( this );
1036cdf0e10cSrcweir #endif
1037cdf0e10cSrcweir 
1038cdf0e10cSrcweir 	return bRet;
1039cdf0e10cSrcweir }
1040cdf0e10cSrcweir 
1041cdf0e10cSrcweir /**************************************************************************
1042cdf0e10cSrcweir *
1043cdf0e10cSrcweir *	Syntax-Highlighting
1044cdf0e10cSrcweir *
1045cdf0e10cSrcweir **************************************************************************/
1046cdf0e10cSrcweir 
Highlight(const String & rSrc,SbTextPortions & rList)1047cdf0e10cSrcweir void StarBASIC::Highlight( const String& rSrc, SbTextPortions& rList )
1048cdf0e10cSrcweir {
1049cdf0e10cSrcweir 	SbiTokenizer aTok( rSrc );
1050cdf0e10cSrcweir 	aTok.Hilite( rList );
1051cdf0e10cSrcweir }
1052cdf0e10cSrcweir 
1053