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