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 OUString& 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 : OUString aStr;
286 : if( pMethod == NULL )
287 : {
288 : return aStr;
289 : }
290 : SbxError eOld = SbxBase::GetError();
291 :
292 : SbxArray* pParams = pMethod->GetParameters();
293 : SbxInfo* pInfo = pMethod->GetInfo();
294 : if ( pParams )
295 : {
296 : aStr += '(';
297 : // 0 is sub itself
298 : for ( sal_uInt16 nParam = 1; nParam < pParams->Count(); nParam++ )
299 : {
300 : SbxVariable* pVar = pParams->Get( nParam );
301 : DBG_ASSERT( pVar, "Parameter?!" );
302 : if ( !pVar->GetName().isEmpty() )
303 : {
304 : aStr += pVar->GetName();
305 : }
306 : else if ( pInfo )
307 : {
308 : const SbxParamInfo* pParam = pInfo->GetParam( nParam );
309 : if ( pParam )
310 : {
311 : aStr += pParam->aName;
312 : }
313 : }
314 : aStr += '=';
315 : SbxDataType eType = pVar->GetType();
316 : if( eType & SbxARRAY )
317 : {
318 : aStr += "...";
319 : }
320 : else if( eType != SbxOBJECT )
321 : {
322 : aStr += pVar->GetString();
323 : }
324 : if ( nParam < ( pParams->Count() - 1 ) )
325 : {
326 : aStr += ", ";
327 : }
328 : }
329 : aStr += ')';
330 : }
331 :
332 : SbxBase::ResetError();
333 : if( eOld != SbxERR_OK )
334 : {
335 : SbxBase::SetError( eOld );
336 : }
337 : return aStr;
338 : }
339 :
340 :
341 : // Public functions
342 : static bool GbSavTraceOn = false;
343 :
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;
350 :
351 : struct FunctionItem
352 : {
353 : OUString m_aCompleteFunctionName;
354 : double m_dTotalTime;
355 : double m_dNetTime;
356 : int m_nCallCount;
357 : bool m_bBlockAll;
358 : bool m_bBlockSteps;
359 :
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 )
366 : {}
367 : };
368 : typedef std::hash_map< ::rtl::OUString, FunctionItem*, ::rtl::OUStringHash, ::std::equal_to< ::rtl::OUString > > FunctionItemMap;
369 :
370 : static std::stack< double > GaCallEnterTimeStack;
371 : static std::stack< FunctionItem* > GaFunctionItemStack;
372 : static FunctionItemMap GaFunctionItemMap;
373 :
374 : bool compareFunctionNetTime( FunctionItem* p1, FunctionItem* p2 )
375 : {
376 : return (p1->m_dNetTime > p2->m_dNetTime);
377 : }
378 :
379 : void lcl_printTimeOutput( void )
380 : {
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( "" );
389 :
390 : if( GbTimerOn )
391 : {
392 : lcl_lineOut( "Functions:" );
393 :
394 : std::vector<FunctionItem*> avFunctionItems;
395 :
396 : FunctionItemMap::iterator it;
397 : for( it = GaFunctionItemMap.begin() ; it != GaFunctionItemMap.end() ; ++it )
398 : {
399 : FunctionItem* pFunctionItem = it->second;
400 : if( pFunctionItem != NULL )
401 : {
402 : avFunctionItems.push_back( pFunctionItem );
403 : }
404 : }
405 :
406 : std::sort( avFunctionItems.begin(), avFunctionItems.end(), compareFunctionNetTime );
407 :
408 : std::vector<FunctionItem*>::iterator itv;
409 : for( itv = avFunctionItems.begin() ; itv != avFunctionItems.end() ; ++itv )
410 : {
411 : FunctionItem* pFunctionItem = *itv;
412 : if( pFunctionItem != NULL )
413 : {
414 : OUString aCompleteFunctionName = pFunctionItem->m_aCompleteFunctionName;
415 : const char* pName = OUStringToOString( aCompleteFunctionName, RTL_TEXTENCODING_ASCII_US ).getStr();
416 : int nNameLen = aCompleteFunctionName.getLength();
417 :
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 )
424 : {
425 : nSpaceCount = 2;
426 : }
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 );
431 : }
432 : }
433 : }
434 : }
435 : #endif
436 :
437 :
438 : static bool GbInitTraceAlreadyCalled = false;
439 :
440 : void dbg_InitTrace( void )
441 : {
442 : if( GbInitOnlyAtOfficeStart && GbInitTraceAlreadyCalled )
443 : {
444 : #ifdef DBG_TRACE_PROFILING
445 : if( GbTimerOn )
446 : {
447 : GpTimer->continueTimer();
448 : }
449 : #endif
450 : GpGlobalFile = fopen( GpTraceFileName, "a+" );
451 : return;
452 : }
453 : GbInitTraceAlreadyCalled = true;
454 :
455 : if( const sal_Char* pcIniFileName = ::getenv( "OOO_BASICTRACEINI" ) )
456 : {
457 : lcl_ReadIniFile( pcIniFileName );
458 : }
459 : else if( GpTraceIniFile != NULL )
460 : {
461 : lcl_ReadIniFile( GpTraceIniFile );
462 : }
463 : GpGlobalFile = fopen( GpTraceFileName, "w" );
464 : GbSavTraceOn = GbTraceOn;
465 : if( !GbTraceOn )
466 : {
467 : lcl_lineOut( "### Program started with trace off ###" );
468 : }
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
476 : }
477 :
478 : void dbg_DeInitTrace( void )
479 : {
480 : GbTraceOn = GbSavTraceOn;
481 :
482 : #ifdef DBG_TRACE_PROFILING
483 : while( !GaCallEnterTimeStack.empty() )
484 : {
485 : GaCallEnterTimeStack.pop();
486 : }
487 : while( !GaFunctionItemStack.empty() )
488 : {
489 : GaFunctionItemStack.pop();
490 : }
491 : lcl_printTimeOutput();
492 :
493 : for( FunctionItemMap::iterator it = GaFunctionItemMap.begin() ; it != GaFunctionItemMap.end() ; ++it )
494 : {
495 : delete it->second;
496 : }
497 : GaFunctionItemMap.clear();
498 :
499 : if( GpGlobalFile )
500 : {
501 : fclose( GpGlobalFile );
502 : GpGlobalFile = NULL;
503 : }
504 :
505 : if( GbInitOnlyAtOfficeStart )
506 : {
507 : if( GbTimerOn )
508 : {
509 : GpTimer->pauseTimer();
510 : }
511 : }
512 : else
513 : {
514 : delete GpTimer;
515 : }
516 : #endif
517 : }
518 :
519 : static sal_Int32 GnLastCallLvl = 0;
520 :
521 : void dbg_tracePrint( const OUString& aStr, sal_Int32 nCallLvl, bool bCallLvlRelativeToCurrent )
522 : {
523 : if( bCallLvlRelativeToCurrent )
524 : {
525 : nCallLvl += GnLastCallLvl;
526 : }
527 : int nIndent = nCallLvl * GnIndentPerCallLevel;
528 : lcl_lineOut( OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr(), lcl_getSpaces( nIndent ) );
529 : }
530 :
531 : void dbg_traceStep( SbModule* pModule, sal_uInt32 nPC, sal_Int32 nCallLvl )
532 : {
533 : if( !GbTraceOn )
534 : {
535 : return;
536 : }
537 : #ifdef DBG_TRACE_PROFILING
538 : if( GbBlockSteps || GbBlockAll )
539 : {
540 : return;
541 : }
542 : double dCurTime = 0.0;
543 : bool bPrintTimeStamp = false;
544 : if( GbTimerOn )
545 : {
546 : GpTimer->pauseTimer();
547 : dCurTime = GpTimer->getElapsedTime();
548 : bPrintTimeStamp = GbTimeStampForEachStep;
549 : }
550 : #else
551 : bool bPrintTimeStamp = false;
552 : #endif
553 :
554 : GnLastCallLvl = nCallLvl;
555 :
556 : SbModule* pTraceMod = pModule;
557 : if( pTraceMod->ISA(SbClassModuleObject) )
558 : {
559 : SbClassModuleObject* pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
560 : pTraceMod = pClassModuleObj->getClassModule();
561 : }
562 :
563 : OUString aModuleName = pTraceMod->GetName();
564 : ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
565 : if( it == rModuleTraceMap.end() )
566 : {
567 : const char* pModuleNameStr = OUStringToOString( rtl::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;
572 : }
573 :
574 : PCToTextDataMap* pInnerMap = it->second;
575 : if( pInnerMap == NULL )
576 : {
577 : lcl_lineOut( "TRACE INTERNAL ERROR: No inner map" );
578 : return;
579 : }
580 :
581 : PCToTextDataMap::iterator itInner = pInnerMap->find( nPC );
582 : if( itInner == pInnerMap->end() )
583 : {
584 : const char* pModuleNameStr = OUStringToOString( rtl::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;
589 : }
590 :
591 : int nIndent = nCallLvl * GnIndentPerCallLevel;
592 :
593 : const TraceTextData& rTraceTextData = itInner->second;
594 : const rtl::OString& rStr_STMNT = rTraceTextData.m_aTraceStr_STMNT;
595 : bool bSTMT = false;
596 : if( rStr_STMNT.getLength() )
597 : {
598 : bSTMT = true;
599 : }
600 : char TimeBuffer[200];
601 : #ifdef DBG_TRACE_PROFILING
602 : if( bPrintTimeStamp )
603 : {
604 : double dDiffTime = dCurTime - GdLastTime;
605 : GdLastTime = dCurTime;
606 : sprintf( TimeBuffer, "\t\t// Time = %f ms / += %f ms", dCurTime*1000.0, dDiffTime*1000.0 );
607 : }
608 : #endif
609 :
610 : if( bSTMT )
611 : {
612 : lcl_lineOut( rStr_STMNT.getStr(), lcl_getSpaces( nIndent ),
613 : (bPrintTimeStamp && !GbIncludePCodes) ? TimeBuffer : NULL );
614 : }
615 :
616 : if( !GbIncludePCodes )
617 : {
618 : #ifdef DBG_TRACE_PROFILING
619 : if( GbTimerOn )
620 : {
621 : GpTimer->continueTimer();
622 : }
623 : #endif
624 : return;
625 : }
626 :
627 : nIndent += GnIndentForPCode;
628 : const rtl::OString& rStr_PCode = rTraceTextData.m_aTraceStr_PCode;
629 : if( rStr_PCode.getLength() )
630 : {
631 : lcl_lineOut( rStr_PCode.getStr(), lcl_getSpaces( nIndent ),
632 : bPrintTimeStamp ? TimeBuffer : NULL );
633 : }
634 :
635 : #ifdef DBG_TRACE_PROFILING
636 : if( GbTimerOn )
637 : {
638 : GpTimer->continueTimer();
639 : }
640 : #endif
641 : }
642 :
643 :
644 : void dbg_traceNotifyCall( SbModule* pModule, SbMethod* pMethod, sal_Int32 nCallLvl, bool bLeave )
645 : {
646 : static const char* pSeparator = "' ================================================================================";
647 :
648 : if( !GbTraceOn )
649 : {
650 : return;
651 : }
652 : #ifdef DBG_TRACE_PROFILING
653 : double dCurTime = 0.0;
654 : double dExecutionTime = 0.0;
655 : if( GbTimerOn )
656 : {
657 : dCurTime = GpTimer->getElapsedTime();
658 : GpTimer->pauseTimer();
659 : }
660 : #endif
661 :
662 : GnLastCallLvl = nCallLvl;
663 :
664 : SbModule* pTraceMod = pModule;
665 : SbClassModuleObject* pClassModuleObj = NULL;
666 : if( pTraceMod->ISA(SbClassModuleObject) )
667 : {
668 : pClassModuleObj = (SbClassModuleObject*)(SbxBase*)pTraceMod;
669 : pTraceMod = pClassModuleObj->getClassModule();
670 : }
671 :
672 : OUString aCompleteFunctionName = pTraceMod->GetName();
673 : if( pMethod != NULL )
674 : {
675 : aCompleteFunctionName += "::";
676 : OUString aMethodName = pMethod->GetName();
677 : aCompleteFunctionName += aMethodName;
678 : }
679 : else
680 : {
681 : aCompleteFunctionName += "/RunInit";
682 : }
683 :
684 : bool bOwnBlockSteps = false;
685 : #ifdef DBG_TRACE_PROFILING
686 : bool bOwnBlockAll = false;
687 : FunctionItem* pFunctionItem = NULL;
688 : if( GbTimerOn )
689 : {
690 : FunctionItemMap::iterator itFunctionItem = GaFunctionItemMap.find( aCompleteFunctionName );
691 : if( itFunctionItem != GaFunctionItemMap.end() )
692 : {
693 : pFunctionItem = itFunctionItem->second;
694 : }
695 : if( pFunctionItem == NULL )
696 : {
697 : DBG_ASSERT( !bLeave, "No FunctionItem in leave!" );
698 :
699 : pFunctionItem = new FunctionItem();
700 : pFunctionItem->m_aCompleteFunctionName = aCompleteFunctionName;
701 : GaFunctionItemMap[ aCompleteFunctionName ] = pFunctionItem;
702 : }
703 : else if( GbBlockAllAfterFirstFunctionUsage && !bLeave )
704 : {
705 : pFunctionItem->m_bBlockAll = true;
706 : }
707 : else if( GbBlockStepsAfterFirstFunctionUsage && !bLeave )
708 : {
709 : pFunctionItem->m_bBlockSteps = true;
710 : }
711 :
712 : if( bLeave )
713 : {
714 : bOwnBlockAll = GbBlockAll;
715 : bOwnBlockSteps = GbBlockSteps;
716 : GbBlockAll = false;
717 : GbBlockSteps = false;
718 :
719 : dExecutionTime = dCurTime - GaCallEnterTimeStack.top();
720 : GaCallEnterTimeStack.pop();
721 :
722 : pFunctionItem->m_dTotalTime += dExecutionTime;
723 : pFunctionItem->m_dNetTime += dExecutionTime;
724 : pFunctionItem->m_nCallCount++;
725 :
726 : GaFunctionItemStack.pop();
727 : if( !GaFunctionItemStack.empty() )
728 : {
729 : FunctionItem* pParentItem = GaFunctionItemStack.top();
730 : if( pParentItem != NULL )
731 : {
732 : pParentItem->m_dNetTime -= dExecutionTime;
733 :
734 : GbBlockSteps = pParentItem->m_bBlockSteps;
735 : GbBlockAll = pParentItem->m_bBlockAll;
736 : }
737 : }
738 : }
739 : else
740 : {
741 : GbBlockSteps = bOwnBlockSteps = pFunctionItem->m_bBlockSteps;
742 : GbBlockAll = bOwnBlockAll = pFunctionItem->m_bBlockAll;
743 :
744 : GaCallEnterTimeStack.push( dCurTime );
745 : GaFunctionItemStack.push( pFunctionItem );
746 : }
747 : }
748 :
749 : if( bOwnBlockAll )
750 : {
751 : if( GbTimerOn )
752 : {
753 : GpTimer->continueTimer();
754 : }
755 : return;
756 : }
757 : #endif
758 :
759 : if( nCallLvl > 0 )
760 : {
761 : nCallLvl--;
762 : }
763 : int nIndent = nCallLvl * GnIndentPerCallLevel;
764 : if( !bLeave && !bOwnBlockSteps )
765 : {
766 : lcl_lineOut( "" );
767 : lcl_lineOut( pSeparator, lcl_getSpaces( nIndent ) );
768 : }
769 :
770 : OUString aStr;
771 : if( bLeave )
772 : {
773 : if( !bOwnBlockSteps )
774 : {
775 : lcl_lineOut( "}", lcl_getSpaces( nIndent ) );
776 : aStr = "' Leaving ";
777 : }
778 : }
779 : else
780 : {
781 : aStr = "Entering " ;
782 : }
783 : if( !bLeave || !bOwnBlockSteps )
784 : {
785 : aStr += aCompleteFunctionName;
786 : }
787 : if( !bOwnBlockSteps && pClassModuleObj != NULL )
788 : {
789 : aStr += "[this=";
790 : aStr += pClassModuleObj->GetName();
791 : aStr += "]" ;
792 : }
793 : if( !bLeave )
794 : {
795 : aStr += lcl_dumpMethodParameters( pMethod );
796 : }
797 : const char* pPostStr = NULL;
798 : #ifdef DBG_TRACE_PROFILING
799 : char TimeBuffer[200];
800 : if( GbTimerOn && bLeave )
801 : {
802 : sprintf( TimeBuffer, " // Execution Time = %f ms", dExecutionTime*1000.0 );
803 : pPostStr = TimeBuffer;
804 : }
805 : #endif
806 : lcl_lineOut( (!bLeave || !bOwnBlockSteps) ? OUStringToOString( rtl::OUString( aStr ), RTL_TEXTENCODING_ASCII_US ).getStr() : "}",
807 : lcl_getSpaces( nIndent ), pPostStr );
808 : if( !bLeave )
809 : {
810 : lcl_lineOut( "{", lcl_getSpaces( nIndent ) );
811 : }
812 : if( bLeave && !bOwnBlockSteps )
813 : {
814 : lcl_lineOut( "" );
815 : }
816 : #ifdef DBG_TRACE_PROFILING
817 : if( GbTimerOn )
818 : {
819 : GpTimer->continueTimer();
820 : }
821 : #endif
822 : }
823 :
824 : void dbg_traceNotifyError( SbError nTraceErr, const OUString& aTraceErrMsg,
825 : bool bTraceErrHandled, sal_Int32 nCallLvl )
826 : {
827 : if( !GbTraceOn )
828 : {
829 : return;
830 : }
831 : #ifdef DBG_TRACE_PROFILING
832 : if( GbBlockSteps || GbBlockAll )
833 : {
834 : return;
835 : }
836 : #endif
837 : GnLastCallLvl = nCallLvl;
838 :
839 : rtl::OString aOTraceErrMsg = OUStringToOString( rtl::OUString( aTraceErrMsg ), RTL_TEXTENCODING_ASCII_US );
840 :
841 : char Buffer[200];
842 : const char* pHandledStr = bTraceErrHandled ? " / HANDLED" : "";
843 : sprintf( Buffer, "*** ERROR%s, Id = %d, Msg = \"%s\" ***", pHandledStr, (int)nTraceErr, aOTraceErrMsg.getStr() );
844 : int nIndent = nCallLvl * GnIndentPerCallLevel;
845 : lcl_lineOut( Buffer, lcl_getSpaces( nIndent ) );
846 : }
847 :
848 : void dbg_RegisterTraceTextForPC( SbModule* pModule, sal_uInt32 nPC,
849 : const OUString& aTraceStr_STMNT, const OUString& aTraceStr_PCode )
850 : {
851 : OUString aModuleName = pModule->GetName();
852 : ModuleTraceMap::iterator it = rModuleTraceMap.find( aModuleName );
853 : PCToTextDataMap* pInnerMap;
854 : if( it == rModuleTraceMap.end() )
855 : {
856 : pInnerMap = new PCToTextDataMap();
857 : rModuleTraceMap[ aModuleName ] = pInnerMap;
858 : }
859 : else
860 : {
861 : pInnerMap = it->second;
862 : }
863 :
864 : TraceTextData aData;
865 :
866 : rtl::OString aOTraceStr_STMNT = lcl_toOStringSkipLeadingWhites( aTraceStr_STMNT );
867 : aData.m_aTraceStr_STMNT = aOTraceStr_STMNT;
868 :
869 : rtl::OString aOTraceStr_PCode = lcl_toOStringSkipLeadingWhites( aTraceStr_PCode );
870 : aData.m_aTraceStr_PCode = aOTraceStr_PCode;
871 :
872 : (*pInnerMap)[nPC] = aData;
873 : }
874 :
875 : void RTL_Impl_TraceCommand( StarBASIC* pBasic, SbxArray& rPar, sal_Bool bWrite )
876 : {
877 : (void)pBasic;
878 : (void)bWrite;
879 :
880 : if ( rPar.Count() < 2 )
881 : {
882 : StarBASIC::Error( SbERR_BAD_ARGUMENT );
883 : return;
884 : }
885 :
886 : OUString aCommand = rPar.Get(1)->GetString();
887 :
888 : if( aCommand.equalsIngoreAsciiCase( "TraceOn" ) )
889 : {
890 : GbTraceOn = true;
891 : }
892 : else if( aCommand.equalsIngoreAsciiCase( "TraceOff" ) )
893 : {
894 : GbTraceOn = false;
895 : }
896 : else if( aCommand.equalsIngoreAsciiCase( "PCodeOn" ) )
897 : {
898 : GbIncludePCodes = true;
899 : }
900 : else if( aCommand.equalsIngoreAsciiCase( "PCodeOff" ) )
901 : {
902 : GbIncludePCodes = false;
903 : }
904 : else if( aCommand.equalsIngoreAsciiCase( "Print" ) )
905 : {
906 : if ( rPar.Count() < 3 )
907 : {
908 : StarBASIC::Error( SbERR_BAD_ARGUMENT );
909 : return;
910 : }
911 :
912 : SbxError eOld = SbxBase::GetError();
913 : if( eOld != SbxERR_OK )
914 : SbxBase::ResetError();
915 :
916 : OUString aValStr = rPar.Get(2)->GetString();
917 : SbxError eErr = SbxBase::GetError();
918 : if( eErr != SbxERR_OK )
919 : {
920 : aValStr = "<ERROR converting value to String>";
921 : SbxBase::ResetError();
922 : }
923 :
924 : char Buffer[500];
925 : const char* pValStr = OUStringToOString( rtl::OUString( aValStr ), RTL_TEXTENCODING_ASCII_US ).getStr();
926 :
927 : sprintf( Buffer, "### TRACE_PRINT: %s ###", pValStr );
928 : int nIndent = GnLastCallLvl * GnIndentPerCallLevel;
929 : lcl_lineOut( Buffer, lcl_getSpaces( nIndent ) );
930 :
931 : if( eOld != SbxERR_OK )
932 : {
933 : SbxBase::SetError( eOld );
934 : }
935 : }
936 : }
937 :
938 : #endif
939 :
940 : // This routine is defined here, so that the
941 : // compiler can be loaded as a discrete segment.
942 :
943 8 : sal_Bool SbModule::Compile()
944 : {
945 8 : if( pImage )
946 0 : return sal_True;
947 8 : StarBASIC* pBasic = PTR_CAST(StarBASIC,GetParent());
948 8 : if( !pBasic )
949 0 : return sal_False;
950 8 : SbxBase::ResetError();
951 :
952 8 : SbModule* pOld = GetSbData()->pCompMod;
953 8 : GetSbData()->pCompMod = this;
954 :
955 8 : SbiParser* pParser = new SbiParser( (StarBASIC*) GetParent(), this );
956 8 : while( pParser->Parse() ) {}
957 8 : if( !pParser->GetErrors() )
958 8 : pParser->aGen.Save();
959 8 : delete pParser;
960 : // for the disassembler
961 8 : if( pImage )
962 8 : pImage->aOUSource = aOUSource;
963 :
964 8 : GetSbData()->pCompMod = pOld;
965 :
966 : // compiling a module, the module-global
967 : // variables of all modules become invalid
968 8 : sal_Bool bRet = IsCompiled();
969 8 : if( bRet )
970 : {
971 8 : if( !this->ISA(SbObjModule) )
972 8 : pBasic->ClearAllModuleVars();
973 8 : RemoveVars(); // remove 'this' Modules variables
974 : // clear all method statics
975 16 : for( sal_uInt16 i = 0; i < pMethods->Count(); i++ )
976 : {
977 8 : SbMethod* p = PTR_CAST(SbMethod,pMethods->Get( i ) );
978 8 : if( p )
979 8 : p->ClearStatics();
980 : }
981 :
982 : // #i31510 Init other libs only if Basic isn't running
983 8 : if( GetSbData()->pInst == NULL )
984 : {
985 8 : SbxObject* pParent_ = pBasic->GetParent();
986 8 : if( pParent_ )
987 0 : pBasic = PTR_CAST(StarBASIC,pParent_);
988 8 : if( pBasic )
989 8 : pBasic->ClearAllModuleVars();
990 : }
991 : }
992 :
993 8 : return bRet;
994 : }
995 :
996 : /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
|