//+---------------------------------------------------------------------------
//  Copyright (C) 1991, Microsoft Corporation.
//
//  File:       debug.h
//
//  Contents:   Debugging macros. Stolen from old Cairo debnot.h with the
//              following history...
//
//  History:    23-Jul-91   KyleP       Created.
//              15-Oct-91   KevinRo     Major changes and comments added
//              18-Oct-91   vich        Consolidated win4p.hxx
//              22-Oct-91   SatoNa      Added SHLSTRICT
//              29-Apr-92   BartoszM    Moved from win4p.h
//               3-Jun-92   BruceFo     Added SMUISTRICT
//              17-Dec-92   AlexT       Moved UN..._PARM out of DEVL==1
//              30-Sep-93   KyleP       DEVL obsolete
//              18-Jun-94   AlexT       Make Assert a better statement
//               7-Oct-94   BruceFo     Stole and ripped out everything except
//                                      debug prints and asserts.
//              30-Dec-95   BruceFo     More cleanup, make suitable for DFS
//                                      project. Get rid of Win4 naming.
//
//  NOTE: you must call the DebugInitialize() API before calling any other
//  APIs!
//
//----------------------------------------------------------------------------

#ifndef __DEBUG_H__
#define __DEBUG_H__

#ifdef __cplusplus
extern "C" {
#endif

#include <stdio.h>      // for vsprintf
#include <stdarg.h>

//----------------------------------------------------------------------------
//  Parameter Macros
//
//  To avoid compiler warnings for unimplemented functions, use
//  UNIMPLEMENTED_PARM(x) for each unreferenced parameter.  This will
//  later be defined to nul to reveal functions that we forgot to implement.
//
//  For functions which will never use a parameter, use
//  UNREFERENCED_PARM(x).
//

#define UNIMPLEMENTED_PARM(x)   (x)
#define UNREFERENCED_PARM(x)    (x)

#if DBG == 1

//
// DEBUG -- DEBUG -- DEBUG -- DEBUG -- DEBUG
//

#ifndef DEBUGAPI
    #define DEBUGAPI __stdcall
#endif

//
// The following APIs are public and may be called
//

void DEBUGAPI
DebugInitialize(
    void);

unsigned long DEBUGAPI
DebugSetInfoLevel(
    unsigned long ulNewLevel);

unsigned long DEBUGAPI
DebugSetInfoMask(
    unsigned long ulNewMask);

unsigned long DEBUGAPI
DebugSetAssertLevel(
    unsigned long ulNewLevel);

//
// The following APIs should never be called directly. They will be called
// via macros defined herein.
//

void DEBUGAPI
Debugvprintf(
    unsigned long ulCompMask,
    char const *pszComp,
    char const *ppszfmt,
    va_list ArgList);

void DEBUGAPI
DebugAssertEx(
    char const *pszFile,
    int iLine,
    char const *pszMsg);

void DEBUGAPI
DebugCheckInit(
    char* pInfoLevelString,
    unsigned long* InfoLevel);

//
// Public assertion macros
//

#define DebugAssert(x) (void)((x) || (DebugAssertEx(__FILE__, __LINE__, #x),0))
#define DebugVerify(x) DebugAssert(x)

//
// Debug print macros
//

#define DEB_ERROR               0x00000001      // exported error paths
#define DEB_WARN                0x00000002      // exported warnings
#define DEB_TRACE               0x00000004      // exported trace messages

#define DEB_DBGOUT              0x00000010      // Output to debugger
#define DEB_STDOUT              0x00000020      // Output to stdout

#define DEB_IERROR              0x00000100      // internal error paths
#define DEB_IWARN               0x00000200      // internal warnings
#define DEB_ITRACE              0x00000400      // internal trace messages

#define DEB_USER1               0x00010000      // User defined
#define DEB_USER2               0x00020000      // User defined
#define DEB_USER3               0x00040000      // User defined
#define DEB_USER4               0x00080000      // User defined
#define DEB_USER5               0x00100000      // User defined
#define DEB_USER6               0x00200000      // User defined
#define DEB_USER7               0x00400000      // User defined
#define DEB_USER8               0x00800000      // User defined
#define DEB_USER9               0x01000000      // User defined
#define DEB_USER10              0x02000000      // User defined
#define DEB_USER11              0x04000000      // User defined
#define DEB_USER12              0x08000000      // User defined
#define DEB_USER13              0x10000000      // User defined
#define DEB_USER14              0x20000000      // User defined
#define DEB_USER15              0x40000000      // User defined

#define DEB_NOCOMPNAME          0x80000000      // suppress component name

#define DEB_FORCE               0x7fffffff      // force message

#define ASSRT_MESSAGE           0x00000001      // Output a message
#define ASSRT_BREAK             0x00000002      // Int 3 on assertion
#define ASSRT_POPUP             0x00000004      // And popup message

//+----------------------------------------------------------------------
//
// DECLARE_DEBUG(comp)
// DECLARE_INFOLEVEL(comp)
//
// This macro defines xxDebugOut where xx is the component prefix
// to be defined. This declares a static variable 'xxInfoLevel', which
// can be used to control the type of xxDebugOut messages printed to
// the terminal. For example, xxInfoLevel may be set at the debug terminal.
// This will enable the user to turn debugging messages on or off, based
// on the type desired. The predefined types are defined below. Component
// specific values should use the upper 24 bits
//
// To Use:
//
// 1)   In your components main include file, include the line
//              DECLARE_DEBUG(comp)
//      where comp is your component prefix
//
// 2)   In one of your components source files, include the line
//              DECLARE_INFOLEVEL(comp)
//      where comp is your component prefix. This will define the
//      global variable that will control output.
//
// It is suggested that any component define bits be combined with
// existing bits. For example, if you had a specific error path that you
// wanted, you might define DEB_<comp>_ERRORxxx as being
//
// (0x100 | DEB_ERROR)
//
// This way, we can turn on DEB_ERROR and get the error, or just 0x100
// and get only your error.
//
//-----------------------------------------------------------------------

#ifndef DEF_INFOLEVEL
    #define DEF_INFOLEVEL 0
#endif

#ifdef __cplusplus

    #define DECLARE_INFOLEVEL(comp) \
        extern "C" unsigned long comp##InfoLevel = DEF_INFOLEVEL; \
        extern "C" char* comp##InfoLevelString = #comp;

    #define DECLARE_DEBUG(comp) \
        extern "C" unsigned long comp##InfoLevel;\
        extern "C" char* comp##InfoLevelString;\
        __inline void\
        comp##InlineDebugOut(unsigned long fDebugMask, char const *pszfmt, ...)\
        {\
            DebugCheckInit(comp##InfoLevelString, &comp##InfoLevel);\
            if (comp##InfoLevel & fDebugMask)\
            {\
                va_list va;\
                va_start(va, pszfmt);\
                Debugvprintf(fDebugMask, comp##InfoLevelString, pszfmt, va);\
                va_end(va);\
            }\
        }\
        class comp##CDbgTrace\
        {\
        private:\
            unsigned long _ulFlags;\
            char const * const _pszName;\
        public:\
            comp##CDbgTrace(unsigned long ulFlags, char const * const pszName)\
            : _ulFlags(ulFlags), _pszName(pszName)\
            {\
                comp##InlineDebugOut(_ulFlags, "Entering %s\n", _pszName);\
            }\
            ~comp##CDbgTrace()\
            {\
                comp##InlineDebugOut(_ulFlags, "Exiting %s\n", _pszName);\
            }\
        };

#else  // ! __cplusplus

    #define DECLARE_INFOLEVEL(comp) \
        extern unsigned long comp##InfoLevel = DEF_INFOLEVEL; \
        extern char* comp##InfoLevelString = #comp;

    #define DECLARE_DEBUG(comp) \
        extern unsigned long comp##InfoLevel;\
        extern char *comp##InfoLevelString;\
        __inline void\
        comp##InlineDebugOut(unsigned long fDebugMask, char const *pszfmt, ...)\
        {\
            DebugCheckInit(comp##InfoLevelString, &comp##InfoLevel);\
            if (comp##InfoLevel & fDebugMask)\
            {\
                va_list va;\
                va_start(va, pszfmt);\
                Debugvprintf(fDebugMask, comp##InfoLevelString, pszfmt, va);\
                va_end(va);\
            }\
        }

#endif // ! __cplusplus

#else // DBG == 0

//
// NO DEBUG -- NO DEBUG -- NO DEBUG -- NO DEBUG -- NO DEBUG
//

#define DebugInitialize()

#define DebugAssert(x)  NULL
#define DebugVerify(x)  (x)

#define DECLARE_DEBUG(comp)
#define DECLARE_INFOLEVEL(comp)

#endif // DBG == 0

#ifdef __cplusplus
}
#endif // __cplusplus

#endif // __DEBUG_H__
