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 "sbobjmod.hxx"
25 #include <svtools/miscopt.hxx>
27 #include <boost/scoped_ptr.hpp>
28 #include <rtl/character.hxx>
30 // To activate tracing enable in sbtrace.hxx
31 #ifdef DBG_TRACE_BASIC
33 // Trace ini file (set NULL to ignore)
34 // can be overridden with the environment variable OOO_BASICTRACEINI
35 static char GpTraceIniFile
[] = "~/BasicTrace.ini";
36 //static char* GpTraceIniFile = NULL;
38 // Trace Settings, used if no ini file / not found in ini file
39 static char GpTraceFileNameDefault
[] = "~/BasicTrace.txt";
40 static char* GpTraceFileName
= GpTraceFileNameDefault
;
43 // true = tracing is active, false = tracing is disabled, default = true
44 // Set to false initially if you want to activate tracing on demand with
45 // TraceCommand( "TraceOn" ), see below
46 static bool GbTraceOn
= true;
49 // true = PCodes are written to trace, default = false, correspondents
50 // with TraceCommand( "PCodeOn" / "PCodeOff" ), see below
51 static bool GbIncludePCodes
= false;
53 // GbInitOnlyAtOfficeStart:
54 // true = Tracing is only intialized onces after Office start when
55 // Basic runs the first time. Further calls to Basic, e.g. via events
56 // use the same output file. The trace ini file is not read again.
57 static bool GbInitOnlyAtOfficeStart
= false;
59 static int GnIndentPerCallLevel
= 4;
60 static int GnIndentForPCode
= 2;
63 With trace enabled the runtime function TraceCommand
64 can be used to influence the trace functionality
65 from within the running Basic macro.
67 Format: TraceCommand( command as String [, param as Variant] )
69 Supported commands (command is NOT case sensitive):
70 TraceCommand "TraceOn" sets GbTraceOn = true
71 TraceCommand "TraceOff" sets GbTraceOn = false
73 TraceCommand "PCodeOn" sets GbIncludePCodes = true
74 TraceCommand "PCodeOff" sets GbIncludePCodes = false
76 TraceCommand "Print", aVal writes aVal into the trace file as
77 long as it can be converted to string
80 #ifdef DBG_TRACE_PROFILING
84 #include <canvas/elapsedtime.hxx>
88 // true = including time stamps
89 static bool GbTimerOn
= true;
91 // GbTimeStampForEachStep:
92 // true = prints time stamp after each command / pcode (very slow)
93 static bool GbTimeStampForEachStep
= false;
95 // GbBlockAllAfterFirstFunctionUsage:
96 // true = everything (commands, pcodes, functions) is only printed
97 // for the first usage (improves performance when tracing / pro-
98 // filing large macros)
99 static bool GbBlockAllAfterFirstFunctionUsage
= false;
101 // GbBlockStepsAfterFirstFunctionUsage:
102 // true = commands / pcodes are only printed for the first time
103 // a function is executed. Afterwards only the entering/leaving
104 // messages are logged (improves performance when tracing / pro-
105 // filing large macros)
106 static bool GbBlockStepsAfterFirstFunctionUsage
= false;
111 static void lcl_skipWhites( char*& rpc
)
113 while( *rpc
== ' ' || *rpc
== '\t' )
117 inline void lcl_findNextLine( char*& rpc
, char* pe
)
120 while( rpc
< pe
&& *rpc
!= 13 && *rpc
!= 10 )
124 while( rpc
< pe
&& (*rpc
== 13 || *rpc
== 10) )
128 static void lcl_ReadIniFile( const char* pIniFileName
)
130 const int BUF_SIZE
= 1000;
131 static sal_Char TraceFileNameBuffer
[BUF_SIZE
];
132 sal_Char Buffer
[BUF_SIZE
];
133 sal_Char VarNameBuffer
[BUF_SIZE
];
134 sal_Char ValBuffer
[BUF_SIZE
];
136 FILE* pFile
= fopen( pIniFileName
,"rb" );
140 size_t nRead
= fread( Buffer
, 1, BUF_SIZE
, pFile
);
144 char* pe
= Buffer
+ nRead
;
147 lcl_skipWhites( pc
); if( pc
== pe
) break;
150 char* pVarStart
= pc
;
151 while( pc
< pe
&& rtl::isAsciiAlpha( *pc
) )
153 int nVarLen
= pc
- pVarStart
;
156 lcl_findNextLine( pc
, pe
);
159 strncpy( VarNameBuffer
, pVarStart
, nVarLen
);
160 VarNameBuffer
[nVarLen
] = '\0';
163 lcl_skipWhites( pc
); if( pc
== pe
) break;
167 lcl_skipWhites( pc
); if( pc
== pe
) break;
170 char* pValStart
= pc
;
171 while( pc
< pe
&& *pc
!= 13 && *pc
!= 10 )
173 int nValLen
= pc
- pValStart
;
176 lcl_findNextLine( pc
, pe
);
179 strncpy( ValBuffer
, pValStart
, nValLen
);
180 ValBuffer
[nValLen
] = '\0';
183 if( strcmp( VarNameBuffer
, "GpTraceFileName") == 0 )
185 strcpy( TraceFileNameBuffer
, ValBuffer
);
186 GpTraceFileName
= TraceFileNameBuffer
;
189 if( strcmp( VarNameBuffer
, "GbTraceOn") == 0 )
190 GbTraceOn
= (strcmp( ValBuffer
, "true" ) == 0);
192 if( strcmp( VarNameBuffer
, "GbIncludePCodes") == 0 )
193 GbIncludePCodes
= (strcmp( ValBuffer
, "true" ) == 0);
195 if( strcmp( VarNameBuffer
, "GbInitOnlyAtOfficeStart") == 0 )
196 GbInitOnlyAtOfficeStart
= (strcmp( ValBuffer
, "true" ) == 0);
198 if( strcmp( VarNameBuffer
, "GnIndentPerCallLevel") == 0 )
199 GnIndentPerCallLevel
= strtol( ValBuffer
, NULL
, 10 );
201 if( strcmp( VarNameBuffer
, "GnIndentForPCode") == 0 )
202 GnIndentForPCode
= strtol( ValBuffer
, NULL
, 10 );
203 #ifdef DBG_TRACE_PROFILING
205 if( strcmp( VarNameBuffer
, "GbTimerOn") == 0 )
206 GbTimerOn
= (strcmp( ValBuffer
, "true" ) == 0);
208 if( strcmp( VarNameBuffer
, "GbTimeStampForEachStep") == 0 )
209 GbTimeStampForEachStep
= (strcmp( ValBuffer
, "true" ) == 0);
211 if( strcmp( VarNameBuffer
, "GbBlockAllAfterFirstFunctionUsage") == 0 )
212 GbBlockAllAfterFirstFunctionUsage
= (strcmp( ValBuffer
, "true" ) == 0);
214 if( strcmp( VarNameBuffer
, "GbBlockStepsAfterFirstFunctionUsage") == 0 )
215 GbBlockStepsAfterFirstFunctionUsage
= (strcmp( ValBuffer
, "true" ) == 0);
223 OString m_aTraceStr_STMNT
;
224 OString m_aTraceStr_PCode
;
226 typedef std::hash_map
< sal_Int32
, TraceTextData
> PCToTextDataMap
;
227 typedef std::hash_map
< OUString
, PCToTextDataMap
*, OUStringHash
, ::std::equal_to
< OUString
> > ModuleTraceMap
;
229 ModuleTraceMap GaModuleTraceMap
;
230 ModuleTraceMap
& rModuleTraceMap
= GaModuleTraceMap
;
232 static FILE* GpGlobalFile
= NULL
;
234 static void lcl_lineOut( const char* pStr
, const char* pPreStr
= NULL
, const char* pPostStr
= NULL
)
236 if( GpGlobalFile
!= NULL
)
238 fprintf( GpGlobalFile
, "%s%s%s\n", pPreStr
? pPreStr
: "", pStr
, pPostStr
? pPostStr
: "" );
239 fflush( GpGlobalFile
);
243 const char* lcl_getSpaces( int nSpaceCount
)
245 static const sal_Char Spaces
[] = " "
248 static const int nAvailableSpaceCount
= strlen( Spaces
);
249 static const sal_Char
* pSpacesEnd
= Spaces
+ nAvailableSpaceCount
;
251 if( nSpaceCount
> nAvailableSpaceCount
)
252 nSpaceCount
= nAvailableSpaceCount
;
254 return pSpacesEnd
- nSpaceCount
;
257 static OString
lcl_toOStringSkipLeadingWhites( const OUString
& aStr
)
259 OString aOStr
= OUStringToOString( OUString( aStr
), RTL_TEXTENCODING_ASCII_US
);
260 const sal_Char
* pStr
= aOStr
.getStr();
264 while( c
== ' ' || c
== '\t' )
270 OString
aORetStr( pStr
, strlen(pStr
) );
274 OUString
lcl_dumpMethodParameters( SbMethod
* pMethod
)
277 if( pMethod
== NULL
)
281 SbxError eOld
= SbxBase::GetError();
283 SbxArray
* pParams
= pMethod
->GetParameters();
284 SbxInfo
* pInfo
= pMethod
->GetInfo();
289 for ( sal_uInt16 nParam
= 1; nParam
< pParams
->Count(); nParam
++ )
291 SbxVariable
* pVar
= pParams
->Get( nParam
);
292 DBG_ASSERT( pVar
, "Parameter?!" );
293 if ( !pVar
->GetName().isEmpty() )
295 aStr
+= pVar
->GetName();
299 const SbxParamInfo
* pParam
= pInfo
->GetParam( nParam
);
302 aStr
+= pParam
->aName
;
306 SbxDataType eType
= pVar
->GetType();
307 if( eType
& SbxARRAY
)
311 else if( eType
!= SbxOBJECT
)
313 aStr
+= pVar
->GetString();
315 if ( nParam
< ( pParams
->Count() - 1 ) )
323 SbxBase::ResetError();
324 if( eOld
!= SbxERR_OK
)
326 SbxBase::SetError( eOld
);
333 static bool GbSavTraceOn
= false;
335 #ifdef DBG_TRACE_PROFILING
336 static canvas::tools::ElapsedTime
* GpTimer
= NULL
;
337 static double GdStartTime
= 0.0;
338 static double GdLastTime
= 0.0;
339 static bool GbBlockSteps
= false;
340 static bool GbBlockAll
= false;
344 OUString m_aCompleteFunctionName
;
352 : m_dTotalTime( 0.0 )
355 , m_bBlockAll( false )
356 , m_bBlockSteps( false )
359 typedef std::hash_map
< OUString
, FunctionItem
*, OUStringHash
, ::std::equal_to
< OUString
> > FunctionItemMap
;
361 static std::stack
< double > GaCallEnterTimeStack
;
362 static std::stack
< FunctionItem
* > GaFunctionItemStack
;
363 static FunctionItemMap GaFunctionItemMap
;
365 bool compareFunctionNetTime( FunctionItem
* p1
, FunctionItem
* p2
)
367 return (p1
->m_dNetTime
> p2
->m_dNetTime
);
370 void lcl_printTimeOutput()
372 // Overall time output
374 lcl_lineOut( "***** Time Output *****" );
375 char TimeBuffer
[500];
376 double dTotalTime
= GpTimer
->getElapsedTime() - GdStartTime
;
377 sprintf( TimeBuffer
, "Total execution time = %f ms", dTotalTime
*1000.0 );
378 lcl_lineOut( TimeBuffer
);
383 lcl_lineOut( "Functions:" );
385 std::vector
<FunctionItem
*> avFunctionItems
;
387 FunctionItemMap::iterator it
;
388 for( it
= GaFunctionItemMap
.begin() ; it
!= GaFunctionItemMap
.end() ; ++it
)
390 FunctionItem
* pFunctionItem
= it
->second
;
391 if( pFunctionItem
!= NULL
)
393 avFunctionItems
.push_back( pFunctionItem
);
397 std::sort( avFunctionItems
.begin(), avFunctionItems
.end(), compareFunctionNetTime
);
399 std::vector
<FunctionItem
*>::iterator itv
;
400 for( itv
= avFunctionItems
.begin() ; itv
!= avFunctionItems
.end() ; ++itv
)
402 FunctionItem
* pFunctionItem
= *itv
;
403 if( pFunctionItem
!= NULL
)
405 OUString aCompleteFunctionName
= pFunctionItem
->m_aCompleteFunctionName
;
406 OString aName
= OUStringToOString( aCompleteFunctionName
, RTL_TEXTENCODING_ASCII_US
);
407 int nNameLen
= aCompleteFunctionName
.getLength();
409 double dFctTotalTime
= pFunctionItem
->m_dTotalTime
;
410 double dFctNetTime
= pFunctionItem
->m_dNetTime
;
411 double dFctTotalTimePercent
= 100.0 * dFctTotalTime
/ dTotalTime
;
412 double dFctNetTimePercent
= 100.0 * dFctNetTime
/ dTotalTime
;
413 int nSpaceCount
= 30 - nNameLen
;
414 if( nSpaceCount
< 0 )
418 sprintf( TimeBuffer
, "%s:%sCalled %d times\t%f ms (%f%%) / net %f (%f%%) ms",
419 aName
.getStr(), lcl_getSpaces( nSpaceCount
), pFunctionItem
->m_nCallCount
,
420 dFctTotalTime
*1000.0, dFctTotalTimePercent
, dFctNetTime
*1000.0, dFctNetTimePercent
);
421 lcl_lineOut( TimeBuffer
);
429 static bool GbInitTraceAlreadyCalled
= false;
433 if( GbInitOnlyAtOfficeStart
&& GbInitTraceAlreadyCalled
)
435 #ifdef DBG_TRACE_PROFILING
438 GpTimer
->continueTimer();
441 GpGlobalFile
= fopen( GpTraceFileName
, "a+" );
444 GbInitTraceAlreadyCalled
= true;
446 if( const sal_Char
* pcIniFileName
= ::getenv( "OOO_BASICTRACEINI" ) )
448 lcl_ReadIniFile( pcIniFileName
);
450 else if( GpTraceIniFile
!= NULL
)
452 lcl_ReadIniFile( GpTraceIniFile
);
454 GpGlobalFile
= fopen( GpTraceFileName
, "w" );
455 GbSavTraceOn
= GbTraceOn
;
458 lcl_lineOut( "### Program started with trace off ###" );
460 #ifdef DBG_TRACE_PROFILING
461 GpTimer
= new canvas::tools::ElapsedTime();
462 GdStartTime
= GpTimer
->getElapsedTime();
463 GdLastTime
= GdStartTime
;
464 GbBlockSteps
= false;
469 void dbg_DeInitTrace()
471 GbTraceOn
= GbSavTraceOn
;
473 #ifdef DBG_TRACE_PROFILING
474 while( !GaCallEnterTimeStack
.empty() )
476 GaCallEnterTimeStack
.pop();
478 while( !GaFunctionItemStack
.empty() )
480 GaFunctionItemStack
.pop();
482 lcl_printTimeOutput();
484 for( FunctionItemMap::iterator it
= GaFunctionItemMap
.begin() ; it
!= GaFunctionItemMap
.end() ; ++it
)
488 GaFunctionItemMap
.clear();
492 fclose( GpGlobalFile
);
496 if( GbInitOnlyAtOfficeStart
)
500 GpTimer
->pauseTimer();
510 static sal_Int32 GnLastCallLvl
= 0;
512 void dbg_tracePrint( const OUString
& aStr
, sal_Int32 nCallLvl
, bool bCallLvlRelativeToCurrent
)
514 if( bCallLvlRelativeToCurrent
)
516 nCallLvl
+= GnLastCallLvl
;
518 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
519 lcl_lineOut( OUStringToOString( OUString( aStr
), RTL_TEXTENCODING_ASCII_US
).getStr(), lcl_getSpaces( nIndent
) );
522 void dbg_traceStep( SbModule
* pModule
, sal_uInt32 nPC
, sal_Int32 nCallLvl
)
528 #ifdef DBG_TRACE_PROFILING
529 if( GbBlockSteps
|| GbBlockAll
)
533 double dCurTime
= 0.0;
534 bool bPrintTimeStamp
= false;
537 GpTimer
->pauseTimer();
538 dCurTime
= GpTimer
->getElapsedTime();
539 bPrintTimeStamp
= GbTimeStampForEachStep
;
542 bool bPrintTimeStamp
= false;
545 GnLastCallLvl
= nCallLvl
;
547 SbModule
* pTraceMod
= pModule
;
548 if( pTraceMod
->ISA(SbClassModuleObject
) )
550 SbClassModuleObject
* pClassModuleObj
= (SbClassModuleObject
*)(SbxBase
*)pTraceMod
;
551 pTraceMod
= pClassModuleObj
->getClassModule();
554 OUString aModuleName
= pTraceMod
->GetName();
555 ModuleTraceMap::iterator it
= rModuleTraceMap
.find( aModuleName
);
556 if( it
== rModuleTraceMap
.end() )
558 OString aModuleNameStr
= OUStringToOString( OUString( aModuleName
), RTL_TEXTENCODING_ASCII_US
);
560 sprintf( Buffer
, "TRACE ERROR: Unknown module \"%s\"", aModuleNameStr
.getStr() );
561 lcl_lineOut( Buffer
);
565 PCToTextDataMap
* pInnerMap
= it
->second
;
566 if( pInnerMap
== NULL
)
568 lcl_lineOut( "TRACE INTERNAL ERROR: No inner map" );
572 PCToTextDataMap::iterator itInner
= pInnerMap
->find( nPC
);
573 if( itInner
== pInnerMap
->end() )
575 OString aModuleNameStr
= OUStringToOString( OUString( aModuleName
), RTL_TEXTENCODING_ASCII_US
);
577 sprintf( Buffer
, "TRACE ERROR: No info for PC = %d in module \"%s\"", (int)nPC
, aModuleNameStr
.getStr() );
578 lcl_lineOut( Buffer
);
582 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
584 const TraceTextData
& rTraceTextData
= itInner
->second
;
585 const OString
& rStr_STMNT
= rTraceTextData
.m_aTraceStr_STMNT
;
587 if( !rStr_STMNT
.isEmpty() )
591 char TimeBuffer
[200];
592 memset (TimeBuffer
, 0, size(TimeBuffer
));
593 #ifdef DBG_TRACE_PROFILING
594 if( bPrintTimeStamp
)
596 double dDiffTime
= dCurTime
- GdLastTime
;
597 GdLastTime
= dCurTime
;
598 sprintf( TimeBuffer
, "\t\t// Time = %f ms / += %f ms", dCurTime
*1000.0, dDiffTime
*1000.0 );
604 lcl_lineOut( rStr_STMNT
.getStr(), lcl_getSpaces( nIndent
),
605 (bPrintTimeStamp
&& !GbIncludePCodes
) ? TimeBuffer
: NULL
);
608 if( !GbIncludePCodes
)
610 #ifdef DBG_TRACE_PROFILING
613 GpTimer
->continueTimer();
619 nIndent
+= GnIndentForPCode
;
620 const OString
& rStr_PCode
= rTraceTextData
.m_aTraceStr_PCode
;
621 if( !rStr_PCode
.isEmpty() )
623 lcl_lineOut( rStr_PCode
.getStr(), lcl_getSpaces( nIndent
),
624 bPrintTimeStamp
? TimeBuffer
: NULL
);
627 #ifdef DBG_TRACE_PROFILING
630 GpTimer
->continueTimer();
636 void dbg_traceNotifyCall( SbModule
* pModule
, SbMethod
* pMethod
, sal_Int32 nCallLvl
, bool bLeave
)
643 #ifdef DBG_TRACE_PROFILING
644 double dCurTime
= 0.0;
645 double dExecutionTime
= 0.0;
648 dCurTime
= GpTimer
->getElapsedTime();
649 GpTimer
->pauseTimer();
653 GnLastCallLvl
= nCallLvl
;
655 SbModule
* pTraceMod
= pModule
;
656 SbClassModuleObject
* pClassModuleObj
= NULL
;
657 if( pTraceMod
->ISA(SbClassModuleObject
) )
659 pClassModuleObj
= (SbClassModuleObject
*)(SbxBase
*)pTraceMod
;
660 pTraceMod
= pClassModuleObj
->getClassModule();
663 OUString aCompleteFunctionName
= pTraceMod
->GetName();
664 if( pMethod
!= NULL
)
666 aCompleteFunctionName
+= "::";
667 OUString aMethodName
= pMethod
->GetName();
668 aCompleteFunctionName
+= aMethodName
;
672 aCompleteFunctionName
+= "/RunInit";
675 bool bOwnBlockSteps
= false;
676 #ifdef DBG_TRACE_PROFILING
677 bool bOwnBlockAll
= false;
678 FunctionItem
* pFunctionItem
= NULL
;
681 FunctionItemMap::iterator itFunctionItem
= GaFunctionItemMap
.find( aCompleteFunctionName
);
682 if( itFunctionItem
!= GaFunctionItemMap
.end() )
684 pFunctionItem
= itFunctionItem
->second
;
686 if( pFunctionItem
== NULL
)
688 DBG_ASSERT( !bLeave
, "No FunctionItem in leave!" );
690 pFunctionItem
= new FunctionItem();
691 pFunctionItem
->m_aCompleteFunctionName
= aCompleteFunctionName
;
692 GaFunctionItemMap
[ aCompleteFunctionName
] = pFunctionItem
;
694 else if( GbBlockAllAfterFirstFunctionUsage
&& !bLeave
)
696 pFunctionItem
->m_bBlockAll
= true;
698 else if( GbBlockStepsAfterFirstFunctionUsage
&& !bLeave
)
700 pFunctionItem
->m_bBlockSteps
= true;
705 bOwnBlockAll
= GbBlockAll
;
706 bOwnBlockSteps
= GbBlockSteps
;
708 GbBlockSteps
= false;
710 dExecutionTime
= dCurTime
- GaCallEnterTimeStack
.top();
711 GaCallEnterTimeStack
.pop();
713 pFunctionItem
->m_dTotalTime
+= dExecutionTime
;
714 pFunctionItem
->m_dNetTime
+= dExecutionTime
;
715 pFunctionItem
->m_nCallCount
++;
717 GaFunctionItemStack
.pop();
718 if( !GaFunctionItemStack
.empty() )
720 FunctionItem
* pParentItem
= GaFunctionItemStack
.top();
721 if( pParentItem
!= NULL
)
723 pParentItem
->m_dNetTime
-= dExecutionTime
;
725 GbBlockSteps
= pParentItem
->m_bBlockSteps
;
726 GbBlockAll
= pParentItem
->m_bBlockAll
;
732 GbBlockSteps
= bOwnBlockSteps
= pFunctionItem
->m_bBlockSteps
;
733 GbBlockAll
= bOwnBlockAll
= pFunctionItem
->m_bBlockAll
;
735 GaCallEnterTimeStack
.push( dCurTime
);
736 GaFunctionItemStack
.push( pFunctionItem
);
744 GpTimer
->continueTimer();
754 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
755 if( !bLeave
&& !bOwnBlockSteps
)
757 static const char* pSeparator
= "' ================================================================================";
759 lcl_lineOut( pSeparator
, lcl_getSpaces( nIndent
) );
765 if( !bOwnBlockSteps
)
767 lcl_lineOut( "}", lcl_getSpaces( nIndent
) );
775 if( !bLeave
|| !bOwnBlockSteps
)
777 aStr
+= aCompleteFunctionName
;
779 if( !bOwnBlockSteps
&& pClassModuleObj
!= NULL
)
782 aStr
+= pClassModuleObj
->GetName();
787 aStr
+= lcl_dumpMethodParameters( pMethod
);
789 const char* pPostStr
= NULL
;
790 #ifdef DBG_TRACE_PROFILING
791 char TimeBuffer
[200];
792 if( GbTimerOn
&& bLeave
)
794 sprintf( TimeBuffer
, " // Execution Time = %f ms", dExecutionTime
*1000.0 );
795 pPostStr
= TimeBuffer
;
798 lcl_lineOut( (!bLeave
|| !bOwnBlockSteps
) ? OUStringToOString( OUString( aStr
), RTL_TEXTENCODING_ASCII_US
).getStr() : "}",
799 lcl_getSpaces( nIndent
), pPostStr
);
802 lcl_lineOut( "{", lcl_getSpaces( nIndent
) );
804 if( bLeave
&& !bOwnBlockSteps
)
808 #ifdef DBG_TRACE_PROFILING
811 GpTimer
->continueTimer();
816 void dbg_traceNotifyError( SbError nTraceErr
, const OUString
& aTraceErrMsg
,
817 bool bTraceErrHandled
, sal_Int32 nCallLvl
)
823 #ifdef DBG_TRACE_PROFILING
824 if( GbBlockSteps
|| GbBlockAll
)
829 GnLastCallLvl
= nCallLvl
;
831 OString aOTraceErrMsg
= OUStringToOString( OUString( aTraceErrMsg
), RTL_TEXTENCODING_ASCII_US
);
834 const char* pHandledStr
= bTraceErrHandled
? " / HANDLED" : "";
835 sprintf( Buffer
, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr
, (int)nTraceErr
, aOTraceErrMsg
.getStr() );
836 int nIndent
= nCallLvl
* GnIndentPerCallLevel
;
837 lcl_lineOut( Buffer
, lcl_getSpaces( nIndent
) );
840 void dbg_RegisterTraceTextForPC( SbModule
* pModule
, sal_uInt32 nPC
,
841 const OUString
& aTraceStr_STMNT
, const OUString
& aTraceStr_PCode
)
843 OUString aModuleName
= pModule
->GetName();
844 ModuleTraceMap::iterator it
= rModuleTraceMap
.find( aModuleName
);
845 PCToTextDataMap
* pInnerMap
;
846 if( it
== rModuleTraceMap
.end() )
848 pInnerMap
= new PCToTextDataMap();
849 rModuleTraceMap
[ aModuleName
] = pInnerMap
;
853 pInnerMap
= it
->second
;
858 OString aOTraceStr_STMNT
= lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT
);
859 aData
.m_aTraceStr_STMNT
= aOTraceStr_STMNT
;
861 OString aOTraceStr_PCode
= lcl_toOStringSkipLeadingWhites( aTraceStr_PCode
);
862 aData
.m_aTraceStr_PCode
= aOTraceStr_PCode
;
864 (*pInnerMap
)[nPC
] = aData
;
867 void RTL_Impl_TraceCommand( StarBASIC
* pBasic
, SbxArray
& rPar
, sal_Bool bWrite
)
872 if ( rPar
.Count() < 2 )
874 StarBASIC::Error( SbERR_BAD_ARGUMENT
);
878 OUString aCommand
= rPar
.Get(1)->GetString();
880 if( aCommand
.equalsIngoreAsciiCase( "TraceOn" ) )
884 else if( aCommand
.equalsIngoreAsciiCase( "TraceOff" ) )
888 else if( aCommand
.equalsIngoreAsciiCase( "PCodeOn" ) )
890 GbIncludePCodes
= true;
892 else if( aCommand
.equalsIngoreAsciiCase( "PCodeOff" ) )
894 GbIncludePCodes
= false;
896 else if( aCommand
.equalsIngoreAsciiCase( "Print" ) )
898 if ( rPar
.Count() < 3 )
900 StarBASIC::Error( SbERR_BAD_ARGUMENT
);
904 SbxError eOld
= SbxBase::GetError();
905 if( eOld
!= SbxERR_OK
)
906 SbxBase::ResetError();
908 OUString aValStr
= rPar
.Get(2)->GetString();
909 SbxError eErr
= SbxBase::GetError();
910 if( eErr
!= SbxERR_OK
)
912 aValStr
= "<ERROR converting value to String>";
913 SbxBase::ResetError();
918 sprintf( Buffer
, "### TRACE_PRINT: %s ###", OUStringToOString( OUString( aValStr
), RTL_TEXTENCODING_ASCII_US
).getStr() );
919 int nIndent
= GnLastCallLvl
* GnIndentPerCallLevel
;
920 lcl_lineOut( Buffer
, lcl_getSpaces( nIndent
) );
922 if( eOld
!= SbxERR_OK
)
924 SbxBase::SetError( eOld
);
931 // This routine is defined here, so that the
932 // compiler can be loaded as a discrete segment.
934 bool SbModule::Compile()
938 StarBASIC
* pBasic
= PTR_CAST(StarBASIC
,GetParent());
941 SbxBase::ResetError();
943 SbModule
* pOld
= GetSbData()->pCompMod
;
944 GetSbData()->pCompMod
= this;
946 boost::scoped_ptr
<SbiParser
> pParser(new SbiParser( static_cast<StarBASIC
*>(GetParent()), this ));
947 while( pParser
->Parse() ) {}
948 if( !pParser
->GetErrors() )
949 pParser
->aGen
.Save();
951 // for the disassembler
953 pImage
->aOUSource
= aOUSource
;
955 GetSbData()->pCompMod
= pOld
;
957 // compiling a module, the module-global
958 // variables of all modules become invalid
959 bool bRet
= IsCompiled();
962 if( !this->ISA(SbObjModule
) )
963 pBasic
->ClearAllModuleVars();
964 RemoveVars(); // remove 'this' Modules variables
965 // clear all method statics
966 for( sal_uInt16 i
= 0; i
< pMethods
->Count(); i
++ )
968 SbMethod
* p
= PTR_CAST(SbMethod
,pMethods
->Get( i
) );
973 // #i31510 Init other libs only if Basic isn't running
974 if( GetSbData()->pInst
== NULL
)
976 SbxObject
* pParent_
= pBasic
->GetParent();
978 pBasic
= PTR_CAST(StarBASIC
,pParent_
);
980 pBasic
->ClearAllModuleVars();
986 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */