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