1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
3 * This file is part of the LibreOffice project.
5 * This Source Code Form is subject to the terms of the Mozilla Public
6 * License, v. 2.0. If a copy of the MPL was not distributed with this
7 * file, You can obtain one at http://mozilla.org/MPL/2.0/.
9 * This file incorporates work covered by the following license notice:
11 * Licensed to the Apache Software Foundation (ASF) under one or more
12 * contributor license agreements. See the NOTICE file distributed
13 * with this work for additional information regarding copyright
14 * ownership. The ASF licenses this file to you under the Apache
15 * License, Version 2.0 (the "License"); you may not use this file
16 * except in compliance with the License. You may obtain a copy of
17 * the License at http://www.apache.org/licenses/LICENSE-2.0 .
21 #include <basic/sbx.hxx>
24 #include <basic/sbobjmod.hxx>
27 // To activate tracing enable in sbtrace.hxx
28 #ifdef DBG_TRACE_BASIC
30 // Trace ini file (set NULL to ignore)
31 // can be overridden with the environment variable OOO_BASICTRACEINI
32 static char GpTraceIniFile
[] = "~/BasicTrace.ini";
33 //static char* GpTraceIniFile = NULL;
35 // Trace Settings, used if no ini file / not found in ini file
36 static char GpTraceFileNameDefault
[] = "~/BasicTrace.txt";
37 static char* GpTraceFileName
= GpTraceFileNameDefault
;
40 // true = tracing is active, false = tracing is disabled, default = true
41 // Set to false initially if you want to activate tracing on demand with
42 // TraceCommand( "TraceOn" ), see below
43 static bool GbTraceOn
= true;
46 // true = PCodes are written to trace, default = false, correspondents
47 // with TraceCommand( "PCodeOn" / "PCodeOff" ), see below
48 static bool GbIncludePCodes
= false;
50 // GbInitOnlyAtOfficeStart:
51 // true = Tracing is only intialized onces after Office start when
52 // Basic runs the first time. Further calls to Basic, e.g. via events
53 // use the same output file. The trace ini file is not read again.
54 static bool GbInitOnlyAtOfficeStart
= false;
56 static int GnIndentPerCallLevel
= 4;
57 static int GnIndentForPCode
= 2;
60 With trace enabled the runtime function TraceCommand
61 can be used to influence the trace functionality
62 from within the running Basic macro.
64 Format: TraceCommand( command as String [, param as Variant] )
66 Supported commands (command is NOT case sensitive):
67 TraceCommand "TraceOn" sets GbTraceOn = true
68 TraceCommand "TraceOff" sets GbTraceOn = false
70 TraceCommand "PCodeOn" sets GbIncludePCodes = true
71 TraceCommand "PCodeOff" sets GbIncludePCodes = false
73 TraceCommand "Print", aVal writes aVal into the trace file as
74 long as it can be converted to string
77 #ifdef DBG_TRACE_PROFILING
81 #include "canvas/elapsedtime.hxx"
85 // true = including time stamps
86 static bool GbTimerOn
= true;
88 // GbTimeStampForEachStep:
89 // true = prints time stamp after each command / pcode (very slow)
90 static bool GbTimeStampForEachStep
= false;
92 // GbBlockAllAfterFirstFunctionUsage:
93 // true = everything (commands, pcodes, functions) is only printed
94 // for the first usage (improves performance when tracing / pro-
95 // filing large macros)
96 static bool GbBlockAllAfterFirstFunctionUsage
= false;
98 // GbBlockStepsAfterFirstFunctionUsage:
99 // true = commands / pcodes are only printed for the first time
100 // a function is executed. Afterwards only the entering/leaving
101 // messages are logged (improves performance when tracing / pro-
102 // filing large macros)
103 static bool GbBlockStepsAfterFirstFunctionUsage
= false;
108 static void lcl_skipWhites( char*& rpc
)
110 while( *rpc
== ' ' || *rpc
== '\t' )
114 inline void lcl_findNextLine( char*& rpc
, char* pe
)
117 while( rpc
< pe
&& *rpc
!= 13 && *rpc
!= 10 )
121 while( rpc
< pe
&& (*rpc
== 13 || *rpc
== 10) )
125 inline bool lcl_isAlpha( char c
)
127 bool bRet
= (c
>= 'a' && c
<= 'z') || (c
>= 'A' && c
<= 'Z');
131 static void lcl_ReadIniFile( const char* pIniFileName
)
133 const int BUF_SIZE
= 1000;
134 static sal_Char TraceFileNameBuffer
[BUF_SIZE
];
135 sal_Char Buffer
[BUF_SIZE
];
136 sal_Char VarNameBuffer
[BUF_SIZE
];
137 sal_Char ValBuffer
[BUF_SIZE
];
139 FILE* pFile
= fopen( pIniFileName
,"rb" );
143 size_t nRead
= fread( Buffer
, 1, BUF_SIZE
, pFile
);
147 char* pe
= Buffer
+ nRead
;
150 lcl_skipWhites( pc
); if( pc
== pe
) break;
153 char* pVarStart
= pc
;
154 while( pc
< pe
&& lcl_isAlpha( *pc
) )
156 int nVarLen
= pc
- pVarStart
;
159 lcl_findNextLine( pc
, pe
);
162 strncpy( VarNameBuffer
, pVarStart
, nVarLen
);
163 VarNameBuffer
[nVarLen
] = '\0';
166 lcl_skipWhites( pc
); if( pc
== pe
) break;
170 lcl_skipWhites( pc
); if( pc
== pe
) break;
173 char* pValStart
= pc
;
174 while( pc
< pe
&& *pc
!= 13 && *pc
!= 10 )
176 int nValLen
= pc
- pValStart
;
179 lcl_findNextLine( pc
, pe
);
182 strncpy( ValBuffer
, pValStart
, nValLen
);
183 ValBuffer
[nValLen
] = '\0';
186 if( strcmp( VarNameBuffer
, "GpTraceFileName") == 0 )
188 strcpy( TraceFileNameBuffer
, ValBuffer
);
189 GpTraceFileName
= TraceFileNameBuffer
;
192 if( strcmp( VarNameBuffer
, "GbTraceOn") == 0 )
193 GbTraceOn
= (strcmp( ValBuffer
, "true" ) == 0);
195 if( strcmp( VarNameBuffer
, "GbIncludePCodes") == 0 )
196 GbIncludePCodes
= (strcmp( ValBuffer
, "true" ) == 0);
198 if( strcmp( VarNameBuffer
, "GbInitOnlyAtOfficeStart") == 0 )
199 GbInitOnlyAtOfficeStart
= (strcmp( ValBuffer
, "true" ) == 0);
201 if( strcmp( VarNameBuffer
, "GnIndentPerCallLevel") == 0 )
202 GnIndentPerCallLevel
= strtol( ValBuffer
, NULL
, 10 );
204 if( strcmp( VarNameBuffer
, "GnIndentForPCode") == 0 )
205 GnIndentForPCode
= strtol( ValBuffer
, NULL
, 10 );
206 #ifdef DBG_TRACE_PROFILING
208 if( strcmp( VarNameBuffer
, "GbTimerOn") == 0 )
209 GbTimerOn
= (strcmp( ValBuffer
, "true" ) == 0);
211 if( strcmp( VarNameBuffer
, "GbTimeStampForEachStep") == 0 )
212 GbTimeStampForEachStep
= (strcmp( ValBuffer
, "true" ) == 0);
214 if( strcmp( VarNameBuffer
, "GbBlockAllAfterFirstFunctionUsage") == 0 )
215 GbBlockAllAfterFirstFunctionUsage
= (strcmp( ValBuffer
, "true" ) == 0);
217 if( strcmp( VarNameBuffer
, "GbBlockStepsAfterFirstFunctionUsage") == 0 )
218 GbBlockStepsAfterFirstFunctionUsage
= (strcmp( ValBuffer
, "true" ) == 0);
226 OString m_aTraceStr_STMNT
;
227 OString m_aTraceStr_PCode
;
229 typedef std::hash_map
< sal_Int32
, TraceTextData
> PCToTextDataMap
;
230 typedef std::hash_map
< OUString
, PCToTextDataMap
*, OUStringHash
, ::std::equal_to
< OUString
> > ModuleTraceMap
;
232 ModuleTraceMap GaModuleTraceMap
;
233 ModuleTraceMap
& rModuleTraceMap
= GaModuleTraceMap
;
235 static FILE* GpGlobalFile
= NULL
;
237 static void lcl_lineOut( const char* pStr
, const char* pPreStr
= NULL
, const char* pPostStr
= NULL
)
239 if( GpGlobalFile
!= NULL
)
241 fprintf( GpGlobalFile
, "%s%s%s\n", pPreStr
? pPreStr
: "", pStr
, pPostStr
? pPostStr
: "" );
242 fflush( GpGlobalFile
);
246 const char* lcl_getSpaces( int nSpaceCount
)
248 static sal_Char Spaces
[] = " "
251 static int nAvailableSpaceCount
= strlen( Spaces
);
252 static sal_Char
* pSpacesEnd
= Spaces
+ nAvailableSpaceCount
;
254 if( nSpaceCount
> nAvailableSpaceCount
)
255 nSpaceCount
= nAvailableSpaceCount
;
257 return pSpacesEnd
- nSpaceCount
;
260 static OString
lcl_toOStringSkipLeadingWhites( const OUString
& aStr
)
262 static sal_Char Buffer
[1000];
264 OString aOStr
= OUStringToOString( OUString( aStr
), RTL_TEXTENCODING_ASCII_US
);
265 const sal_Char
* pStr
= aOStr
.getStr();
269 while( c
== ' ' || c
== '\t' )
275 int nLen
= strlen( pStr
);
276 strncpy( Buffer
, pStr
, nLen
);
279 OString
aORetStr( Buffer
);
283 String
lcl_dumpMethodParameters( SbMethod
* pMethod
)
286 if( pMethod
== NULL
)
290 SbxError eOld
= SbxBase::GetError();
292 SbxArray
* pParams
= pMethod
->GetParameters();
293 SbxInfo
* pInfo
= pMethod
->GetInfo();
298 for ( sal_uInt16 nParam
= 1; nParam
< pParams
->Count(); nParam
++ )
300 SbxVariable
* pVar
= pParams
->Get( nParam
);
301 DBG_ASSERT( pVar
, "Parameter?!" );
302 if ( !pVar
->GetName().isEmpty() )
304 aStr
+= pVar
->GetName();
308 const SbxParamInfo
* pParam
= pInfo
->GetParam( nParam
);
311 aStr
+= pParam
->aName
;
315 SbxDataType eType
= pVar
->GetType();
316 if( eType
& SbxARRAY
)
320 else if( eType
!= SbxOBJECT
)
322 aStr
+= pVar
->GetString();
324 if ( nParam
< ( pParams
->Count() - 1 ) )
332 SbxBase::ResetError();
333 if( eOld
!= SbxERR_OK
)
335 SbxBase::SetError( eOld
);
342 static bool GbSavTraceOn
= false;
344 #ifdef DBG_TRACE_PROFILING
345 static canvas::tools::ElapsedTime
* GpTimer
= NULL
;
346 static double GdStartTime
= 0.0;
347 static double GdLastTime
= 0.0;
348 static bool GbBlockSteps
= false;
349 static bool GbBlockAll
= false;
353 OUString m_aCompleteFunctionName
;
361 : m_dTotalTime( 0.0 )
364 , m_bBlockAll( false )
365 , m_bBlockSteps( false )
368 typedef std::hash_map
< OUString
, FunctionItem
*, OUStringHash
, ::std::equal_to
< OUString
> > FunctionItemMap
;
370 static std::stack
< double > GaCallEnterTimeStack
;
371 static std::stack
< FunctionItem
* > GaFunctionItemStack
;
372 static FunctionItemMap GaFunctionItemMap
;
374 bool compareFunctionNetTime( FunctionItem
* p1
, FunctionItem
* p2
)
376 return (p1
->m_dNetTime
> p2
->m_dNetTime
);
379 void lcl_printTimeOutput( void )
381 // Overall time output
383 lcl_lineOut( "***** Time Output *****" );
384 char TimeBuffer
[500];
385 double dTotalTime
= GpTimer
->getElapsedTime() - GdStartTime
;
386 sprintf( TimeBuffer
, "Total execution time = %f ms", dTotalTime
*1000.0 );
387 lcl_lineOut( TimeBuffer
);
392 lcl_lineOut( "Functions:" );
394 std::vector
<FunctionItem
*> avFunctionItems
;
396 FunctionItemMap::iterator it
;
397 for( it
= GaFunctionItemMap
.begin() ; it
!= GaFunctionItemMap
.end() ; ++it
)
399 FunctionItem
* pFunctionItem
= it
->second
;
400 if( pFunctionItem
!= NULL
)
402 avFunctionItems
.push_back( pFunctionItem
);
406 std::sort( avFunctionItems
.begin(), avFunctionItems
.end(), compareFunctionNetTime
);
408 std::vector
<FunctionItem
*>::iterator itv
;
409 for( itv
= avFunctionItems
.begin() ; itv
!= avFunctionItems
.end() ; ++itv
)
411 FunctionItem
* pFunctionItem
= *itv
;
412 if( pFunctionItem
!= NULL
)
414 OUString aCompleteFunctionName
= pFunctionItem
->m_aCompleteFunctionName
;
415 const char* pName
= OUStringToOString( aCompleteFunctionName
, RTL_TEXTENCODING_ASCII_US
).getStr();
416 int nNameLen
= aCompleteFunctionName
.getLength();
418 double dFctTotalTime
= pFunctionItem
->m_dTotalTime
;
419 double dFctNetTime
= pFunctionItem
->m_dNetTime
;
420 double dFctTotalTimePercent
= 100.0 * dFctTotalTime
/ dTotalTime
;
421 double dFctNetTimePercent
= 100.0 * dFctNetTime
/ dTotalTime
;
422 int nSpaceCount
= 30 - nNameLen
;
423 if( nSpaceCount
< 0 )
427 sprintf( TimeBuffer
, "%s:%sCalled %d times\t%f ms (%f%%) / net %f (%f%%) ms",
428 pName
, lcl_getSpaces( nSpaceCount
), pFunctionItem
->m_nCallCount
,
429 dFctTotalTime
*1000.0, dFctTotalTimePercent
, dFctNetTime
*1000.0, dFctNetTimePercent
);
430 lcl_lineOut( TimeBuffer
);
438 static bool GbInitTraceAlreadyCalled
= false;
440 void dbg_InitTrace( void )
442 if( GbInitOnlyAtOfficeStart
&& GbInitTraceAlreadyCalled
)
444 #ifdef DBG_TRACE_PROFILING
447 GpTimer
->continueTimer();
450 GpGlobalFile
= fopen( GpTraceFileName
, "a+" );
453 GbInitTraceAlreadyCalled
= true;
455 if( const sal_Char
* pcIniFileName
= ::getenv( "OOO_BASICTRACEINI" ) )
457 lcl_ReadIniFile( pcIniFileName
);
459 else if( GpTraceIniFile
!= NULL
)
461 lcl_ReadIniFile( GpTraceIniFile
);
463 GpGlobalFile
= fopen( GpTraceFileName
, "w" );
464 GbSavTraceOn
= GbTraceOn
;
467 lcl_lineOut( "### Program started with trace off ###" );
469 #ifdef DBG_TRACE_PROFILING
470 GpTimer
= new canvas::tools::ElapsedTime();
471 GdStartTime
= GpTimer
->getElapsedTime();
472 GdLastTime
= GdStartTime
;
473 GbBlockSteps
= false;
478 void dbg_DeInitTrace( void )
480 GbTraceOn
= GbSavTraceOn
;
482 #ifdef DBG_TRACE_PROFILING
483 while( !GaCallEnterTimeStack
.empty() )
485 GaCallEnterTimeStack
.pop();
487 while( !GaFunctionItemStack
.empty() )
489 GaFunctionItemStack
.pop();
491 lcl_printTimeOutput();
493 for( FunctionItemMap::iterator it
= GaFunctionItemMap
.begin() ; it
!= GaFunctionItemMap
.end() ; ++it
)
497 GaFunctionItemMap
.clear();
501 fclose( GpGlobalFile
);
505 if( GbInitOnlyAtOfficeStart
)
509 GpTimer
->pauseTimer();
519 static sal_Int32 GnLastCallLvl
= 0;
521 void dbg_tracePrint( const OUString
& aStr
, sal_Int32 nCallLvl
, bool bCallLvlRelativeToCurrent
)
523 if( bCallLvlRelativeToCurrent
)
525 nCallLvl
+= GnLastCallLvl
;
527 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
528 lcl_lineOut( OUStringToOString( OUString( aStr
), RTL_TEXTENCODING_ASCII_US
).getStr(), lcl_getSpaces( nIndent
) );
531 void dbg_traceStep( SbModule
* pModule
, sal_uInt32 nPC
, sal_Int32 nCallLvl
)
537 #ifdef DBG_TRACE_PROFILING
538 if( GbBlockSteps
|| GbBlockAll
)
542 double dCurTime
= 0.0;
543 bool bPrintTimeStamp
= false;
546 GpTimer
->pauseTimer();
547 dCurTime
= GpTimer
->getElapsedTime();
548 bPrintTimeStamp
= GbTimeStampForEachStep
;
551 bool bPrintTimeStamp
= false;
554 GnLastCallLvl
= nCallLvl
;
556 SbModule
* pTraceMod
= pModule
;
557 if( pTraceMod
->ISA(SbClassModuleObject
) )
559 SbClassModuleObject
* pClassModuleObj
= (SbClassModuleObject
*)(SbxBase
*)pTraceMod
;
560 pTraceMod
= pClassModuleObj
->getClassModule();
563 OUString aModuleName
= pTraceMod
->GetName();
564 ModuleTraceMap::iterator it
= rModuleTraceMap
.find( aModuleName
);
565 if( it
== rModuleTraceMap
.end() )
567 const char* pModuleNameStr
= OUStringToOString( OUString( aModuleName
), RTL_TEXTENCODING_ASCII_US
).getStr();
569 sprintf( Buffer
, "TRACE ERROR: Unknown module \"%s\"", pModuleNameStr
);
570 lcl_lineOut( Buffer
);
574 PCToTextDataMap
* pInnerMap
= it
->second
;
575 if( pInnerMap
== NULL
)
577 lcl_lineOut( "TRACE INTERNAL ERROR: No inner map" );
581 PCToTextDataMap::iterator itInner
= pInnerMap
->find( nPC
);
582 if( itInner
== pInnerMap
->end() )
584 const char* pModuleNameStr
= OUStringToOString( OUString( aModuleName
), RTL_TEXTENCODING_ASCII_US
).getStr();
586 sprintf( Buffer
, "TRACE ERROR: No info for PC = %d in module \"%s\"", (int)nPC
, pModuleNameStr
);
587 lcl_lineOut( Buffer
);
591 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
593 const TraceTextData
& rTraceTextData
= itInner
->second
;
594 const OString
& rStr_STMNT
= rTraceTextData
.m_aTraceStr_STMNT
;
596 if( rStr_STMNT
.getLength() )
600 char TimeBuffer
[200];
601 memset (TimeBuffer
, 0, size(TimeBuffer
));
602 #ifdef DBG_TRACE_PROFILING
603 if( bPrintTimeStamp
)
605 double dDiffTime
= dCurTime
- GdLastTime
;
606 GdLastTime
= dCurTime
;
607 sprintf( TimeBuffer
, "\t\t// Time = %f ms / += %f ms", dCurTime
*1000.0, dDiffTime
*1000.0 );
613 lcl_lineOut( rStr_STMNT
.getStr(), lcl_getSpaces( nIndent
),
614 (bPrintTimeStamp
&& !GbIncludePCodes
) ? TimeBuffer
: NULL
);
617 if( !GbIncludePCodes
)
619 #ifdef DBG_TRACE_PROFILING
622 GpTimer
->continueTimer();
628 nIndent
+= GnIndentForPCode
;
629 const OString
& rStr_PCode
= rTraceTextData
.m_aTraceStr_PCode
;
630 if( rStr_PCode
.getLength() )
632 lcl_lineOut( rStr_PCode
.getStr(), lcl_getSpaces( nIndent
),
633 bPrintTimeStamp
? TimeBuffer
: NULL
);
636 #ifdef DBG_TRACE_PROFILING
639 GpTimer
->continueTimer();
645 void dbg_traceNotifyCall( SbModule
* pModule
, SbMethod
* pMethod
, sal_Int32 nCallLvl
, bool bLeave
)
652 #ifdef DBG_TRACE_PROFILING
653 double dCurTime
= 0.0;
654 double dExecutionTime
= 0.0;
657 dCurTime
= GpTimer
->getElapsedTime();
658 GpTimer
->pauseTimer();
662 GnLastCallLvl
= nCallLvl
;
664 SbModule
* pTraceMod
= pModule
;
665 SbClassModuleObject
* pClassModuleObj
= NULL
;
666 if( pTraceMod
->ISA(SbClassModuleObject
) )
668 pClassModuleObj
= (SbClassModuleObject
*)(SbxBase
*)pTraceMod
;
669 pTraceMod
= pClassModuleObj
->getClassModule();
672 OUString aCompleteFunctionName
= pTraceMod
->GetName();
673 if( pMethod
!= NULL
)
675 aCompleteFunctionName
+= "::";
676 OUString aMethodName
= pMethod
->GetName();
677 aCompleteFunctionName
+= aMethodName
;
681 aCompleteFunctionName
+= "/RunInit";
684 bool bOwnBlockSteps
= false;
685 #ifdef DBG_TRACE_PROFILING
686 bool bOwnBlockAll
= false;
687 FunctionItem
* pFunctionItem
= NULL
;
690 FunctionItemMap::iterator itFunctionItem
= GaFunctionItemMap
.find( aCompleteFunctionName
);
691 if( itFunctionItem
!= GaFunctionItemMap
.end() )
693 pFunctionItem
= itFunctionItem
->second
;
695 if( pFunctionItem
== NULL
)
697 DBG_ASSERT( !bLeave
, "No FunctionItem in leave!" );
699 pFunctionItem
= new FunctionItem();
700 pFunctionItem
->m_aCompleteFunctionName
= aCompleteFunctionName
;
701 GaFunctionItemMap
[ aCompleteFunctionName
] = pFunctionItem
;
703 else if( GbBlockAllAfterFirstFunctionUsage
&& !bLeave
)
705 pFunctionItem
->m_bBlockAll
= true;
707 else if( GbBlockStepsAfterFirstFunctionUsage
&& !bLeave
)
709 pFunctionItem
->m_bBlockSteps
= true;
714 bOwnBlockAll
= GbBlockAll
;
715 bOwnBlockSteps
= GbBlockSteps
;
717 GbBlockSteps
= false;
719 dExecutionTime
= dCurTime
- GaCallEnterTimeStack
.top();
720 GaCallEnterTimeStack
.pop();
722 pFunctionItem
->m_dTotalTime
+= dExecutionTime
;
723 pFunctionItem
->m_dNetTime
+= dExecutionTime
;
724 pFunctionItem
->m_nCallCount
++;
726 GaFunctionItemStack
.pop();
727 if( !GaFunctionItemStack
.empty() )
729 FunctionItem
* pParentItem
= GaFunctionItemStack
.top();
730 if( pParentItem
!= NULL
)
732 pParentItem
->m_dNetTime
-= dExecutionTime
;
734 GbBlockSteps
= pParentItem
->m_bBlockSteps
;
735 GbBlockAll
= pParentItem
->m_bBlockAll
;
741 GbBlockSteps
= bOwnBlockSteps
= pFunctionItem
->m_bBlockSteps
;
742 GbBlockAll
= bOwnBlockAll
= pFunctionItem
->m_bBlockAll
;
744 GaCallEnterTimeStack
.push( dCurTime
);
745 GaFunctionItemStack
.push( pFunctionItem
);
753 GpTimer
->continueTimer();
763 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
764 if( !bLeave
&& !bOwnBlockSteps
)
766 static const char* pSeparator
= "' ================================================================================";
768 lcl_lineOut( pSeparator
, lcl_getSpaces( nIndent
) );
774 if( !bOwnBlockSteps
)
776 lcl_lineOut( "}", lcl_getSpaces( nIndent
) );
784 if( !bLeave
|| !bOwnBlockSteps
)
786 aStr
+= aCompleteFunctionName
;
788 if( !bOwnBlockSteps
&& pClassModuleObj
!= NULL
)
791 aStr
+= pClassModuleObj
->GetName();
796 aStr
+= lcl_dumpMethodParameters( pMethod
);
798 const char* pPostStr
= NULL
;
799 #ifdef DBG_TRACE_PROFILING
800 char TimeBuffer
[200];
801 if( GbTimerOn
&& bLeave
)
803 sprintf( TimeBuffer
, " // Execution Time = %f ms", dExecutionTime
*1000.0 );
804 pPostStr
= TimeBuffer
;
807 lcl_lineOut( (!bLeave
|| !bOwnBlockSteps
) ? OUStringToOString( OUString( aStr
), RTL_TEXTENCODING_ASCII_US
).getStr() : "}",
808 lcl_getSpaces( nIndent
), pPostStr
);
811 lcl_lineOut( "{", lcl_getSpaces( nIndent
) );
813 if( bLeave
&& !bOwnBlockSteps
)
817 #ifdef DBG_TRACE_PROFILING
820 GpTimer
->continueTimer();
825 void dbg_traceNotifyError( SbError nTraceErr
, const OUString
& aTraceErrMsg
,
826 bool bTraceErrHandled
, sal_Int32 nCallLvl
)
832 #ifdef DBG_TRACE_PROFILING
833 if( GbBlockSteps
|| GbBlockAll
)
838 GnLastCallLvl
= nCallLvl
;
840 OString aOTraceErrMsg
= OUStringToOString( OUString( aTraceErrMsg
), RTL_TEXTENCODING_ASCII_US
);
843 const char* pHandledStr
= bTraceErrHandled
? " / HANDLED" : "";
844 sprintf( Buffer
, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr
, (int)nTraceErr
, aOTraceErrMsg
.getStr() );
845 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
846 lcl_lineOut( Buffer
, lcl_getSpaces( nIndent
) );
849 void dbg_RegisterTraceTextForPC( SbModule
* pModule
, sal_uInt32 nPC
,
850 const OUString
& aTraceStr_STMNT
, const OUString
& aTraceStr_PCode
)
852 OUString aModuleName
= pModule
->GetName();
853 ModuleTraceMap::iterator it
= rModuleTraceMap
.find( aModuleName
);
854 PCToTextDataMap
* pInnerMap
;
855 if( it
== rModuleTraceMap
.end() )
857 pInnerMap
= new PCToTextDataMap();
858 rModuleTraceMap
[ aModuleName
] = pInnerMap
;
862 pInnerMap
= it
->second
;
867 OString aOTraceStr_STMNT
= lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT
);
868 aData
.m_aTraceStr_STMNT
= aOTraceStr_STMNT
;
870 OString aOTraceStr_PCode
= lcl_toOStringSkipLeadingWhites( aTraceStr_PCode
);
871 aData
.m_aTraceStr_PCode
= aOTraceStr_PCode
;
873 (*pInnerMap
)[nPC
] = aData
;
876 void RTL_Impl_TraceCommand( StarBASIC
* pBasic
, SbxArray
& rPar
, sal_Bool bWrite
)
881 if ( rPar
.Count() < 2 )
883 StarBASIC::Error( SbERR_BAD_ARGUMENT
);
887 OUString aCommand
= rPar
.Get(1)->GetString();
889 if( aCommand
.equalsIngoreAsciiCase( "TraceOn" ) )
893 else if( aCommand
.equalsIngoreAsciiCase( "TraceOff" ) )
897 else if( aCommand
.equalsIngoreAsciiCase( "PCodeOn" ) )
899 GbIncludePCodes
= true;
901 else if( aCommand
.equalsIngoreAsciiCase( "PCodeOff" ) )
903 GbIncludePCodes
= false;
905 else if( aCommand
.equalsIngoreAsciiCase( "Print" ) )
907 if ( rPar
.Count() < 3 )
909 StarBASIC::Error( SbERR_BAD_ARGUMENT
);
913 SbxError eOld
= SbxBase::GetError();
914 if( eOld
!= SbxERR_OK
)
915 SbxBase::ResetError();
917 OUString aValStr
= rPar
.Get(2)->GetString();
918 SbxError eErr
= SbxBase::GetError();
919 if( eErr
!= SbxERR_OK
)
921 aValStr
= "<ERROR converting value to String>";
922 SbxBase::ResetError();
926 const char* pValStr
= OUStringToOString( OUString( aValStr
), RTL_TEXTENCODING_ASCII_US
).getStr();
928 sprintf( Buffer
, "### TRACE_PRINT: %s ###", pValStr
);
929 int nIndent
= GnLastCallLvl
* GnIndentPerCallLevel
;
930 lcl_lineOut( Buffer
, lcl_getSpaces( nIndent
) );
932 if( eOld
!= SbxERR_OK
)
934 SbxBase::SetError( eOld
);
941 // This routine is defined here, so that the
942 // compiler can be loaded as a discrete segment.
944 sal_Bool
SbModule::Compile()
948 StarBASIC
* pBasic
= PTR_CAST(StarBASIC
,GetParent());
951 SbxBase::ResetError();
953 SbModule
* pOld
= GetSbData()->pCompMod
;
954 GetSbData()->pCompMod
= this;
956 SbiParser
* pParser
= new SbiParser( (StarBASIC
*) GetParent(), this );
957 while( pParser
->Parse() ) {}
958 if( !pParser
->GetErrors() )
959 pParser
->aGen
.Save();
961 // for the disassembler
963 pImage
->aOUSource
= aOUSource
;
965 GetSbData()->pCompMod
= pOld
;
967 // compiling a module, the module-global
968 // variables of all modules become invalid
969 sal_Bool bRet
= IsCompiled();
972 if( !this->ISA(SbObjModule
) )
973 pBasic
->ClearAllModuleVars();
974 RemoveVars(); // remove 'this' Modules variables
975 // clear all method statics
976 for( sal_uInt16 i
= 0; i
< pMethods
->Count(); i
++ )
978 SbMethod
* p
= PTR_CAST(SbMethod
,pMethods
->Get( i
) );
983 // #i31510 Init other libs only if Basic isn't running
984 if( GetSbData()->pInst
== NULL
)
986 SbxObject
* pParent_
= pBasic
->GetParent();
988 pBasic
= PTR_CAST(StarBASIC
,pParent_
);
990 pBasic
->ClearAllModuleVars();
997 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */