From f97c9d9f46284dd8706138fcfdae55708595787b Mon Sep 17 00:00:00 2001 From: s1lentq Date: Thu, 14 Dec 2023 02:16:59 +0700 Subject: [PATCH] Improve dbg code to work Assertion properly --- .gitignore | 1 + regamedll/CMakeLists.txt | 3 + regamedll/dlls/client.cpp | 6 +- regamedll/dlls/game.cpp | 30 ++ regamedll/dlls/h_export.cpp | 19 +- regamedll/dlls/util.cpp | 13 +- regamedll/engine/unicode_strtools.cpp | 10 +- regamedll/msvc/ReGameDLL.vcxproj | 6 + regamedll/msvc/ReGameDLL.vcxproj.filters | 14 + regamedll/public/tier0/assert_dialog.cpp | 302 ++++++++++++++ regamedll/public/tier0/assert_dialog.rc | 117 ++++++ regamedll/public/tier0/dbg.cpp | 356 +++++------------ regamedll/public/tier0/dbg.h | 463 +++++++++++----------- regamedll/public/tier0/platform.h | 40 +- regamedll/public/tier0/platform_posix.cpp | 113 ++++++ regamedll/public/tier0/platform_win32.cpp | 57 +++ regamedll/public/tier0/resource.h | 44 ++ 17 files changed, 1077 insertions(+), 517 deletions(-) create mode 100644 regamedll/public/tier0/assert_dialog.cpp create mode 100644 regamedll/public/tier0/assert_dialog.rc create mode 100644 regamedll/public/tier0/platform_posix.cpp create mode 100644 regamedll/public/tier0/platform_win32.cpp create mode 100644 regamedll/public/tier0/resource.h diff --git a/.gitignore b/.gitignore index dc6d161e8..6aa9bce05 100644 --- a/.gitignore +++ b/.gitignore @@ -2,6 +2,7 @@ *.bat *.log *.lnk +*.aps **/msvc/Debug* **/msvc/Release* **/msvc/Tests diff --git a/regamedll/CMakeLists.txt b/regamedll/CMakeLists.txt index 735d54fc8..69f710b31 100644 --- a/regamedll/CMakeLists.txt +++ b/regamedll/CMakeLists.txt @@ -161,6 +161,9 @@ set(SHARED_SRCS "public/FileSystem.cpp" "public/interface.cpp" "public/MemPool.cpp" + "public/MemPool.cpp" + "public/tier0/dbg.cpp" + "public/tier0/platform_posix.cpp" ) set(GAMEDLL_SRCS diff --git a/regamedll/dlls/client.cpp b/regamedll/dlls/client.cpp index dca3c5690..4d42cbe34 100644 --- a/regamedll/dlls/client.cpp +++ b/regamedll/dlls/client.cpp @@ -673,7 +673,7 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity) CBaseEntity *pTarget = nullptr; pPlayer->m_pIntroCamera = UTIL_FindEntityByClassname(nullptr, "trigger_camera"); -#ifndef REGAMEDLL_FIXES +#ifndef REGAMEDLL_FIXES if (g_pGameRules && g_pGameRules->IsMultiplayer()) { CSGameRules()->m_bMapHasCameras = (pPlayer->m_pIntroCamera != nullptr); @@ -696,8 +696,8 @@ void EXT_FUNC ClientPutInServer(edict_t *pEntity) pPlayer->pev->angles = CamAngles; pPlayer->pev->v_angle = pPlayer->pev->angles; - pPlayer->m_fIntroCamTime = -#ifdef REGAMEDLL_FIXES + pPlayer->m_fIntroCamTime = +#ifdef REGAMEDLL_FIXES (CSGameRules()->m_bMapHasCameras <= 1) ? 0.0 : // no need to refresh cameras if map has only one #endif gpGlobals->time + 6; diff --git a/regamedll/dlls/game.cpp b/regamedll/dlls/game.cpp index 55c2600c1..423250ce6 100644 --- a/regamedll/dlls/game.cpp +++ b/regamedll/dlls/game.cpp @@ -228,8 +228,13 @@ void GameDLL_SwapTeams_f() #endif // REGAMEDLL_ADD +SpewRetval_t GameDLL_SpewHandler(SpewType_t spewType, int level, const char *pMsg); + void EXT_FUNC GameDLLInit() { + // By default, direct dbg reporting... + SpewOutputFunc(GameDLL_SpewHandler); + g_pskill = CVAR_GET_POINTER("skill"); g_psv_gravity = CVAR_GET_POINTER("sv_gravity"); g_psv_aim = CVAR_GET_POINTER("sv_aim"); @@ -455,3 +460,28 @@ void EXT_FUNC GameDLLInit() #endif } + +SpewRetval_t GameDLL_SpewHandler(SpewType_t spewType, int level, const char *pMsg) +{ + bool bSpewPrint = (CVAR_GET_FLOAT("developer") >= level); + switch (spewType) + { + case SPEW_LOG: + case SPEW_MESSAGE: + if (bSpewPrint) UTIL_ServerPrint("%s", pMsg); + break; + case SPEW_WARNING: + if (bSpewPrint) UTIL_ServerPrint("Warning: %s", pMsg); + break; + case SPEW_ERROR: + Sys_Error("%s", pMsg); + return SPEW_ABORT; // fatal error, terminate it! + case SPEW_ASSERT: + UTIL_ServerPrint("Assert: %s", pMsg); + return SPEW_DEBUGGER; // assert always tries to debugger break + default: + break; + } + + return SPEW_CONTINUE; // spew handled, continue on +} diff --git a/regamedll/dlls/h_export.cpp b/regamedll/dlls/h_export.cpp index 47189b833..486a3eedf 100644 --- a/regamedll/dlls/h_export.cpp +++ b/regamedll/dlls/h_export.cpp @@ -16,22 +16,7 @@ C_DLLEXPORT void WINAPI GiveFnptrsToDll(enginefuncs_t *pEnginefuncsTable, global Regamedll_Game_Init(); } -#ifdef _WIN32 - -// DLL entry point -BOOL WINAPI DllMain(HINSTANCE hinstDLL, DWORD fdwReason, LPVOID lpvReserved) -{ - if (fdwReason == DLL_PROCESS_ATTACH) - { - } - else if (fdwReason == DLL_PROCESS_DETACH) - { - } - - return TRUE; -} - -#else // _WIN32 +#if defined(_LINUX) void __attribute__((constructor)) DllMainLoad() { @@ -41,4 +26,4 @@ void __attribute__((destructor)) DllMainUnload() { } -#endif // _WIN32 +#endif // _LINUX diff --git a/regamedll/dlls/util.cpp b/regamedll/dlls/util.cpp index 714fe79d1..7c3c3db6c 100644 --- a/regamedll/dlls/util.cpp +++ b/regamedll/dlls/util.cpp @@ -1497,7 +1497,7 @@ void UTIL_RestartOther(const char *szClassname) while ((pEntity = UTIL_FindEntityByClassname(pEntity, szClassname))) { pEntity->Restart(); - + #ifdef REGAMEDLL_ADD FireTargets("game_entity_restart", pEntity, nullptr, USE_TOGGLE, 0.0); #endif @@ -1731,7 +1731,7 @@ bool UTIL_AreHostagesImprov() #ifdef REGAMEDLL_ADD if (g_engfuncs.pfnEngCheckParm == nullptr) return false; - + // someday in CS 1.6 int improv = ENG_CHECK_PARM("-host-improv", nullptr); if (improv) @@ -1819,10 +1819,11 @@ void NORETURN Sys_Error(const char *error, ...) CONSOLE_ECHO("FATAL ERROR (shutting down): %s\n", text); - //TerminateProcess(GetCurrentProcess(), 1); - int *null = 0; - *null = 0; - exit(-1); +#if defined(_WIN32) + MessageBoxA(NULL, text, "Fatal error", MB_ICONERROR | MB_OK); +#endif + + exit(EXIT_FAILURE); } int UTIL_CountPlayersInBrushVolume(bool bOnlyAlive, CBaseEntity *pBrushEntity, int &playersInCount, int &playersOutCount, CPlayerInVolumeAdapter *pAdapter) diff --git a/regamedll/engine/unicode_strtools.cpp b/regamedll/engine/unicode_strtools.cpp index e7e113ba6..6dbf19417 100644 --- a/regamedll/engine/unicode_strtools.cpp +++ b/regamedll/engine/unicode_strtools.cpp @@ -756,9 +756,8 @@ int Q_UnicodeConvertT(const SrcType *pIn, int nInChars, DstType *pOut, int nOutB if (bErr) { -#ifdef _DEBUG - AssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); -#endif + DbgAssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); + if (ePolicy & _STRINGCONVERTFLAG_SKIP) { nOut -= EncodeDstLen(uVal); @@ -793,9 +792,8 @@ int Q_UnicodeConvertT(const SrcType *pIn, int nInChars, DstType *pOut, int nOutB nOut += EncodeDst(uVal, pOut + nOut); if (bErr) { -#ifdef _DEBUG - AssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); -#endif + DbgAssertMsg(!(ePolicy & _STRINGCONVERTFLAG_ASSERT), "invalid Unicode byte sequence"); + if (ePolicy & _STRINGCONVERTFLAG_SKIP) { nOut -= EncodeDstLen(uVal); diff --git a/regamedll/msvc/ReGameDLL.vcxproj b/regamedll/msvc/ReGameDLL.vcxproj index c31abc6e9..1c51c7fd1 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj +++ b/regamedll/msvc/ReGameDLL.vcxproj @@ -540,6 +540,7 @@ + @@ -548,6 +549,7 @@ true true + true true @@ -787,6 +789,7 @@ + @@ -810,6 +813,9 @@ false + + + {70A2B904-B7DB-4C48-8DE0-AF567360D572} ReGameDLL diff --git a/regamedll/msvc/ReGameDLL.vcxproj.filters b/regamedll/msvc/ReGameDLL.vcxproj.filters index 84536f321..ef2017ae4 100644 --- a/regamedll/msvc/ReGameDLL.vcxproj.filters +++ b/regamedll/msvc/ReGameDLL.vcxproj.filters @@ -555,6 +555,12 @@ public + + public\tier0 + + + public\tier0 + @@ -1055,5 +1061,13 @@ public + + public\tier0 + + + + + public\tier0 + \ No newline at end of file diff --git a/regamedll/public/tier0/assert_dialog.cpp b/regamedll/public/tier0/assert_dialog.cpp new file mode 100644 index 000000000..11bb9442b --- /dev/null +++ b/regamedll/public/tier0/assert_dialog.cpp @@ -0,0 +1,302 @@ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// + +#include "precompiled.h" +#include "resource.h" + +class CDialogInitInfo +{ +public: + const char *m_pFilename; + int m_iLine; + const char *m_pExpression; +}; + +class CAssertDisable +{ +public: + char m_Filename[MAX_OSPATH]; + + // If these are not -1, then this CAssertDisable only disables asserts on lines between + // these values (inclusive). + int m_LineMin; + int m_LineMax; + + // Decremented each time we hit this assert and ignore it, until it's 0. + // Then the CAssertDisable is removed. + // If this is -1, then we always ignore this assert. + int m_nIgnoreTimes; + + CAssertDisable *m_pNext; +}; + +static CDialogInitInfo g_Info{}; +static bool g_bAssertsEnabled = true; +static CAssertDisable *g_pAssertDisables = nullptr; + +// Set to true if they want to break in the debugger +static bool g_bBreak = false; + +// Internal functions +static HINSTANCE g_hTier0Instance = nullptr; +BOOL WINAPI DllMain( + HINSTANCE hinstDLL, // handle to the DLL module + DWORD fdwReason, // reason for calling function + LPVOID lpvReserved // reserved +) +{ + g_hTier0Instance = hinstDLL; + return true; +} + +static bool IsDebugBreakEnabled() +{ + static bool bResult = (Q_strstr(Plat_GetCommandLine(), "-debugbreak") != nullptr); + return bResult; +} + +static bool AreAssertsDisabled() +{ + static bool bResult = (Q_strstr(Plat_GetCommandLine(), "-noassert") != nullptr); + return bResult; +} + +static bool AreAssertsEnabledInFileLine(const char *pFilename, int iLine) +{ + CAssertDisable **pPrev = &g_pAssertDisables; + CAssertDisable *pNext = nullptr; + + for (CAssertDisable *pCur = g_pAssertDisables; pCur; pCur = pNext) + { + pNext = pCur->m_pNext; + + if (Q_stricmp(pFilename, pCur->m_Filename) == 0) + { + // Are asserts disabled in the whole file? + bool bAssertsEnabled = true; + if (pCur->m_LineMin == -1 && pCur->m_LineMax == -1) + bAssertsEnabled = false; + + // Are asserts disabled on the specified line? + if (iLine >= pCur->m_LineMin && iLine <= pCur->m_LineMax) + bAssertsEnabled = false; + + if (!bAssertsEnabled) + { + // If this assert is only disabled for the next N times, then countdown.. + if (pCur->m_nIgnoreTimes > 0) + { + pCur->m_nIgnoreTimes--; + + if (pCur->m_nIgnoreTimes == 0) + { + // Remove this one from the list. + *pPrev = pNext; + delete pCur; + continue; + } + } + + return false; + } + } + + pPrev = &pCur->m_pNext; + } + + return true; +} + +CAssertDisable *CreateNewAssertDisable(const char *pFilename) +{ + CAssertDisable *pDisable = new CAssertDisable; + pDisable->m_pNext = g_pAssertDisables; + g_pAssertDisables = pDisable; + + pDisable->m_LineMin = pDisable->m_LineMax = -1; + pDisable->m_nIgnoreTimes = -1; + + Q_strlcpy(pDisable->m_Filename, g_Info.m_pFilename); + + return pDisable; +} + +void IgnoreAssertsInCurrentFile() +{ + CreateNewAssertDisable(g_Info.m_pFilename); +} + +CAssertDisable *IgnoreAssertsNearby(int nRange) +{ + CAssertDisable *pDisable = CreateNewAssertDisable(g_Info.m_pFilename); + pDisable->m_LineMin = g_Info.m_iLine - nRange; + pDisable->m_LineMax = g_Info.m_iLine - nRange; + return pDisable; +} + +static int g_iLastLineRange = 5; +static int g_nLastIgnoreNumTimes = 1; + +int CALLBACK AssertDialogProc( + HWND hDlg, // handle to dialog box + UINT uMsg, // message + WPARAM wParam, // first message parameter + LPARAM lParam // second message parameter +) +{ + switch (uMsg) + { + case WM_INITDIALOG: + { + SetDlgItemText(hDlg, IDC_ASSERT_MSG_CTRL, g_Info.m_pExpression); + SetDlgItemText(hDlg, IDC_FILENAME_CONTROL, g_Info.m_pFilename); + + SetDlgItemInt(hDlg, IDC_LINE_CONTROL, g_Info.m_iLine, false); + SetDlgItemInt(hDlg, IDC_IGNORE_NUMLINES, g_iLastLineRange, false); + SetDlgItemInt(hDlg, IDC_IGNORE_NUMTIMES, g_nLastIgnoreNumTimes, false); + + // Center the dialog. + RECT rcDlg, rcDesktop; + GetWindowRect(hDlg, &rcDlg); + GetWindowRect(GetDesktopWindow(), &rcDesktop); + SetWindowPos(hDlg, HWND_TOP, + ((rcDesktop.right - rcDesktop.left) - (rcDlg.right - rcDlg.left)) / 2, + ((rcDesktop.bottom - rcDesktop.top) - (rcDlg.bottom - rcDlg.top)) / 2, + 0, 0, + SWP_NOSIZE + ); + + return TRUE; + } + case WM_COMMAND: + { + switch (LOWORD(wParam)) + { + // Ignore this assert N times + case IDC_IGNORE_THIS: + { + BOOL bTranslated = false; + UINT value = GetDlgItemInt(hDlg, IDC_IGNORE_NUMTIMES, &bTranslated, false); + if (bTranslated && value > 1) + { + CAssertDisable *pDisable = IgnoreAssertsNearby(0); + pDisable->m_nIgnoreTimes = value - 1; + g_nLastIgnoreNumTimes = value; + } + + EndDialog(hDlg, 0); + return TRUE; + } + case IDC_IGNORE_NEARBY: + { + BOOL bTranslated = false; + UINT value = GetDlgItemInt(hDlg, IDC_IGNORE_NUMLINES, &bTranslated, false); + if (!bTranslated || value < 1) + return TRUE; + + IgnoreAssertsNearby(value); + EndDialog(hDlg, 0); + return TRUE; + } + case IDC_IGNORE_FILE: + IgnoreAssertsInCurrentFile(); + EndDialog(hDlg, 0); + return TRUE; + // Always ignore this assert + case IDC_IGNORE_ALWAYS: + IgnoreAssertsNearby(0); + EndDialog(hDlg, 0); + return TRUE; + case IDC_IGNORE_ALL: + g_bAssertsEnabled = false; + EndDialog(hDlg, 0); + return TRUE; + case IDC_BREAK: + g_bBreak = true; + EndDialog(hDlg, 0); + return TRUE; + } + case WM_KEYDOWN: + { + // Escape? + if (wParam == 2) + { + // Ignore this assert + EndDialog(hDlg, 0); + return TRUE; + } + + break; + } + + return TRUE; + } + } + + return FALSE; +} + +static HWND g_hBestParentWindow = nullptr; + +static BOOL CALLBACK ParentWindowEnumProc( + HWND hWnd, // handle to parent window + LPARAM lParam // application-defined value +) +{ + if (IsWindowVisible(hWnd)) + { + DWORD procID; + GetWindowThreadProcessId(hWnd, &procID); + if (procID == (DWORD)lParam) + { + g_hBestParentWindow = hWnd; + return FALSE; // don't iterate any more. + } + } + + return TRUE; +} + +static HWND FindLikelyParentWindow() +{ + // Enumerate top-level windows and take the first visible one with our processID. + g_hBestParentWindow = nullptr; + EnumWindows(ParentWindowEnumProc, GetCurrentProcessId()); + return g_hBestParentWindow; +} + +bool DoNewAssertDialog(const char *pFilename, int line, const char *pExpression) +{ + if (AreAssertsDisabled()) + return false; + + // If they have the old mode enabled (always break immediately), then just break right into + // the debugger like we used to do. + if (IsDebugBreakEnabled()) + return true; + + // Have ALL Asserts been disabled? + if (!g_bAssertsEnabled) + return false; + + // Has this specific Assert been disabled? + if (!AreAssertsEnabledInFileLine(pFilename, line)) + return false; + + // Now create the dialog. + g_Info.m_pFilename = pFilename; + g_Info.m_iLine = line; + g_Info.m_pExpression = pExpression; + + g_bBreak = false; + + HWND hParentWindow = FindLikelyParentWindow(); + DialogBox(g_hTier0Instance, MAKEINTRESOURCE(IDD_ASSERT_DIALOG), hParentWindow, AssertDialogProc); + + return g_bBreak; +} diff --git a/regamedll/public/tier0/assert_dialog.rc b/regamedll/public/tier0/assert_dialog.rc new file mode 100644 index 000000000..513f46878 --- /dev/null +++ b/regamedll/public/tier0/assert_dialog.rc @@ -0,0 +1,117 @@ +//Microsoft Developer Studio generated resource script. +// +#include "resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "winres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE DISCARDABLE +BEGIN + "resource.h\0" +END + +2 TEXTINCLUDE DISCARDABLE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE DISCARDABLE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Dialog +// + +IDD_ASSERT_DIALOG DIALOG DISCARDABLE 0, 0, 268, 158 +STYLE DS_MODALFRAME | WS_POPUP | WS_CAPTION | WS_SYSMENU +CAPTION "Assert" +FONT 8, "MS Sans Serif" +BEGIN + LTEXT "File:",IDC_NOID,7,7,23,9 + LTEXT "c:/gsclient/src/blah.cpp",IDC_FILENAME_CONTROL,36,7,217,8 + LTEXT "Line:",IDC_NOID,7,18,23,9 + LTEXT "45",IDC_LINE_CONTROL,36,18,217,8 + LTEXT "Assert:",IDC_NOID,7,29,23,9 + CONTROL "ASSERT MESSAGE",IDC_ASSERT_MSG_CTRL,"Static", + SS_LEFTNOWORDWRAP | SS_NOPREFIX | WS_GROUP,36,29,217,9 + DEFPUSHBUTTON "&Break in Debugger",IDC_BREAK,7,49,98,14 + PUSHBUTTON "&Ignore This Assert",IDC_IGNORE_THIS,7,66,98,14 + EDITTEXT IDC_IGNORE_NUMTIMES,110,66,24,14,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "time(s).",IDC_NOID,138,68,23,8 + PUSHBUTTON "Always Ignore &This Assert",IDC_IGNORE_ALWAYS,7,84,98, + 14 + PUSHBUTTON "Ignore &Nearby Asserts",IDC_IGNORE_NEARBY,7,102,98,14 + LTEXT "within",IDC_NOID,109,105,19,8 + EDITTEXT IDC_IGNORE_NUMLINES,131,102,40,14,ES_AUTOHSCROLL | + ES_NUMBER + LTEXT "lines.",IDC_NOID,175,105,17,8 + PUSHBUTTON "Ignore Asserts in This &File",IDC_IGNORE_FILE,7,120,98, + 14 + PUSHBUTTON "Ignore &All Asserts",IDC_IGNORE_ALL,7,137,98,14 +END + + +///////////////////////////////////////////////////////////////////////////// +// +// DESIGNINFO +// + +#ifdef APSTUDIO_INVOKED +GUIDELINES DESIGNINFO DISCARDABLE +BEGIN + IDD_ASSERT_DIALOG, DIALOG + BEGIN + LEFTMARGIN, 7 + RIGHTMARGIN, 261 + TOPMARGIN, 7 + BOTTOMMARGIN, 151 + END +END +#endif // APSTUDIO_INVOKED + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/regamedll/public/tier0/dbg.cpp b/regamedll/public/tier0/dbg.cpp index ebf36c2e4..35c99fe38 100644 --- a/regamedll/public/tier0/dbg.cpp +++ b/regamedll/public/tier0/dbg.cpp @@ -1,50 +1,17 @@ -/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program 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 -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// #include "precompiled.h" -// Internal structures -enum -{ - MAX_GROUP_NAME_LENGTH = 48 -}; - -struct SpewGroup_t -{ - char m_GroupName[MAX_GROUP_NAME_LENGTH]; - int m_Level; -}; - - // Templates to assist in validating pointers: void _AssertValidReadPtr(void *ptr, int count) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!IsBadReadPtr(ptr, count)); #else Assert(ptr); @@ -54,7 +21,7 @@ void _AssertValidReadPtr(void *ptr, int count) void _AssertValidWritePtr(void *ptr, int count) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!IsBadWritePtr(ptr, count)); #else Assert(ptr); @@ -63,26 +30,29 @@ void _AssertValidWritePtr(void *ptr, int count) void _AssertValidReadWritePtr(void *ptr, int count) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!(IsBadWritePtr(ptr, count) || IsBadReadPtr(ptr, count))); #else Assert(ptr); #endif } +#if defined(DBGFLAG_ASSERT) void AssertValidStringPtr(const char *ptr, int maxchar) { -#ifdef _WIN32 +#if defined(_WIN32) Assert(!IsBadStringPtr(ptr, maxchar)); #else Assert(ptr); #endif } +#endif // DBGFLAG_ASSERT // Globals -SpewRetval_t DefaultSpewFunc(SpewType_t type, const char *pMsg) +SpewRetval_t DefaultSpewFunc(SpewType_t type, int level, const char *pMsg) { printf("%s", pMsg); + if (type == SPEW_ASSERT) return SPEW_DEBUGGER; else if (type == SPEW_ERROR) @@ -93,13 +63,10 @@ SpewRetval_t DefaultSpewFunc(SpewType_t type, const char *pMsg) static SpewOutputFunc_t s_SpewOutputFunc = DefaultSpewFunc; -static const char *s_pFileName; -static int s_Line; -static SpewType_t s_SpewType; - -static SpewGroup_t *s_pSpewGroups = 0; -static int s_GroupCount = 0; -static int s_DefaultLevel = 0; +static const char *s_pMessage = nullptr; +static const char *s_pFileName = nullptr; +static int s_Line = 0; +static SpewType_t s_SpewType = SPEW_MESSAGE; // Spew output management. void SpewOutputFunc(SpewOutputFunc_t func) @@ -119,54 +86,92 @@ SpewOutputFunc_t GetSpewOutputFunc() } } +void _ExitOnFatalAssert() +{ + Msg("Fatal assert failed: %s, file %s line %d. Application exiting.\n", s_pMessage, s_pFileName, s_Line); + +#if defined(WIN32) + TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); // die, die RIGHT NOW! (don't call exit() so destructors will not get run) +#else + exit(EXIT_FAILURE); // forcefully shutdown of the process without destructors running +#endif +} + // Spew functions void _SpewInfo(SpewType_t type, const char *pFile, int line) { - // Only grab the file name. Ignore the path. - const char *pSlash = strrchr(pFile, '\\'); - const char *pSlash2 = strrchr(pFile, '/'); + // Only grab the file name. Ignore the path + const char *pSlash = Q_strrchr(pFile, '\\'); + const char *pSlash2 = Q_strrchr(pFile, '/'); + if (pSlash < pSlash2) pSlash = pSlash2; s_pFileName = pSlash ? pSlash + 1 : pFile; - s_Line = line; - s_SpewType = type; + s_Line = line; + s_SpewType = type; } -SpewRetval_t _SpewMessage(SpewType_t spewType, const char *pMsgFormat, va_list args) +SpewRetval_t _SpewMessageV(SpewType_t spewType, int level, const char *pMsgFormat, va_list args) { - char pTempBuffer[1024]; + if (level < 0) level = DBG_DEFAULT_LEVEL; + + static char szTempBuffer[4096]{}; + szTempBuffer[0] = '\0'; + s_pMessage = szTempBuffer; + + // check that we won't artifically truncate the string + assert(Q_strlen(pMsgFormat) < sizeof(szTempBuffer)); // Printf the file and line for warning + assert only... int len = 0; - if ((spewType == SPEW_ASSERT)) + if (spewType == SPEW_ASSERT) + { + len = Q_snprintf(szTempBuffer, sizeof(szTempBuffer), "%s (%d) : ", s_pFileName, s_Line); + } + + if (len == -1) { - len = sprintf(pTempBuffer, "%s (%d) : ", s_pFileName, s_Line); + return SPEW_ABORT; } // Create the message.... - len += vsprintf(&pTempBuffer[len], pMsgFormat, args); + len += Q_vsnprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, pMsgFormat, args); + + // Use normal assert here; to avoid recursion + assert(len < sizeof(szTempBuffer)); // Add \n for warning and assert if ((spewType == SPEW_ASSERT)) { - len += sprintf(&pTempBuffer[len], "\n"); + len += Q_snprintf(&szTempBuffer[len], sizeof(szTempBuffer) - len, "\n"); + Plat_OutputDebugString(szTempBuffer); } - assert(len < 1024); // use normal assert here; to avoid recursion. + // use normal assert here; to avoid recursion + assert((size_t)len < (sizeof(szTempBuffer) / sizeof(szTempBuffer[0]) - 1)); assert(s_SpewOutputFunc); // direct it to the appropriate target(s) - SpewRetval_t ret = s_SpewOutputFunc(spewType, pTempBuffer); + SpewRetval_t ret = s_SpewOutputFunc(spewType, level, szTempBuffer); switch (ret) { // Put the break into the macro so it would occur in the right place - //case SPEW_DEBUGGER: - // DebuggerBreak(); - // break; + case SPEW_DEBUGGER: + { + if (spewType != SPEW_ASSERT) + DebuggerBreakIfDebugging(); + break; + } case SPEW_ABORT: - // MessageBox(nullptr, "Error in _SpewMessage", "Error", MB_OK); - exit(0); + { +#if defined(WIN32) + TerminateProcess(GetCurrentProcess(), EXIT_FAILURE); // die, die RIGHT NOW! (don't call exit() so destructors will not get run) +#else + exit(EXIT_FAILURE); // forcefully shutdown of the process without destructors running +#endif + break; + } default: break; } @@ -174,81 +179,52 @@ SpewRetval_t _SpewMessage(SpewType_t spewType, const char *pMsgFormat, va_list a return ret; } -SpewRetval_t _SpewMessage(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); - va_end(args); - return ret; -} - -SpewRetval_t _DSpewMessage(const char *pGroupName, int level, const char *pMsgFormat, ...) -{ - if (!IsSpewActive(pGroupName, level)) - return SPEW_CONTINUE; - - va_list args; - va_start(args, pMsgFormat); - SpewRetval_t ret = _SpewMessage(s_SpewType, pMsgFormat, args); - va_end(args); - return ret; -} +#if defined(_WIN32) +// Returns true if they want to break in the debugger +bool DoNewAssertDialog(const char *pFile, int line, const char *pExpression); +#endif -void Msg(const char *pMsgFormat, ...) +bool _SpewAssertDialog() { - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); +#if defined(_WIN32) + return DoNewAssertDialog(s_pFileName, s_Line, s_pMessage); +#else + return false; +#endif } -void DMsg(const char *pGroupName, int level, const char *pMsgFormat, ...) +SpewRetval_t _SpewAssert(const char *pFile, int line, int level, const char *pMsgFormat, ...) { - if (!IsSpewActive(pGroupName, level)) - return; + _SpewInfo(SPEW_ASSERT, pFile, line); va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); -} - -void Warning(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); + SpewRetval_t ret = _SpewMessageV(s_SpewType, level, pMsgFormat, args); va_end(args); + return ret; } -void DWarning(const char *pGroupName, int level, const char *pMsgFormat, ...) +void _Msg(int level, const char *pMsgFormat, ...) { - if (!IsSpewActive(pGroupName, level)) - return; - va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); + _SpewMessageV(SPEW_MESSAGE, level, pMsgFormat, args); va_end(args); } -void Log(const char *pMsgFormat, ...) +void _Warning(int level, const char *pMsgFormat, ...) { va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); + _SpewMessageV(SPEW_WARNING, level, pMsgFormat, args); va_end(args); } -void DLog(const char *pGroupName, int level, const char *pMsgFormat, ...) +void _Log(int level, const char *pMsgFormat, ...) { - if (!IsSpewActive(pGroupName, level)) - return; - va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); + _SpewMessageV(SPEW_LOG, level, pMsgFormat, args); va_end(args); } @@ -256,146 +232,6 @@ void Error(const char *pMsgFormat, ...) { va_list args; va_start(args, pMsgFormat); - _SpewMessage(SPEW_ERROR, pMsgFormat, args); + _SpewMessageV(SPEW_ERROR, DBG_DEFAULT_LEVEL, pMsgFormat, args); va_end(args); } - -// A couple of super-common dynamic spew messages, here for convenience -// These looked at the "developer" group, print if it's level 1 or higher -void DevMsg(int level, char const *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", level)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); -} - -void DevWarning(int level, const char *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", level)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); - va_end(args); -} - -void DevLog(int level, const char *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", level)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); - va_end(args); -} - -void DevMsg(const char *pMsgFormat, ...) -{ - if (!IsSpewActive("developer", 1)) - return; - - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_MESSAGE, pMsgFormat, args); - va_end(args); -} - -void DevWarning(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_WARNING, pMsgFormat, args); - va_end(args); -} - -void DevLog(const char *pMsgFormat, ...) -{ - va_list args; - va_start(args, pMsgFormat); - _SpewMessage(SPEW_LOG, pMsgFormat, args); - va_end(args); -} - -// Find a group, return true if found, false if not. Return in ind the -// index of the found group, or the index of the group right before where the -// group should be inserted into the list to maintain sorted order. -bool FindSpewGroup(const char *pGroupName, int *pInd) -{ - int s = 0; - if (s_GroupCount) - { - int e = (int)(s_GroupCount - 1); - while (s <= e) - { - int m = (s + e) >> 1; - int cmp = Q_stricmp(pGroupName, s_pSpewGroups[m].m_GroupName); - if (!cmp) - { - *pInd = m; - return true; - } - - if (cmp < 0) - e = m - 1; - else - s = m + 1; - } - } - - *pInd = s; - return false; -} - -// Sets the priority level for a spew group -void SpewActivate(const char *pGroupName, int level) -{ - Assert(pGroupName); - - // check for the default group first... - if ((pGroupName[0] == '*') && (pGroupName[1] == '\0')) - { - s_DefaultLevel = level; - return; - } - - // Normal case, search in group list using binary search. - // If not found, grow the list of groups and insert it into the - // right place to maintain sorted order. Then set the level. - int ind; - if (!FindSpewGroup(pGroupName, &ind)) - { - // not defined yet, insert an entry. - s_GroupCount++; - if (s_pSpewGroups) - { - s_pSpewGroups = (SpewGroup_t *)realloc(s_pSpewGroups, s_GroupCount * sizeof(SpewGroup_t)); - - // shift elements down to preserve order - int numToMove = s_GroupCount - ind - 1; - memmove(&s_pSpewGroups[ind + 1], &s_pSpewGroups[ind], numToMove * sizeof(SpewGroup_t)); - } - else - s_pSpewGroups = (SpewGroup_t *)malloc(s_GroupCount * sizeof(SpewGroup_t)); - - Assert(strlen(pGroupName) < MAX_GROUP_NAME_LENGTH); - strcpy(s_pSpewGroups[ind].m_GroupName, pGroupName); - } - s_pSpewGroups[ind].m_Level = level; -} - -// Tests to see if a particular spew is active -bool IsSpewActive(const char *pGroupName, int level) -{ - // If we don't find the spew group, use the default level. - int ind; - if (FindSpewGroup(pGroupName, &ind)) - return s_pSpewGroups[ind].m_Level >= level; - else - return s_DefaultLevel >= level; -} diff --git a/regamedll/public/tier0/dbg.h b/regamedll/public/tier0/dbg.h index 38e992f67..848250414 100644 --- a/regamedll/public/tier0/dbg.h +++ b/regamedll/public/tier0/dbg.h @@ -1,30 +1,10 @@ -/* -* -* This program is free software; you can redistribute it and/or modify it -* under the terms of the GNU General Public License as published by the -* Free Software Foundation; either version 2 of the License, or (at -* your option) any later version. -* -* This program 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 -* General Public License for more details. -* -* You should have received a copy of the GNU General Public License -* along with this program; if not, write to the Free Software Foundation, -* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA -* -* In addition, as a special exception, the author gives permission to -* link the code of this program with the Half-Life Game Engine ("HL -* Engine") and Modified Game Libraries ("MODs") developed by Valve, -* L.L.C ("Valve"). You must obey the GNU General Public License in all -* respects for all of the code used other than the HL Engine and MODs -* from Valve. If you modify this file, you may extend this exception -* to your version of the file, but you are not obligated to do so. If -* you do not wish to do so, delete this exception statement from your -* version. -* -*/ +//========= Copyright Valve Corporation, All rights reserved. ============// +// +// Purpose: +// +// $NoKeywords: $ +// +//===========================================================================// #pragma once @@ -34,16 +14,7 @@ #include #include -// dll export stuff -#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 +#define DBG_DEFAULT_LEVEL 0 // Usage model for the Dbg library // @@ -87,22 +58,6 @@ // 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 @@ -131,12 +86,6 @@ // } // ); // -// 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 @@ -170,7 +119,7 @@ enum SpewRetval_t }; // Type of externally defined function used to display debug spew -typedef SpewRetval_t (*SpewOutputFunc_t)(SpewType_t spewType, const char *pMsg); +typedef SpewRetval_t (*SpewOutputFunc_t)(SpewType_t spewType, int level, const char *pMsg); // Used to redirect spew output void SpewOutputFunc(SpewOutputFunc_t func); @@ -178,134 +127,220 @@ void SpewOutputFunc(SpewOutputFunc_t func); // Used ot get the current spew output function SpewOutputFunc_t GetSpewOutputFunc(); -// Used to manage spew groups and subgroups -void SpewActivate(const char *pGroupName, int level); -bool IsSpewActive(const char *pGroupName, int level); - // Used to display messages, should never be called directly. -void _SpewInfo(SpewType_t type, const char *pFile, int line); -SpewRetval_t _SpewMessage(const char *pMsg, ...); -SpewRetval_t _DSpewMessage(const char *pGroupName, int level, const char *pMsg, ...); - -// Used to define macros, never use these directly. -#define _Assert(_exp) \ - do { \ - if (!(_exp)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - if (_SpewMessage("Assertion Failed: " #_exp) == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ - } while (0) - -#define _AssertMsg(_exp, _msg) \ - do { \ - if (!(_exp)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - if (_SpewMessage(_msg) == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ - } while (0) - -#define _AssertFunc(_exp, _f) \ - do { \ - if (!(_exp)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - SpewRetval_t ret = _SpewMessage("Assertion Failed!" #_exp); \ - _f; \ - if (ret == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ - } while (0) +SpewRetval_t _SpewAssert(const char *pFile, int line, int level, const char *pMsg, ...); +void _ExitOnFatalAssert(); +bool _SpewAssertDialog(); -#define _AssertEquals(_exp, _expectedValue) \ - do { \ - if ((_exp) != (_expectedValue)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - SpewRetval_t ret = _SpewMessage("Expected %d but got %d!", (_expectedValue), (_exp)); \ - if (ret == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ +inline bool ShouldUseNewAssertDialog() +{ +#if defined(DBGFLAG_ASSERTDLG) + return true; // always show an assert dialog +#else + return Plat_IsInDebugSession(); // only show an assert dialog if the process is being debugged +#endif // DBGFLAG_ASSERTDLG +} + +#define _AssertMsg(_exp, _msg, _executeExp, _bFatal) \ + do { \ + if (!(_exp)) \ + { \ + SpewRetval_t ret = _SpewAssert(__FILE__, __LINE__, DBG_DEFAULT_LEVEL, _msg); \ + if (ret == SPEW_DEBUGGER) \ + { \ + if (!ShouldUseNewAssertDialog() || _SpewAssertDialog()) \ + DebuggerBreakIfDebugging(); \ + } \ + _executeExp; \ + if (_bFatal) \ + _ExitOnFatalAssert(); \ + } \ } while (0) -#define _AssertFloatEquals(_exp, _expectedValue, _tol) \ - do { \ - if (fabs((_exp) - (_expectedValue)) > (_tol)) \ - { \ - _SpewInfo(SPEW_ASSERT, __FILE__, __LINE__); \ - SpewRetval_t ret = _SpewMessage("Expected %f but got %f!", (_expectedValue), (_exp)); \ - if (ret == SPEW_DEBUGGER) \ - { \ - DebuggerBreak(); \ - } \ - } \ +#define _AssertMsgWarn(_exp, _msg) \ + if (!(_exp)) \ + { \ + Warning("%s (%d) : " _msg, __FILE__, __LINE__); \ + } \ + +#define _AssertMsgOnce(_exp, _msg, _bFatal) \ + do { \ + static bool fAsserted = false; \ + if (!fAsserted && !(_exp)) \ + { \ + fAsserted = true; \ + _AssertMsg(_exp, _msg, (fAsserted = true), _bFatal); \ + } \ } while (0) // Spew macros... -#ifdef _DEBUG - -#define Assert(_exp) _Assert(_exp) -#define AssertMsg(_exp, _msg) _AssertMsg(_exp, _msg) -#define AssertFunc(_exp, _f) _AssertFunc(_exp, _f) -#define AssertEquals(_exp, _expectedValue) _AssertEquals(_exp, _expectedValue) -#define AssertFloatEquals(_exp, _expectedValue, _tol) _AssertFloatEquals(_exp, _expectedValue, _tol) -#define Verify(_exp) _Assert(_exp) - -#define AssertMsg1(_exp, _msg, a1) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1)) -#define AssertMsg2(_exp, _msg, a1, a2) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2)) -#define AssertMsg3(_exp, _msg, a1, a2, a3) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3)) -#define AssertMsg4(_exp, _msg, a1, a2, a3, a4) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4)) -#define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5)) -#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6)) -#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6)) -#define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7)) -#define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8)) -#define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) _AssertMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9)) - -#else // _DEBUG +// 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 + +#if defined(DBGFLAG_ASSERTFATAL) + +#define AssertWarn(_exp) _AssertMsgWarn(_exp, "Assertion Failed: " #_exp) +#define AssertFatal(_exp) _AssertMsg(_exp, "Assertion Failed: " #_exp, ((void)0), true) +#define AssertFatalOnce(_exp) _AssertMsgOnce(_exp, "Assertion Failed: " #_exp, true) +#define AssertFatalMsg(_exp, _msg) _AssertMsg(_exp, _msg, ((void)0), true) +#define AssertFatalMsgOnce(_exp, _msg) _AssertMsgOnce(_exp, _msg, true) +#define AssertFatalFunc(_exp, _f) _AssertMsg(_exp, "Assertion Failed: " #_exp, _f, true) +#define AssertFatalEquals(_exp, _expectedValue) AssertFatalMsg2((_exp) == (_expectedValue), "Expected %d but got %d!", (_expectedValue), (_exp)) +#define AssertFatalFloatEquals(_exp, _expectedValue, _tol) AssertFatalMsg2(fabs((_exp) - (_expectedValue)) <= (_tol), "Expected %f but got %f!", (_expectedValue), (_exp)) +#define VerifyFatal(_exp) AssertFatal(_exp) +#define VerifyEqualsFatal(_exp, _expectedValue) AssertFatalEquals(_exp, _expectedValue) + +#if defined(_DEBUG) + #define DbgVerifyFatal(_exp) AssertFatal(_exp) +#else + #define DbgVerifyFatal(_exp) ((void)0) +#endif -#define Assert(_exp) ((void)0) -#define AssertMsg(_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 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) +#define AssertFatalMsg1(_exp, _msg, a1) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1).ToString()) +#define AssertFatalMsg2(_exp, _msg, a1, a2) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2).ToString()) +#define AssertFatalMsg3(_exp, _msg, a1, a2, a3) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3).ToString()) +#define AssertFatalMsg4(_exp, _msg, a1, a2, a3, a4) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4).ToString()) +#define AssertFatalMsg5(_exp, _msg, a1, a2, a3, a4, a5) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5).ToString()) +#define AssertFatalMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6).ToString()) +#define AssertFatalMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7).ToString()) +#define AssertFatalMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8).ToString()) +#define AssertFatalMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) AssertFatalMsg(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9).ToString()) + +#else // DBGFLAG_ASSERTFATAL + +#define AssertWarn(_exp) ((void)0) +#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 DbgVerifyFatal(_exp) (_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 + +#if defined(DBGFLAG_ASSERT) + +#define Assert(_exp) _AssertMsg(_exp, "Assertion Failed: " #_exp, ((void)0), false) +#define AssertMsg_(_exp, _msg) _AssertMsg(_exp, _msg, ((void)0), false) +#define AssertOnce(_exp) _AssertMsgOnce(_exp, "Assertion Failed: " #_exp, false) +#define AssertMsgOnce(_exp, _msg) _AssertMsgOnce(_exp, _msg, false) +#define AssertFunc(_exp, _f) _AssertMsg(_exp, "Assertion Failed: " #_exp, _f, false) +#define AssertEquals(_exp, _expectedValue) AssertMsg2((_exp) == (_expectedValue), "Expected %d but got %d!", (_expectedValue), (_exp)) +#define AssertFloatEquals(_exp, _expectedValue, _tol) AssertMsg2(fabs((_exp) - (_expectedValue)) <= (_tol), "Expected %f but got %f!", (_expectedValue), (_exp)) +#define Verify(_exp) (_exp) +#define VerifyEquals(_exp, _expectedValue) AssertEquals(_exp, _expectedValue) + +#if defined(_DEBUG) + #define DbgVerify(_exp) (_exp) + #define DbgAssert(_exp) Assert(_exp) + #define DbgAssertMsg(_exp, _msg) AssertMsg(_exp, _msg) + #define DbgAssertMsg1(_exp, _msg, a1) AssertMsg1(_exp, _msg, a1) + #define DbgAssertMsg2(_exp, _msg, a1, a2) AssertMsg2(_exp, _msg, a1, a2) + #define DbgAssertMsg3(_exp, _msg, a1, a2, a3) AssertMsg3(_exp, _msg, a1, a2, a3) + #define DbgAssertMsg4(_exp, _msg, a1, a2, a3) AssertMsg4(_exp, _msg, a1, a2, a3, a4) + #define DbgAssertMsg5(_exp, _msg, a1, a2, a3) AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) + #define DbgAssertMsg6(_exp, _msg, a1, a2, a3) AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) + #define DbgAssertMsg7(_exp, _msg, a1, a2, a3) AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) + #define DbgAssertMsg8(_exp, _msg, a1, a2, a3) AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) + #define DbgAssertMsg9(_exp, _msg, a1, a2, a3) AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) +#else + #define DbgVerify(_exp) ((void)0) + #define DbgAssert(_exp) ((void)0) + #define DbgAssertMsg(_exp, _msg) ((void)0) + #define DbgAssertMsg1(_exp, _msg, a1) ((void)0) + #define DbgAssertMsg2(_exp, _msg, a1, a2) ((void)0) + #define DbgAssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg4(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg5(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg6(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg7(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg8(_exp, _msg, a1, a2, a3) ((void)0) + #define DbgAssertMsg9(_exp, _msg, a1, a2, a3) ((void)0) +#endif -#endif // _DEBUG +#define AssertMsg(_exp, _msg) AssertMsg_(_exp, _msg) +#define AssertMsg1(_exp, _msg, a1) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1).ToString()) +#define AssertMsg2(_exp, _msg, a1, a2) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2).ToString()) +#define AssertMsg3(_exp, _msg, a1, a2, a3) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3).ToString()) +#define AssertMsg4(_exp, _msg, a1, a2, a3, a4) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4).ToString()) +#define AssertMsg5(_exp, _msg, a1, a2, a3, a4, a5) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5).ToString()) +#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6).ToString()) +#define AssertMsg6(_exp, _msg, a1, a2, a3, a4, a5, a6) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6).ToString()) +#define AssertMsg7(_exp, _msg, a1, a2, a3, a4, a5, a6, a7) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7).ToString()) +#define AssertMsg8(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8).ToString()) +#define AssertMsg9(_exp, _msg, a1, a2, a3, a4, a5, a6, a7, a8, a9) AssertMsg_(_exp, CDbgFmtMsg(_msg, a1, a2, a3, a4, a5, a6, a7, a8, a9).ToString()) + +#else // DBGFLAG_ASSERT + +#define Assert(_exp) ((void)0) +#define AssertMsg(_exp, _msg) ((void)0) +#define AssertOnce(_exp) ((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) ((void)0) +#define VerifyEquals(_exp, _expectedValue) ((void)0) + +#define DbgVerify(_exp) ((void)0) +#define DbgAssert(_exp) ((void)0) +#define DbgAssertMsg(_exp, _msg) ((void)0) +#define DbgAssertMsg1(_exp, _msg, a1) ((void)0) +#define DbgAssertMsg2(_exp, _msg, a1, a2) ((void)0) +#define DbgAssertMsg3(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg4(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg5(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg6(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg7(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg8(_exp, _msg, a1, a2, a3) ((void)0) +#define DbgAssertMsg9(_exp, _msg, a1, a2, a3) ((void)0) + +#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 + +// default level versions (level 0) +#define Msg(...) _Msg (0, __VA_ARGS__) +#define Warning(...) _Warning(0, __VA_ARGS__) +#define Log(...) _Log (0, __VA_ARGS__) + +// These looked at the "developer" functions +#define DevMsg(...) _Msg (1, __VA_ARGS__) +#define DevWarning(...) _Warning(1, __VA_ARGS__) +#define DevLog(...) _Log (1, __VA_ARGS__) // These are always compiled in -void Msg(const char *pMsg, ...); -void DMsg(const char *pGroupName, int level, const char *pMsg, ...); - -void Warning(const char *pMsg, ...); -void DWarning(const char *pGroupName, int level, const char *pMsg, ...); - -void Log(const char *pMsg, ...); -void DLog(const char *pGroupName, int level, const char *pMsg, ...); - -void Error(const char *pMsg, ...); +void _Msg (int level, const char *pMsg, ...); +void _Warning(int level, const char *pMsg, ...); +void _Log (int level, const char *pMsg, ...); +void Error (const char *pMsg, ...); // 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 @@ -320,57 +355,39 @@ void Error(const char *pMsg, ...); Error msg; \ } -// A couple of super-common dynamic spew messages, here for convenience -// These looked at the "developer" group -void DevMsg(int level, char const* pMsg, ...); -void DevWarning(int level, const char *pMsg, ...); -void DevLog(int level, const char *pMsg, ...); - -// default level versions (level 1) -void DevMsg(char const* pMsg, ...); -void DevWarning(const char *pMsg, ...); -void DevLog(const char *pMsg, ...); - // Code macros, debugger interface -#ifdef _DEBUG -#define DBG_CODE(_code) if (0) ; else { _code } -#define DBG_DCODE(_g, _l, _code) if (IsSpewActive(_g, _l)) { _code } else {} -#define DBG_BREAK() DebuggerBreak() +#if defined(_DEBUG) + #define DBG_CODE(_code) if (0) ; else { _code } + #define DBG_DCODE(_g, _l, _code) if (IsSpewActive(_g, _l)) { _code } else {} + #define DBG_BREAK() DebuggerBreakIfDebugging() #else // _DEBUG -#define DBG_CODE(_code) ((void)0) -#define DBG_DCODE(_g, _l, _code) ((void)0) -#define DBG_BREAK() ((void)0) + #define DBG_CODE(_code) ((void)0) + #define DBG_DCODE(_g, _l, _code) ((void)0) + #define DBG_BREAK() ((void)0) #endif // _DEBUG -// Macro to assist in asserting constant invariants during compilation -#define UID_PREFIX generated_id_ -#define UID_CAT1(a, c) a ## c -#define UID_CAT2(a, c) UID_CAT1(a,c) -#define UNIQUE_ID UID_CAT2(UID_PREFIX, __LINE__) - -#ifdef _DEBUG -#define COMPILE_TIME_ASSERT(pred) switch(0){case 0:case pred:;} -#define ASSERT_INVARIANT(pred) static void UNIQUE_ID() { COMPILE_TIME_ASSERT(pred) } -#else -#define COMPILE_TIME_ASSERT(pred) -#define ASSERT_INVARIANT(pred) -#endif - // Templates to assist in validating pointers: // Have to use these stubs so we don't have to include windows.h here. void _AssertValidReadPtr(void *ptr, int count = 1); void _AssertValidWritePtr(void *ptr, int count = 1); void _AssertValidReadWritePtr(void *ptr, int count = 1); - void AssertValidStringPtr(const char *ptr, int maxchar = 0xFFFFFF); -template inline void AssertValidReadPtr(T *ptr, int count = 1) { _AssertValidReadPtr((void *)ptr, count); } -template inline void AssertValidWritePtr(T *ptr, int count = 1) { _AssertValidWritePtr((void *)ptr, count); } -template inline void AssertValidReadWritePtr(T *ptr, int count = 1) { _AssertValidReadWritePtr((void *)ptr, count); } - -#define AssertValidThis() AssertValidReadWritePtr(this, sizeof(*this)) +#if defined(DBGFLAG_ASSERT) + void AssertValidStringPtr(const char *ptr, int maxchar = 0xFFFFFF); + template inline void AssertValidReadPtr(T *ptr, int count = 1) { _AssertValidReadPtr((void *)ptr, count); } + template inline void AssertValidWritePtr(T *ptr, int count = 1) { _AssertValidWritePtr((void *)ptr, count); } + template inline void AssertValidReadWritePtr(T *ptr, int count = 1) { _AssertValidReadWritePtr((void *)ptr, count); } + #define AssertValidThis() AssertValidReadWritePtr(this, sizeof(*this)) +#else + #define AssertValidStringPtr(...) ((void)0) + #define AssertValidReadPtr(...) ((void)0) + #define AssertValidWritePtr(...) ((void)0) + #define AssertValidReadWritePtr(...) ((void)0) + #define AssertValidThis() ((void)0) +#endif // #if defined(DBGFLAG_ASSERT) // Macro to protect functions that are not reentrant -#ifdef _DEBUG +#if defined(_DEBUG) class CReentryGuard { public: @@ -406,6 +423,7 @@ class CDbgFmtMsg va_start(arg_ptr, pszFormat); _vsnprintf(m_szBuf, sizeof(m_szBuf) - 1, pszFormat, arg_ptr); va_end(arg_ptr); + m_szBuf[sizeof(m_szBuf) - 1] = '\0'; } @@ -414,14 +432,11 @@ class CDbgFmtMsg return m_szBuf; } + const char *ToString() const + { + return m_szBuf; + } + private: char m_szBuf[256]; }; - -// Embed debug info in each file. -//#ifdef _WIN32 -//#ifdef _DEBUG -//#pragma comment(compiler) -//#pragma comment(exestr,"*** DEBUG file detected, Last Compile: " __DATE__ ", " __TIME__ " ***") -//#endif -//#endif diff --git a/regamedll/public/tier0/platform.h b/regamedll/public/tier0/platform.h index c10ae8b9b..5703cf53b 100644 --- a/regamedll/public/tier0/platform.h +++ b/regamedll/public/tier0/platform.h @@ -41,7 +41,14 @@ #endif // Used to step into the debugger -#define DebuggerBreak() __asm { int 3 } +#if defined(__GNUC__) && !defined(__clang__) + #define DebuggerBreak() __asm__ __volatile__("int3;") +#else + #define DebuggerBreak() __asm { int 3 } +#endif + +#define DebuggerBreakIfDebugging() if (Plat_IsInDebugSession()) { DebuggerBreak(); } +#define DebuggerSegFault() { volatile int *null = 0; *null = 0; } // C functions for external declarations that call the appropriate C++ methods #ifndef EXPORT @@ -105,6 +112,37 @@ #endif #endif +// +// Macro to assist in asserting constant invariants during compilation + +#define STRINGIFY_INTERNAL(x) #x +#define STRINGIFY(x) STRINGIFY_INTERNAL(x) + +// 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. +#define COMPILE_TIME_ASSERT(pred) static_assert(pred, "Compile time assert constraint is not true: " #pred) + +// 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) + +// Macro to assist in asserting constant invariants during compilation +// +// If available use static_assert instead of weird language tricks. This +// leads to much more readable messages when compile time assert constraints +// are violated. +#if !defined(OSX) && (_MSC_VER > 1500 || __GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 5)) + #define PLAT_COMPILE_TIME_ASSERT(pred) static_assert(pred, "Compile time assert constraint is not true: " #pred) +#else + #define PLAT_COMPILE_TIME_ASSERT(pred) typedef int UNIQUE_ID[ (pred) ? 1 : -1] +#endif + +bool Plat_IsInDebugSession(); +void Plat_DebugString(const char *psz); +void Plat_OutputDebugString(const char *psz); +void Plat_OutputDebugStringRaw(const char *psz); +const char *Plat_GetCommandLine(); + // Methods to invoke the constructor, copy constructor, and destructor template inline void Construct(T *pMemory) diff --git a/regamedll/public/tier0/platform_posix.cpp b/regamedll/public/tier0/platform_posix.cpp new file mode 100644 index 000000000..202040b90 --- /dev/null +++ b/regamedll/public/tier0/platform_posix.cpp @@ -0,0 +1,113 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool Plat_IsInDebugSession() +{ +#if defined(OSX) + int mib[4]; + struct kinfo_proc info; + size_t size; + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_PID; + mib[3] = getpid(); + size = sizeof(info); + info.kp_proc.p_flag = 0; + sysctl(mib, 4, &info, &size, NULL, 0); + bool result = ((info.kp_proc.p_flag & P_TRACED) == P_TRACED); + return result; +#elif defined(_LINUX) + char s[256]; + snprintf(s, 256, "/proc/%d/cmdline", getppid()); + FILE *fp = fopen(s, "r"); + if (fp) + { + fread(s, 256, 1, fp); + fclose(fp); + return (0 == strncmp(s, "gdb", 3)); + } + return false; +#endif +} + +void Plat_OutputDebugStringRaw(const char *psz) +{ + fprintf(stderr, "%s", psz); +} + +void Plat_OutputDebugString(const char *psz) +{ + fprintf(stderr, "%s", psz); +} + +void Plat_DebugString(const char *psz) +{ + fprintf(stderr, "%s", psz); +} + +static char g_CmdLine[2048]{}; + +const char *Plat_GetCommandLine() +{ +#if defined(_LINUX) + static bool commandline_initialized = false; + if (!commandline_initialized) + { + commandline_initialized = true; + + FILE *fp = fopen("/proc/self/cmdline", "rb"); + if (fp) + { + size_t nCharRead = 0; + + // -1 to leave room for the '\0' + nCharRead = fread(g_CmdLine, sizeof(g_CmdLine[0]), ARRAYSIZE(g_CmdLine) - 1, fp); + if (feof(fp) && !ferror(fp)) // Should have read the whole command line without error + { + Assert(nCharRead < ARRAYSIZE(g_CmdLine)); + + for (int i = 0; i < nCharRead; i++) + { + if (!g_CmdLine[i]) + g_CmdLine[i] = ' '; + } + + g_CmdLine[nCharRead] = '\0'; + } + + fclose(fp); + } + + Assert(g_CmdLine[0]); + } +#endif // LINUX + + return g_CmdLine; +} diff --git a/regamedll/public/tier0/platform_win32.cpp b/regamedll/public/tier0/platform_win32.cpp new file mode 100644 index 000000000..0ffbf7cf3 --- /dev/null +++ b/regamedll/public/tier0/platform_win32.cpp @@ -0,0 +1,57 @@ +/* +* +* This program is free software; you can redistribute it and/or modify it +* under the terms of the GNU General Public License as published by the +* Free Software Foundation; either version 2 of the License, or (at +* your option) any later version. +* +* This program 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 +* General Public License for more details. +* +* You should have received a copy of the GNU General Public License +* along with this program; if not, write to the Free Software Foundation, +* Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +* +* In addition, as a special exception, the author gives permission to +* link the code of this program with the Half-Life Game Engine ("HL +* Engine") and Modified Game Libraries ("MODs") developed by Valve, +* L.L.C ("Valve"). You must obey the GNU General Public License in all +* respects for all of the code used other than the HL Engine and MODs +* from Valve. If you modify this file, you may extend this exception +* to your version of the file, but you are not obligated to do so. If +* you do not wish to do so, delete this exception statement from your +* version. +* +*/ + +#include "precompiled.h" + +bool Plat_IsInDebugSession() +{ + return IsDebuggerPresent() != FALSE; +} + +void Plat_OutputDebugStringRaw(const char *psz) +{ + OutputDebugString(psz); +} + +void Plat_OutputDebugString(const char *psz) +{ + static char buf[4096]; + int len = Q_snprintf(buf, sizeof(buf), "%s", psz); + Assert(len > 0); + OutputDebugString(buf); +} + +void Plat_DebugString(const char *psz) +{ + Plat_OutputDebugString(psz); +} + +const char *Plat_GetCommandLine() +{ + return GetCommandLineA(); +} diff --git a/regamedll/public/tier0/resource.h b/regamedll/public/tier0/resource.h new file mode 100644 index 000000000..d261901a6 --- /dev/null +++ b/regamedll/public/tier0/resource.h @@ -0,0 +1,44 @@ +/* +* +* Copyright (c) 1996-2002, Valve LLC. All rights reserved. +* +* This product contains software technology licensed from Id +* Software, Inc. ("Id Technology"). Id Technology (c) 1996 Id Software, Inc. +* All Rights Reserved. +* +* Use, distribution, and modification of this source code and/or resulting +* object code is restricted to non-commercial enhancements to products from +* Valve LLC. All other use, distribution, or modification is prohibited +* without written permission from Valve LLC. +* +*/ + +//{{NO_DEPENDENCIES}} +// Microsoft Developer Studio generated include file. +// Used by assert_dialog.rc +// + +#define IDD_ASSERT_DIALOG 101 +#define IDC_FILENAME_CONTROL 1000 +#define IDC_LINE_CONTROL 1001 +#define IDC_IGNORE_FILE 1002 +#define IDC_IGNORE_NEARBY 1003 +#define IDC_IGNORE_NUMLINES 1004 +#define IDC_IGNORE_THIS 1005 +#define IDC_BREAK 1006 +#define IDC_IGNORE_ALL 1008 +#define IDC_IGNORE_ALWAYS 1009 +#define IDC_IGNORE_NUMTIMES 1010 +#define IDC_ASSERT_MSG_CTRL 1011 +#define IDC_NOID -1 + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 103 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1005 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif