bump product version to 4.1.6.2
[LibreOffice.git] / basic / source / comp / sbcomp.cxx
blob20d5262aafb14df31d80a98742fd6d193fa749bb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
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>
22 #include "sbcomp.hxx"
23 #include "image.hxx"
24 #include <basic/sbobjmod.hxx>
25 #include <stdio.h>
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;
39 // GbTraceOn:
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;
45 // GbIncludePCodes:
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
79 #include <algorithm>
80 #include <stack>
81 #include "canvas/elapsedtime.hxx"
83 //*** Profiling ***
84 // GbTimerOn:
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;
105 #endif
108 static void lcl_skipWhites( char*& rpc )
110 while( *rpc == ' ' || *rpc == '\t' )
111 ++rpc;
114 inline void lcl_findNextLine( char*& rpc, char* pe )
116 // Find line end
117 while( rpc < pe && *rpc != 13 && *rpc != 10 )
118 ++rpc;
120 // Read all
121 while( rpc < pe && (*rpc == 13 || *rpc == 10) )
122 ++rpc;
125 inline bool lcl_isAlpha( char c )
127 bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
128 return bRet;
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" );
140 if( pFile == NULL )
141 return;
143 size_t nRead = fread( Buffer, 1, BUF_SIZE, pFile );
145 // Scan
146 char* pc = Buffer;
147 char* pe = Buffer + nRead;
148 while( pc < pe )
150 lcl_skipWhites( pc ); if( pc == pe ) break;
152 // Read variable
153 char* pVarStart = pc;
154 while( pc < pe && lcl_isAlpha( *pc ) )
155 ++pc;
156 int nVarLen = pc - pVarStart;
157 if( nVarLen == 0 )
159 lcl_findNextLine( pc, pe );
160 continue;
162 strncpy( VarNameBuffer, pVarStart, nVarLen );
163 VarNameBuffer[nVarLen] = '\0';
165 // Check =
166 lcl_skipWhites( pc ); if( pc == pe ) break;
167 if( *pc != '=' )
168 continue;
169 ++pc;
170 lcl_skipWhites( pc ); if( pc == pe ) break;
172 // Read value
173 char* pValStart = pc;
174 while( pc < pe && *pc != 13 && *pc != 10 )
175 ++pc;
176 int nValLen = pc - pValStart;
177 if( nValLen == 0 )
179 lcl_findNextLine( pc, pe );
180 continue;
182 strncpy( ValBuffer, pValStart, nValLen );
183 ValBuffer[nValLen] = '\0';
185 // Match variables
186 if( strcmp( VarNameBuffer, "GpTraceFileName") == 0 )
188 strcpy( TraceFileNameBuffer, ValBuffer );
189 GpTraceFileName = TraceFileNameBuffer;
191 else
192 if( strcmp( VarNameBuffer, "GbTraceOn") == 0 )
193 GbTraceOn = (strcmp( ValBuffer, "true" ) == 0);
194 else
195 if( strcmp( VarNameBuffer, "GbIncludePCodes") == 0 )
196 GbIncludePCodes = (strcmp( ValBuffer, "true" ) == 0);
197 else
198 if( strcmp( VarNameBuffer, "GbInitOnlyAtOfficeStart") == 0 )
199 GbInitOnlyAtOfficeStart = (strcmp( ValBuffer, "true" ) == 0);
200 else
201 if( strcmp( VarNameBuffer, "GnIndentPerCallLevel") == 0 )
202 GnIndentPerCallLevel = strtol( ValBuffer, NULL, 10 );
203 else
204 if( strcmp( VarNameBuffer, "GnIndentForPCode") == 0 )
205 GnIndentForPCode = strtol( ValBuffer, NULL, 10 );
206 #ifdef DBG_TRACE_PROFILING
207 else
208 if( strcmp( VarNameBuffer, "GbTimerOn") == 0 )
209 GbTimerOn = (strcmp( ValBuffer, "true" ) == 0);
210 else
211 if( strcmp( VarNameBuffer, "GbTimeStampForEachStep") == 0 )
212 GbTimeStampForEachStep = (strcmp( ValBuffer, "true" ) == 0);
213 else
214 if( strcmp( VarNameBuffer, "GbBlockAllAfterFirstFunctionUsage") == 0 )
215 GbBlockAllAfterFirstFunctionUsage = (strcmp( ValBuffer, "true" ) == 0);
216 else
217 if( strcmp( VarNameBuffer, "GbBlockStepsAfterFirstFunctionUsage") == 0 )
218 GbBlockStepsAfterFirstFunctionUsage = (strcmp( ValBuffer, "true" ) == 0);
219 #endif
221 fclose( pFile );
224 struct TraceTextData
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[] = " "
250 " ";
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();
267 // Skip whitespace
268 sal_Char c = *pStr;
269 while( c == ' ' || c == '\t' )
271 pStr++;
272 c = *pStr;
275 int nLen = strlen( pStr );
276 strncpy( Buffer, pStr, nLen );
277 Buffer[nLen] = 0;
279 OString aORetStr( Buffer );
280 return aORetStr;
283 String lcl_dumpMethodParameters( SbMethod* pMethod )
285 OUString aStr;
286 if( pMethod == NULL )
288 return aStr;
290 SbxError eOld = SbxBase::GetError();
292 SbxArray* pParams = pMethod->GetParameters();
293 SbxInfo* pInfo = pMethod->GetInfo();
294 if ( pParams )
296 aStr += '(';
297 // 0 is sub itself
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();
306 else if ( pInfo )
308 const SbxParamInfo* pParam = pInfo->GetParam( nParam );
309 if ( pParam )
311 aStr += pParam->aName;
314 aStr += '=';
315 SbxDataType eType = pVar->GetType();
316 if( eType & SbxARRAY )
318 aStr += "...";
320 else if( eType != SbxOBJECT )
322 aStr += pVar->GetString();
324 if ( nParam < ( pParams->Count() - 1 ) )
326 aStr += ", ";
329 aStr += ')';
332 SbxBase::ResetError();
333 if( eOld != SbxERR_OK )
335 SbxBase::SetError( eOld );
337 return aStr;
341 // Public functions
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;
351 struct FunctionItem
353 OUString m_aCompleteFunctionName;
354 double m_dTotalTime;
355 double m_dNetTime;
356 int m_nCallCount;
357 bool m_bBlockAll;
358 bool m_bBlockSteps;
360 FunctionItem( void )
361 : m_dTotalTime( 0.0 )
362 , m_dNetTime( 0.0 )
363 , m_nCallCount( 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
382 lcl_lineOut( "" );
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 );
388 lcl_lineOut( "" );
390 if( GbTimerOn )
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 )
425 nSpaceCount = 2;
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 );
435 #endif
438 static bool GbInitTraceAlreadyCalled = false;
440 void dbg_InitTrace( void )
442 if( GbInitOnlyAtOfficeStart && GbInitTraceAlreadyCalled )
444 #ifdef DBG_TRACE_PROFILING
445 if( GbTimerOn )
447 GpTimer->continueTimer();
449 #endif
450 GpGlobalFile = fopen( GpTraceFileName, "a+" );
451 return;
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;
465 if( !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;
474 GbBlockAll = false;
475 #endif
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 )
495 delete it->second;
497 GaFunctionItemMap.clear();
499 if( GpGlobalFile )
501 fclose( GpGlobalFile );
502 GpGlobalFile = NULL;
505 if( GbInitOnlyAtOfficeStart )
507 if( GbTimerOn )
509 GpTimer->pauseTimer();
512 else
514 delete GpTimer;
516 #endif
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 )
533 if( !GbTraceOn )
535 return;
537 #ifdef DBG_TRACE_PROFILING
538 if( GbBlockSteps || GbBlockAll )
540 return;
542 double dCurTime = 0.0;
543 bool bPrintTimeStamp = false;
544 if( GbTimerOn )
546 GpTimer->pauseTimer();
547 dCurTime = GpTimer->getElapsedTime();
548 bPrintTimeStamp = GbTimeStampForEachStep;
550 #else
551 bool bPrintTimeStamp = false;
552 #endif
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();
568 char Buffer[200];
569 sprintf( Buffer, "TRACE ERROR: Unknown module \"%s\"", pModuleNameStr );
570 lcl_lineOut( Buffer );
571 return;
574 PCToTextDataMap* pInnerMap = it->second;
575 if( pInnerMap == NULL )
577 lcl_lineOut( "TRACE INTERNAL ERROR: No inner map" );
578 return;
581 PCToTextDataMap::iterator itInner = pInnerMap->find( nPC );
582 if( itInner == pInnerMap->end() )
584 const char* pModuleNameStr = OUStringToOString( OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
585 char Buffer[200];
586 sprintf( Buffer, "TRACE ERROR: No info for PC = %d in module \"%s\"", (int)nPC, pModuleNameStr );
587 lcl_lineOut( Buffer );
588 return;
591 int nIndent = nCallLvl * GnIndentPerCallLevel;
593 const TraceTextData& rTraceTextData = itInner->second;
594 const OString& rStr_STMNT = rTraceTextData.m_aTraceStr_STMNT;
595 bool bSTMT = false;
596 if( rStr_STMNT.getLength() )
598 bSTMT = true;
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 );
609 #endif
611 if( bSTMT )
613 lcl_lineOut( rStr_STMNT.getStr(), lcl_getSpaces( nIndent ),
614 (bPrintTimeStamp && !GbIncludePCodes) ? TimeBuffer : NULL );
617 if( !GbIncludePCodes )
619 #ifdef DBG_TRACE_PROFILING
620 if( GbTimerOn )
622 GpTimer->continueTimer();
624 #endif
625 return;
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
637 if( GbTimerOn )
639 GpTimer->continueTimer();
641 #endif
645 void dbg_traceNotifyCall( SbModule* pModule, SbMethod* pMethod, sal_Int32 nCallLvl, bool bLeave )
648 if( !GbTraceOn )
650 return;
652 #ifdef DBG_TRACE_PROFILING
653 double dCurTime = 0.0;
654 double dExecutionTime = 0.0;
655 if( GbTimerOn )
657 dCurTime = GpTimer->getElapsedTime();
658 GpTimer->pauseTimer();
660 #endif
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;
679 else
681 aCompleteFunctionName += "/RunInit";
684 bool bOwnBlockSteps = false;
685 #ifdef DBG_TRACE_PROFILING
686 bool bOwnBlockAll = false;
687 FunctionItem* pFunctionItem = NULL;
688 if( GbTimerOn )
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;
712 if( bLeave )
714 bOwnBlockAll = GbBlockAll;
715 bOwnBlockSteps = GbBlockSteps;
716 GbBlockAll = false;
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;
739 else
741 GbBlockSteps = bOwnBlockSteps = pFunctionItem->m_bBlockSteps;
742 GbBlockAll = bOwnBlockAll = pFunctionItem->m_bBlockAll;
744 GaCallEnterTimeStack.push( dCurTime );
745 GaFunctionItemStack.push( pFunctionItem );
749 if( bOwnBlockAll )
751 if( GbTimerOn )
753 GpTimer->continueTimer();
755 return;
757 #endif
759 if( nCallLvl > 0 )
761 nCallLvl--;
763 int nIndent = nCallLvl * GnIndentPerCallLevel;
764 if( !bLeave && !bOwnBlockSteps )
766 static const char* pSeparator = "' ================================================================================";
767 lcl_lineOut( "" );
768 lcl_lineOut( pSeparator, lcl_getSpaces( nIndent ) );
771 OUString aStr;
772 if( bLeave )
774 if( !bOwnBlockSteps )
776 lcl_lineOut( "}", lcl_getSpaces( nIndent ) );
777 aStr = "' Leaving ";
780 else
782 aStr = "Entering " ;
784 if( !bLeave || !bOwnBlockSteps )
786 aStr += aCompleteFunctionName;
788 if( !bOwnBlockSteps && pClassModuleObj != NULL )
790 aStr += "[this=";
791 aStr += pClassModuleObj->GetName();
792 aStr += "]" ;
794 if( !bLeave )
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;
806 #endif
807 lcl_lineOut( (!bLeave || !bOwnBlockSteps) ? OUStringToOString( OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr() : "}",
808 lcl_getSpaces( nIndent ), pPostStr );
809 if( !bLeave )
811 lcl_lineOut( "{", lcl_getSpaces( nIndent ) );
813 if( bLeave && !bOwnBlockSteps )
815 lcl_lineOut( "" );
817 #ifdef DBG_TRACE_PROFILING
818 if( GbTimerOn )
820 GpTimer->continueTimer();
822 #endif
825 void dbg_traceNotifyError( SbError nTraceErr, const OUString& aTraceErrMsg,
826 bool bTraceErrHandled, sal_Int32 nCallLvl )
828 if( !GbTraceOn )
830 return;
832 #ifdef DBG_TRACE_PROFILING
833 if( GbBlockSteps || GbBlockAll )
835 return;
837 #endif
838 GnLastCallLvl = nCallLvl;
840 OString aOTraceErrMsg = OUStringToOString( OUString( aTraceErrMsg ), RTL_TEXTENCODING_ASCII_US );
842 char Buffer[200];
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;
860 else
862 pInnerMap = it->second;
865 TraceTextData aData;
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 )
878 (void)pBasic;
879 (void)bWrite;
881 if ( rPar.Count() < 2 )
883 StarBASIC::Error( SbERR_BAD_ARGUMENT );
884 return;
887 OUString aCommand = rPar.Get(1)->GetString();
889 if( aCommand.equalsIngoreAsciiCase( "TraceOn" ) )
891 GbTraceOn = true;
893 else if( aCommand.equalsIngoreAsciiCase( "TraceOff" ) )
895 GbTraceOn = false;
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 );
910 return;
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();
925 char Buffer[500];
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 );
939 #endif
941 // This routine is defined here, so that the
942 // compiler can be loaded as a discrete segment.
944 sal_Bool SbModule::Compile()
946 if( pImage )
947 return sal_True;
948 StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
949 if( !pBasic )
950 return sal_False;
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();
960 delete pParser;
961 // for the disassembler
962 if( pImage )
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();
970 if( bRet )
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 ) );
979 if( p )
980 p->ClearStatics();
983 // #i31510 Init other libs only if Basic isn't running
984 if( GetSbData()->pInst == NULL )
986 SbxObject* pParent_ = pBasic->GetParent();
987 if( pParent_ )
988 pBasic = PTR_CAST(StarBASIC,pParent_);
989 if( pBasic )
990 pBasic->ClearAllModuleVars();
994 return bRet;
997 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */