//========= Copyright Valve Corporation, All rights reserved. ============// // // Purpose: // // $NoKeywords: $ // //=============================================================================// #ifndef DBG_H #define DBG_H #ifdef _WIN32 #pragma once #endif #include #include #include #include "basetypes.h" #include "dbgflag.h" #include "platform.h" #ifdef POSIX #define __cdecl #endif //----------------------------------------------------------------------------- // dll export stuff //----------------------------------------------------------------------------- #ifndef STATIC_TIER0 #ifdef TIER0_DLL_EXPORT #define DBG_INTERFACE DLL_EXPORT #define DBG_OVERLOAD DLL_GLOBAL_EXPORT #define DBG_CLASS DLL_CLASS_EXPORT #else #define DBG_INTERFACE DLL_IMPORT #define DBG_OVERLOAD DLL_GLOBAL_IMPORT #define DBG_CLASS DLL_CLASS_IMPORT #endif #else // BUILD_AS_DLL #define DBG_INTERFACE extern #define DBG_OVERLOAD #define DBG_CLASS #endif // BUILD_AS_DLL class Color; //----------------------------------------------------------------------------- // Usage model for the Dbg library // // 1. Spew. // // Spew can be used in a static and a dynamic mode. The static // mode allows us to display assertions and other messages either only // in debug builds, or in non-release builds. The dynamic mode allows us to // turn on and off certain spew messages while the application is running. // // Static Spew messages: // // Assertions are used to detect and warn about invalid states // Spews are used to display a particular status/warning message. // // To use an assertion, use // // Assert( (f == 5) ); // AssertMsg( (f == 5), ("F needs to be %d here!\n", 5) ); // AssertFunc( (f == 5), BadFunc() ); // AssertEquals( f, 5 ); // AssertFloatEquals( f, 5.0f, 1e-3 ); // // The first will simply report that an assertion failed on a particular // code file and line. The second version will display a print-f formatted // message // along with the file and line, the third will display a generic //message and // will also cause the function BadFunc to be executed, and the last two // will report an error if f is not equal to 5 (the last one asserts //within a particular tolerance). // // To use a warning, use // // Warning("Oh I feel so %s all over\n", "yummy"); // // Warning will do its magic in only Debug builds. To perform spew in *all* // builds, use RelWarning. // // Three other spew types, Msg, Log, and Error, are compiled into all //builds. These error types do *not* need two sets of parenthesis. // // Msg( "Isn't this exciting %d?", 5 ); // Error( "I'm just thrilled" ); // // Dynamic Spew messages // // It is possible to dynamically turn spew on and off. Dynamic spew is // identified by a spew group and priority level. To turn spew on for a // particular spew group, use SpewActivate( "group", level ). This will // cause all spew in that particular group with priority levels <= the // level specified in the SpewActivate function to be printed. Use DSpew // to perform the spew: // // DWarning( "group", level, "Oh I feel even yummier!\n" ); // // Priority level 0 means that the spew will *always* be printed, and group // '*' is the default spew group. If a DWarning is encountered using a group // whose priority has not been set, it will use the priority of the default // group. The priority of the default group is initially set to 0. // // Spew output // // The output of the spew system can be redirected to an externally-supplied // function which is responsible for outputting the spew. By default, the // spew is simply printed using printf. // // To redirect spew output, call SpewOutput. // // SpewOutputFunc( OutputFunc ); // // This will cause OutputFunc to be called every time a spew message is // generated. OutputFunc will be passed a spew type and a message to print. // It must return a value indicating whether the debugger should be invoked, // whether the program should continue running, or whether the program // should abort. // // 2. Code activation // // To cause code to be run only in debug builds, use DBG_CODE: // An example is below. // // DBG_CODE( // { // int x = 5; // ++x; // } // ); // // Code can be activated based on the dynamic spew groups also. Use // // DBG_DCODE( "group", level, // { int x = 5; ++x; } // ); // // 3. Breaking into the debugger. // // To cause an unconditional break into the debugger in debug builds only, use // DBG_BREAK // // DBG_BREAK(); // // You can force a break in any build (release or debug) using // // DebuggerBreak(); //----------------------------------------------------------------------------- /* Various types of spew messages */ // I'm sure you're asking yourself why SPEW_ instead of DBG_ ? // It's because DBG_ is used all over the place in windows.h // For example, DBG_CONTINUE is defined. Feh. enum SpewType_t { SPEW_MESSAGE = 0, SPEW_WARNING, SPEW_ASSERT, SPEW_ERROR, SPEW_LOG, SPEW_TYPE_COUNT }; enum SpewRetval_t { SPEW_DEBUGGER = 0, SPEW_CONTINUE, SPEW_ABORT }; /* type of externally defined function used to display debug spew */ typedef SpewRetval_t (*SpewOutputFunc_t)(SpewType_t spewType, const tchar *pMsg); /* Used to redirect spew output */ DBG_INTERFACE void SpewOutputFunc(SpewOutputFunc_t func); /* Used to get the current spew output function */ DBG_INTERFACE SpewOutputFunc_t GetSpewOutputFunc(void); /* This is the default spew fun, which is used if you don't specify one */ DBG_INTERFACE SpewRetval_t DefaultSpewFunc(SpewType_t type, const tchar *pMsg); /* Same as the default spew func, but returns SPEW_ABORT for asserts */ DBG_INTERFACE SpewRetval_t DefaultSpewFuncAbortOnAsserts(SpewType_t type, const tchar *pMsg); /* Should be called only inside a SpewOutputFunc_t, returns groupname, level, * color */ DBG_INTERFACE const tchar *GetSpewOutputGroup(void); DBG_INTERFACE int GetSpewOutputLevel(void); DBG_INTERFACE const Color *GetSpewOutputColor(void); /* Used to manage spew groups and subgroups */ DBG_INTERFACE void SpewActivate(const tchar *pGroupName, int level); DBG_INTERFACE bool IsSpewActive(const tchar *pGroupName, int level); /* Used to display messages, should never be called directly. */ DBG_INTERFACE void _SpewInfo(SpewType_t type, const tchar *pFile, int line); DBG_INTERFACE SpewRetval_t _SpewMessage(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE SpewRetval_t _DSpewMessage(const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(3, 4); DBG_INTERFACE SpewRetval_t ColorSpewMessage(SpewType_t type, const Color *pColor, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(3, 4); DBG_INTERFACE void _ExitOnFatalAssert(const tchar *pFile, int line); DBG_INTERFACE bool ShouldUseNewAssertDialog(); DBG_INTERFACE bool SetupWin32ConsoleIO(); // Returns true if they want to break in the debugger. DBG_INTERFACE bool DoNewAssertDialog(const tchar *pFile, int line, const tchar *pExpression); // Allows the assert dialogs to be turned off from code DBG_INTERFACE bool AreAllAssertsDisabled(); DBG_INTERFACE void SetAllAssertsDisabled(bool bAssertsEnabled); // Provides a callback that is called on asserts regardless of spew levels typedef void (*AssertFailedNotifyFunc_t)(const char *pchFile, int nLine, const char *pchMessage); DBG_INTERFACE void SetAssertFailedNotifyFunc(AssertFailedNotifyFunc_t func); DBG_INTERFACE void CallAssertFailedNotifyFunc(const char *pchFile, int nLine, const char *pchMessage); /* True if -hushasserts was passed on command line. */ DBG_INTERFACE bool HushAsserts(); #if defined(USE_SDL) DBG_INTERFACE void SetAssertDialogParent(struct SDL_Window *window); DBG_INTERFACE struct SDL_Window *GetAssertDialogParent(); #endif /* Used to define macros, never use these directly. */ #ifdef _PREFAST_ // When doing /analyze builds define _AssertMsg to be __analysis_assume. This // tells the compiler to assume that the condition is true, which helps to // suppress many warnings. This define is done in debug and release builds. The // unfortunate !! is necessary because otherwise /analyze is incapable of // evaluating all of the logical expressions that the regular compiler can // handle. Include _msg in the macro so that format errors in it are detected. #define _AssertMsg(_exp, _msg, _executeExp, _bFatal) \ do { \ __analysis_assume(!!(_exp)); \ _msg; \ } while (0) #define _AssertMsgOnce(_exp, _msg, _bFatal) \ do { \ __analysis_assume(!!(_exp)); \ _msg; \ } while (0) // Force asserts on for /analyze so that we get a __analysis_assume of all of // the constraints. #define DBGFLAG_ASSERT #define DBGFLAG_ASSERTFATAL #define DBGFLAG_ASSERTDEBUG #else #define _AssertMsg(_exp, _msg, _executeExp, _bFatal) \ do { \ if (!(_exp)) { \ _SpewInfo(SPEW_ASSERT, __TFILE__, __LINE__); \ SpewRetval_t ret = \ _SpewMessage("%s", static_cast(_msg)); \ CallAssertFailedNotifyFunc(__TFILE__, __LINE__, _msg); \ _executeExp; \ if (ret == SPEW_DEBUGGER) { \ if (!ShouldUseNewAssertDialog() || \ DoNewAssertDialog(__TFILE__, __LINE__, _msg)) { \ DebuggerBreak(); \ } \ if (_bFatal) { \ _ExitOnFatalAssert(__TFILE__, __LINE__); \ } \ } \ } \ } while (0) #define _AssertMsgOnce(_exp, _msg, _bFatal) \ do { \ static bool fAsserted; \ if (!fAsserted) { \ _AssertMsg(_exp, _msg, (fAsserted = true), _bFatal); \ } \ } while (0) #endif /* Spew macros... */ // AssertFatal macros // AssertFatal is used to detect an unrecoverable error condition. // If enabled, it may display an assert dialog (if DBGFLAG_ASSERTDLG is turned // on or running under the debugger), and always terminates the application #ifdef DBGFLAG_ASSERTFATAL #define AssertFatal(_exp) \ _AssertMsg(_exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), true) #define AssertFatalOnce(_exp) \ _AssertMsgOnce(_exp, _T("Assertion Failed: ") _T(#_exp), true) #define AssertFatalMsg(_exp, _msg, ...) \ _AssertMsg(_exp, (const tchar *)CDbgFmtMsg(_msg, ##__VA_ARGS__), \ ((void)0), true) #define AssertFatalMsgOnce(_exp, _msg) _AssertMsgOnce(_exp, _msg, true) #define AssertFatalFunc(_exp, _f) _AssertMsg( _exp, _T("Assertion Failed: " _T(#_exp), _f, true ) #define AssertFatalEquals(_exp, _expectedValue) \ AssertFatalMsg2((_exp) == (_expectedValue), _T("Expected %d but got %d!"), \ (_expectedValue), (_exp)) #define AssertFatalFloatEquals(_exp, _expectedValue, _tol) \ AssertFatalMsg2(fabs((_exp) - (_expectedValue)) <= (_tol), \ _T("Expected %f but got %f!"), (_expectedValue), (_exp)) #define VerifyFatal(_exp) AssertFatal(_exp) #define VerifyEqualsFatal(_exp, _expectedValue) \ AssertFatalEquals(_exp, _expectedValue) #define AssertFatalMsg1(_exp, _msg, a1) AssertFatalMsg(_exp, _msg, a1) #define AssertFatalMsg2(_exp, _msg, a1, a2) AssertFatalMsg(_exp, _msg, a1, a2) #define AssertFatalMsg3(_exp, _msg, a1, a2, a3) \ AssertFatalMsg(_exp, _msg, a1, a2, a3) #define AssertFatalMsg4(_exp, _msg, a1, a2, a3, a4) \ AssertFatalMsg(_exp, _msg, a1, a2, a3, a4) #define AssertFatalMsg5(_exp, _msg, a1, a2, a3, a4, a5) \ AssertFatalMsg(_exp, _msg, a1, a2, a3, a4, a5) #define AssertFatalMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) \ AssertFatalMsg(_exp, _msg, a1, a2, a3, a4, a5, a6) #define AssertFatalMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) \ AssertFatalMsg(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) #define AssertFatalMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) \ AssertFatalMsg(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) #define AssertFatalMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ AssertFatalMsg(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) #else // DBGFLAG_ASSERTFATAL #define AssertFatal(_exp) ((void)0) #define AssertFatalOnce(_exp) ((void)0) #define AssertFatalMsg(_exp, _msg) ((void)0) #define AssertFatalMsgOnce(_exp, _msg) ((void)0) #define AssertFatalFunc(_exp, _f) ((void)0) #define AssertFatalEquals(_exp, _expectedValue) ((void)0) #define AssertFatalFloatEquals(_exp, _expectedValue, _tol) ((void)0) #define VerifyFatal(_exp) (_exp) #define VerifyEqualsFatal(_exp, _expectedValue) (_exp) #define AssertFatalMsg1(_exp, _msg, a1) ((void)0) #define AssertFatalMsg2(_exp, _msg, a1, a2) ((void)0) #define AssertFatalMsg3(_exp, _msg, a1, a2, a3) ((void)0) #define AssertFatalMsg4(_exp, _msg, a1, a2, a3, a4) ((void)0) #define AssertFatalMsg5(_exp, _msg, a1, a2, a3, a4, a5) ((void)0) #define AssertFatalMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) #define AssertFatalMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) ((void)0) #define AssertFatalMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) ((void)0) #define AssertFatalMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ ((void)0) #endif // DBGFLAG_ASSERTFATAL // Assert macros // Assert is used to detect an important but survivable error. // It's only turned on when DBGFLAG_ASSERT is true. #ifdef DBGFLAG_ASSERT #define Assert(_exp) \ _AssertMsg(_exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false) #define AssertMsg(_exp, _msg, ...) \ _AssertMsg(_exp, (const tchar *)CDbgFmtMsg(_msg, ##__VA_ARGS__), \ ((void)0), false) #define AssertOnce(_exp) \ _AssertMsgOnce(_exp, _T("Assertion Failed: ") _T(#_exp), false) #define AssertMsgOnce(_exp, _msg) _AssertMsgOnce(_exp, _msg, false) #define AssertFunc(_exp, _f) \ _AssertMsg(_exp, _T("Assertion Failed: ") _T(#_exp), _f, false) #define AssertEquals(_exp, _expectedValue) \ AssertMsg2((_exp) == (_expectedValue), _T("Expected %d but got %d!"), \ (_expectedValue), (_exp)) #define AssertFloatEquals(_exp, _expectedValue, _tol) \ AssertMsg2(fabs((_exp) - (_expectedValue)) <= (_tol), \ _T("Expected %f but got %f!"), (_expectedValue), (_exp)) #define Verify(_exp) Assert(_exp) #define VerifyMsg1(_exp, _msg, a1) AssertMsg1(_exp, _msg, a1) #define VerifyMsg2(_exp, _msg, a1, a2) AssertMsg2(_exp, _msg, a1, a2) #define VerifyMsg3(_exp, _msg, a1, a2, a3) AssertMsg3(_exp, _msg, a1, a2, a3) #define VerifyEquals(_exp, _expectedValue) AssertEquals(_exp, _expectedValue) #define DbgVerify(_exp) Assert(_exp) #define AssertMsg1(_exp, _msg, a1) AssertMsg(_exp, _msg, a1) #define AssertMsg2(_exp, _msg, a1, a2) AssertMsg(_exp, _msg, a1, a2) #define AssertMsg3(_exp, _msg, a1, a2, a3) AssertMsg(_exp, _msg, a1, a2, a3) #define AssertMsg4(_exp, _msg, a1, a2, a3, a4) \ AssertMsg(_exp, _msg, a1, a2, a3, a4) #define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) \ AssertMsg(_exp, _msg, a1, a2, a3, a4, a5) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) \ AssertMsg(_exp, _msg, a1, a2, a3, a4, a5, a6) #define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) \ AssertMsg(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) #define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) \ AssertMsg(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) #define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) \ AssertMsg(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) #else // DBGFLAG_ASSERT #define Assert(_exp) ((void)0) #define AssertOnce(_exp) ((void)0) #define AssertMsg(_exp, _msg, ...) ((void)0) #define AssertMsgOnce(_exp, _msg) ((void)0) #define AssertFunc(_exp, _f) ((void)0) #define AssertEquals(_exp, _expectedValue) ((void)0) #define AssertFloatEquals(_exp, _expectedValue, _tol) ((void)0) #define Verify(_exp) (_exp) #define VerifyMsg1(_exp, _msg, a1) (_exp) #define VerifyMsg2(_exp, _msg, a1, a2) (_exp) #define VerifyMsg3(_exp, _msg, a1, a2, a3) (_exp) #define VerifyEquals(_exp, _expectedValue) (_exp) #define DbgVerify(_exp) (_exp) #define AssertMsg1(_exp, _msg, a1) ((void)0) #define AssertMsg2(_exp, _msg, a1, a2) ((void)0) #define AssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) #define AssertMsg4(_exp, _msg, a1, a2, a3, a4) ((void)0) #define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) ((void)0) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) #define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) ((void)0) #define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) ((void)0) #define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) ((void)0) #define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) ((void)0) #endif // DBGFLAG_ASSERT // The Always version of the assert macros are defined even when DBGFLAG_ASSERT // is not, so they will be available even in release. #define AssertAlways(_exp) \ _AssertMsg(_exp, _T("Assertion Failed: ") _T(#_exp), ((void)0), false) #define AssertMsgAlways(_exp, _msg) _AssertMsg(_exp, _msg, ((void)0), false) // Stringify a number #define V_STRINGIFY_INTERNAL(x) #x // Extra level of indirection needed when passing in a macro to avoid getting // the macro name instead of value #define V_STRINGIFY(x) V_STRINGIFY_INTERNAL(x) // Macros to help decorate warnings or errors with the location in code #define FILE_LINE_FUNCTION_STRING \ __FILE__ "(" V_STRINGIFY(__LINE__) "):" __FUNCTION__ ":" #define FILE_LINE_STRING __FILE__ "(" V_STRINGIFY(__LINE__) "):" #define FUNCTION_LINE_STRING __FUNCTION__ "(" V_STRINGIFY(__LINE__) "): " // Handy define for inserting clickable messages into the build output. // Use like this: // #pragma MESSAGE("Some message") #define MESSAGE(msg) message(__FILE__ "(" V_STRINGIFY(__LINE__) "): " msg) #if !defined(_X360) || !defined(_RETAIL) /* These are always compiled in */ DBG_INTERFACE void Msg(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE void DMsg(const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(3, 4); DBG_INTERFACE void MsgV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist); DBG_INTERFACE void Warning(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE void DWarning(const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(3, 4); DBG_INTERFACE void WarningV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist); DBG_INTERFACE void Log(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE void DLog(const tchar *pGroupName, int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(3, 4); DBG_INTERFACE void LogV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist); #ifdef Error // p4.cpp does a #define Error Warning and in that case the Error prototype // needs to be consistent with the Warning prototype. DBG_INTERFACE void Error(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); #else DBG_INTERFACE void NORETURN Error(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE void NORETURN ErrorV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist); #endif #else inline void Msg(...) {} inline void DMsg(...) {} inline void MsgV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist) {} inline void Warning(PRINTF_FORMAT_STRING const tchar *pMsg, ...) {} inline void WarningV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist) {} inline void DWarning(...) {} inline void Log(...) {} inline void DLog(...) {} inline void LogV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist) {} inline void Error(...) {} inline void ErrorV(PRINTF_FORMAT_STRING const tchar *pMsg, va_list arglist) {} #endif // You can use this macro like a runtime assert macro. // If the condition fails, then Error is called with the message. This macro is // called like AssertMsg, where msg must be enclosed in parenthesis: // // ErrorIfNot( bCondition, ("a b c %d %d %d", 1, 2, 3) ); #define ErrorIfNot(condition, msg) \ if (condition) \ ; \ else { \ Error msg; \ } #if !defined(_X360) || !defined(_RETAIL) /* A couple of super-common dynamic spew messages, here for convenience */ /* These looked at the "developer" group */ DBG_INTERFACE void DevMsg(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void DevWarning(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void DevLog(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); /* default level versions (level 1) */ DBG_OVERLOAD void DevMsg(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_OVERLOAD void DevWarning(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_OVERLOAD void DevLog(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); /* These looked at the "console" group */ DBG_INTERFACE void ConColorMsg(int level, const Color &clr, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(3, 4); DBG_INTERFACE void ConMsg(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void ConWarning(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void ConLog(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); /* default console version (level 1) */ DBG_OVERLOAD void ConColorMsg(const Color &clr, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_OVERLOAD void ConMsg(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_OVERLOAD void ConWarning(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_OVERLOAD void ConLog(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); /* developer console version (level 2) */ DBG_INTERFACE void ConDColorMsg(const Color &clr, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void ConDMsg(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE void ConDWarning(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); DBG_INTERFACE void ConDLog(PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(1, 2); /* These looked at the "network" group */ DBG_INTERFACE void NetMsg(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void NetWarning(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); DBG_INTERFACE void NetLog(int level, PRINTF_FORMAT_STRING const tchar *pMsg, ...) FMTFUNCTION(2, 3); void ValidateSpew(class CValidator &validator); #else inline void DevMsg(...) {} inline void DevWarning(...) {} inline void DevLog(...) {} inline void ConMsg(...) {} inline void ConLog(...) {} inline void NetMsg(...) {} inline void NetWarning(...) {} inline void NetLog(...) {} #endif DBG_INTERFACE void COM_TimestampedLog(PRINTF_FORMAT_STRING char const *fmt, ...) FMTFUNCTION(1, 2); /* Code macros, debugger interface */ #ifdef DBGFLAG_ASSERT #define DBG_CODE(_code) \ if (0) \ ; \ else { \ _code \ } #define DBG_CODE_NOSCOPE(_code) _code #define DBG_DCODE(_g, _l, _code) \ if (IsSpewActive(_g, _l)) { \ _code \ } else { \ } #define DBG_BREAK() DebuggerBreak() /* defined in platform.h */ #else /* not _DEBUG */ #define DBG_CODE(_code) ((void)0) #define DBG_CODE_NOSCOPE(_code) #define DBG_DCODE(_g, _l, _code) ((void)0) #define DBG_BREAK() ((void)0) #endif /* _DEBUG */ //----------------------------------------------------------------------------- #ifndef _RETAIL class CScopeMsg { public: CScopeMsg(const char *pszScope) { m_pszScope = pszScope; Msg("%s { ", pszScope); } ~CScopeMsg() { Msg("} %s", m_pszScope); } const char *m_pszScope; }; #define SCOPE_MSG(msg) CScopeMsg scopeMsg(msg) #else #define SCOPE_MSG(msg) #endif //----------------------------------------------------------------------------- // Macro to assist in asserting constant invariants during compilation // This implementation of compile time assert has zero cost (so it can safely be // included in release builds) and can be used at file scope or function scope. // We're using an ancient version of GCC that can't quite handle some // of our complicated templates properly. Use some preprocessor trickery // to workaround this #ifdef __GNUC__ #define COMPILE_TIME_ASSERT(pred) typedef int UNIQUE_ID[(pred) ? 1 : -1] #else #if _MSC_VER >= 1600 // If available use static_assert instead of weird language tricks. This // leads to much more readable messages when compile time assert constraints // are violated. #define COMPILE_TIME_ASSERT(pred) \ static_assert(pred, "Compile time assert constraint is not true: " #pred) #else // Due to gcc bugs this can in rare cases (some template functions) cause // redeclaration errors when used multiple times in one scope. Fix by adding // extra scoping. #define COMPILE_TIME_ASSERT(pred) \ typedef char compile_time_assert_type[(pred) ? 1 : -1]; #endif #endif // ASSERT_INVARIANT used to be needed in order to allow COMPILE_TIME_ASSERTs at // global scope. However the new COMPILE_TIME_ASSERT macro supports that by // default. #define ASSERT_INVARIANT(pred) COMPILE_TIME_ASSERT(pred) #ifdef _DEBUG template inline DEST_POINTER_TYPE assert_cast(SOURCE_POINTER_TYPE *pSource) { Assert(static_cast(pSource) == dynamic_cast(pSource)); return static_cast(pSource); } #else #define assert_cast static_cast #endif //----------------------------------------------------------------------------- // Templates to assist in validating pointers: // Have to use these stubs so we don't have to include windows.h here. DBG_INTERFACE void _AssertValidReadPtr(void *ptr, int count = 1); DBG_INTERFACE void _AssertValidWritePtr(void *ptr, int count = 1); DBG_INTERFACE void _AssertValidReadWritePtr(void *ptr, int count = 1); DBG_INTERFACE void AssertValidStringPtr(const tchar *ptr, int maxchar = 0xFFFFFF); #ifdef DBGFLAG_ASSERT FORCEINLINE void AssertValidReadPtr(const void *ptr, int count = 1) { _AssertValidReadPtr((void *)ptr, count); } FORCEINLINE void AssertValidWritePtr(const void *ptr, int count = 1) { _AssertValidWritePtr((void *)ptr, count); } FORCEINLINE void AssertValidReadWritePtr(const void *ptr, int count = 1) { _AssertValidReadWritePtr((void *)ptr, count); } #else FORCEINLINE void AssertValidReadPtr(const void *ptr, int count = 1) {} FORCEINLINE void AssertValidWritePtr(const void *ptr, int count = 1) {} FORCEINLINE void AssertValidReadWritePtr(const void *ptr, int count = 1) {} #define AssertValidStringPtr AssertValidReadPtr #endif #define AssertValidThis() AssertValidReadWritePtr(this, sizeof(*this)) //----------------------------------------------------------------------------- // Macro to protect functions that are not reentrant #ifdef _DEBUG class CReentryGuard { public: CReentryGuard(int *pSemaphore) : m_pSemaphore(pSemaphore) { ++(*m_pSemaphore); } ~CReentryGuard() { --(*m_pSemaphore); } private: int *m_pSemaphore; }; #define ASSERT_NO_REENTRY() \ static int fSemaphore##__LINE__; \ Assert(!fSemaphore##__LINE__); \ CReentryGuard ReentryGuard##__LINE__(&fSemaphore##__LINE__) #else #define ASSERT_NO_REENTRY() #endif //----------------------------------------------------------------------------- // // Purpose: Inline string formatter // #include "valve_off.h" class CDbgFmtMsg { public: CDbgFmtMsg(PRINTF_FORMAT_STRING const tchar *pszFormat, ...) FMTFUNCTION(2, 3) { va_list arg_ptr; va_start(arg_ptr, pszFormat); _vsntprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); va_end(arg_ptr); m_szBuf[sizeof(m_szBuf) - 1] = 0; } operator const tchar *() const { return m_szBuf; } private: tchar m_szBuf[256]; }; #include "valve_on.h" //----------------------------------------------------------------------------- // // Purpose: Embed debug info in each file. // #if defined(_WIN32) && !defined(_X360) #ifdef _DEBUG #pragma comment(compiler) #endif #endif //----------------------------------------------------------------------------- // // Purpose: Wrap around a variable to create a simple place to put a breakpoint // #ifdef _DEBUG template class CDataWatcher { public: const Type &operator=(const Type &val) { return Set(val); } const Type &operator=(const CDataWatcher &val) { return Set(val.m_Value); } const Type &Set(const Type &val) { // Put your breakpoint here m_Value = val; return m_Value; } Type &GetForModify() { return m_Value; } const Type &operator+=(const Type &val) { return Set(m_Value + val); } const Type &operator-=(const Type &val) { return Set(m_Value - val); } const Type &operator/=(const Type &val) { return Set(m_Value / val); } const Type &operator*=(const Type &val) { return Set(m_Value * val); } const Type &operator^=(const Type &val) { return Set(m_Value ^ val); } const Type &operator|=(const Type &val) { return Set(m_Value | val); } const Type &operator++() { return (*this += 1); } Type operator--() { return (*this -= 1); } Type operator++(int) // postfix version.. { Type val = m_Value; (*this += 1); return val; } Type operator--(int) // postfix version.. { Type val = m_Value; (*this -= 1); return val; } // For some reason the compiler only generates type conversion warnings for // this operator when used like CNetworkVarBase = 0x1 (it // warns about converting from an int to an unsigned char). template const Type &operator&=(C val) { return Set(m_Value & val); } operator const Type &() const { return m_Value; } const Type &Get() const { return m_Value; } const Type *operator->() const { return &m_Value; } Type m_Value; }; #else template class CDataWatcher { private: CDataWatcher(); // refuse to compile in non-debug builds }; #endif //----------------------------------------------------------------------------- #endif /* DBG_H */