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