LCOV - code coverage report
Current view: top level - basic/source/comp - sbcomp.cxx (source / functions) Hit Total Coverage
Test: libreoffice_filtered.info Lines: 31 33 93.9 %
Date: 2012-08-25 Functions: 1 1 100.0 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 25 40 62.5 %

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

Generated by: LCOV version 1.10