Branch libreoffice-5-0-4
[LibreOffice.git] / tools / source / debug / debug.cxx
blob38b6ba5f6c9a074a5408362990044774677495fb
1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3 * This file is part of the LibreOffice project.
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/.
9 * This file incorporates work covered by the following license notice:
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 .
20 #if defined (UNX) || defined (__GNUC__)
21 #include <unistd.h>
22 #else
23 #include <direct.h>
24 #endif
26 #include <errno.h>
27 #include <time.h>
28 #include <cstdarg>
29 #include <stdlib.h>
30 #include <string.h>
31 #include <stdio.h>
33 #if defined ( WNT )
34 #include <windows.h>
35 #endif
37 #include <com/sun/star/task/ErrorCodeIOException.hpp>
38 #include <tools/debug.hxx>
39 #include <rtl/string.h>
40 #include <sal/log.hxx>
41 #include <sal/macros.h>
43 #include <vector>
45 #include <osl/diagnose.h>
46 #include <tools/diagnose_ex.h>
48 #ifdef DBG_UTIL
50 struct DebugData
52 DbgData aDbgData;
53 bool bInit;
54 DbgTestSolarMutexProc pDbgTestSolarMutex;
56 DebugData()
57 :bInit( false )
58 ,pDbgTestSolarMutex( NULL )
60 aDbgData.nTestFlags = DBG_TEST_RESOURCE;
61 aDbgData.aDbgWinState[0] = 0;
65 static DebugData aDebugData;
67 #define FILE_LINEEND "\n"
69 typedef FILE* FILETYPE;
70 #define FileOpen fopen
71 #define FileRead fread
72 #define FilePrintF fprintf
73 #define FileClose fclose
75 namespace
77 enum ConfigSection
79 eGUI,
80 eTest,
82 eUnknown
85 void lcl_lineFeed( FILETYPE _pFile )
87 FilePrintF( _pFile, "%s", FILE_LINEEND );
90 const sal_Char* lcl_getSectionName( ConfigSection _eSection )
92 const sal_Char* pSectionName = NULL;
93 switch ( _eSection )
95 case eGUI : pSectionName = "gui"; break;
96 case eTest : pSectionName = "test"; break;
97 case eUnknown:
98 OSL_ASSERT(false);
99 break;
101 return pSectionName;
104 ConfigSection lcl_getSectionFromName( const sal_Char* _pSectionName, size_t _nSectionNameLength )
106 if ( strncmp( _pSectionName, "gui", _nSectionNameLength < 3 ? _nSectionNameLength : 3 ) == 0 )
107 return eGUI;
108 if ( strncmp( _pSectionName, "test", _nSectionNameLength < 4 ? _nSectionNameLength : 4 ) == 0 )
109 return eTest;
110 return eUnknown;
113 void lcl_startSection( FILETYPE _pFile, ConfigSection _eSection )
115 FilePrintF( _pFile, "[%s]%s", lcl_getSectionName( _eSection ), FILE_LINEEND );
118 void lcl_writeConfigString( FILETYPE _pFile, const sal_Char* _pKeyName, const sal_Char* _pValue )
120 FilePrintF( _pFile, "%s=%s%s", _pKeyName, _pValue, FILE_LINEEND );
123 void lcl_writeConfigBoolean( FILETYPE _pFile, const sal_Char* _pKeyName, bool _bValue )
125 lcl_writeConfigString( _pFile, _pKeyName, _bValue ? "1" : "0" );
128 void lcl_writeConfigFlag( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uIntPtr _nAllFlags, sal_uIntPtr _nCheckFlag )
130 lcl_writeConfigBoolean( _pFile, _pKeyName, ( _nAllFlags & _nCheckFlag ) != 0 );
133 bool lcl_isConfigSection( const sal_Char* _pLine, size_t _nLineLen )
135 if ( _nLineLen < 2 )
136 // not even enough space for '[' and ']'
137 return false;
138 if ( ( _pLine[0] == '[' ) && ( _pLine[ _nLineLen - 1 ] == ']' ) )
139 return true;
140 return false;
143 bool lcl_isConfigKey( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName )
145 size_t nKeyLength = strlen( _pKeyName );
146 if ( nKeyLength + 1 >= _nLineLen )
147 // not even long enough for the key name plus "=" plus a one-character value
148 return false;
149 if ( ( strncmp( _pLine, _pKeyName, nKeyLength ) == 0 ) && ( _pLine[ nKeyLength ] == '=' ) )
150 return true;
151 return false;
154 sal_Int32 lcl_tryReadConfigString( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_Char* _pValue, size_t _nValueLen )
156 if ( !lcl_isConfigKey( _pLine, _nLineLen, _pKeyName ) )
157 return 0;
158 size_t nValuePos = strlen( _pKeyName ) + 1;
159 size_t nValueLen = _nLineLen - nValuePos;
160 const sal_Char* pValue = _pLine + nValuePos;
161 strncpy( _pValue, pValue, ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen );
162 _pValue[ ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen - 1 ] = 0;
163 return strlen( _pValue );
166 void lcl_tryReadConfigFlag( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnAllFlags, sal_uIntPtr _nCheckFlag )
168 sal_Char aBuf[2];
169 size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
170 if ( nValueLen )
172 if ( strcmp( aBuf, "1" ) == 0 )
173 *_out_pnAllFlags |= _nCheckFlag;
174 else
175 *_out_pnAllFlags &= ~_nCheckFlag;
180 static void DbgGetDbgFileName( sal_Char* pStr, sal_Int32 nMaxLen )
182 #if defined( UNX )
183 const sal_Char* pName = getenv("DBGSV_INIT");
184 if ( !pName )
185 pName = ".dbgsv.init";
186 strncpy( pStr, pName, nMaxLen );
187 #elif defined( WNT )
188 const sal_Char* pName = getenv("DBGSV_INIT");
189 if ( pName )
190 strncpy( pStr, pName, nMaxLen );
191 else
192 GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, nMaxLen );
193 #else
194 strncpy( pStr, "dbgsv.ini", nMaxLen );
195 #endif
196 pStr[ nMaxLen - 1 ] = 0;
199 static DebugData* GetDebugData()
201 if ( !aDebugData.bInit )
203 aDebugData.bInit = true;
205 // DEBUG.INI-File
206 sal_Char aBuf[ 4096 ];
207 DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
208 FILETYPE pIniFile = FileOpen( aBuf, "r" );
209 if ( pIniFile != NULL )
211 ConfigSection eCurrentSection = eUnknown;
213 // no sophisticated algorithm here, assume that the whole file fits into aBuf ...
214 sal_uIntPtr nReallyRead = FileRead( aBuf, 1, sizeof( aBuf ) / sizeof( sal_Char ) - 1, pIniFile );
215 aBuf[ nReallyRead ] = 0;
216 const sal_Char* pLine = aBuf;
217 while ( const sal_Char* pNextLine = strstr( pLine, FILE_LINEEND ) )
219 size_t nLineLength = pNextLine - pLine;
221 if ( lcl_isConfigSection( pLine, nLineLength ) )
222 eCurrentSection = lcl_getSectionFromName( pLine + 1, nLineLength - 2 );
224 // elements of the [gui] section
225 if ( eCurrentSection == eGUI )
227 lcl_tryReadConfigString( pLine, nLineLength, "debug_window_state", aDebugData.aDbgData.aDbgWinState, sizeof( aDebugData.aDbgData.aDbgWinState ) );
230 // elements of the [test] section
231 if ( eCurrentSection == eTest )
233 lcl_tryReadConfigFlag( pLine, nLineLength, "resources", &aDebugData.aDbgData.nTestFlags, DBG_TEST_RESOURCE );
234 lcl_tryReadConfigFlag( pLine, nLineLength, "dialog", &aDebugData.aDbgData.nTestFlags, DBG_TEST_DIALOG );
235 lcl_tryReadConfigFlag( pLine, nLineLength, "bold_app_font", &aDebugData.aDbgData.nTestFlags, DBG_TEST_BOLDAPPFONT );
238 pLine = pNextLine + strlen( FILE_LINEEND );
241 FileClose( pIniFile );
245 return &aDebugData;
248 inline DebugData* ImplGetDebugData()
250 if ( !aDebugData.bInit )
251 return GetDebugData();
252 else
253 return &aDebugData;
256 void* DbgFunc( sal_uInt16 nAction, void* pParam )
258 DebugData* pDebugData = ImplGetDebugData();
260 if ( nAction == DBG_FUNC_GETDATA )
261 return (void*)&(pDebugData->aDbgData);
262 else
264 switch ( nAction )
266 case DBG_FUNC_SAVEDATA:
268 const DbgData* pData = static_cast< const DbgData* >( pParam );
270 sal_Char aBuf[ 4096 ];
271 DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
272 FILETYPE pIniFile = FileOpen( aBuf, "w" );
273 if ( pIniFile == NULL )
274 break;
276 lcl_lineFeed( pIniFile );
277 lcl_startSection( pIniFile, eGUI );
278 lcl_writeConfigString( pIniFile, "debug_window_state", pData->aDbgWinState );
280 lcl_lineFeed( pIniFile );
281 lcl_startSection( pIniFile, eTest );
282 lcl_writeConfigFlag( pIniFile, "resources", pData->nTestFlags, DBG_TEST_RESOURCE );
283 lcl_writeConfigFlag( pIniFile, "dialog", pData->nTestFlags, DBG_TEST_DIALOG );
284 lcl_writeConfigFlag( pIniFile, "bold_app_font", pData->nTestFlags, DBG_TEST_BOLDAPPFONT );
286 FileClose( pIniFile );
288 break;
290 case DBG_FUNC_SETTESTSOLARMUTEX:
291 pDebugData->pDbgTestSolarMutex = reinterpret_cast<DbgTestSolarMutexProc>(reinterpret_cast<sal_uIntPtr>(pParam));
292 break;
294 case DBG_FUNC_TESTSOLARMUTEX:
295 SAL_WARN_IF(
296 pDebugData->pDbgTestSolarMutex == 0, "tools.debug",
297 "no DbgTestSolarMutex function set");
298 if ( pDebugData->pDbgTestSolarMutex )
299 pDebugData->pDbgTestSolarMutex();
300 break;
303 return NULL;
307 #endif
309 #if OSL_DEBUG_LEVEL > 0
311 void DbgUnhandledException(const css::uno::Any & caught, const char* currentFunction, const char* fileAndLineNo)
313 OString sMessage( "caught an exception!" );
314 sMessage += "\nin function:";
315 sMessage += currentFunction;
316 sMessage += "\ntype: ";
317 sMessage += OUStringToOString( caught.getValueTypeName(), osl_getThreadTextEncoding() );
318 ::com::sun::star::uno::Exception exception;
319 caught >>= exception;
320 if ( !exception.Message.isEmpty() )
322 sMessage += "\nmessage: ";
323 sMessage += OUStringToOString( exception.Message, osl_getThreadTextEncoding() );
325 if ( exception.Context.is() )
327 const char* pContext = typeid( *exception.Context.get() ).name();
328 sMessage += "\ncontext: ";
329 sMessage += pContext;
332 ::com::sun::star::configuration::CorruptedConfigurationException
333 specialized;
334 if ( caught >>= specialized )
336 sMessage += "\ndetails: ";
337 sMessage += OUStringToOString(
338 specialized.Details, osl_getThreadTextEncoding() );
342 ::com::sun::star::task::ErrorCodeIOException specialized;
343 if ( caught >>= specialized )
345 sMessage += "\ndetails: ";
346 sMessage += OString::number( specialized.ErrCode );
349 sMessage += "\n";
351 SAL_DETAIL_LOG_FORMAT(
352 SAL_DETAIL_ENABLE_LOG_WARN, SAL_DETAIL_LOG_LEVEL_WARN,
353 "legacy.osl", fileAndLineNo, "%s", sMessage.getStr());
356 #endif
360 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */