Branch data Line data Source code
1 : : /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 : : /*
3 : : * This file is part of the LibreOffice project.
4 : : *
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/.
8 : : *
9 : : * This file incorporates work covered by the following license notice:
10 : : *
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 .
18 : : */
19 : :
20 : :
21 : : #include <basic/sbx.hxx>
22 : : #include "sbcomp.hxx"
23 : : #include "image.hxx"
24 : : #include <basic/sbobjmod.hxx>
25 : : #include <stdio.h>
26 : :
27 : : // To activate tracing enable in sbtrace.hxx
28 : : #ifdef DBG_TRACE_BASIC
29 : :
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;
34 : :
35 : : // Trace Settings, used if no ini file / not found in ini file
36 : : static char GpTraceFileNameDefault[] = "~/BasicTrace.txt";
37 : : static char* GpTraceFileName = GpTraceFileNameDefault;
38 : :
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;
44 : :
45 : : // GbIncludePCodes:
46 : : // true = PCodes are written to trace, default = false, correspondents
47 : : // with TraceCommand( "PCodeOn" / "PCodeOff" ), see below
48 : : static bool GbIncludePCodes = false;
49 : :
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;
55 : :
56 : : static int GnIndentPerCallLevel = 4;
57 : : static int GnIndentForPCode = 2;
58 : :
59 : : /*
60 : : With trace enabled the runtime function TraceCommand
61 : : can be used to influence the trace functionality
62 : : from within the running Basic macro.
63 : :
64 : : Format: TraceCommand( command as String [, param as Variant] )
65 : :
66 : : Supported commands (command is NOT case sensitive):
67 : : TraceCommand "TraceOn" sets GbTraceOn = true
68 : : TraceCommand "TraceOff" sets GbTraceOn = false
69 : :
70 : : TraceCommand "PCodeOn" sets GbIncludePCodes = true
71 : : TraceCommand "PCodeOff" sets GbIncludePCodes = false
72 : :
73 : : TraceCommand "Print", aVal writes aVal into the trace file as
74 : : long as it can be converted to string
75 : : */
76 : :
77 : : #ifdef DBG_TRACE_PROFILING
78 : :
79 : : #include <algorithm>
80 : : #include <stack>
81 : : #include "canvas/elapsedtime.hxx"
82 : :
83 : : //*** Profiling ***
84 : : // GbTimerOn:
85 : : // true = including time stamps
86 : : static bool GbTimerOn = true;
87 : :
88 : : // GbTimeStampForEachStep:
89 : : // true = prints time stamp after each command / pcode (very slow)
90 : : static bool GbTimeStampForEachStep = false;
91 : :
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;
97 : :
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;
104 : :
105 : : #endif
106 : :
107 : :
108 : : static void lcl_skipWhites( char*& rpc )
109 : : {
110 : : while( *rpc == ' ' || *rpc == '\t' )
111 : : ++rpc;
112 : : }
113 : :
114 : : inline void lcl_findNextLine( char*& rpc, char* pe )
115 : : {
116 : : // Find line end
117 : : while( rpc < pe && *rpc != 13 && *rpc != 10 )
118 : : ++rpc;
119 : :
120 : : // Read all
121 : : while( rpc < pe && (*rpc == 13 || *rpc == 10) )
122 : : ++rpc;
123 : : }
124 : :
125 : : inline bool lcl_isAlpha( char c )
126 : : {
127 : : bool bRet = (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z');
128 : : return bRet;
129 : : }
130 : :
131 : : static void lcl_ReadIniFile( const char* pIniFileName )
132 : : {
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];
138 : :
139 : : FILE* pFile = fopen( pIniFileName ,"rb" );
140 : : if( pFile == NULL )
141 : : return;
142 : :
143 : : size_t nRead = fread( Buffer, 1, BUF_SIZE, pFile );
144 : :
145 : : // Scan
146 : : char* pc = Buffer;
147 : : char* pe = Buffer + nRead;
148 : : while( pc < pe )
149 : : {
150 : : lcl_skipWhites( pc ); if( pc == pe ) break;
151 : :
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 )
158 : : {
159 : : lcl_findNextLine( pc, pe );
160 : : continue;
161 : : }
162 : : strncpy( VarNameBuffer, pVarStart, nVarLen );
163 : : VarNameBuffer[nVarLen] = '\0';
164 : :
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;
171 : :
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 )
178 : : {
179 : : lcl_findNextLine( pc, pe );
180 : : continue;
181 : : }
182 : : strncpy( ValBuffer, pValStart, nValLen );
183 : : ValBuffer[nValLen] = '\0';
184 : :
185 : : // Match variables
186 : : if( strcmp( VarNameBuffer, "GpTraceFileName") == 0 )
187 : : {
188 : : strcpy( TraceFileNameBuffer, ValBuffer );
189 : : GpTraceFileName = TraceFileNameBuffer;
190 : : }
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
220 : : }
221 : : fclose( pFile );
222 : : }
223 : :
224 : : struct TraceTextData
225 : : {
226 : : rtl::OString m_aTraceStr_STMNT;
227 : : rtl::OString m_aTraceStr_PCode;
228 : : };
229 : : typedef std::hash_map< sal_Int32, TraceTextData > PCToTextDataMap;
230 : : typedef std::hash_map< ::rtl::OUString, PCToTextDataMap*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > ModuleTraceMap;
231 : :
232 : : ModuleTraceMap GaModuleTraceMap;
233 : : ModuleTraceMap& rModuleTraceMap = GaModuleTraceMap;
234 : :
235 : : static FILE* GpGlobalFile = NULL;
236 : :
237 : : static void lcl_lineOut( const char* pStr, const char* pPreStr = NULL, const char* pPostStr = NULL )
238 : : {
239 : : if( GpGlobalFile != NULL )
240 : : {
241 : : fprintf( GpGlobalFile, "%s%s%s\n", pPreStr ? pPreStr : "", pStr, pPostStr ? pPostStr : "" );
242 : : fflush( GpGlobalFile );
243 : : }
244 : : }
245 : :
246 : : const char* lcl_getSpaces( int nSpaceCount )
247 : : {
248 : : static sal_Char Spaces[] = " "
249 : : " "
250 : : " ";
251 : : static int nAvailableSpaceCount = strlen( Spaces );
252 : : static sal_Char* pSpacesEnd = Spaces + nAvailableSpaceCount;
253 : :
254 : : if( nSpaceCount > nAvailableSpaceCount )
255 : : nSpaceCount = nAvailableSpaceCount;
256 : :
257 : : return pSpacesEnd - nSpaceCount;
258 : : }
259 : :
260 : : static rtl::OString lcl_toOStringSkipLeadingWhites( const String& aStr )
261 : : {
262 : : static sal_Char Buffer[1000];
263 : :
264 : : rtl::OString aOStr = OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US );
265 : : const sal_Char* pStr = aOStr.getStr();
266 : :
267 : : // Skip whitespace
268 : : sal_Char c = *pStr;
269 : : while( c == ' ' || c == '\t' )
270 : : {
271 : : pStr++;
272 : : c = *pStr;
273 : : }
274 : :
275 : : int nLen = strlen( pStr );
276 : : strncpy( Buffer, pStr, nLen );
277 : : Buffer[nLen] = 0;
278 : :
279 : : rtl::OString aORetStr( Buffer );
280 : : return aORetStr;
281 : : }
282 : :
283 : : String lcl_dumpMethodParameters( SbMethod* pMethod )
284 : : {
285 : : String aStr;
286 : : if( pMethod == NULL )
287 : : return aStr;
288 : :
289 : : SbxError eOld = SbxBase::GetError();
290 : :
291 : : SbxArray* pParams = pMethod->GetParameters();
292 : : SbxInfo* pInfo = pMethod->GetInfo();
293 : : if ( pParams )
294 : : {
295 : : aStr += '(';
296 : : // 0 is sub itself
297 : : for ( sal_uInt16 nParam = 1; nParam < pParams->Count(); nParam++ )
298 : : {
299 : : SbxVariable* pVar = pParams->Get( nParam );
300 : : DBG_ASSERT( pVar, "Parameter?!" );
301 : : if ( pVar->GetName().Len() )
302 : : aStr += pVar->GetName();
303 : : else if ( pInfo )
304 : : {
305 : : const SbxParamInfo* pParam = pInfo->GetParam( nParam );
306 : : if ( pParam )
307 : : aStr += pParam->aName;
308 : : }
309 : : aStr += '=';
310 : : SbxDataType eType = pVar->GetType();
311 : : if( eType & SbxARRAY )
312 : : aStr += String( RTL_CONSTASCII_USTRINGPARAM( "..." ) );
313 : : else if( eType != SbxOBJECT )
314 : : aStr += pVar->GetString();
315 : : if ( nParam < ( pParams->Count() - 1 ) )
316 : : aStr += String( RTL_CONSTASCII_USTRINGPARAM( ", " ) );
317 : : }
318 : : aStr += ')';
319 : : }
320 : :
321 : : SbxBase::ResetError();
322 : : if( eOld != SbxERR_OK )
323 : : SbxBase::SetError( eOld );
324 : :
325 : : return aStr;
326 : : }
327 : :
328 : :
329 : : // Public functions
330 : : static bool GbSavTraceOn = false;
331 : :
332 : : #ifdef DBG_TRACE_PROFILING
333 : : static canvas::tools::ElapsedTime* GpTimer = NULL;
334 : : static double GdStartTime = 0.0;
335 : : static double GdLastTime = 0.0;
336 : : static bool GbBlockSteps = false;
337 : : static bool GbBlockAll = false;
338 : :
339 : : struct FunctionItem
340 : : {
341 : : String m_aCompleteFunctionName;
342 : : double m_dTotalTime;
343 : : double m_dNetTime;
344 : : int m_nCallCount;
345 : : bool m_bBlockAll;
346 : : bool m_bBlockSteps;
347 : :
348 : : FunctionItem( void )
349 : : : m_dTotalTime( 0.0 )
350 : : , m_dNetTime( 0.0 )
351 : : , m_nCallCount( 0 )
352 : : , m_bBlockAll( false )
353 : : , m_bBlockSteps( false )
354 : : {}
355 : : };
356 : : typedef std::hash_map< ::rtl::OUString, FunctionItem*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > FunctionItemMap;
357 : :
358 : : static std::stack< double > GaCallEnterTimeStack;
359 : : static std::stack< FunctionItem* > GaFunctionItemStack;
360 : : static FunctionItemMap GaFunctionItemMap;
361 : :
362 : : bool compareFunctionNetTime( FunctionItem* p1, FunctionItem* p2 )
363 : : {
364 : : return (p1->m_dNetTime > p2->m_dNetTime);
365 : : }
366 : :
367 : : void lcl_printTimeOutput( void )
368 : : {
369 : : // Overall time output
370 : : lcl_lineOut( "" );
371 : : lcl_lineOut( "***** Time Output *****" );
372 : : char TimeBuffer[500];
373 : : double dTotalTime = GpTimer->getElapsedTime() - GdStartTime;
374 : : sprintf( TimeBuffer, "Total execution time = %f ms", dTotalTime*1000.0 );
375 : : lcl_lineOut( TimeBuffer );
376 : : lcl_lineOut( "" );
377 : :
378 : : if( GbTimerOn )
379 : : {
380 : : lcl_lineOut( "Functions:" );
381 : :
382 : : std::vector<FunctionItem*> avFunctionItems;
383 : :
384 : : FunctionItemMap::iterator it;
385 : : for( it = GaFunctionItemMap.begin() ; it != GaFunctionItemMap.end() ; ++it )
386 : : {
387 : : FunctionItem* pFunctionItem = it->second;
388 : : if( pFunctionItem != NULL )
389 : : avFunctionItems.push_back( pFunctionItem );
390 : : }
391 : :
392 : : std::sort( avFunctionItems.begin(), avFunctionItems.end(), compareFunctionNetTime );
393 : :
394 : : std::vector<FunctionItem*>::iterator itv;
395 : : for( itv = avFunctionItems.begin() ; itv != avFunctionItems.end() ; ++itv )
396 : : {
397 : : FunctionItem* pFunctionItem = *itv;
398 : : if( pFunctionItem != NULL )
399 : : {
400 : : rtl::OUString aCompleteFunctionName = pFunctionItem->m_aCompleteFunctionName;
401 : : const char* pName = OUStringToOString( aCompleteFunctionName, RTL_TEXTENCODING_ASCII_US ).getStr();
402 : : int nNameLen = aCompleteFunctionName.getLength();
403 : :
404 : : double dFctTotalTime = pFunctionItem->m_dTotalTime;
405 : : double dFctNetTime = pFunctionItem->m_dNetTime;
406 : : double dFctTotalTimePercent = 100.0 * dFctTotalTime / dTotalTime;
407 : : double dFctNetTimePercent = 100.0 * dFctNetTime / dTotalTime;
408 : : int nSpaceCount = 30 - nNameLen;
409 : : if( nSpaceCount < 0 )
410 : : nSpaceCount = 2;
411 : : sprintf( TimeBuffer, "%s:%sCalled %d times\t%f ms (%f%%) / net %f (%f%%) ms",
412 : : pName, lcl_getSpaces( nSpaceCount ), pFunctionItem->m_nCallCount,
413 : : dFctTotalTime*1000.0, dFctTotalTimePercent, dFctNetTime*1000.0, dFctNetTimePercent );
414 : : lcl_lineOut( TimeBuffer );
415 : : }
416 : : }
417 : : }
418 : : }
419 : : #endif
420 : :
421 : :
422 : : static bool GbInitTraceAlreadyCalled = false;
423 : :
424 : : void dbg_InitTrace( void )
425 : : {
426 : : if( GbInitOnlyAtOfficeStart && GbInitTraceAlreadyCalled )
427 : : {
428 : : #ifdef DBG_TRACE_PROFILING
429 : : if( GbTimerOn )
430 : : GpTimer->continueTimer();
431 : : #endif
432 : : GpGlobalFile = fopen( GpTraceFileName, "a+" );
433 : : return;
434 : : }
435 : : GbInitTraceAlreadyCalled = true;
436 : :
437 : : if( const sal_Char* pcIniFileName = ::getenv( "OOO_BASICTRACEINI" ) )
438 : : lcl_ReadIniFile( pcIniFileName );
439 : : else if( GpTraceIniFile != NULL )
440 : : lcl_ReadIniFile( GpTraceIniFile );
441 : :
442 : : GpGlobalFile = fopen( GpTraceFileName, "w" );
443 : : GbSavTraceOn = GbTraceOn;
444 : : if( !GbTraceOn )
445 : : lcl_lineOut( "### Program started with trace off ###" );
446 : :
447 : : #ifdef DBG_TRACE_PROFILING
448 : : GpTimer = new canvas::tools::ElapsedTime();
449 : : GdStartTime = GpTimer->getElapsedTime();
450 : : GdLastTime = GdStartTime;
451 : : GbBlockSteps = false;
452 : : GbBlockAll = false;
453 : : #endif
454 : : }
455 : :
456 : : void dbg_DeInitTrace( void )
457 : : {
458 : : GbTraceOn = GbSavTraceOn;
459 : :
460 : : #ifdef DBG_TRACE_PROFILING
461 : : while( !GaCallEnterTimeStack.empty() )
462 : : GaCallEnterTimeStack.pop();
463 : : while( !GaFunctionItemStack.empty() )
464 : : GaFunctionItemStack.pop();
465 : :
466 : : lcl_printTimeOutput();
467 : :
468 : : for( FunctionItemMap::iterator it = GaFunctionItemMap.begin() ; it != GaFunctionItemMap.end() ; ++it )
469 : : delete it->second;
470 : : GaFunctionItemMap.clear();
471 : :
472 : : if( GpGlobalFile )
473 : : {
474 : : fclose( GpGlobalFile );
475 : : GpGlobalFile = NULL;
476 : : }
477 : :
478 : : if( GbInitOnlyAtOfficeStart )
479 : : {
480 : : if( GbTimerOn )
481 : : GpTimer->pauseTimer();
482 : : }
483 : : else
484 : : {
485 : : delete GpTimer;
486 : : }
487 : : #endif
488 : : }
489 : :
490 : : static sal_Int32 GnLastCallLvl = 0;
491 : :
492 : : void dbg_tracePrint( const String& aStr, sal_Int32 nCallLvl, bool bCallLvlRelativeToCurrent )
493 : : {
494 : : if( bCallLvlRelativeToCurrent )
495 : : nCallLvl += GnLastCallLvl;
496 : :
497 : : int nIndent = nCallLvl * GnIndentPerCallLevel;
498 : : lcl_lineOut( OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr(), lcl_getSpaces( nIndent ) );
499 : : }
500 : :
501 : : void dbg_traceStep( SbModule* pModule, sal_uInt32 nPC, sal_Int32 nCallLvl )
502 : : {
503 : : if( !GbTraceOn )
504 : : return;
505 : :
506 : : #ifdef DBG_TRACE_PROFILING
507 : : if( GbBlockSteps || GbBlockAll )
508 : : return;
509 : :
510 : : double dCurTime = 0.0;
511 : : bool bPrintTimeStamp = false;
512 : : if( GbTimerOn )
513 : : {
514 : : GpTimer->pauseTimer();
515 : : dCurTime = GpTimer->getElapsedTime();
516 : : bPrintTimeStamp = GbTimeStampForEachStep;
517 : : }
518 : : #else
519 : : bool bPrintTimeStamp = false;
520 : : #endif
521 : :
522 : : GnLastCallLvl = nCallLvl;
523 : :
524 : : SbModule* pTraceMod = pModule;
525 : : if( pTraceMod->ISA(SbClassModuleObject) )
526 : : {
527 : : SbClassModuleObject* pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
528 : : pTraceMod = pClassModuleObj->getClassModule();
529 : : }
530 : :
531 : : String aModuleName = pTraceMod->GetName();
532 : : ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
533 : : if( it == rModuleTraceMap.end() )
534 : : {
535 : : const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
536 : : char Buffer[200];
537 : : sprintf( Buffer, "TRACE ERROR: Unknown module \"%s\"", pModuleNameStr );
538 : : lcl_lineOut( Buffer );
539 : : return;
540 : : }
541 : :
542 : : PCToTextDataMap* pInnerMap = it->second;
543 : : if( pInnerMap == NULL )
544 : : {
545 : : lcl_lineOut( "TRACE INTERNAL ERROR: No inner map" );
546 : : return;
547 : : }
548 : :
549 : : PCToTextDataMap::iterator itInner = pInnerMap->find( nPC );
550 : : if( itInner == pInnerMap->end() )
551 : : {
552 : : const char* pModuleNameStr = OUStringToOString( rtl::OUString( aModuleName ), RTL_TEXTENCODING_ASCII_US ).getStr();
553 : : char Buffer[200];
554 : : sprintf( Buffer, "TRACE ERROR: No info for PC = %d in module \"%s\"", (int)nPC, pModuleNameStr );
555 : : lcl_lineOut( Buffer );
556 : : return;
557 : : }
558 : :
559 : : int nIndent = nCallLvl * GnIndentPerCallLevel;
560 : :
561 : : const TraceTextData& rTraceTextData = itInner->second;
562 : : const rtl::OString& rStr_STMNT = rTraceTextData.m_aTraceStr_STMNT;
563 : : bool bSTMT = false;
564 : : if( rStr_STMNT.getLength() )
565 : : bSTMT = true;
566 : :
567 : : char TimeBuffer[200];
568 : : #ifdef DBG_TRACE_PROFILING
569 : : if( bPrintTimeStamp )
570 : : {
571 : : double dDiffTime = dCurTime - GdLastTime;
572 : : GdLastTime = dCurTime;
573 : : sprintf( TimeBuffer, "\t\t// Time = %f ms / += %f ms", dCurTime*1000.0, dDiffTime*1000.0 );
574 : : }
575 : : #endif
576 : :
577 : : if( bSTMT )
578 : : {
579 : : lcl_lineOut( rStr_STMNT.getStr(), lcl_getSpaces( nIndent ),
580 : : (bPrintTimeStamp && !GbIncludePCodes) ? TimeBuffer : NULL );
581 : : }
582 : :
583 : : if( !GbIncludePCodes )
584 : : {
585 : : #ifdef DBG_TRACE_PROFILING
586 : : if( GbTimerOn )
587 : : GpTimer->continueTimer();
588 : : #endif
589 : : return;
590 : : }
591 : :
592 : : nIndent += GnIndentForPCode;
593 : : const rtl::OString& rStr_PCode = rTraceTextData.m_aTraceStr_PCode;
594 : : if( rStr_PCode.getLength() )
595 : : {
596 : : lcl_lineOut( rStr_PCode.getStr(), lcl_getSpaces( nIndent ),
597 : : bPrintTimeStamp ? TimeBuffer : NULL );
598 : : }
599 : :
600 : : #ifdef DBG_TRACE_PROFILING
601 : : if( GbTimerOn )
602 : : GpTimer->continueTimer();
603 : : #endif
604 : : }
605 : :
606 : :
607 : : void dbg_traceNotifyCall( SbModule* pModule, SbMethod* pMethod, sal_Int32 nCallLvl, bool bLeave )
608 : : {
609 : : static const char* pSeparator = "' ================================================================================";
610 : :
611 : : if( !GbTraceOn )
612 : : return;
613 : :
614 : : #ifdef DBG_TRACE_PROFILING
615 : : double dCurTime = 0.0;
616 : : double dExecutionTime = 0.0;
617 : : if( GbTimerOn )
618 : : {
619 : : dCurTime = GpTimer->getElapsedTime();
620 : : GpTimer->pauseTimer();
621 : : }
622 : : #endif
623 : :
624 : : GnLastCallLvl = nCallLvl;
625 : :
626 : : SbModule* pTraceMod = pModule;
627 : : SbClassModuleObject* pClassModuleObj = NULL;
628 : : if( pTraceMod->ISA(SbClassModuleObject) )
629 : : {
630 : : pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
631 : : pTraceMod = pClassModuleObj->getClassModule();
632 : : }
633 : :
634 : : String aCompleteFunctionName = pTraceMod->GetName();
635 : : if( pMethod != NULL )
636 : : {
637 : : aCompleteFunctionName.AppendAscii( "::" );
638 : : String aMethodName = pMethod->GetName();
639 : : aCompleteFunctionName += aMethodName;
640 : : }
641 : : else
642 : : {
643 : : aCompleteFunctionName.AppendAscii( "/RunInit" );
644 : : }
645 : :
646 : : bool bOwnBlockSteps = false;
647 : : #ifdef DBG_TRACE_PROFILING
648 : : bool bOwnBlockAll = false;
649 : : FunctionItem* pFunctionItem = NULL;
650 : : if( GbTimerOn )
651 : : {
652 : : FunctionItemMap::iterator itFunctionItem = GaFunctionItemMap.find( aCompleteFunctionName );
653 : : if( itFunctionItem != GaFunctionItemMap.end() )
654 : : pFunctionItem = itFunctionItem->second;
655 : :
656 : : if( pFunctionItem == NULL )
657 : : {
658 : : DBG_ASSERT( !bLeave, "No FunctionItem in leave!" );
659 : :
660 : : pFunctionItem = new FunctionItem();
661 : : pFunctionItem->m_aCompleteFunctionName = aCompleteFunctionName;
662 : : GaFunctionItemMap[ aCompleteFunctionName ] = pFunctionItem;
663 : : }
664 : : else if( GbBlockAllAfterFirstFunctionUsage && !bLeave )
665 : : {
666 : : pFunctionItem->m_bBlockAll = true;
667 : : }
668 : : else if( GbBlockStepsAfterFirstFunctionUsage && !bLeave )
669 : : {
670 : : pFunctionItem->m_bBlockSteps = true;
671 : : }
672 : :
673 : : if( bLeave )
674 : : {
675 : : bOwnBlockAll = GbBlockAll;
676 : : bOwnBlockSteps = GbBlockSteps;
677 : : GbBlockAll = false;
678 : : GbBlockSteps = false;
679 : :
680 : : dExecutionTime = dCurTime - GaCallEnterTimeStack.top();
681 : : GaCallEnterTimeStack.pop();
682 : :
683 : : pFunctionItem->m_dTotalTime += dExecutionTime;
684 : : pFunctionItem->m_dNetTime += dExecutionTime;
685 : : pFunctionItem->m_nCallCount++;
686 : :
687 : : GaFunctionItemStack.pop();
688 : : if( !GaFunctionItemStack.empty() )
689 : : {
690 : : FunctionItem* pParentItem = GaFunctionItemStack.top();
691 : : if( pParentItem != NULL )
692 : : {
693 : : pParentItem->m_dNetTime -= dExecutionTime;
694 : :
695 : : GbBlockSteps = pParentItem->m_bBlockSteps;
696 : : GbBlockAll = pParentItem->m_bBlockAll;
697 : : }
698 : : }
699 : : }
700 : : else
701 : : {
702 : : GbBlockSteps = bOwnBlockSteps = pFunctionItem->m_bBlockSteps;
703 : : GbBlockAll = bOwnBlockAll = pFunctionItem->m_bBlockAll;
704 : :
705 : : GaCallEnterTimeStack.push( dCurTime );
706 : : GaFunctionItemStack.push( pFunctionItem );
707 : : }
708 : : }
709 : :
710 : : if( bOwnBlockAll )
711 : : {
712 : : if( GbTimerOn )
713 : : GpTimer->continueTimer();
714 : : return;
715 : : }
716 : : #endif
717 : :
718 : : if( nCallLvl > 0 )
719 : : nCallLvl--;
720 : : int nIndent = nCallLvl * GnIndentPerCallLevel;
721 : : if( !bLeave && !bOwnBlockSteps )
722 : : {
723 : : lcl_lineOut( "" );
724 : : lcl_lineOut( pSeparator, lcl_getSpaces( nIndent ) );
725 : : }
726 : :
727 : : String aStr;
728 : : if( bLeave )
729 : : {
730 : : if( !bOwnBlockSteps )
731 : : {
732 : : lcl_lineOut( "}", lcl_getSpaces( nIndent ) );
733 : : aStr.AppendAscii( "' Leaving " );
734 : : }
735 : : }
736 : : else
737 : : {
738 : : aStr.AppendAscii( "Entering " );
739 : : }
740 : : if( !bLeave || !bOwnBlockSteps )
741 : : aStr += aCompleteFunctionName;
742 : :
743 : : if( !bOwnBlockSteps && pClassModuleObj != NULL )
744 : : {
745 : : aStr.AppendAscii( "[this=" );
746 : : aStr += pClassModuleObj->GetName();
747 : : aStr.AppendAscii( "]" );
748 : : }
749 : : if( !bLeave )
750 : : aStr += lcl_dumpMethodParameters( pMethod );
751 : :
752 : : const char* pPostStr = NULL;
753 : : #ifdef DBG_TRACE_PROFILING
754 : : char TimeBuffer[200];
755 : : if( GbTimerOn && bLeave )
756 : : {
757 : : sprintf( TimeBuffer, " // Execution Time = %f ms", dExecutionTime*1000.0 );
758 : : pPostStr = TimeBuffer;
759 : : }
760 : : #endif
761 : : lcl_lineOut( (!bLeave || !bOwnBlockSteps) ? OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr() : "}",
762 : : lcl_getSpaces( nIndent ), pPostStr );
763 : : if( !bLeave )
764 : : lcl_lineOut( "{", lcl_getSpaces( nIndent ) );
765 : :
766 : : if( bLeave && !bOwnBlockSteps )
767 : : lcl_lineOut( "" );
768 : :
769 : : #ifdef DBG_TRACE_PROFILING
770 : : if( GbTimerOn )
771 : : GpTimer->continueTimer();
772 : : #endif
773 : : }
774 : :
775 : : void dbg_traceNotifyError( SbError nTraceErr, const String& aTraceErrMsg, bool bTraceErrHandled, sal_Int32 nCallLvl )
776 : : {
777 : : if( !GbTraceOn )
778 : : return;
779 : : #ifdef DBG_TRACE_PROFILING
780 : : if( GbBlockSteps || GbBlockAll )
781 : : return;
782 : : #endif
783 : : GnLastCallLvl = nCallLvl;
784 : :
785 : : rtl::OString aOTraceErrMsg = OUStringToOString( rtl::OUString( aTraceErrMsg ), RTL_TEXTENCODING_ASCII_US );
786 : :
787 : : char Buffer[200];
788 : : const char* pHandledStr = bTraceErrHandled ? " / HANDLED" : "";
789 : : sprintf( Buffer, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr, (int)nTraceErr, aOTraceErrMsg.getStr() );
790 : : int nIndent = nCallLvl * GnIndentPerCallLevel;
791 : : lcl_lineOut( Buffer, lcl_getSpaces( nIndent ) );
792 : : }
793 : :
794 : : void dbg_RegisterTraceTextForPC( SbModule* pModule, sal_uInt32 nPC,
795 : : const String& aTraceStr_STMNT, const String& aTraceStr_PCode )
796 : : {
797 : : String aModuleName = pModule->GetName();
798 : : ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
799 : : PCToTextDataMap* pInnerMap;
800 : : if( it == rModuleTraceMap.end() )
801 : : {
802 : : pInnerMap = new PCToTextDataMap();
803 : : rModuleTraceMap[ aModuleName ] = pInnerMap;
804 : : }
805 : : else
806 : : {
807 : : pInnerMap = it->second;
808 : : }
809 : :
810 : : TraceTextData aData;
811 : :
812 : : rtl::OString aOTraceStr_STMNT = lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT );
813 : : aData.m_aTraceStr_STMNT = aOTraceStr_STMNT;
814 : :
815 : : rtl::OString aOTraceStr_PCode = lcl_toOStringSkipLeadingWhites( aTraceStr_PCode );
816 : : aData.m_aTraceStr_PCode = aOTraceStr_PCode;
817 : :
818 : : (*pInnerMap)[nPC] = aData;
819 : : }
820 : :
821 : : void RTL_Impl_TraceCommand( StarBASIC* pBasic, SbxArray& rPar, sal_Bool bWrite )
822 : : {
823 : : (void)pBasic;
824 : : (void)bWrite;
825 : :
826 : : if ( rPar.Count() < 2 )
827 : : {
828 : : StarBASIC::Error( SbERR_BAD_ARGUMENT );
829 : : return;
830 : : }
831 : :
832 : : String aCommand = rPar.Get(1)->GetString();
833 : :
834 : : if( aCommand.EqualsIgnoreCaseAscii( "TraceOn" ) )
835 : : GbTraceOn = true;
836 : : else
837 : : if( aCommand.EqualsIgnoreCaseAscii( "TraceOff" ) )
838 : : GbTraceOn = false;
839 : : else
840 : : if( aCommand.EqualsIgnoreCaseAscii( "PCodeOn" ) )
841 : : GbIncludePCodes = true;
842 : : else
843 : : if( aCommand.EqualsIgnoreCaseAscii( "PCodeOff" ) )
844 : : GbIncludePCodes = false;
845 : : else
846 : : if( aCommand.EqualsIgnoreCaseAscii( "Print" ) )
847 : : {
848 : : if ( rPar.Count() < 3 )
849 : : {
850 : : StarBASIC::Error( SbERR_BAD_ARGUMENT );
851 : : return;
852 : : }
853 : :
854 : : SbxError eOld = SbxBase::GetError();
855 : : if( eOld != SbxERR_OK )
856 : : SbxBase::ResetError();
857 : :
858 : : String aValStr = rPar.Get(2)->GetString();
859 : : SbxError eErr = SbxBase::GetError();
860 : : if( eErr != SbxERR_OK )
861 : : {
862 : : aValStr = String( RTL_CONSTASCII_USTRINGPARAM( "<ERROR converting value to String>" ) );
863 : : SbxBase::ResetError();
864 : : }
865 : :
866 : : char Buffer[500];
867 : : const char* pValStr = OUStringToOString( rtl::OUString( aValStr ), RTL_TEXTENCODING_ASCII_US ).getStr();
868 : :
869 : : sprintf( Buffer, "### TRACE_PRINT: %s ###", pValStr );
870 : : int nIndent = GnLastCallLvl * GnIndentPerCallLevel;
871 : : lcl_lineOut( Buffer, lcl_getSpaces( nIndent ) );
872 : :
873 : : if( eOld != SbxERR_OK )
874 : : SbxBase::SetError( eOld );
875 : : }
876 : : }
877 : :
878 : : #endif
879 : :
880 : : // This routine is defined here, so that the
881 : : // compiler can be loaded as a discrete segment.
882 : :
883 : 65 : sal_Bool SbModule::Compile()
884 : : {
885 [ - + ]: 65 : if( pImage )
886 : 0 : return sal_True;
887 [ + - ][ + - ]: 65 : StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
888 [ - + ]: 65 : if( !pBasic )
889 : 0 : return sal_False;
890 : 65 : SbxBase::ResetError();
891 : :
892 : 65 : SbModule* pOld = GetSbData()->pCompMod;
893 : 65 : GetSbData()->pCompMod = this;
894 : :
895 [ + - ]: 65 : SbiParser* pParser = new SbiParser( (StarBASIC*) GetParent(), this );
896 [ + + ]: 1037 : while( pParser->Parse() ) {}
897 [ + - ]: 65 : if( !pParser->GetErrors() )
898 : 65 : pParser->aGen.Save();
899 [ + - ]: 65 : delete pParser;
900 : : // for the disassembler
901 [ + - ]: 65 : if( pImage )
902 : 65 : pImage->aOUSource = aOUSource;
903 : :
904 : 65 : GetSbData()->pCompMod = pOld;
905 : :
906 : : // compiling a module, the module-global
907 : : // variables of all modules become invalid
908 : 65 : sal_Bool bRet = IsCompiled();
909 [ + - ]: 65 : if( bRet )
910 : : {
911 [ + + ]: 65 : if( !this->ISA(SbObjModule) )
912 : 40 : pBasic->ClearAllModuleVars();
913 : 65 : RemoveVars(); // remove 'this' Modules variables
914 : : // clear all method statics
915 [ + + ]: 262 : for( sal_uInt16 i = 0; i < pMethods->Count(); i++ )
916 : : {
917 [ + - ][ + - ]: 197 : SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
918 [ + - ]: 197 : if( p )
919 : 197 : p->ClearStatics();
920 : : }
921 : :
922 : : // #i31510 Init other libs only if Basic isn't running
923 [ + + ]: 65 : if( GetSbData()->pInst == NULL )
924 : : {
925 : 41 : SbxObject* pParent_ = pBasic->GetParent();
926 [ + + ]: 41 : if( pParent_ )
927 [ + - ][ + - ]: 23 : pBasic = PTR_CAST(StarBASIC,pParent_);
928 [ + - ]: 41 : if( pBasic )
929 : 41 : pBasic->ClearAllModuleVars();
930 : : }
931 : : }
932 : :
933 : 65 : return bRet;
934 : : }
935 : :
936 : : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|