xref: /aoo41x/main/tools/source/debug/debug.cxx (revision cdf0e10c)
1 /*************************************************************************
2  *
3  * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4  *
5  * Copyright 2000, 2010 Oracle and/or its affiliates.
6  *
7  * OpenOffice.org - a multi-platform office productivity suite
8  *
9  * This file is part of OpenOffice.org.
10  *
11  * OpenOffice.org is free software: you can redistribute it and/or modify
12  * it under the terms of the GNU Lesser General Public License version 3
13  * only, as published by the Free Software Foundation.
14  *
15  * OpenOffice.org is distributed in the hope that it will be useful,
16  * but WITHOUT ANY WARRANTY; without even the implied warranty of
17  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
18  * GNU Lesser General Public License version 3 for more details
19  * (a copy is included in the LICENSE file that accompanied this code).
20  *
21  * You should have received a copy of the GNU Lesser General Public License
22  * version 3 along with OpenOffice.org.  If not, see
23  * <http://www.openoffice.org/license.html>
24  * for a copy of the LGPLv3 License.
25  *
26  ************************************************************************/
27 
28 // MARKER(update_precomp.py): autogen include statement, do not remove
29 #include "precompiled_tools.hxx"
30 
31 #define _TOOLS_DEBUG_CXX
32 
33 #if defined (UNX) || defined (GCC)
34 #include <unistd.h>
35 #else
36 #include <direct.h>
37 #endif
38 
39 #include <time.h>
40 #include <cstdarg>  // combinations
41 #include <stdlib.h>
42 #include <string.h>
43 #include <stdio.h>
44 
45 #ifdef OS2
46 #define INCL_DOSSEMAPHORES
47 #define INCL_DOSMISC
48 #define INCL_WINDIALOGS
49 #define INCL_WINSHELLDATA
50 #include <svpm.h>
51 #endif
52 
53 #if defined ( WNT )
54 #ifdef _MSC_VER
55 #pragma warning (push,1)
56 #endif
57 #include <tools/svwin.h>
58 #ifdef _MSC_VER
59 #pragma warning (pop)
60 #endif
61 #endif
62 
63 #include <tools/debug.hxx>
64 #include <rtl/string.h>
65 
66 #include <vector>
67 
68 #include <osl/diagnose.h>
69 
70 // =======================================================================
71 
72 #ifdef DBG_UTIL
73 
74 // --- DbgErrors ---
75 
76 static sal_Char const DbgError_ProfEnd1[]   = "DBG_PROF...() without DBG_PROFSTART(): ";
77 static sal_Char const DbgError_Xtor1[]      = "DBG_DTOR() or DBG_CHKTHIS() without DBG_CTOR(): ";
78 
79 static sal_Char const DbgError_CtorDtor1[]  = "this == NULL in class ";
80 static sal_Char const DbgError_CtorDtor2[]  = "invalid this-Pointer %p in class ";
81 static sal_Char const DbgError_CtorDtor3[]  = "Error-Msg from Object %p in class ";
82 
83 static sal_Char const DbgTrace_EnterCtor[]  = "Enter Ctor from class ";
84 static sal_Char const DbgTrace_LeaveCtor[]  = "Leave Ctor from class ";
85 static sal_Char const DbgTrace_EnterDtor[]  = "Enter Dtor from class ";
86 static sal_Char const DbgTrace_LeaveDtor[]  = "Leave Dtor from class ";
87 static sal_Char const DbgTrace_EnterMeth[]  = "Enter method from class ";
88 static sal_Char const DbgTrace_LeaveMeth[]  = "Leave method from class ";
89 
90 // --- PointerList ---
91 
92 #define PBLOCKCOUNT     1024
93 
94 struct PBlock
95 {
96     void*       aData[PBLOCKCOUNT];
97     sal_uInt16      nCount;
98     PBlock*     pPrev;
99     PBlock*     pNext;
100 };
101 
102 class PointerList
103 {
104 private:
105     PBlock*     pFirst;
106     PBlock*     pLast;
107     sal_uIntPtr       nCount;
108 
109 public:
110                 PointerList() { pFirst = NULL; pLast = NULL; nCount = 0; }
111                 ~PointerList();
112 
113     void        Add( const void* p );
114     sal_Bool        Remove( const void* p );
115 
116     const void* Get( sal_uIntPtr nPos ) const;
117     sal_Bool        IsIn( const void* p ) const;
118     sal_uIntPtr       Count() const { return nCount; }
119 };
120 
121 // --- Datentypen ---
122 
123 #define DBG_MAXNAME     28
124 
125 struct ProfType
126 {
127     sal_uIntPtr                   nCount;
128     sal_uIntPtr                   nTime;
129     sal_uIntPtr                   nMinTime;
130     sal_uIntPtr                   nMaxTime;
131     sal_uIntPtr                   nStart;
132     sal_uIntPtr                   nContinueTime;
133     sal_uIntPtr                   nContinueStart;
134     sal_Char                aName[DBG_MAXNAME+1];
135 };
136 
137 struct XtorType
138 {
139     sal_uIntPtr                   nCtorCalls;
140     sal_uIntPtr                   nDtorCalls;
141     sal_uIntPtr                   nMaxCount;
142     sal_uIntPtr                   nStatics;
143     sal_Char                aName[DBG_MAXNAME+1];
144     sal_Bool                    bTest;
145     PointerList             aThisList;
146 };
147 
148 struct DebugData
149 {
150     DbgData                 aDbgData;
151     sal_uInt16                  bInit;
152     DbgPrintLine            pDbgPrintMsgBox;
153     DbgPrintLine            pDbgPrintWindow;
154     DbgPrintLine            pDbgPrintTestTool;
155 	DbgPrintLine			pDbgAbort;
156     ::std::vector< DbgPrintLine >
157                             aDbgPrintUserChannels;
158     PointerList*            pProfList;
159     PointerList*            pXtorList;
160     DbgTestSolarMutexProc   pDbgTestSolarMutex;
161     pfunc_osl_printDetailedDebugMessage
162                             pOldDebugMessageFunc;
163     bool                    bOslIsHooked;
164 
165     DebugData()
166         :bInit( sal_False )
167         ,pDbgPrintMsgBox( NULL )
168         ,pDbgPrintWindow( NULL )
169         ,pDbgPrintTestTool( NULL )
170 		,pDbgAbort( NULL )
171         ,pProfList( NULL )
172         ,pXtorList( NULL )
173         ,pDbgTestSolarMutex( NULL )
174         ,pOldDebugMessageFunc( NULL )
175         ,bOslIsHooked( false )
176     {
177         aDbgData.nTestFlags = DBG_TEST_RESOURCE | DBG_TEST_MEM_INIT;
178         aDbgData.bOverwrite = sal_True;
179         aDbgData.nTraceOut = DBG_OUT_NULL;
180         aDbgData.nWarningOut = DBG_OUT_NULL;
181         aDbgData.nErrorOut = DBG_OUT_MSGBOX;
182         aDbgData.bMemInit = 0x77;
183         aDbgData.bMemBound = 0x55;
184         aDbgData.bMemFree = 0x33;
185         aDbgData.bHookOSLAssert = sal_True;
186         aDbgData.aDebugName[0] = 0;
187         aDbgData.aInclFilter[0] = 0;
188         aDbgData.aExclFilter[0] = 0;
189         aDbgData.aInclClassFilter[0] = 0;
190         aDbgData.aExclClassFilter[0] = 0;
191         aDbgData.aDbgWinState[0] = 0;
192     }
193 };
194 
195 #define DBG_TEST_XTOR_EXTRA (DBG_TEST_XTOR_THIS |  DBG_TEST_XTOR_FUNC |               \
196                              DBG_TEST_XTOR_EXIT |  DBG_TEST_XTOR_REPORT )
197 
198 // ------------------------------
199 // - statische Verwaltungsdaten -
200 // ------------------------------
201 
202 static DebugData aDebugData;
203 
204 static sal_Char aCurPath[260];
205 
206 static int bDbgImplInMain = sal_False;
207 
208 // =======================================================================
209 
210 #if defined( WNT )
211 static CRITICAL_SECTION aImplCritDbgSection;
212 #elif defined( OS2 )
213 static HMTX             hImplCritDbgSection = 0;
214 #endif
215 static sal_Bool             bImplCritDbgSectionInit = sal_False;
216 
217 // -----------------------------------------------------------------------
218 
219 void ImplDbgInitLock()
220 {
221 #if defined( WNT )
222     InitializeCriticalSection( &aImplCritDbgSection );
223 #elif defined( OS2 )
224     DosCreateMutexSem( NULL, &hImplCritDbgSection, 0, sal_False );
225 #endif
226     bImplCritDbgSectionInit = sal_True;
227 }
228 
229 // -----------------------------------------------------------------------
230 
231 void ImplDbgDeInitLock()
232 {
233 #if defined( WNT )
234     DeleteCriticalSection( &aImplCritDbgSection );
235 #elif defined( OS2 )
236     DosCloseMutexSem( hImplCritDbgSection );
237 #endif
238     bImplCritDbgSectionInit = sal_False;
239 }
240 
241 // -----------------------------------------------------------------------
242 
243 void ImplDbgLock()
244 {
245     if ( !bImplCritDbgSectionInit )
246         return;
247 
248 #if defined( WNT )
249     EnterCriticalSection( &aImplCritDbgSection );
250 #elif defined( OS2 )
251     DosRequestMutexSem( hImplCritDbgSection, SEM_INDEFINITE_WAIT );
252 #endif
253 }
254 
255 // -----------------------------------------------------------------------
256 
257 void ImplDbgUnlock()
258 {
259     if ( !bImplCritDbgSectionInit )
260         return;
261 
262 #if defined( WNT )
263     LeaveCriticalSection( &aImplCritDbgSection );
264 #elif defined( OS2 )
265     DosReleaseMutexSem( hImplCritDbgSection );
266 #endif
267 }
268 
269 // =======================================================================
270 
271 #if (defined WNT || defined OS2) && !defined SVX_LIGHT
272 //#define SV_MEMMGR //
273 #endif
274 #ifdef SV_MEMMGR
275 void DbgImpCheckMemory( void* p = NULL );
276 void DbgImpCheckMemoryDeInit();
277 void DbgImpMemoryInfo( sal_Char* pBuf );
278 #endif
279 
280 #define FILE_LINEEND    "\n"
281 
282 // =======================================================================
283 
284 static sal_Bool ImplActivateDebugger( const sal_Char* pMsg )
285 {
286 #if defined( WNT )
287     static sal_Char aImplDbgOutBuf[DBG_BUF_MAXLEN];
288     strcpy( aImplDbgOutBuf, pMsg );
289     strcat( aImplDbgOutBuf, "\r\n" );
290     OutputDebugString( aImplDbgOutBuf );
291     DebugBreak();
292     return sal_True;
293 #else
294     (void) pMsg; // avoid warning about unused parameter
295     return sal_False;
296 #endif
297 }
298 
299 // -----------------------------------------------------------------------
300 
301 static sal_Bool ImplCoreDump()
302 {
303 #if defined( WNT )
304     DebugBreak();
305 #else
306     long* pTemp = 0;
307     *pTemp = 0xCCCC;
308 #endif
309     return sal_True;
310 }
311 
312 // =======================================================================
313 
314 static sal_uIntPtr ImplGetPerfTime()
315 {
316 #if defined( WNT )
317     return (sal_uIntPtr)GetTickCount();
318 #elif defined( OS2 )
319     sal_uIntPtr nClock;
320     DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) );
321     return (sal_uIntPtr)nClock;
322 #else
323     static sal_uIntPtr    nImplTicksPerSecond = 0;
324     static double   dImplTicksPerSecond;
325     sal_uIntPtr           nTicks = (sal_uIntPtr)clock();
326 
327     if ( !nImplTicksPerSecond )
328     {
329         nImplTicksPerSecond = CLOCKS_PER_SEC;
330         dImplTicksPerSecond = nImplTicksPerSecond;
331     }
332 
333     double fTicks = nTicks;
334     fTicks *= 1000;
335     fTicks /= dImplTicksPerSecond;
336     return (sal_uIntPtr)fTicks;
337 #endif
338 }
339 
340 // -----------------------------------------------------------------------
341 
342 typedef FILE*       FILETYPE;
343 #define FileOpen    fopen
344 #define FileRead    fread
345 #define FileWrite   fwrite
346 #define FilePrintF  fprintf
347 #define FileClose   fclose
348 
349 // =======================================================================
350 
351 namespace
352 {
353     enum ConfigSection
354     {
355         eOutput,
356         eMemory,
357         eGUI,
358         eObjects,
359         eTest,
360 
361         eUnknown
362     };
363 
364     void lcl_lineFeed( FILETYPE _pFile )
365     {
366         FilePrintF( _pFile, "%s", FILE_LINEEND );
367     }
368 
369     const sal_Char* lcl_getSectionName( ConfigSection _eSection )
370     {
371         const sal_Char* pSectionName = NULL;
372         switch ( _eSection )
373         {
374             case eOutput    : pSectionName = "output";  break;
375             case eMemory    : pSectionName = "memory";  break;
376             case eGUI       : pSectionName = "gui";     break;
377             case eObjects   : pSectionName = "objects"; break;
378             case eTest      : pSectionName = "test";    break;
379             case eUnknown:
380                 OSL_ASSERT(false);
381                 break;
382         }
383         return pSectionName;
384     }
385 
386     ConfigSection lcl_getSectionFromName( const sal_Char* _pSectionName, size_t _nSectionNameLength )
387     {
388         if ( strncmp( _pSectionName, "output",  _nSectionNameLength < 6 ? _nSectionNameLength : 6 ) == 0 )
389             return eOutput;
390         if ( strncmp( _pSectionName, "memory",  _nSectionNameLength < 6 ? _nSectionNameLength : 6 ) == 0 )
391             return eMemory;
392         if ( strncmp( _pSectionName, "gui",     _nSectionNameLength < 3 ? _nSectionNameLength : 3 ) == 0 )
393             return eGUI;
394         if ( strncmp( _pSectionName, "objects", _nSectionNameLength < 7 ? _nSectionNameLength : 7 ) == 0 )
395             return eObjects;
396         if ( strncmp( _pSectionName, "test",    _nSectionNameLength < 4 ? _nSectionNameLength : 4 ) == 0 )
397             return eTest;
398         return eUnknown;
399     }
400 
401     void lcl_startSection( FILETYPE _pFile, ConfigSection _eSection )
402     {
403         FilePrintF( _pFile, "[%s]%s", lcl_getSectionName( _eSection ), FILE_LINEEND );
404     }
405 
406     void lcl_writeConfigString( FILETYPE _pFile, const sal_Char* _pKeyName, const sal_Char* _pValue )
407     {
408         FilePrintF( _pFile, "%s=%s%s", _pKeyName, _pValue, FILE_LINEEND );
409     }
410 
411     void lcl_writeConfigBoolean( FILETYPE _pFile, const sal_Char* _pKeyName, bool _bValue )
412     {
413         lcl_writeConfigString( _pFile, _pKeyName, _bValue ? "1" : "0" );
414     }
415 
416     void lcl_writeConfigFlag( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uIntPtr _nAllFlags, sal_uIntPtr _nCheckFlag )
417     {
418         lcl_writeConfigBoolean( _pFile, _pKeyName, ( _nAllFlags & _nCheckFlag ) != 0 );
419     }
420 
421     void lcl_writeConfigOutChannel( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uIntPtr _nValue )
422     {
423         const sal_Char* names[ DBG_OUT_COUNT ] =
424         {
425             "dev/null", "file", "window", "shell", "messagebox", "testtool", "debugger", "abort"
426         };
427         lcl_writeConfigString( _pFile, _pKeyName, names[ _nValue ] );
428     }
429     void lcl_writeHexByte( FILETYPE _pFile, const sal_Char* _pKeyName, sal_uInt8 _nValue )
430     {
431         sal_Char buf[RTL_STR_MAX_VALUEOFINT32];
432         rtl_String* stringData = NULL;
433         rtl_string_newFromStr_WithLength( &stringData, buf, rtl_str_valueOfInt32( buf, _nValue, 16 ) );
434 
435         lcl_writeConfigString( _pFile, _pKeyName, stringData->buffer );
436 
437         rtl_string_release( stringData );
438     }
439     bool lcl_isConfigSection( const sal_Char* _pLine, size_t _nLineLen )
440     {
441         if ( _nLineLen < 2 )
442             // not even enough space for '[' and ']'
443             return false;
444         if ( ( _pLine[0] == '[' ) && ( _pLine[ _nLineLen - 1 ] == ']' ) )
445             return true;
446         return false;
447     }
448     bool lcl_isConfigKey( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName )
449     {
450         size_t nKeyLength = strlen( _pKeyName );
451         if ( nKeyLength + 1 >= _nLineLen )
452             // not even long enough for the key name plus "=" plus a one-character value
453             return false;
454         if ( ( strncmp( _pLine, _pKeyName, nKeyLength ) == 0 ) && ( _pLine[ nKeyLength ] == '=' ) )
455             return true;
456         return false;
457     }
458     sal_Int32 lcl_tryReadConfigString( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_Char* _pValue, size_t _nValueLen )
459     {
460         if ( !lcl_isConfigKey( _pLine, _nLineLen, _pKeyName ) )
461             return 0;
462         size_t nValuePos = strlen( _pKeyName ) + 1;
463         size_t nValueLen = _nLineLen - nValuePos;
464         const sal_Char* pValue = _pLine + nValuePos;
465         strncpy( _pValue, pValue, ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen );
466         _pValue[ ( _nValueLen > nValueLen ) ? nValueLen : _nValueLen - 1 ] = 0;
467         return strlen( _pValue );
468     }
469     void lcl_tryReadConfigBoolean( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnValue )
470     {
471         sal_Char aBuf[2];
472         size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
473         if ( nValueLen )
474             *_out_pnValue = strcmp( aBuf, "1" ) == 0 ? sal_True : sal_False;
475     }
476     void lcl_matchOutputChannel( sal_Char const * i_buffer, sal_uIntPtr* o_value )
477     {
478         if ( i_buffer == NULL )
479             return;
480         const sal_Char* names[ DBG_OUT_COUNT ] =
481         {
482             "dev/null", "file", "window", "shell", "messagebox", "testtool", "debugger", "abort"
483         };
484         for ( sal_uIntPtr name = 0; name < sizeof( names ) / sizeof( names[0] ); ++name )
485         {
486             if ( strcmp( i_buffer, names[ name ] ) == 0 )
487             {
488                 *o_value = name;
489                 return;
490             }
491         }
492     }
493     void lcl_tryReadOutputChannel( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnValue )
494     {
495         sal_Char aBuf[20];
496         size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
497         if ( nValueLen )
498             lcl_matchOutputChannel( aBuf, _out_pnValue );
499     }
500     void lcl_tryReadConfigFlag( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uIntPtr* _out_pnAllFlags, sal_uIntPtr _nCheckFlag )
501     {
502         sal_Char aBuf[2];
503         size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
504         if ( nValueLen )
505             if ( strcmp( aBuf, "1" ) == 0 )
506                 *_out_pnAllFlags |= _nCheckFlag;
507             else
508                 *_out_pnAllFlags &= ~_nCheckFlag;
509     }
510     void lcl_tryReadHexByte( const sal_Char* _pLine, size_t _nLineLen, const sal_Char* _pKeyName, sal_uInt8* _out_pnValue )
511     {
512         sal_Char aBuf[3];
513         size_t nValueLen = lcl_tryReadConfigString( _pLine, _nLineLen, _pKeyName, aBuf, sizeof( aBuf ) );
514         if ( nValueLen )
515             *_out_pnValue = (sal_uInt8)rtl_str_toInt32( aBuf, 16 );
516     }
517 }
518 
519 // =======================================================================
520 
521 PointerList::~PointerList()
522 {
523     PBlock* pBlock = pFirst;
524     while ( pBlock )
525     {
526         PBlock* pNextBlock = pBlock->pNext;
527         delete pBlock;
528         pBlock = pNextBlock;
529     }
530 }
531 
532 // -----------------------------------------------------------------------
533 
534 void PointerList::Add( const void* p )
535 {
536     if ( !pFirst )
537     {
538         pFirst = new PBlock;
539         memset( pFirst->aData, 0, PBLOCKCOUNT * sizeof( void* ) );
540         pFirst->nCount = 0;
541         pFirst->pPrev  = NULL;
542         pFirst->pNext  = NULL;
543         pLast = pFirst;
544     }
545 
546     PBlock* pBlock = pFirst;
547     while ( pBlock && (pBlock->nCount == PBLOCKCOUNT) )
548         pBlock = pBlock->pNext;
549 
550     if ( !pBlock )
551     {
552         pBlock = new PBlock;
553         memset( pBlock->aData, 0, PBLOCKCOUNT * sizeof( void* ) );
554         pBlock->nCount = 0;
555         pBlock->pPrev  = pLast;
556         pBlock->pNext  = NULL;
557         pLast->pNext   = pBlock;
558         pLast          = pBlock;
559     }
560 
561     sal_uInt16 i = 0;
562     while ( pBlock->aData[i] )
563         i++;
564 
565     pBlock->aData[i] = (void*)p;
566     pBlock->nCount++;
567     nCount++;
568 }
569 
570 // -----------------------------------------------------------------------
571 
572 sal_Bool PointerList::Remove( const void* p )
573 {
574     if ( !p )
575        return sal_False;
576 
577     PBlock* pBlock = pFirst;
578     while ( pBlock )
579     {
580         sal_uInt16 i = 0;
581         while ( i < PBLOCKCOUNT )
582         {
583             if ( ((sal_uIntPtr)p) == ((sal_uIntPtr)pBlock->aData[i]) )
584             {
585                 pBlock->aData[i] = NULL;
586                 pBlock->nCount--;
587                 nCount--;
588 
589                 if ( !pBlock->nCount )
590                 {
591                     if ( pBlock->pPrev )
592                         pBlock->pPrev->pNext = pBlock->pNext;
593                     if ( pBlock->pNext )
594                         pBlock->pNext->pPrev = pBlock->pPrev;
595                     if ( pBlock == pFirst )
596                         pFirst = pBlock->pNext;
597                     if ( pBlock == pLast )
598                         pLast = pBlock->pPrev;
599                     delete pBlock;
600                 }
601 
602                 return sal_True;
603             }
604             i++;
605         }
606 
607         pBlock = pBlock->pNext;
608     }
609 
610     return sal_False;
611 }
612 
613 // -----------------------------------------------------------------------
614 
615 const void* PointerList::Get( sal_uIntPtr nPos ) const
616 {
617     if ( nCount <= nPos )
618         return NULL;
619 
620     PBlock* pBlock = pFirst;
621     sal_uIntPtr   nStart = 0;
622     while ( pBlock )
623     {
624         sal_uInt16 i = 0;
625         while ( i < PBLOCKCOUNT )
626         {
627             if ( pBlock->aData[i] )
628             {
629                 nStart++;
630                 if ( (nStart-1) == nPos )
631                     return pBlock->aData[i];
632             }
633 
634             i++;
635         }
636 
637         pBlock = pBlock->pNext;
638     }
639 
640     return NULL;
641 }
642 
643 // -----------------------------------------------------------------------
644 
645 sal_Bool PointerList::IsIn( const void* p ) const
646 {
647     if ( !p )
648        return sal_False;
649 
650     PBlock* pBlock = pFirst;
651     while ( pBlock )
652     {
653         sal_uInt16 i = 0;
654         while ( i < PBLOCKCOUNT )
655         {
656             if ( ((sal_uIntPtr)p) == ((sal_uIntPtr)pBlock->aData[i]) )
657                 return sal_True;
658             i++;
659         }
660 
661         pBlock = pBlock->pNext;
662     }
663 
664     return sal_False;
665 }
666 
667 
668 // =======================================================================
669 
670 static void DbgGetDbgFileName( sal_Char* pStr, sal_Int32 nMaxLen )
671 {
672 #if defined( UNX )
673     const sal_Char* pName = getenv("DBGSV_INIT");
674     if ( !pName )
675         pName = ".dbgsv.init";
676     strncpy( pStr, pName, nMaxLen );
677 #elif defined( WNT )
678     const sal_Char* pName = getenv("DBGSV_INIT");
679     if ( pName )
680         strncpy( pStr, pName, nMaxLen );
681     else
682         GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, nMaxLen );
683 #elif defined( OS2 )
684     PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSV",
685                            "dbgsv.ini", (PSZ)pStr, nMaxLen );
686 #else
687     strncpy( pStr, "dbgsv.ini", nMaxLen );
688 #endif
689     pStr[ nMaxLen - 1 ] = 0;
690 }
691 
692 // -----------------------------------------------------------------------
693 
694 static void DbgGetLogFileName( sal_Char* pStr )
695 {
696 #if defined( UNX )
697     const sal_Char* pName = getenv("DBGSV_LOG");
698     if ( !pName )
699         pName = "dbgsv.log";
700     strcpy( pStr, pName );
701 #elif defined( WNT )
702     const sal_Char* pName = getenv("DBGSV_LOG");
703     if ( pName )
704         strcpy( pStr, pName );
705     else
706         GetProfileStringA( "sv", "dbgsvlog", "dbgsv.log", pStr, 200 );
707 #elif defined( OS2 )
708     PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSVLOG",
709                            "dbgsv.log", (PSZ)pStr, 200 );
710 #else
711     strcpy( pStr, "dbgsv.log" );
712 #endif
713 }
714 
715 // -----------------------------------------------------------------------
716 
717 static void DbgDebugBeep()
718 {
719 #if defined( WNT )
720     MessageBeep( MB_ICONHAND );
721 #elif defined( OS2 )
722     WinAlarm( HWND_DESKTOP, WA_ERROR );
723 #endif
724 }
725 
726 // -----------------------------------------------------------------------
727 
728 static DebugData* GetDebugData()
729 {
730     if ( !aDebugData.bInit )
731     {
732         aDebugData.bInit = sal_True;
733 
734         // Default Debug-Namen setzen
735         DbgGetLogFileName( aDebugData.aDbgData.aDebugName );
736 
737         // DEBUG.INI-File
738         sal_Char aBuf[ 4096 ];
739         DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
740         FILETYPE pIniFile = FileOpen( aBuf, "r" );
741         if ( pIniFile != NULL )
742         {
743             ConfigSection eCurrentSection = eUnknown;
744 
745             // no sophisticated algorithm here, assume that the whole file fits into aBuf ...
746             sal_uIntPtr nReallyRead = FileRead( aBuf, 1, sizeof( aBuf ) / sizeof( sal_Char ) - 1, pIniFile );
747             aBuf[ nReallyRead ] = 0;
748             const sal_Char* pLine = aBuf;
749             while ( const sal_Char* pNextLine = strstr( pLine, FILE_LINEEND ) )
750             {
751                 size_t nLineLength = pNextLine - pLine;
752 
753                 if ( lcl_isConfigSection( pLine, nLineLength ) )
754                     eCurrentSection = lcl_getSectionFromName( pLine + 1, nLineLength - 2 );
755 
756                 // elements of the [output] section
757                 if ( eCurrentSection == eOutput )
758                 {
759                     lcl_tryReadConfigString( pLine, nLineLength, "log_file", aDebugData.aDbgData.aDebugName, sizeof( aDebugData.aDbgData.aDebugName ) );
760                     lcl_tryReadConfigBoolean( pLine, nLineLength, "overwrite", &aDebugData.aDbgData.bOverwrite );
761                     lcl_tryReadConfigString( pLine, nLineLength, "include", aDebugData.aDbgData.aInclFilter, sizeof( aDebugData.aDbgData.aInclFilter ) );
762                     lcl_tryReadConfigString( pLine, nLineLength, "exclude", aDebugData.aDbgData.aExclFilter, sizeof( aDebugData.aDbgData.aExclFilter ) );
763                     lcl_tryReadConfigString( pLine, nLineLength, "include_class", aDebugData.aDbgData.aInclClassFilter, sizeof( aDebugData.aDbgData.aInclClassFilter ) );
764                     lcl_tryReadConfigString( pLine, nLineLength, "exclude_class", aDebugData.aDbgData.aExclClassFilter, sizeof( aDebugData.aDbgData.aExclClassFilter ) );
765                     lcl_tryReadOutputChannel( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTraceOut );
766                     lcl_tryReadOutputChannel( pLine, nLineLength, "warning", &aDebugData.aDbgData.nWarningOut );
767                     lcl_tryReadOutputChannel( pLine, nLineLength, "error", &aDebugData.aDbgData.nErrorOut );
768                     lcl_tryReadConfigBoolean( pLine, nLineLength, "oslhook", &aDebugData.aDbgData.bHookOSLAssert );
769                 }
770 
771                 // elements of the [memory] section
772                 if ( eCurrentSection == eMemory )
773                 {
774                     lcl_tryReadConfigFlag( pLine, nLineLength, "initialize", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_INIT );
775                     lcl_tryReadConfigFlag( pLine, nLineLength, "overwrite", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_OVERWRITE );
776                     lcl_tryReadConfigFlag( pLine, nLineLength, "overwrite_free", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_OVERWRITEFREE );
777                     lcl_tryReadConfigFlag( pLine, nLineLength, "pointer", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_POINTER );
778                     lcl_tryReadConfigFlag( pLine, nLineLength, "report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_REPORT );
779                     lcl_tryReadConfigFlag( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_TRACE );
780                     lcl_tryReadConfigFlag( pLine, nLineLength, "new_and_delete", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_NEWDEL );
781                     lcl_tryReadConfigFlag( pLine, nLineLength, "object_test", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_XTOR );
782                     lcl_tryReadConfigFlag( pLine, nLineLength, "sys_alloc", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_SYSALLOC );
783                     lcl_tryReadConfigFlag( pLine, nLineLength, "leak_report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_MEM_LEAKREPORT );
784 
785                     lcl_tryReadHexByte( pLine, nLineLength, "init_byte", &aDebugData.aDbgData.bMemInit );
786                     lcl_tryReadHexByte( pLine, nLineLength, "bound_byte", &aDebugData.aDbgData.bMemBound );
787                     lcl_tryReadHexByte( pLine, nLineLength, "free_byte", &aDebugData.aDbgData.bMemFree );
788                 }
789 
790                 // elements of the [gui] section
791                 if ( eCurrentSection == eGUI )
792                 {
793                     lcl_tryReadConfigString( pLine, nLineLength, "debug_window_state", aDebugData.aDbgData.aDbgWinState, sizeof( aDebugData.aDbgData.aDbgWinState ) );
794                 }
795 
796                 // elements of the [objects] section
797                 if ( eCurrentSection == eObjects )
798                 {
799                     lcl_tryReadConfigFlag( pLine, nLineLength, "check_this", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_THIS );
800                     lcl_tryReadConfigFlag( pLine, nLineLength, "check_function", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_FUNC );
801                     lcl_tryReadConfigFlag( pLine, nLineLength, "check_exit", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_EXIT );
802                     lcl_tryReadConfigFlag( pLine, nLineLength, "generate_report", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_REPORT );
803                     lcl_tryReadConfigFlag( pLine, nLineLength, "trace", &aDebugData.aDbgData.nTestFlags, DBG_TEST_XTOR_TRACE );
804                 }
805 
806                 // elements of the [test] section
807                 if ( eCurrentSection == eTest )
808                 {
809                     lcl_tryReadConfigFlag( pLine, nLineLength, "profiling", &aDebugData.aDbgData.nTestFlags, DBG_TEST_PROFILING );
810                     lcl_tryReadConfigFlag( pLine, nLineLength, "resources", &aDebugData.aDbgData.nTestFlags, DBG_TEST_RESOURCE );
811                     lcl_tryReadConfigFlag( pLine, nLineLength, "dialog", &aDebugData.aDbgData.nTestFlags, DBG_TEST_DIALOG );
812                     lcl_tryReadConfigFlag( pLine, nLineLength, "bold_app_font", &aDebugData.aDbgData.nTestFlags, DBG_TEST_BOLDAPPFONT );
813                 }
814 
815                 pLine = pNextLine + strlen( FILE_LINEEND );
816             }
817 
818             FileClose( pIniFile );
819         }
820         else
821         {
822             lcl_matchOutputChannel( getenv( "DBGSV_TRACE_OUT" ), &aDebugData.aDbgData.nTraceOut );
823             lcl_matchOutputChannel( getenv( "DBGSV_WARNING_OUT" ), &aDebugData.aDbgData.nWarningOut );
824             lcl_matchOutputChannel( getenv( "DBGSV_ERROR_OUT" ), &aDebugData.aDbgData.nErrorOut );
825 
826         }
827 
828         getcwd( aCurPath, sizeof( aCurPath ) );
829 
830         // Daten initialisieren
831         if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_XTOR )
832             aDebugData.pXtorList = new PointerList;
833         if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_PROFILING )
834             aDebugData.pProfList = new PointerList;
835     }
836 
837     return &aDebugData;
838 }
839 
840 // -----------------------------------------------------------------------
841 
842 inline DebugData* ImplGetDebugData()
843 {
844     if ( !aDebugData.bInit )
845         return GetDebugData();
846     else
847         return &aDebugData;
848 }
849 
850 // -----------------------------------------------------------------------
851 
852 static FILETYPE ImplDbgInitFile()
853 {
854     static sal_Bool bFileInit = sal_False;
855 
856     sal_Char aBuf[4096];
857     getcwd( aBuf, sizeof( aBuf ) );
858     chdir( aCurPath );
859 
860     DebugData*  pData = GetDebugData();
861     FILETYPE    pDebugFile;
862 
863     if ( !bFileInit )
864     {
865         bFileInit = sal_True;
866 
867         if ( pData->aDbgData.bOverwrite )
868             pDebugFile = FileOpen( pData->aDbgData.aDebugName, "w" );
869         else
870             pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" );
871 
872         if ( pDebugFile )
873         {
874             time_t  nTime = time( 0 );
875             tm*     pTime;
876 #ifdef UNX
877             tm      aTime;
878             pTime = localtime_r( &nTime, &aTime );
879 #else
880             pTime = localtime( &nTime );
881 #endif
882 
883             // Header ausgeben
884             FilePrintF( pDebugFile, "******************************************************************************%s", FILE_LINEEND );
885             FilePrintF( pDebugFile, "%s%s", pData->aDbgData.aDebugName, FILE_LINEEND );
886             if ( pTime )
887                 FilePrintF( pDebugFile, "%s%s", asctime( pTime ), FILE_LINEEND );
888         }
889     }
890     else
891         pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" );
892 
893     chdir( aBuf );
894 
895     return pDebugFile;
896 }
897 
898 // -----------------------------------------------------------------------
899 
900 static void ImplDbgPrintFile( const sal_Char* pLine )
901 {
902     FILETYPE pDebugFile = ImplDbgInitFile();
903 
904     if ( pDebugFile )
905     {
906         FilePrintF( pDebugFile, "%s%s", pLine, FILE_LINEEND );
907         FileClose( pDebugFile );
908     }
909 }
910 
911 // -----------------------------------------------------------------------
912 
913 static int ImplStrSearch( const sal_Char* pSearchStr, int nSearchLen,
914                           const sal_Char* pStr, int nLen )
915 {
916     int nPos = 0;
917     while ( nPos+nSearchLen <= nLen )
918     {
919         if ( strncmp( pStr+nPos, pSearchStr, nSearchLen ) == 0 )
920             return 1;
921         nPos++;
922     }
923 
924     return 0;
925 }
926 
927 // -----------------------------------------------------------------------
928 
929 static int ImplDbgFilter( const sal_Char* pFilter, const sal_Char* pMsg,
930                           int bEmpty )
931 {
932     int nStrLen = strlen( pFilter );
933     if ( !nStrLen )
934         return bEmpty;
935 
936     int nMsgLen = strlen( pMsg );
937     const sal_Char* pTok = pFilter;
938     int         nTok = 0;
939     while ( pTok[nTok] )
940     {
941         if ( pTok[nTok] == ';' )
942         {
943             if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) )
944                 return sal_True;
945 
946             pTok += nTok+1;
947             nTok = 0;
948         }
949 
950         nTok++;
951     }
952 
953     if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) )
954         return sal_True;
955     else
956         return sal_False;
957 }
958 
959 // -----------------------------------------------------------------------
960 
961 extern "C"
962 void SAL_CALL dbg_printOslDebugMessage( const sal_Char * pszFileName, sal_Int32 nLine, const sal_Char * pszMessage )
963 {
964     DbgOut( pszMessage ? pszMessage : "assertion failed!", DBG_OUT_ERROR, pszFileName, (sal_uInt16)nLine );
965 }
966 
967 // -----------------------------------------------------------------------
968 
969 static void DebugInit()
970 {
971     bDbgImplInMain = sal_True;
972     ImplDbgInitLock();
973 
974     DebugData* pData = GetDebugData();
975     if( pData->aDbgData.bHookOSLAssert && ! pData->bOslIsHooked )
976     {
977         pData->pOldDebugMessageFunc = osl_setDetailedDebugMessageFunc( &dbg_printOslDebugMessage );
978         pData->bOslIsHooked = true;
979     }
980 }
981 
982 // -----------------------------------------------------------------------
983 
984 static void DebugDeInit()
985 {
986     DebugData*  pData = GetDebugData();
987     sal_uIntPtr       i;
988     sal_uIntPtr       nCount;
989     sal_uIntPtr       nOldOut;
990 
991     if( pData->bOslIsHooked )
992     {
993         osl_setDetailedDebugMessageFunc( pData->pOldDebugMessageFunc );
994         pData->bOslIsHooked = sal_False;
995     }
996 
997     // Statistik-Ausgaben immer in File
998     nOldOut = pData->aDbgData.nTraceOut;
999     pData->aDbgData.nTraceOut = DBG_OUT_FILE;
1000 
1001     // Xtor-Liste ausgeben
1002     if ( pData->pXtorList && pData->pXtorList->Count() &&
1003          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) )
1004     {
1005         DbgOutf( "------------------------------------------------------------------------------" );
1006         DbgOutf( "Object Report" );
1007         DbgOutf( "------------------------------------------------------------------------------" );
1008         DbgOutf( "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :",
1009                  "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." );
1010         DbgOutf( "----------------------------:-----------:-----------:---------:----:---------:" );
1011         for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
1012         {
1013             XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
1014             if ( pXtorData->bTest )
1015             {
1016                 // Static-Objekte dazurechnen
1017                 pXtorData->nDtorCalls += pXtorData->nStatics;
1018                 if ( pXtorData->nStatics && (pXtorData->nDtorCalls > pXtorData->nCtorCalls) )
1019                     pXtorData->nDtorCalls = pXtorData->nCtorCalls;
1020                 DbgOutf( "%-27s : %9lu : %9lu : %7lu : %3lu : %4lu %-1s :",
1021                          pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls,
1022                          pXtorData->nMaxCount, pXtorData->nStatics,
1023                          pXtorData->nCtorCalls - pXtorData->nDtorCalls,
1024                          (pXtorData->nCtorCalls - pXtorData->nDtorCalls) ? "!" : " " );
1025             }
1026         }
1027         DbgOutf( "==============================================================================" );
1028     }
1029 
1030     // Aufraeumen
1031     if ( pData->pXtorList )
1032     {
1033         for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
1034         {
1035             XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
1036             delete pXtorData;
1037         }
1038         delete pData->pXtorList;
1039         pData->pXtorList = NULL;
1040     }
1041 
1042     // Alles auf sal_False setzen, damit globale Variablen nicht das
1043     // System zum Abstuerzen bringt. Dabei muessen aber die
1044     // Memory-Flags erhalten bleiben, da sonst new/delete in globalen
1045     // Variablen abstuerzen, da die Pointeranpassung dann nicht mehr richtig
1046     // funktioniert
1047     pData->aDbgData.nTraceOut   = nOldOut;
1048     pData->aDbgData.nTestFlags &= (DBG_TEST_MEM | DBG_TEST_PROFILING);
1049     pData->aDbgPrintUserChannels.clear();
1050     pData->pDbgPrintTestTool    = NULL;
1051     pData->pDbgPrintWindow      = NULL;
1052     pData->pOldDebugMessageFunc = NULL;
1053     ImplDbgDeInitLock();
1054 }
1055 
1056 // -----------------------------------------------------------------------
1057 
1058 static void DebugGlobalDeInit()
1059 {
1060     DebugData*  pData = GetDebugData();
1061     sal_uIntPtr       i;
1062     sal_uIntPtr       nCount;
1063     sal_uIntPtr       nOldOut;
1064 
1065     // Statistik-Ausgaben immer in File
1066     nOldOut = pData->aDbgData.nTraceOut;
1067     pData->aDbgData.nTraceOut = DBG_OUT_FILE;
1068 
1069     // Profileliste ausgeben
1070     if ( pData->pProfList && pData->pProfList->Count() )
1071     {
1072         DbgOutf( "------------------------------------------------------------------------------" );
1073         DbgOutf( "Profiling Report" );
1074         DbgOutf( "------------------------------------------------------------------------------" );
1075         DbgOutf( "%-25s : %-9s : %-6s : %-6s : %-6s : %-9s :",
1076                  "Prof-List (ms)", "Time", "Min", "Max", "Ave", "Count" );
1077         DbgOutf( "--------------------------:-----------:--------:--------:--------:-----------:" );
1078         for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ )
1079         {
1080             ProfType* pProfData = (ProfType*)pData->pProfList->Get( i );
1081             sal_uIntPtr nAve = pProfData->nTime / pProfData->nCount;
1082             DbgOutf( "%-25s : %9lu : %6lu : %6lu : %6lu : %9lu :",
1083                      pProfData->aName, pProfData->nTime,
1084                      pProfData->nMinTime, pProfData->nMaxTime, nAve,
1085                      pProfData->nCount );
1086         }
1087         DbgOutf( "==============================================================================" );
1088     }
1089 
1090     // Aufraeumen
1091     if ( pData->pProfList )
1092     {
1093         for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ )
1094         {
1095             ProfType* pProfData = (ProfType*)pData->pProfList->Get( i );
1096             delete pProfData;
1097         }
1098         delete pData->pProfList;
1099         pData->pProfList = NULL;
1100     }
1101 
1102 #ifdef SV_MEMMGR
1103     DbgImpCheckMemoryDeInit();
1104 #endif
1105 
1106     // Profiling-Flags ausschalten
1107     pData->aDbgData.nTraceOut   = nOldOut;
1108     pData->aDbgData.nTestFlags &= ~DBG_TEST_PROFILING;
1109 }
1110 
1111 // -----------------------------------------------------------------------
1112 
1113 void ImpDbgOutfBuf( sal_Char* pBuf, const sal_Char* pFStr, ... )
1114 {
1115     va_list pList;
1116 
1117     va_start( pList, pFStr );
1118     sal_Char aBuf[DBG_BUF_MAXLEN];
1119     vsprintf( aBuf, pFStr, pList );
1120     va_end( pList );
1121 
1122     strcat( pBuf, aBuf );
1123     strcat( pBuf, "\n" );
1124 }
1125 
1126 // -----------------------------------------------------------------------
1127 
1128 static void DebugXTorInfo( sal_Char* pBuf )
1129 {
1130     DebugData*  pData = GetDebugData();
1131     sal_uIntPtr       i;
1132     sal_uIntPtr       nCount;
1133 
1134     // Xtor-Liste ausgeben
1135     if ( pData->pXtorList && pData->pXtorList->Count() &&
1136          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) )
1137     {
1138         ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" );
1139         ImpDbgOutfBuf( pBuf, "Object Report" );
1140         ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" );
1141         ImpDbgOutfBuf( pBuf, "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :",
1142                        "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." );
1143         ImpDbgOutfBuf( pBuf, "----------------------------:-----------:-----------:---------:----:---------:" );
1144         for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
1145         {
1146             XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
1147             if ( pXtorData->bTest )
1148             {
1149                 ImpDbgOutfBuf( pBuf, "%-27s : %9lu : %9lu : %7lu : %3lu : %6lu :",
1150                                pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls,
1151                                pXtorData->nMaxCount, pXtorData->nStatics,
1152                                pXtorData->nCtorCalls - pXtorData->nDtorCalls );
1153             }
1154         }
1155         ImpDbgOutfBuf( pBuf, "==============================================================================" );
1156         ImpDbgOutfBuf( pBuf, "" );
1157     }
1158 }
1159 
1160 // -----------------------------------------------------------------------
1161 sal_Bool ImplDbgFilterMessage( const sal_Char* pMsg )
1162 {
1163     DebugData*  pData = GetDebugData();
1164     if ( !ImplDbgFilter( pData->aDbgData.aInclFilter, pMsg, sal_True ) )
1165         return sal_True;
1166     if ( ImplDbgFilter( pData->aDbgData.aExclFilter, pMsg, sal_False ) )
1167         return sal_True;
1168     return sal_False;
1169 }
1170 
1171 // -----------------------------------------------------------------------
1172 
1173 void* DbgFunc( sal_uInt16 nAction, void* pParam )
1174 {
1175     DebugData* pDebugData = ImplGetDebugData();
1176 
1177     if ( nAction == DBG_FUNC_GETDATA )
1178         return (void*)&(pDebugData->aDbgData);
1179     else if ( nAction == DBG_FUNC_GETPRINTMSGBOX )
1180         return (void*)(long)(pDebugData->pDbgPrintMsgBox);
1181     else if ( nAction == DBG_FUNC_FILTERMESSAGE )
1182         if ( ImplDbgFilterMessage( (const sal_Char*) pParam ) )
1183             return (void*) -1;
1184         else
1185             return (void*) 0;   // aka NULL
1186     else
1187 
1188     {
1189         switch ( nAction )
1190         {
1191             case DBG_FUNC_DEBUGSTART:
1192                 DebugInit();
1193                 break;
1194 
1195             case DBG_FUNC_DEBUGEND:
1196                 DebugDeInit();
1197                 break;
1198 
1199             case DBG_FUNC_GLOBALDEBUGEND:
1200                 DebugGlobalDeInit();
1201                 break;
1202 
1203             case DBG_FUNC_SETPRINTMSGBOX:
1204                 pDebugData->pDbgPrintMsgBox = (DbgPrintLine)(long)pParam;
1205                 break;
1206 
1207             case DBG_FUNC_SETPRINTWINDOW:
1208                 pDebugData->pDbgPrintWindow = (DbgPrintLine)(long)pParam;
1209                 break;
1210 
1211             case DBG_FUNC_SETPRINTTESTTOOL:
1212                 pDebugData->pDbgPrintTestTool = (DbgPrintLine)(long)pParam;
1213                 break;
1214 
1215             case DBG_FUNC_SET_ABORT:
1216                 pDebugData->pDbgAbort = (DbgPrintLine)(long)pParam;
1217                 break;
1218 
1219             case DBG_FUNC_SAVEDATA:
1220                 {
1221                 const DbgData* pData = static_cast< const DbgData* >( pParam );
1222 
1223                 sal_Char aBuf[ 4096 ];
1224                 DbgGetDbgFileName( aBuf, sizeof( aBuf ) );
1225                 FILETYPE pIniFile = FileOpen( aBuf, "w" );
1226                 if ( pIniFile == NULL )
1227                     break;
1228 
1229                 lcl_startSection( pIniFile, eOutput );
1230                 lcl_writeConfigString( pIniFile, "log_file", pData->aDebugName );
1231                 lcl_writeConfigBoolean( pIniFile, "overwrite", pData->bOverwrite );
1232                 lcl_writeConfigString( pIniFile, "include", pData->aInclFilter );
1233                 lcl_writeConfigString( pIniFile, "exclude", pData->aExclFilter );
1234                 lcl_writeConfigString( pIniFile, "include_class", pData->aInclClassFilter );
1235                 lcl_writeConfigString( pIniFile, "exclude_class", pData->aExclClassFilter );
1236                 lcl_writeConfigOutChannel( pIniFile, "trace", pData->nTraceOut );
1237                 lcl_writeConfigOutChannel( pIniFile, "warning", pData->nWarningOut );
1238                 lcl_writeConfigOutChannel( pIniFile, "error", pData->nErrorOut );
1239                 lcl_writeConfigBoolean( pIniFile, "oslhook", pData->bHookOSLAssert );
1240 
1241                 lcl_lineFeed( pIniFile );
1242                 lcl_startSection( pIniFile, eMemory );
1243                 lcl_writeConfigFlag( pIniFile, "initialize", pData->nTestFlags, DBG_TEST_MEM_INIT );
1244                 lcl_writeConfigFlag( pIniFile, "overwrite", pData->nTestFlags, DBG_TEST_MEM_OVERWRITE );
1245                 lcl_writeConfigFlag( pIniFile, "overwrite_free", pData->nTestFlags, DBG_TEST_MEM_OVERWRITEFREE );
1246                 lcl_writeConfigFlag( pIniFile, "pointer", pData->nTestFlags, DBG_TEST_MEM_POINTER );
1247                 lcl_writeConfigFlag( pIniFile, "report", pData->nTestFlags, DBG_TEST_MEM_REPORT );
1248                 lcl_writeConfigFlag( pIniFile, "trace", pData->nTestFlags, DBG_TEST_MEM_TRACE );
1249                 lcl_writeConfigFlag( pIniFile, "new_and_delete", pData->nTestFlags, DBG_TEST_MEM_NEWDEL );
1250                 lcl_writeConfigFlag( pIniFile, "object_test", pData->nTestFlags, DBG_TEST_MEM_XTOR );
1251                 lcl_writeConfigFlag( pIniFile, "sys_alloc", pData->nTestFlags, DBG_TEST_MEM_SYSALLOC );
1252                 lcl_writeConfigFlag( pIniFile, "leak_report", pData->nTestFlags, DBG_TEST_MEM_LEAKREPORT );
1253 
1254                 lcl_lineFeed( pIniFile );
1255                 lcl_writeHexByte( pIniFile, "init_byte", pData->bMemInit );
1256                 lcl_writeHexByte( pIniFile, "bound_byte", pData->bMemBound );
1257                 lcl_writeHexByte( pIniFile, "free_byte", pData->bMemFree );
1258 
1259                 lcl_lineFeed( pIniFile );
1260                 lcl_startSection( pIniFile, eGUI );
1261                 lcl_writeConfigString( pIniFile, "debug_window_state", pData->aDbgWinState );
1262 
1263                 lcl_lineFeed( pIniFile );
1264                 lcl_startSection( pIniFile, eObjects );
1265                 lcl_writeConfigFlag( pIniFile, "check_this", pData->nTestFlags, DBG_TEST_XTOR_THIS );
1266                 lcl_writeConfigFlag( pIniFile, "check_function", pData->nTestFlags, DBG_TEST_XTOR_FUNC );
1267                 lcl_writeConfigFlag( pIniFile, "check_exit", pData->nTestFlags, DBG_TEST_XTOR_EXIT );
1268                 lcl_writeConfigFlag( pIniFile, "generate_report", pData->nTestFlags, DBG_TEST_XTOR_REPORT );
1269                 lcl_writeConfigFlag( pIniFile, "trace", pData->nTestFlags, DBG_TEST_XTOR_TRACE );
1270 
1271                 lcl_lineFeed( pIniFile );
1272                 lcl_startSection( pIniFile, eTest );
1273                 lcl_writeConfigFlag( pIniFile, "profiling", pData->nTestFlags, DBG_TEST_PROFILING );
1274                 lcl_writeConfigFlag( pIniFile, "resources", pData->nTestFlags, DBG_TEST_RESOURCE );
1275                 lcl_writeConfigFlag( pIniFile, "dialog", pData->nTestFlags, DBG_TEST_DIALOG );
1276                 lcl_writeConfigFlag( pIniFile, "bold_app_font", pData->nTestFlags, DBG_TEST_BOLDAPPFONT );
1277 
1278                 FileClose( pIniFile );
1279                 }
1280                 break;
1281 
1282             case DBG_FUNC_MEMTEST:
1283 #ifdef SV_MEMMGR
1284                 DbgImpCheckMemory( pParam );
1285 #endif
1286                 break;
1287 
1288             case DBG_FUNC_XTORINFO:
1289                 DebugXTorInfo( (sal_Char*)pParam );
1290                 break;
1291 
1292             case DBG_FUNC_MEMINFO:
1293 #ifdef SV_MEMMGR
1294                 DbgImpMemoryInfo( (sal_Char*)pParam );
1295 #endif
1296                 break;
1297 
1298             case DBG_FUNC_COREDUMP:
1299                 ImplCoreDump();
1300                 break;
1301 
1302             case DBG_FUNC_ALLERROROUT:
1303                 return (void*)(sal_uIntPtr)sal_True;
1304 
1305             case DBG_FUNC_SETTESTSOLARMUTEX:
1306                 pDebugData->pDbgTestSolarMutex = (DbgTestSolarMutexProc)(long)pParam;
1307                 break;
1308 
1309             case DBG_FUNC_TESTSOLARMUTEX:
1310                 if ( pDebugData->pDbgTestSolarMutex )
1311                     pDebugData->pDbgTestSolarMutex();
1312                 break;
1313 
1314             case DBG_FUNC_PRINTFILE:
1315                 ImplDbgPrintFile( (const sal_Char*)pParam );
1316                 break;
1317             case DBG_FUNC_UPDATEOSLHOOK:
1318             {
1319                 const DbgData* pData = static_cast< const DbgData* >( pParam );
1320                 pDebugData->aDbgData.bHookOSLAssert = pData->bHookOSLAssert;
1321                 if( pDebugData->bOslIsHooked && ! pData->bHookOSLAssert )
1322                 {
1323                     osl_setDetailedDebugMessageFunc( pDebugData->pOldDebugMessageFunc );
1324                     pDebugData->bOslIsHooked = sal_False;
1325                 }
1326                 else if( ! pDebugData->bOslIsHooked && pData->bHookOSLAssert )
1327                 {
1328                     pDebugData->pOldDebugMessageFunc = osl_setDetailedDebugMessageFunc( &dbg_printOslDebugMessage );
1329                     pDebugData->bOslIsHooked = sal_True;
1330                 }
1331             }
1332             break;
1333        }
1334 
1335         return NULL;
1336     }
1337 }
1338 
1339 // -----------------------------------------------------------------------
1340 
1341 DbgChannelId DbgRegisterUserChannel( DbgPrintLine pProc )
1342 {
1343     DebugData* pData = ImplGetDebugData();
1344     pData->aDbgPrintUserChannels.push_back( pProc );
1345     return (DbgChannelId)( pData->aDbgPrintUserChannels.size() - 1 + DBG_OUT_USER_CHANNEL_0 );
1346 }
1347 
1348 // -----------------------------------------------------------------------
1349 
1350 void DbgProf( sal_uInt16 nAction, DbgDataType* pDbgData )
1351 {
1352     // Ueberhaupt Profiling-Test an
1353     DebugData* pData = ImplGetDebugData();
1354 
1355     if ( !(pData->aDbgData.nTestFlags & DBG_TEST_PROFILING) )
1356         return;
1357 
1358     sal_Char    aBuf[DBG_BUF_MAXLEN];
1359     ProfType*   pProfData = (ProfType*)pDbgData->pData;
1360     sal_uIntPtr       nTime;
1361     if ( (nAction != DBG_PROF_START) && !pProfData )
1362     {
1363         strcpy( aBuf, DbgError_ProfEnd1 );
1364         strcat( aBuf, pDbgData->pName );
1365         DbgError( aBuf );
1366         return;
1367     }
1368 
1369     switch ( nAction )
1370     {
1371         case DBG_PROF_START:
1372             if ( !pDbgData->pData )
1373             {
1374                 pDbgData->pData = (void*)new ProfType;
1375                 pProfData = (ProfType*)pDbgData->pData;
1376                 strncpy( pProfData->aName, pDbgData->pName, DBG_MAXNAME );
1377                 pProfData->aName[DBG_MAXNAME] = '\0';
1378                 pProfData->nCount           = 0;
1379                 pProfData->nTime            = 0;
1380                 pProfData->nMinTime         = 0xFFFFFFFF;
1381                 pProfData->nMaxTime         = 0;
1382                 pProfData->nStart           = 0xFFFFFFFF;
1383                 pProfData->nContinueTime    = 0;
1384                 pProfData->nContinueStart   = 0xFFFFFFFF;
1385                 pData->pProfList->Add( (void*)pProfData );
1386             }
1387 
1388             if ( pProfData->nStart == 0xFFFFFFFF )
1389             {
1390                 pProfData->nStart = ImplGetPerfTime();
1391                 pProfData->nCount++;
1392             }
1393             break;
1394 
1395         case DBG_PROF_STOP:
1396             nTime = ImplGetPerfTime();
1397 
1398             if ( pProfData->nStart == 0xFFFFFFFF )
1399             {
1400                 DbgError( DbgError_ProfEnd1 );
1401                 return;
1402             }
1403 
1404             if ( pProfData->nContinueStart != 0xFFFFFFFF )
1405             {
1406                 pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart;
1407                 pProfData->nContinueStart = 0xFFFFFFFF;
1408             }
1409 
1410             nTime -= pProfData->nStart;
1411             nTime -= pProfData->nContinueTime;
1412 
1413             if ( nTime < pProfData->nMinTime )
1414                 pProfData->nMinTime = nTime;
1415 
1416             if ( nTime > pProfData->nMaxTime )
1417                 pProfData->nMaxTime = nTime;
1418 
1419             pProfData->nTime += nTime;
1420 
1421             pProfData->nStart         = 0xFFFFFFFF;
1422             pProfData->nContinueTime  = 0;
1423             pProfData->nContinueStart = 0xFFFFFFFF;
1424             break;
1425 
1426         case DBG_PROF_CONTINUE:
1427             if ( pProfData->nContinueStart != 0xFFFFFFFF )
1428             {
1429                 pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart;
1430                 pProfData->nContinueStart = 0xFFFFFFFF;
1431             }
1432             break;
1433 
1434         case DBG_PROF_PAUSE:
1435             if ( pProfData->nContinueStart == 0xFFFFFFFF )
1436                 pProfData->nContinueStart = ImplGetPerfTime();
1437             break;
1438     }
1439 }
1440 
1441 // -----------------------------------------------------------------------
1442 
1443 void DbgXtor( DbgDataType* pDbgData, sal_uInt16 nAction, const void* pThis,
1444               DbgUsr fDbgUsr )
1445 {
1446     DebugData* pData = ImplGetDebugData();
1447 
1448     // Verbindung zu Debug-Memory-Manager testen
1449 #ifdef SV_MEMMGR
1450     if ( pData->aDbgData.nTestFlags & DBG_TEST_MEM_XTOR )
1451         DbgImpCheckMemory();
1452 #endif
1453 
1454     // Schnell-Test
1455     if ( !(pData->aDbgData.nTestFlags & DBG_TEST_XTOR) )
1456         return;
1457 
1458     XtorType* pXtorData = (XtorType*)pDbgData->pData;
1459     if ( !pXtorData )
1460     {
1461         pDbgData->pData = (void*)new XtorType;
1462         pXtorData = (XtorType*)pDbgData->pData;
1463         strncpy( pXtorData->aName, pDbgData->pName, DBG_MAXNAME );
1464         pXtorData->aName[DBG_MAXNAME] = '\0';
1465         pXtorData->nCtorCalls   = 0;
1466         pXtorData->nDtorCalls   = 0;
1467         pXtorData->nMaxCount    = 0;
1468         pXtorData->nStatics     = 0;
1469         pXtorData->bTest        = sal_True;
1470         pData->pXtorList->Add( (void*)pXtorData );
1471 
1472         if ( !ImplDbgFilter( pData->aDbgData.aInclClassFilter, pXtorData->aName, sal_True ) )
1473             pXtorData->bTest = sal_False;
1474         if ( ImplDbgFilter( pData->aDbgData.aExclClassFilter, pXtorData->aName, sal_False ) )
1475             pXtorData->bTest = sal_False;
1476     }
1477     if ( !pXtorData->bTest )
1478         return;
1479 
1480     sal_Char    aBuf[DBG_BUF_MAXLEN];
1481     sal_uInt16      nAct = nAction & ~DBG_XTOR_DTOROBJ;
1482 
1483     // Trace (Enter)
1484     if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) &&
1485          !(nAction & DBG_XTOR_DTOROBJ) )
1486     {
1487         if ( nAct != DBG_XTOR_CHKOBJ )
1488         {
1489             if ( nAct == DBG_XTOR_CTOR )
1490                 strcpy( aBuf, DbgTrace_EnterCtor );
1491             else if ( nAct == DBG_XTOR_DTOR )
1492                 strcpy( aBuf, DbgTrace_EnterDtor );
1493             else
1494                 strcpy( aBuf, DbgTrace_EnterMeth );
1495             strcat( aBuf, pDbgData->pName );
1496             DbgTrace( aBuf );
1497         }
1498     }
1499 
1500     // Sind noch Xtor-Tests als Trace an
1501     if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXTRA )
1502     {
1503         // DBG_CTOR-Aufruf vor allen anderen DBG_XTOR-Aufrufen
1504         if ( ((nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR) && !pDbgData->pData )
1505         {
1506             strcpy( aBuf, DbgError_Xtor1 );
1507             strcat( aBuf, pDbgData->pName );
1508             DbgError( aBuf );
1509             return;
1510         }
1511 
1512         // Testen, ob This-Pointer gueltig
1513         if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
1514         {
1515             if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) ||
1516                  !(nAction & DBG_XTOR_DTOROBJ) )
1517             {
1518                 // This-Pointer == NULL
1519                 if ( !pThis )
1520                 {
1521                     strcpy( aBuf, DbgError_CtorDtor1 );
1522                     strcat( aBuf, pDbgData->pName );
1523                     DbgError( aBuf );
1524                     return;
1525                 }
1526 
1527                 if ( (nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR )
1528                 {
1529                     if ( !pXtorData->aThisList.IsIn( pThis ) )
1530                     {
1531                         sprintf( aBuf, DbgError_CtorDtor2, pThis );
1532                         strcat( aBuf, pDbgData->pName );
1533                         DbgError( aBuf );
1534                     }
1535                 }
1536             }
1537         }
1538 
1539         // Function-Test durchfuehren und Verwaltungsdaten updaten
1540         const sal_Char* pMsg = NULL;
1541         switch ( nAction & ~DBG_XTOR_DTOROBJ )
1542         {
1543             case DBG_XTOR_CTOR:
1544                 if ( nAction & DBG_XTOR_DTOROBJ )
1545                 {
1546                     if ( fDbgUsr &&
1547                          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) &&
1548                          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
1549                         pMsg = fDbgUsr( pThis );
1550                 }
1551                 else
1552                 {
1553                     pXtorData->nCtorCalls++;
1554                     if ( !bDbgImplInMain )
1555                         pXtorData->nStatics++;
1556                     if ( (pXtorData->nCtorCalls-pXtorData->nDtorCalls) > pXtorData->nMaxCount )
1557                         pXtorData->nMaxCount = pXtorData->nCtorCalls - pXtorData->nDtorCalls;
1558 
1559                     if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
1560                         pXtorData->aThisList.Add( pThis );
1561                 }
1562                 break;
1563 
1564             case DBG_XTOR_DTOR:
1565                 if ( nAction & DBG_XTOR_DTOROBJ )
1566                 {
1567                     pXtorData->nDtorCalls++;
1568                     if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
1569                         pXtorData->aThisList.Remove( pThis );
1570                 }
1571                 else
1572                 {
1573                     if ( fDbgUsr &&
1574                          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
1575                         pMsg = fDbgUsr( pThis );
1576                 }
1577                 break;
1578 
1579             case DBG_XTOR_CHKTHIS:
1580             case DBG_XTOR_CHKOBJ:
1581                 if ( nAction & DBG_XTOR_DTOROBJ )
1582                 {
1583                     if ( fDbgUsr &&
1584                          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) &&
1585                          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
1586                         pMsg = fDbgUsr( pThis );
1587                 }
1588                 else
1589                 {
1590                     if ( fDbgUsr &&
1591                          (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
1592                         pMsg = fDbgUsr( pThis );
1593                 }
1594                 break;
1595         }
1596 
1597         // Gegebenenfalls Fehlermeldung ausgeben
1598         if ( pMsg )
1599         {
1600             sprintf( aBuf, DbgError_CtorDtor3, pThis );
1601             strcat( aBuf, pDbgData->pName );
1602             strcat( aBuf, ": \n" );
1603             strcat( aBuf, pMsg );
1604             DbgError( aBuf );
1605         }
1606     }
1607 
1608     // Trace (Leave)
1609     if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) &&
1610          (nAction & DBG_XTOR_DTOROBJ) )
1611     {
1612         if ( nAct != DBG_XTOR_CHKOBJ )
1613         {
1614             if ( nAct == DBG_XTOR_CTOR )
1615                 strcpy( aBuf, DbgTrace_LeaveCtor );
1616             else if ( nAct == DBG_XTOR_DTOR )
1617                 strcpy( aBuf, DbgTrace_LeaveDtor );
1618             else
1619                 strcpy( aBuf, DbgTrace_LeaveMeth );
1620             strcat( aBuf, pDbgData->pName );
1621             DbgTrace( aBuf );
1622         }
1623     }
1624 }
1625 
1626 // -----------------------------------------------------------------------
1627 
1628 void DbgOut( const sal_Char* pMsg, sal_uInt16 nDbgOut, const sal_Char* pFile, sal_uInt16 nLine )
1629 {
1630     static sal_Bool bIn = sal_False;
1631     if ( bIn )
1632         return;
1633     bIn = sal_True;
1634 
1635     DebugData*  pData = GetDebugData();
1636     sal_Char const *   pStr;
1637     sal_uIntPtr       nOut;
1638     int         nBufLen = 0;
1639 
1640     if ( nDbgOut == DBG_OUT_ERROR )
1641     {
1642         nOut = pData->aDbgData.nErrorOut;
1643         pStr = "Error: ";
1644         if ( pData->aDbgData.nErrorOut == DBG_OUT_FILE )
1645             DbgDebugBeep();
1646     }
1647     else if ( nDbgOut == DBG_OUT_WARNING )
1648     {
1649         nOut = pData->aDbgData.nWarningOut;
1650         pStr = "Warning: ";
1651     }
1652     else
1653     {
1654         nOut = pData->aDbgData.nTraceOut;
1655         pStr = NULL;
1656     }
1657 
1658     if ( nOut == DBG_OUT_NULL )
1659     {
1660         bIn = sal_False;
1661         return;
1662     }
1663 
1664     if ( ImplDbgFilterMessage( pMsg ) )
1665     {
1666         bIn = sal_False;
1667         return;
1668     }
1669 
1670     ImplDbgLock();
1671 
1672     sal_Char aBufOut[DBG_BUF_MAXLEN];
1673     if ( pStr )
1674     {
1675         strcpy( aBufOut, pStr );
1676         nBufLen = strlen( pStr );
1677     }
1678     else
1679         aBufOut[0] = '\0';
1680 
1681     int nMsgLen = strlen( pMsg );
1682     if ( nBufLen+nMsgLen > DBG_BUF_MAXLEN )
1683     {
1684         int nCopyLen = DBG_BUF_MAXLEN-nBufLen-3;
1685         strncpy( &(aBufOut[nBufLen]), pMsg, nCopyLen );
1686         strcpy( &(aBufOut[nBufLen+nCopyLen]), "..." );
1687     }
1688     else
1689         strcpy( &(aBufOut[nBufLen]), pMsg );
1690 
1691     if ( pFile && nLine && (nBufLen+nMsgLen < DBG_BUF_MAXLEN) )
1692     {
1693         if ( nOut == DBG_OUT_MSGBOX )
1694             strcat( aBufOut, "\n" );
1695         else
1696             strcat( aBufOut, " " );
1697         strcat( aBufOut, "From File " );
1698         strcat( aBufOut, pFile );
1699         strcat( aBufOut, " at Line " );
1700 
1701         // Line in String umwandeln und dranhaengen
1702         sal_Char    aLine[9];
1703         sal_Char*   pLine = &aLine[7];
1704         sal_uInt16      i;
1705         memset( aLine, 0, sizeof( aLine ) );
1706         do
1707         {
1708             i = nLine % 10;
1709             pLine--;
1710             *(pLine) = (sal_Char)i + 48;
1711             nLine /= 10;
1712         }
1713         while ( nLine );
1714         strcat( aBufOut, pLine );
1715     }
1716 
1717     if ( ( nOut >= DBG_OUT_USER_CHANNEL_0 ) && ( nOut - DBG_OUT_USER_CHANNEL_0 < pData->aDbgPrintUserChannels.size() ) )
1718     {
1719         DbgPrintLine pPrinter = pData->aDbgPrintUserChannels[ nOut - DBG_OUT_USER_CHANNEL_0 ];
1720         if ( pPrinter )
1721             pPrinter( aBufOut );
1722         else
1723             nOut = DBG_OUT_DEBUGGER;
1724     }
1725 
1726     if ( nOut == DBG_OUT_ABORT )
1727     {
1728         if ( pData->pDbgAbort != NULL )
1729             pData->pDbgAbort( aBufOut );
1730         abort();
1731     }
1732 
1733     if ( nOut == DBG_OUT_DEBUGGER )
1734     {
1735         if ( !ImplActivateDebugger( aBufOut ) )
1736             nOut = DBG_OUT_TESTTOOL;
1737     }
1738 
1739     if ( nOut == DBG_OUT_TESTTOOL )
1740     {
1741         if ( pData->pDbgPrintTestTool )
1742             pData->pDbgPrintTestTool( aBufOut );
1743         else
1744             nOut = DBG_OUT_MSGBOX;
1745     }
1746 
1747     if ( nOut == DBG_OUT_MSGBOX )
1748     {
1749         if ( pData->pDbgPrintMsgBox )
1750             pData->pDbgPrintMsgBox( aBufOut );
1751         else
1752             nOut = DBG_OUT_WINDOW;
1753     }
1754 
1755     if ( nOut == DBG_OUT_WINDOW )
1756     {
1757         if ( pData->pDbgPrintWindow )
1758             pData->pDbgPrintWindow( aBufOut );
1759         else
1760             nOut = DBG_OUT_FILE;
1761     }
1762 
1763     switch ( nOut )
1764     {
1765     case DBG_OUT_SHELL:
1766         DbgPrintShell( aBufOut );
1767         break;
1768     case DBG_OUT_FILE:
1769         ImplDbgPrintFile( aBufOut );
1770         break;
1771     }
1772 
1773     ImplDbgUnlock();
1774 
1775     bIn = sal_False;
1776 }
1777 
1778 void DbgPrintShell(char const * message) {
1779     fprintf(stderr, "%s\n", message);
1780 #if defined WNT
1781     OutputDebugStringA(message);
1782 #endif
1783 }
1784 
1785 // -----------------------------------------------------------------------
1786 
1787 void DbgOutTypef( sal_uInt16 nDbgOut, const sal_Char* pFStr, ... )
1788 {
1789     va_list pList;
1790 
1791     va_start( pList, pFStr );
1792     sal_Char aBuf[DBG_BUF_MAXLEN];
1793     vsprintf( aBuf, pFStr, pList );
1794     va_end( pList );
1795 
1796     DbgOut( aBuf, nDbgOut );
1797 }
1798 
1799 // -----------------------------------------------------------------------
1800 
1801 void DbgOutf( const sal_Char* pFStr, ... )
1802 {
1803     va_list pList;
1804 
1805     va_start( pList, pFStr );
1806     sal_Char aBuf[DBG_BUF_MAXLEN];
1807     vsprintf( aBuf, pFStr, pList );
1808     va_end( pList );
1809 
1810     DbgOut( aBuf );
1811 }
1812 
1813 // =======================================================================
1814 
1815 #else
1816 
1817 void* DbgFunc( sal_uInt16, void* ) { return NULL; }
1818 
1819 void DbgProf( sal_uInt16, DbgDataType* ) {}
1820 void DbgXtor( DbgDataType*, sal_uInt16, const void*, DbgUsr ) {}
1821 
1822 void DbgOut( const sal_Char*, sal_uInt16, const sal_Char*, sal_uInt16 ) {}
1823 void DbgOutTypef( sal_uInt16, const sal_Char*, ... ) {}
1824 void DbgOutf( const sal_Char*, ... ) {}
1825 
1826 #endif
1827