/*************************************************************************
 *
 *  $RCSfile: debug.cxx,v $
 *
 *  $Revision: 1.8 $
 *
 *  last change: $Author: vg $ $Date: 2005-03-23 15:52:01 $
 *
 *  The Contents of this file are made available subject to the terms of
 *  either of the following licenses
 *
 *         - GNU Lesser General Public License Version 2.1
 *         - Sun Industry Standards Source License Version 1.1
 *
 *  Sun Microsystems Inc., October, 2000
 *
 *  GNU Lesser General Public License Version 2.1
 *  =============================================
 *  Copyright 2000 by Sun Microsystems, Inc.
 *  901 San Antonio Road, Palo Alto, CA 94303, USA
 *
 *  This library is free software; you can redistribute it and/or
 *  modify it under the terms of the GNU Lesser General Public
 *  License version 2.1, as published by the Free Software Foundation.
 *
 *  This library is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 *  Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public
 *  License along with this library; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston,
 *  MA  02111-1307  USA
 *
 *
 *  Sun Industry Standards Source License Version 1.1
 *  =================================================
 *  The contents of this file are subject to the Sun Industry Standards
 *  Source License Version 1.1 (the "License"); You may not use this file
 *  except in compliance with the License. You may obtain a copy of the
 *  License at http://www.openoffice.org/license.html.
 *
 *  Software provided under this License is provided on an "AS IS" basis,
 *  WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING,
 *  WITHOUT LIMITATION, WARRANTIES THAT THE SOFTWARE IS FREE OF DEFECTS,
 *  MERCHANTABLE, FIT FOR A PARTICULAR PURPOSE, OR NON-INFRINGING.
 *  See the License for the specific provisions governing your rights and
 *  obligations concerning the Software.
 *
 *  The Initial Developer of the Original Code is: Sun Microsystems, Inc.
 *
 *  Copyright: 2000 by Sun Microsystems, Inc.
 *
 *  All Rights Reserved.
 *
 *  Contributor(s): _______________________________________
 *
 *
 ************************************************************************/

#define _TOOLS_DEBUG_CXX

#ifndef MAC
#if defined (UNX) || defined (GCC)
#include <unistd.h>
#else
#include <direct.h>
#endif
#endif

#include <time.h>
#include <cstdarg>  // combinations
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

#ifdef OS2
#define INCL_DOSSEMAPHORES
#define INCL_DOSMISC
#define INCL_WINDIALOGS
#include <svpm.h>
#endif

#if defined ( WNT )
#include <svwin.h>
#endif

#include <debug.hxx>

// =======================================================================

#ifdef DBG_UTIL

// --- DbgErrors ---

static sal_Char const DbgError_ProfEnd1[]   = "DBG_PROF...() without DBG_PROFSTART(): ";
static sal_Char const DbgError_Xtor1[]      = "DBG_DTOR() or DBG_CHKTHIS() without DBG_CTOR(): ";

static sal_Char const DbgError_CtorDtor1[]  = "this == NULL in class ";
static sal_Char const DbgError_CtorDtor2[]  = "invalid this-Pointer %p in class ";
static sal_Char const DbgError_CtorDtor3[]  = "Error-Msg from Object %p in class ";

static sal_Char const DbgTrace_EnterCtor[]  = "Enter Ctor from class ";
static sal_Char const DbgTrace_LeaveCtor[]  = "Leave Ctor from class ";
static sal_Char const DbgTrace_EnterDtor[]  = "Enter Dtor from class ";
static sal_Char const DbgTrace_LeaveDtor[]  = "Leave Dtor from class ";
static sal_Char const DbgTrace_EnterMeth[]  = "Enter method from class ";
static sal_Char const DbgTrace_LeaveMeth[]  = "Leave method from class ";

// --- PointerList ---

#define PBLOCKCOUNT     1024

struct PBlock
{
    void*       aData[PBLOCKCOUNT];
    USHORT      nCount;
    PBlock*     pPrev;
    PBlock*     pNext;
};

class PointerList
{
private:
    PBlock*     pFirst;
    PBlock*     pLast;
    ULONG       nCount;

public:
                PointerList() { pFirst = NULL; pLast = NULL; nCount = 0; }
                ~PointerList();

    void        Add( const void* p );
    BOOL        Remove( const void* p );

    const void* Get( ULONG nPos ) const;
    BOOL        IsIn( const void* p ) const;
    ULONG       Count() const { return nCount; }
};

// --- Datentypen ---

#define DBG_MAXNAME     28

struct ProfType
{
    ULONG                   nCount;
    ULONG                   nTime;
    ULONG                   nMinTime;
    ULONG                   nMaxTime;
    ULONG                   nStart;
    ULONG                   nContinueTime;
    ULONG                   nContinueStart;
    sal_Char                aName[DBG_MAXNAME+1];
};

struct XtorType
{
    ULONG                   nCtorCalls;
    ULONG                   nDtorCalls;
    ULONG                   nMaxCount;
    ULONG                   nStatics;
    sal_Char                aName[DBG_MAXNAME+1];
    BOOL                    bTest;
    PointerList             aThisList;
};

struct DebugData
{
    DbgData                 aDbgData;
    USHORT                  bInit;
    DbgPrintLine            pDbgPrintMsgBox;
    DbgPrintLine            pDbgPrintWindow;
    DbgPrintLine            pDbgPrintShell;
    DbgPrintLine            pDbgPrintTestTool;
    PointerList*            pProfList;
    PointerList*            pXtorList;
    DbgTestSolarMutexProc   pDbgTestSolarMutex;
};

#define DBG_TEST_XTOR_EXTRA (DBG_TEST_XTOR_THIS |  DBG_TEST_XTOR_FUNC |               \
                             DBG_TEST_XTOR_EXIT |  DBG_TEST_XTOR_REPORT )

// ------------------------------
// - statische Verwaltungsdaten -
// ------------------------------

static DebugData aDebugData =
{
    {
    DBG_TEST_RESOURCE | DBG_TEST_MEM_INIT,
    TRUE,
    DBG_OUT_NULL,
    DBG_OUT_NULL,
    DBG_OUT_MSGBOX,
    0x77,
    0x55,
    0x33,
    "",
    "",
    "",
    "",
    "",
    "",
    },
    FALSE,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL,
    NULL
};

#ifndef MAC
static sal_Char aCurPath[260];
#endif

static int bDbgImplInMain = FALSE;

// =======================================================================

#if defined( WNT )
static CRITICAL_SECTION aImplCritDbgSection;
#elif defined( OS2 )
static HMTX             hImplCritDbgSection = 0;
#endif
static BOOL             bImplCritDbgSectionInit = FALSE;

// -----------------------------------------------------------------------

void ImplDbgInitLock()
{
#if defined( WNT )
    InitializeCriticalSection( &aImplCritDbgSection );
#elif defined( OS2 )
    DosCreateMutexSem( NULL, &hImplCritDbgSection, 0, FALSE );
#endif
    bImplCritDbgSectionInit = TRUE;
}

// -----------------------------------------------------------------------

void ImplDbgDeInitLock()
{
#if defined( WNT )
    DeleteCriticalSection( &aImplCritDbgSection );
#elif defined( OS2 )
    DosCloseMutexSem( hImplCritDbgSection );
#endif
    bImplCritDbgSectionInit = FALSE;
}

// -----------------------------------------------------------------------

void ImplDbgLock()
{
    if ( !bImplCritDbgSectionInit )
        return;

#if defined( WNT )
    EnterCriticalSection( &aImplCritDbgSection );
#elif defined( OS2 )
    DosRequestMutexSem( hImplCritDbgSection, SEM_INDEFINITE_WAIT );
#endif
}

// -----------------------------------------------------------------------

void ImplDbgUnlock()
{
    if ( !bImplCritDbgSectionInit )
        return;

#if defined( WNT )
    LeaveCriticalSection( &aImplCritDbgSection );
#elif defined( OS2 )
    DosReleaseMutexSem( hImplCritDbgSection );
#endif
}

// =======================================================================

#if (defined( WNT ) || defined( OS2 ) || defined( MAC )) && !defined ( SVX_LIGHT )
//#define SV_MEMMGR //
#endif
#ifdef SV_MEMMGR
void DbgImpCheckMemory( void* p = NULL );
void DbgImpCheckMemoryDeInit();
void DbgImpMemoryInfo( sal_Char* pBuf );
#endif

#if defined( OS2 )
#define FILE_LINEEND    "\r\n"
#else
#define FILE_LINEEND    "\n"
#endif

// =======================================================================

static BOOL ImplActivateDebugger( const sal_Char* pMsg )
{
#if defined( WNT )
    static sal_Char aImplDbgOutBuf[DBG_BUF_MAXLEN];
    strcpy( aImplDbgOutBuf, pMsg );
    strcat( aImplDbgOutBuf, "\r\n" );
    OutputDebugString( aImplDbgOutBuf );
    DebugBreak();
    return TRUE;
#elif defined( MAC )
    debugstr( (sal_Char*)pLine );
    return TRUE;
#else
    return FALSE;
#endif
}

// -----------------------------------------------------------------------

static BOOL ImplCoreDump( const sal_Char* pMsg )
{
#if defined( WNT )
    DebugBreak();
#else
    long* pTemp = 0;
    *pTemp = 0xCCCC;
#endif
    return TRUE;
}

// =======================================================================

static ULONG ImplGetPerfTime()
{
#if defined( WNT )
    return (ULONG)GetTickCount();
#elif defined( OS2 )
    PM_ULONG nClock;
    DosQuerySysInfo( QSV_MS_COUNT, QSV_MS_COUNT, &nClock, sizeof( nClock ) );
    return (ULONG)nClock;
#elif defined( MAC )
    long long millisec;
    Microseconds((UnsignedWide *)&millisec);
    millisec = ( millisec + 500L ) / 1000L;
    return (ULONG)millisec;
#else
    static ULONG    nImplTicksPerSecond = 0;
    static double   dImplTicksPerSecond;
    ULONG           nTicks = (ULONG)clock();

    if ( !nImplTicksPerSecond )
    {
        nImplTicksPerSecond = CLOCKS_PER_SEC;
        dImplTicksPerSecond = nImplTicksPerSecond;
    }

    double fTicks = nTicks;
    fTicks *= 1000;
    fTicks /= dImplTicksPerSecond;
    return (ULONG)fTicks;
#endif
}

// -----------------------------------------------------------------------

#if defined( OS2 )

typedef HFILE FILETYPE;

static FILETYPE FileOpen( const sal_Char* pFileName, const sal_Char* pOpenMode )
{
    HFILE   hFile = 0;
    ULONG   lAction = 0;
    ULONG   nOpen1 = FILE_OPEN;
    ULONG   nOpen2 = OPEN_SHARE_DENYWRITE | OPEN_ACCESS_READONLY;

    if ( *pOpenMode == 'w' )
    {
        nOpen1 = OPEN_ACTION_REPLACE_IF_EXISTS | OPEN_ACTION_CREATE_IF_NEW;
        nOpen2 = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE;
    }
    else if ( *pOpenMode == 'a' )
    {
        nOpen1 = OPEN_ACTION_CREATE_IF_NEW | OPEN_ACTION_OPEN_IF_EXISTS;
        nOpen2 = OPEN_ACCESS_WRITEONLY | OPEN_SHARE_DENYREADWRITE;
    }

    APIRET nRet = DosOpen( pFileName, &hFile, &lAction, 0,
                           FILE_NORMAL, nOpen1, nOpen2, 0L );

    if ( nRet )
        return NULL;
    else
    {
        if ( *pOpenMode == 'a' )
        {
            ULONG nTemp;
            DosSetFilePtr( hFile, 0, FILE_END, &nTemp );
        }

        return hFile;
    }
}

static ULONG FileRead( void* pData, int n1, int n2, FILETYPE pFile )
{
    ULONG nRead;
    DosRead( pFile, pData, n1*n2, &nRead );
    return nRead;
}

static ULONG FileWrite( void* pData, int n1, int n2, FILETYPE pFile )
{
    ULONG nWritten;
    DosWrite( pFile, pData, n1*n2, &nWritten );
    return nWritten;
}

static void FilePrintF( FILETYPE pFile, const sal_Char* pFStr, ... )
{
    static sal_Char aTempBuf[DBG_BUF_MAXLEN];

    va_list pList;

    va_start( pList, pFStr );
    vsprintf( aTempBuf, pFStr, pList );
    va_end( pList );

    FileWrite( aTempBuf, strlen( aTempBuf ), 1, pFile );
}

static void FileClose( FILETYPE pFile )
{
    DosClose( pFile );
}

#else

typedef FILE*       FILETYPE;
#define FileOpen    fopen
#define FileRead    fread
#define FileWrite   fwrite
#define FilePrintF  fprintf
#define FileClose   fclose

#endif

// =======================================================================

PointerList::~PointerList()
{
    PBlock* pBlock = pFirst;
    while ( pBlock )
    {
        PBlock* pNextBlock = pBlock->pNext;
        delete pBlock;
        pBlock = pNextBlock;
    }
}

// -----------------------------------------------------------------------

void PointerList::Add( const void* p )
{
    if ( !pFirst )
    {
        pFirst = new PBlock;
        memset( pFirst->aData, 0, PBLOCKCOUNT * sizeof( void* ) );
        pFirst->nCount = 0;
        pFirst->pPrev  = NULL;
        pFirst->pNext  = NULL;
        pLast = pFirst;
    }

    PBlock* pBlock = pFirst;
    while ( pBlock && (pBlock->nCount == PBLOCKCOUNT) )
        pBlock = pBlock->pNext;

    if ( !pBlock )
    {
        pBlock = new PBlock;
        memset( pBlock->aData, 0, PBLOCKCOUNT * sizeof( void* ) );
        pBlock->nCount = 0;
        pBlock->pPrev  = pLast;
        pBlock->pNext  = NULL;
        pLast->pNext   = pBlock;
        pLast          = pBlock;
    }

    USHORT i = 0;
    while ( pBlock->aData[i] )
        i++;

    pBlock->aData[i] = (void*)p;
    pBlock->nCount++;
    nCount++;
}

// -----------------------------------------------------------------------

BOOL PointerList::Remove( const void* p )
{
    if ( !p )
       return FALSE;

    PBlock* pBlock = pFirst;
    while ( pBlock )
    {
        USHORT i = 0;
        while ( i < PBLOCKCOUNT )
        {
            if ( ((ULONG)p) == ((ULONG)pBlock->aData[i]) )
            {
                pBlock->aData[i] = NULL;
                pBlock->nCount--;
                nCount--;

                if ( !pBlock->nCount )
                {
                    if ( pBlock->pPrev )
                        pBlock->pPrev->pNext = pBlock->pNext;
                    if ( pBlock->pNext )
                        pBlock->pNext->pPrev = pBlock->pPrev;
                    if ( pBlock == pFirst )
                        pFirst = pBlock->pNext;
                    if ( pBlock == pLast )
                        pLast = pBlock->pPrev;
                    delete pBlock;
                }

                return TRUE;
            }
            i++;
        }

        pBlock = pBlock->pNext;
    }

    return FALSE;
}

// -----------------------------------------------------------------------

const void* PointerList::Get( ULONG nPos ) const
{
    if ( nCount <= nPos )
        return NULL;

    PBlock* pBlock = pFirst;
    ULONG   nStart = 0;
    while ( pBlock )
    {
        USHORT i = 0;
        while ( i < PBLOCKCOUNT )
        {
            if ( pBlock->aData[i] )
            {
                nStart++;
                if ( (nStart-1) == nPos )
                    return pBlock->aData[i];
            }

            i++;
        }

        pBlock = pBlock->pNext;
    }

    return NULL;
}

// -----------------------------------------------------------------------

BOOL PointerList::IsIn( const void* p ) const
{
    if ( !p )
       return FALSE;

    PBlock* pBlock = pFirst;
    while ( pBlock )
    {
        USHORT i = 0;
        while ( i < PBLOCKCOUNT )
        {
            if ( ((ULONG)p) == ((ULONG)pBlock->aData[i]) )
                return TRUE;
            i++;
        }

        pBlock = pBlock->pNext;
    }

    return FALSE;
}


// =======================================================================

static void DbgGetDbgFileName( sal_Char* pStr )
{
#if defined( UNX )
    const sal_Char* pName = getenv("DBGSV_INIT");
    if ( !pName )
        pName = ".dbgsv.init";
    strcpy( pStr, pName );
#elif defined( WNT )
    const sal_Char* pName = getenv("DBGSV_INIT");
    if ( pName )
        strcpy( pStr, pName );
    else
        GetProfileStringA( "sv", "dbgsv", "dbgsv.ini", pStr, 200 );
#elif defined( OS2 )
    PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSV",
                           "dbgsv.ini", (PSZ)pStr, 200 );
#else
    strcpy( pStr, "dbgsv.ini" );
#endif
}

// -----------------------------------------------------------------------

static void DbgGetLogFileName( sal_Char* pStr )
{
#if defined( UNX )
    const sal_Char* pName = getenv("DBGSV_LOG");
    if ( !pName )
        pName = "dbgsv.log";
    strcpy( pStr, pName );
#elif defined( WNT )
    const sal_Char* pName = getenv("DBGSV_LOG");
    if ( pName )
        strcpy( pStr, pName );
    else
        GetProfileStringA( "sv", "dbgsvlog", "dbgsv.log", pStr, 200 );
#elif defined( OS2 )
    PrfQueryProfileString( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGSVLOG",
                           "dbgsv.log", (PSZ)pStr, 200 );
#else
    strcpy( pStr, "dbgsv.log" );
#endif
}

// -----------------------------------------------------------------------

static int DbgImplIsAllErrorOut()
{
#if defined( WNT )
    const sal_Char* pName = getenv("UPDATER");
    if ( pName && (strcmp( pName, "YES" ) == 0) )
        return TRUE;
    if ( GetProfileInt( "sv", "dbgallerrorout", 0 ) )
        return TRUE;
    else
        return FALSE;
#elif defined( OS2 )
    const sal_Char* pName = getenv("UPDATER");
    if ( pName && (strcmp( pName, "YES" ) == 0) )
        return TRUE;
    if ( PrfQueryProfileInt( HINI_PROFILE, (PSZ)"SV", (PSZ)"DBGALLERROROUT", 0 ) )
        return TRUE;
    else
        return FALSE;
#else
    return TRUE;
#endif
}

// -----------------------------------------------------------------------

static void DbgDebugBeep()
{
#if defined( WNT )
    MessageBeep( MB_ICONHAND );
#elif defined( OS2 )
    WinAlarm( HWND_DESKTOP, WA_ERROR );
#endif
}

// -----------------------------------------------------------------------

static DebugData* GetDebugData()
{
    if ( !aDebugData.bInit )
    {
        aDebugData.bInit = TRUE;

        // Default Debug-Namen setzen
        DbgGetLogFileName( aDebugData.aDbgData.aDebugName );

        // DEBUG.INI-File
        FILETYPE pDbgFile;
        sal_Char aBuf[4096];
        DbgGetDbgFileName( aBuf );
        if ( (pDbgFile = FileOpen( aBuf, "r" )) != NULL )
        {
            FileRead( &(aDebugData.aDbgData), sizeof( DbgData ), 1, pDbgFile );
            FileClose( pDbgFile );
        }

#ifndef MAC
        getcwd( aCurPath, sizeof( aCurPath ) );
#endif

        // Daten initialisieren
        if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_XTOR )
            aDebugData.pXtorList = new PointerList;
        if ( aDebugData.aDbgData.nTestFlags & DBG_TEST_PROFILING )
            aDebugData.pProfList = new PointerList;
        if ( aDebugData.aDbgData.nErrorOut < DBG_OUT_MSGBOX )
        {
            if ( !DbgImplIsAllErrorOut() )
                aDebugData.aDbgData.nErrorOut = DBG_OUT_MSGBOX;
        }
    }

    return &aDebugData;
}

// -----------------------------------------------------------------------

inline DebugData* ImplGetDebugData()
{
    if ( !aDebugData.bInit )
        return GetDebugData();
    else
        return &aDebugData;
}

// -----------------------------------------------------------------------

static FILETYPE ImplDbgInitFile()
{
    static BOOL bFileInit = FALSE;

#ifndef MAC
    sal_Char aBuf[4096];
    getcwd( aBuf, sizeof( aBuf ) );
    chdir( aCurPath );
#endif

    DebugData*  pData = GetDebugData();
    FILETYPE    pDebugFile;

    if ( !bFileInit )
    {
        bFileInit = TRUE;

        if ( pData->aDbgData.bOverwrite )
            pDebugFile = FileOpen( pData->aDbgData.aDebugName, "w" );
        else
            pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" );

        if ( pDebugFile )
        {
            time_t  nTime = time( 0 );
            tm*     pTime;
#ifdef UNX
            tm      aTime;
            pTime = localtime_r( &nTime, &aTime );
#else
            pTime = localtime( &nTime );
#endif

            // Header ausgeben
            FilePrintF( pDebugFile, "******************************************************************************%s", FILE_LINEEND );
            FilePrintF( pDebugFile, "%s%s", pData->aDbgData.aDebugName, FILE_LINEEND );
            if ( pTime )
                FilePrintF( pDebugFile, "%s%s", asctime( pTime ), FILE_LINEEND );
        }
    }
    else
        pDebugFile = FileOpen( pData->aDbgData.aDebugName, "a" );

#ifndef MAC
    chdir( aBuf );
#endif

    return pDebugFile;
}

// -----------------------------------------------------------------------

static void ImplDbgPrintFile( const sal_Char* pLine )
{
    FILETYPE pDebugFile = ImplDbgInitFile();

    if ( pDebugFile )
    {
        FilePrintF( pDebugFile, "%s%s", pLine, FILE_LINEEND );
        FileClose( pDebugFile );
    }
}

// -----------------------------------------------------------------------

static int ImplStrSearch( const sal_Char* pSearchStr, int nSearchLen,
                          const sal_Char* pStr, int nLen )
{
    int nPos = 0;
    while ( nPos+nSearchLen <= nLen )
    {
        if ( strncmp( pStr+nPos, pSearchStr, nSearchLen ) == 0 )
            return 1;
        nPos++;
    }

    return 0;
}

// -----------------------------------------------------------------------

static int ImplDbgFilter( const sal_Char* pFilter, const sal_Char* pMsg,
                          int bEmpty )
{
    int nStrLen = strlen( pFilter );
    if ( !nStrLen )
        return bEmpty;

    int nMsgLen = strlen( pMsg );
    const sal_Char* pTok = pFilter;
    int         nTok = 0;
    while ( pTok[nTok] )
    {
        if ( pTok[nTok] == ';' )
        {
            if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) )
                return TRUE;

            pTok += nTok+1;
            nTok = 0;
        }

        nTok++;
    }

    if ( nTok && ImplStrSearch( pTok, nTok, pMsg, nMsgLen ) )
        return TRUE;
    else
        return FALSE;
}

// -----------------------------------------------------------------------

static void DebugInit()
{
    bDbgImplInMain = TRUE;
    ImplDbgInitLock();
}

// -----------------------------------------------------------------------

static void DebugDeInit()
{
    DebugData*  pData = GetDebugData();
    ULONG       i;
    ULONG       nCount;
    ULONG       nOldOut;

    // Statistik-Ausgaben immer in File
    nOldOut = pData->aDbgData.nTraceOut;
    pData->aDbgData.nTraceOut = DBG_OUT_FILE;

    // Xtor-Liste ausgeben
    if ( pData->pXtorList && pData->pXtorList->Count() &&
         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) )
    {
        DbgOutf( "------------------------------------------------------------------------------" );
        DbgOutf( "Object Report" );
        DbgOutf( "------------------------------------------------------------------------------" );
        DbgOutf( "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :",
                 "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." );
        DbgOutf( "----------------------------:-----------:-----------:---------:----:---------:" );
        for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
        {
            XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
            if ( pXtorData->bTest )
            {
                // Static-Objekte dazurechnen
                pXtorData->nDtorCalls += pXtorData->nStatics;
                if ( pXtorData->nStatics && (pXtorData->nDtorCalls > pXtorData->nCtorCalls) )
                    pXtorData->nDtorCalls = pXtorData->nCtorCalls;
                DbgOutf( "%-27s : %9lu : %9lu : %7lu : %3lu : %4lu %-1s :",
                         pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls,
                         pXtorData->nMaxCount, pXtorData->nStatics,
                         pXtorData->nCtorCalls - pXtorData->nDtorCalls,
                         (pXtorData->nCtorCalls - pXtorData->nDtorCalls) ? "!" : " " );
            }
        }
        DbgOutf( "==============================================================================" );
    }

    // Aufraeumen
    if ( pData->pXtorList )
    {
        for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
        {
            XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
            delete pXtorData;
        }
        delete pData->pXtorList;
        pData->pXtorList = NULL;
    }

    // Alles auf FALSE setzen, damit globale Variablen nicht das
    // System zum Abstuerzen bringt. Dabei muessen aber die
    // Memory-Flags erhalten bleiben, da sonst new/delete in globalen
    // Variablen abstuerzen, da die Pointeranpassung dann nicht mehr richtig
    // funktioniert
    pData->aDbgData.nTraceOut   = nOldOut;
    pData->aDbgData.nTestFlags &= (DBG_TEST_MEM | DBG_TEST_PROFILING);
    pData->pDbgPrintTestTool    = NULL;
    pData->pDbgPrintShell       = NULL;
    pData->pDbgPrintWindow      = NULL;
    pData->pDbgPrintShell       = NULL;
    ImplDbgDeInitLock();
}

// -----------------------------------------------------------------------

static void DebugGlobalDeInit()
{
    DebugData*  pData = GetDebugData();
    ULONG       i;
    ULONG       nCount;
    ULONG       nOldOut;

    // Statistik-Ausgaben immer in File
    nOldOut = pData->aDbgData.nTraceOut;
    pData->aDbgData.nTraceOut = DBG_OUT_FILE;

    // Profileliste ausgeben
    if ( pData->pProfList && pData->pProfList->Count() )
    {
        DbgOutf( "------------------------------------------------------------------------------" );
        DbgOutf( "Profiling Report" );
        DbgOutf( "------------------------------------------------------------------------------" );
        DbgOutf( "%-25s : %-9s : %-6s : %-6s : %-6s : %-9s :",
                 "Prof-List (ms)", "Time", "Min", "Max", "Ave", "Count" );
        DbgOutf( "--------------------------:-----------:--------:--------:--------:-----------:" );
        for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ )
        {
            ProfType* pProfData = (ProfType*)pData->pProfList->Get( i );
            ULONG nAve = pProfData->nTime / pProfData->nCount;
            DbgOutf( "%-25s : %9lu : %6lu : %6lu : %6lu : %9lu :",
                     pProfData->aName, pProfData->nTime,
                     pProfData->nMinTime, pProfData->nMaxTime, nAve,
                     pProfData->nCount );
        }
        DbgOutf( "==============================================================================" );
    }

    // Aufraeumen
    if ( pData->pProfList )
    {
        for( i = 0, nCount = pData->pProfList->Count(); i < nCount; i++ )
        {
            ProfType* pProfData = (ProfType*)pData->pProfList->Get( i );
            delete pProfData;
        }
        delete pData->pProfList;
        pData->pProfList = NULL;
    }

#ifdef SV_MEMMGR
    DbgImpCheckMemoryDeInit();
#endif

    // Profiling-Flags ausschalten
    pData->aDbgData.nTraceOut   = nOldOut;
    pData->aDbgData.nTestFlags &= ~DBG_TEST_PROFILING;
}

// -----------------------------------------------------------------------

void ImpDbgOutfBuf( sal_Char* pBuf, const sal_Char* pFStr, ... )
{
    va_list pList;

    va_start( pList, pFStr );
    sal_Char aBuf[DBG_BUF_MAXLEN];
    vsprintf( aBuf, pFStr, pList );
    va_end( pList );

    strcat( pBuf, aBuf );
    strcat( pBuf, "\n" );
}

// -----------------------------------------------------------------------

static void DebugXTorInfo( sal_Char* pBuf )
{
    DebugData*  pData = GetDebugData();
    ULONG       i;
    ULONG       nCount;

    // Xtor-Liste ausgeben
    if ( pData->pXtorList && pData->pXtorList->Count() &&
         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_REPORT) )
    {
        ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" );
        ImpDbgOutfBuf( pBuf, "Object Report" );
        ImpDbgOutfBuf( pBuf, "------------------------------------------------------------------------------" );
        ImpDbgOutfBuf( pBuf, "%-27s : %-9s : %-9s : %-7s : %-3s : %-6s :",
                       "XTor-List", "Ctor", "Dtor", "MaxInst", "St.", "Diff." );
        ImpDbgOutfBuf( pBuf, "----------------------------:-----------:-----------:---------:----:---------:" );
        for( i = 0, nCount = pData->pXtorList->Count(); i < nCount; i++ )
        {
            XtorType* pXtorData = (XtorType*)pData->pXtorList->Get( i );
            if ( pXtorData->bTest )
            {
                ImpDbgOutfBuf( pBuf, "%-27s : %9lu : %9lu : %7lu : %3lu : %6lu :",
                               pXtorData->aName, pXtorData->nCtorCalls, pXtorData->nDtorCalls,
                               pXtorData->nMaxCount, pXtorData->nStatics,
                               pXtorData->nCtorCalls - pXtorData->nDtorCalls );
            }
        }
        ImpDbgOutfBuf( pBuf, "==============================================================================" );
        ImpDbgOutfBuf( pBuf, "" );
    }
}

// -----------------------------------------------------------------------
BOOL ImplDbgFilterMessage( const sal_Char* pMsg )
{
    DebugData*  pData = GetDebugData();
    if ( !ImplDbgFilter( pData->aDbgData.aInclFilter, pMsg, TRUE ) )
        return TRUE;
    if ( ImplDbgFilter( pData->aDbgData.aExclFilter, pMsg, FALSE ) )
        return TRUE;
    return FALSE;
}

// -----------------------------------------------------------------------

void* DbgFunc( USHORT nAction, void* pParam )
{
    DebugData* pData = ImplGetDebugData();

    if ( nAction == DBG_FUNC_GETDATA )
        return (void*)&(pData->aDbgData);
    else if ( nAction == DBG_FUNC_GETPRINTMSGBOX )
        return (void*)(pData->pDbgPrintMsgBox);
    else if ( nAction == DBG_FUNC_FILTERMESSAGE )
        if ( ImplDbgFilterMessage( (const sal_Char*) pParam ) )
            return (void*) -1;
        else
            return (void*) 0;   // aka NULL
    else

    {
        switch ( nAction )
        {
            case DBG_FUNC_DEBUGSTART:
                DebugInit();
                break;

            case DBG_FUNC_DEBUGEND:
                DebugDeInit();
                break;

            case DBG_FUNC_GLOBALDEBUGEND:
                DebugGlobalDeInit();
                break;

            case DBG_FUNC_SETPRINTMSGBOX:
                pData->pDbgPrintMsgBox = (DbgPrintLine)pParam;
                break;

            case DBG_FUNC_SETPRINTWINDOW:
                pData->pDbgPrintWindow = (DbgPrintLine)pParam;
                break;

            case DBG_FUNC_SETPRINTSHELL:
                pData->pDbgPrintShell = (DbgPrintLine)pParam;
                break;

            case DBG_FUNC_SETPRINTTESTTOOL:
                pData->pDbgPrintTestTool = (DbgPrintLine)pParam;
                break;

            case DBG_FUNC_SAVEDATA:
                {
                FILETYPE pDbgFile;
                sal_Char aBuf[4096];
                DbgGetDbgFileName( aBuf );
                if ( (pDbgFile = FileOpen( aBuf, "w" )) != NULL )
                {
                    FileWrite( pParam, sizeof( DbgData ), 1, pDbgFile );
                    FileClose( pDbgFile );
                }
                }
                break;

            case DBG_FUNC_MEMTEST:
#ifdef SV_MEMMGR
                DbgImpCheckMemory( pParam );
#endif
                break;

            case DBG_FUNC_XTORINFO:
                DebugXTorInfo( (sal_Char*)pParam );
                break;

            case DBG_FUNC_MEMINFO:
#ifdef SV_MEMMGR
                DbgImpMemoryInfo( (sal_Char*)pParam );
#endif
                break;

            case DBG_FUNC_COREDUMP:
                ImplCoreDump( NULL );
                break;

            case DBG_FUNC_ALLERROROUT:
                return (void*)(ULONG)DbgImplIsAllErrorOut();

            case DBG_FUNC_SETTESTSOLARMUTEX:
                pData->pDbgTestSolarMutex = (DbgTestSolarMutexProc)pParam;
                break;

            case DBG_FUNC_TESTSOLARMUTEX:
                if ( pData->pDbgTestSolarMutex )
                    pData->pDbgTestSolarMutex();
                break;

            case DBG_FUNC_PRINTFILE:
                ImplDbgPrintFile( (const sal_Char*)pParam );
                break;
       }

        return NULL;
    }
}

// -----------------------------------------------------------------------

void DbgProf( USHORT nAction, DbgDataType* pDbgData )
{
    // Ueberhaupt Profiling-Test an
    DebugData* pData = ImplGetDebugData();

    if ( !(pData->aDbgData.nTestFlags & DBG_TEST_PROFILING) )
        return;

    sal_Char    aBuf[DBG_BUF_MAXLEN];
    ProfType*   pProfData = (ProfType*)pDbgData->pData;
    ULONG       nTime;
    if ( (nAction != DBG_PROF_START) && !pProfData )
    {
        strcpy( aBuf, DbgError_ProfEnd1 );
        strcat( aBuf, pDbgData->pName );
        DbgError( aBuf );
        return;
    }

    switch ( nAction )
    {
        case DBG_PROF_START:
            if ( !pDbgData->pData )
            {
                pDbgData->pData = (void*)new ProfType;
                pProfData = (ProfType*)pDbgData->pData;
                strncpy( pProfData->aName, pDbgData->pName, DBG_MAXNAME );
                pProfData->aName[DBG_MAXNAME] = '\0';
                pProfData->nCount           = 0;
                pProfData->nTime            = 0;
                pProfData->nMinTime         = 0xFFFFFFFF;
                pProfData->nMaxTime         = 0;
                pProfData->nStart           = 0xFFFFFFFF;
                pProfData->nContinueTime    = 0;
                pProfData->nContinueStart   = 0xFFFFFFFF;
                pData->pProfList->Add( (void*)pProfData );
            }

            if ( pProfData->nStart == 0xFFFFFFFF )
            {
                pProfData->nStart = ImplGetPerfTime();
                pProfData->nCount++;
            }
            break;

        case DBG_PROF_STOP:
            nTime = ImplGetPerfTime();

            if ( pProfData->nStart == 0xFFFFFFFF )
            {
                DbgError( DbgError_ProfEnd1 );
                return;
            }

            if ( pProfData->nContinueStart != 0xFFFFFFFF )
            {
                pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart;
                pProfData->nContinueStart = 0xFFFFFFFF;
            }

            nTime -= pProfData->nStart;
            nTime -= pProfData->nContinueTime;

            if ( nTime < pProfData->nMinTime )
                pProfData->nMinTime = nTime;

            if ( nTime > pProfData->nMaxTime )
                pProfData->nMaxTime = nTime;

            pProfData->nTime += nTime;

            pProfData->nStart         = 0xFFFFFFFF;
            pProfData->nContinueTime  = 0;
            pProfData->nContinueStart = 0xFFFFFFFF;
            break;

        case DBG_PROF_CONTINUE:
            if ( pProfData->nContinueStart != 0xFFFFFFFF )
            {
                pProfData->nContinueTime += ImplGetPerfTime() - pProfData->nContinueStart;
                pProfData->nContinueStart = 0xFFFFFFFF;
            }
            break;

        case DBG_PROF_PAUSE:
            if ( pProfData->nContinueStart == 0xFFFFFFFF )
                pProfData->nContinueStart = ImplGetPerfTime();
            break;
    }
}

// -----------------------------------------------------------------------

void DbgXtor( DbgDataType* pDbgData, USHORT nAction, const void* pThis,
              DbgUsr fDbgUsr )
{
    DebugData* pData = ImplGetDebugData();

    // Verbindung zu Debug-Memory-Manager testen
#ifdef SV_MEMMGR
    if ( pData->aDbgData.nTestFlags & DBG_TEST_MEM_XTOR )
        DbgImpCheckMemory();
#endif

    // Schnell-Test
    if ( !(pData->aDbgData.nTestFlags & DBG_TEST_XTOR) )
        return;

    XtorType* pXtorData = (XtorType*)pDbgData->pData;
    if ( !pXtorData )
    {
        pDbgData->pData = (void*)new XtorType;
        pXtorData = (XtorType*)pDbgData->pData;
        strncpy( pXtorData->aName, pDbgData->pName, DBG_MAXNAME );
        pXtorData->aName[DBG_MAXNAME] = '\0';
        pXtorData->nCtorCalls   = 0;
        pXtorData->nDtorCalls   = 0;
        pXtorData->nMaxCount    = 0;
        pXtorData->nStatics     = 0;
        pXtorData->bTest        = TRUE;
        pData->pXtorList->Add( (void*)pXtorData );

        if ( !ImplDbgFilter( pData->aDbgData.aInclClassFilter, pXtorData->aName, TRUE ) )
            pXtorData->bTest = FALSE;
        if ( ImplDbgFilter( pData->aDbgData.aExclClassFilter, pXtorData->aName, FALSE ) )
            pXtorData->bTest = FALSE;
    }
    if ( !pXtorData->bTest )
        return;

    sal_Char    aBuf[DBG_BUF_MAXLEN];
    USHORT      nAct = nAction & ~DBG_XTOR_DTOROBJ;

    // Trace (Enter)
    if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) &&
         !(nAction & DBG_XTOR_DTOROBJ) )
    {
        if ( nAct != DBG_XTOR_CHKOBJ )
        {
            if ( nAct == DBG_XTOR_CTOR )
                strcpy( aBuf, DbgTrace_EnterCtor );
            else if ( nAct == DBG_XTOR_DTOR )
                strcpy( aBuf, DbgTrace_EnterDtor );
            else
                strcpy( aBuf, DbgTrace_EnterMeth );
            strcat( aBuf, pDbgData->pName );
            DbgTrace( aBuf );
        }
    }

    // Sind noch Xtor-Tests als Trace an
    if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXTRA )
    {
        // DBG_CTOR-Aufruf vor allen anderen DBG_XTOR-Aufrufen
        if ( ((nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR) && !pDbgData->pData )
        {
            strcpy( aBuf, DbgError_Xtor1 );
            strcat( aBuf, pDbgData->pName );
            DbgError( aBuf );
            return;
        }

        // Testen, ob This-Pointer gueltig
        if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
        {
            if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) ||
                 !(nAction & DBG_XTOR_DTOROBJ) )
            {
                // This-Pointer == NULL
                if ( !pThis )
                {
                    strcpy( aBuf, DbgError_CtorDtor1 );
                    strcat( aBuf, pDbgData->pName );
                    DbgError( aBuf );
                    return;
                }

                if ( (nAction & ~DBG_XTOR_DTOROBJ) != DBG_XTOR_CTOR )
                {
                    if ( !pXtorData->aThisList.IsIn( pThis ) )
                    {
                        sprintf( aBuf, DbgError_CtorDtor2, pThis );
                        strcat( aBuf, pDbgData->pName );
                        DbgError( aBuf );
                    }
                }
            }
        }

        // Function-Test durchfuehren und Verwaltungsdaten updaten
        const sal_Char* pMsg = NULL;
        switch ( nAction & ~DBG_XTOR_DTOROBJ )
        {
            case DBG_XTOR_CTOR:
                if ( nAction & DBG_XTOR_DTOROBJ )
                {
                    if ( fDbgUsr &&
                         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) &&
                         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
                        pMsg = fDbgUsr( pThis );
                }
                else
                {
                    pXtorData->nCtorCalls++;
                    if ( !bDbgImplInMain )
                        pXtorData->nStatics++;
                    if ( (pXtorData->nCtorCalls-pXtorData->nDtorCalls) > pXtorData->nMaxCount )
                        pXtorData->nMaxCount = pXtorData->nCtorCalls - pXtorData->nDtorCalls;

                    if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
                        pXtorData->aThisList.Add( pThis );
                }
                break;

            case DBG_XTOR_DTOR:
                if ( nAction & DBG_XTOR_DTOROBJ )
                {
                    pXtorData->nDtorCalls++;
                    if ( pData->aDbgData.nTestFlags & DBG_TEST_XTOR_THIS )
                        pXtorData->aThisList.Remove( pThis );
                }
                else
                {
                    if ( fDbgUsr &&
                         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
                        pMsg = fDbgUsr( pThis );
                }
                break;

            case DBG_XTOR_CHKTHIS:
            case DBG_XTOR_CHKOBJ:
                if ( nAction & DBG_XTOR_DTOROBJ )
                {
                    if ( fDbgUsr &&
                         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_EXIT) &&
                         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
                        pMsg = fDbgUsr( pThis );
                }
                else
                {
                    if ( fDbgUsr &&
                         (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_FUNC) )
                        pMsg = fDbgUsr( pThis );
                }
                break;
        }

        // Gegebenenfalls Fehlermeldung ausgeben
        if ( pMsg )
        {
            sprintf( aBuf, DbgError_CtorDtor3, pThis );
            strcat( aBuf, pDbgData->pName );
            strcat( aBuf, ": \n" );
            strcat( aBuf, pMsg );
            DbgError( aBuf );
        }
    }

    // Trace (Leave)
    if ( (pData->aDbgData.nTestFlags & DBG_TEST_XTOR_TRACE) &&
         (nAction & DBG_XTOR_DTOROBJ) )
    {
        if ( nAct != DBG_XTOR_CHKOBJ )
        {
            if ( nAct == DBG_XTOR_CTOR )
                strcpy( aBuf, DbgTrace_LeaveCtor );
            else if ( nAct == DBG_XTOR_DTOR )
                strcpy( aBuf, DbgTrace_LeaveDtor );
            else
                strcpy( aBuf, DbgTrace_LeaveMeth );
            strcat( aBuf, pDbgData->pName );
            DbgTrace( aBuf );
        }
    }
}

// -----------------------------------------------------------------------

void DbgOut( const sal_Char* pMsg, USHORT nDbgOut, const sal_Char* pFile, USHORT nLine )
{
    static BOOL bIn = FALSE;
    if ( bIn )
        return;
    bIn = TRUE;

    DebugData*  pData = GetDebugData();
    sal_Char*   pStr;
    ULONG       nOut;
    int         nBufLen = 0;

    if ( nDbgOut == DBG_OUT_ERROR )
    {
        nOut = pData->aDbgData.nErrorOut;
        pStr = "Error: ";
        if ( pData->aDbgData.nErrorOut == DBG_OUT_FILE )
            DbgDebugBeep();
    }
    else if ( nDbgOut == DBG_OUT_WARNING )
    {
        nOut = pData->aDbgData.nWarningOut;
        pStr = "Warning: ";
    }
    else
    {
        nOut = pData->aDbgData.nTraceOut;
        pStr = NULL;
    }

    if ( nOut == DBG_OUT_NULL )
    {
        bIn = FALSE;
        return;
    }

    if ( (nDbgOut != DBG_OUT_ERROR) || DbgImplIsAllErrorOut() )
    {
        if ( ImplDbgFilterMessage( pMsg ) )
        {
            bIn = FALSE;
            return;
        }
    }

    ImplDbgLock();

    sal_Char aBufOut[DBG_BUF_MAXLEN];
    if ( pStr )
    {
        strcpy( aBufOut, pStr );
        nBufLen = strlen( pStr );
    }
    else
        aBufOut[0] = '\0';

    int nMsgLen = strlen( pMsg );
    if ( nBufLen+nMsgLen > DBG_BUF_MAXLEN )
    {
        int nCopyLen = DBG_BUF_MAXLEN-nBufLen-3;
        strncpy( &(aBufOut[nBufLen]), pMsg, nCopyLen );
        strcpy( &(aBufOut[nBufLen+nCopyLen]), "..." );
    }
    else
        strcpy( &(aBufOut[nBufLen]), pMsg );

    if ( pFile && nLine && (nBufLen+nMsgLen < DBG_BUF_MAXLEN) )
    {
        if ( nOut == DBG_OUT_MSGBOX )
            strcat( aBufOut, "\n" );
        else
            strcat( aBufOut, " " );
        strcat( aBufOut, "From File " );
        strcat( aBufOut, pFile );
        strcat( aBufOut, " at Line " );

        // Line in String umwandeln und dranhaengen
        sal_Char    aLine[9];
        sal_Char*   pLine = &aLine[7];
        USHORT      i;
        memset( aLine, 0, sizeof( aLine ) );
        do
        {
            i = nLine % 10;
            pLine--;
            *(pLine) = (sal_Char)i + 48;
            nLine /= 10;
        }
        while ( nLine );
        strcat( aBufOut, pLine );
    }

    if ( nOut == DBG_OUT_COREDUMP )
    {
        if ( !ImplCoreDump( aBufOut ) )
            nOut = DBG_OUT_DEBUGGER;
    }

    if ( nOut == DBG_OUT_DEBUGGER )
    {
        if ( !ImplActivateDebugger( aBufOut ) )
            nOut = DBG_OUT_TESTTOOL;
    }

    if ( nOut == DBG_OUT_TESTTOOL )
    {
        if ( pData->pDbgPrintTestTool )
            pData->pDbgPrintTestTool( aBufOut );
        else
            nOut = DBG_OUT_MSGBOX;
    }

    if ( nOut == DBG_OUT_MSGBOX )
    {
        if ( pData->pDbgPrintMsgBox )
            pData->pDbgPrintMsgBox( aBufOut );
        else
            nOut = DBG_OUT_SHELL;
    }

    if ( nOut == DBG_OUT_SHELL )
    {
        if ( pData->pDbgPrintShell )
            pData->pDbgPrintShell( aBufOut );
        else
            nOut = DBG_OUT_WINDOW;
    }

    if ( nOut == DBG_OUT_WINDOW )
    {
        if ( pData->pDbgPrintWindow )
            pData->pDbgPrintWindow( aBufOut );
        else
            nOut = DBG_OUT_FILE;
    }

    if ( nOut == DBG_OUT_FILE )
        ImplDbgPrintFile( aBufOut );

    ImplDbgUnlock();

    bIn = FALSE;
}

// -----------------------------------------------------------------------

void DbgOutTypef( USHORT nDbgOut, const sal_Char* pFStr, ... )
{
    va_list pList;

    va_start( pList, pFStr );
    sal_Char aBuf[DBG_BUF_MAXLEN];
    vsprintf( aBuf, pFStr, pList );
    va_end( pList );

    DbgOut( aBuf, nDbgOut );
}

// -----------------------------------------------------------------------

void DbgOutf( const sal_Char* pFStr, ... )
{
    va_list pList;

    va_start( pList, pFStr );
    sal_Char aBuf[DBG_BUF_MAXLEN];
    vsprintf( aBuf, pFStr, pList );
    va_end( pList );

    DbgOut( aBuf );
}

// =======================================================================

#else

void* DbgFunc( USHORT, void* ) { return NULL; }

void DbgProf( USHORT, DbgDataType* ) {}
void DbgXtor( DbgDataType*, USHORT, const void*, DbgUsr ) {}

void DbgOut( const sal_Char*, USHORT, const sal_Char*, USHORT ) {}
void DbgOutTypef( USHORT, const sal_Char*, ... ) {}
void DbgOutf( const sal_Char*, ... ) {}

#endif