764 lines
18 KiB
C++
764 lines
18 KiB
C++
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// cppdbg.cpp
|
||
|
//
|
||
|
// C++-only debugging support.
|
||
|
//
|
||
|
// Copyright (C) Microsoft Corporation, 1997.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
#include "pch.cpp"
|
||
|
#pragma hdrstop
|
||
|
|
||
|
#if DBG
|
||
|
|
||
|
#include "cppdbg.hpp"
|
||
|
|
||
|
#ifdef _ALPHA_
|
||
|
// On Alpha va_list is a structure so it's not compatible with NULL.
|
||
|
static va_list NULLVA;
|
||
|
#else
|
||
|
#define NULLVA NULL
|
||
|
#endif
|
||
|
|
||
|
static DebugModuleFlags g_FailureFlags[] =
|
||
|
{
|
||
|
DBG_DECLARE_MODFLAG(DBG_FAILURE, BREAK),
|
||
|
DBG_DECLARE_MODFLAG(DBG_FAILURE, OUTPUT),
|
||
|
DBG_DECLARE_MODFLAG(DBG_FAILURE, PROMPT),
|
||
|
DBG_DECLARE_MODFLAG(DBG_FAILURE, FILENAME_ONLY),
|
||
|
0, NULL,
|
||
|
};
|
||
|
|
||
|
static DebugModuleFlags g_OutputFlags[] =
|
||
|
{
|
||
|
DBG_DECLARE_MODFLAG(DBG_OUTPUT, SUPPRESS),
|
||
|
DBG_DECLARE_MODFLAG(DBG_OUTPUT, ALL_MATCH),
|
||
|
0, NULL,
|
||
|
};
|
||
|
|
||
|
static char *g_pFlagNames[] =
|
||
|
{
|
||
|
"AssertFlags",
|
||
|
"HrFlags",
|
||
|
"OutputFlags",
|
||
|
"OutputMask",
|
||
|
"UserFlags"
|
||
|
};
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::DebugModule
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DebugModule::DebugModule(char *pModule, char *pPrefix,
|
||
|
DebugModuleFlags *pOutputMasks, UINT uOutputMask,
|
||
|
DebugModuleFlags *pUserFlags, UINT uUserFlags)
|
||
|
{
|
||
|
m_pModule = pModule;
|
||
|
m_iModuleStartCol = strlen(m_pModule) + 2;
|
||
|
m_pPrefix = pPrefix;
|
||
|
|
||
|
m_pModFlags[DBG_ASSERT_FLAGS] = g_FailureFlags;
|
||
|
m_pModFlags[DBG_HR_FLAGS] = g_FailureFlags;
|
||
|
m_pModFlags[DBG_OUTPUT_FLAGS] = g_OutputFlags;
|
||
|
m_pModFlags[DBG_OUTPUT_MASK] = pOutputMasks;
|
||
|
m_pModFlags[DBG_USER_FLAGS] = pUserFlags;
|
||
|
|
||
|
m_uFlags[DBG_ASSERT_FLAGS] = DBG_FAILURE_OUTPUT | DBG_FAILURE_BREAK |
|
||
|
DBG_FAILURE_FILENAME_ONLY;
|
||
|
m_uFlags[DBG_HR_FLAGS] = DBG_FAILURE_OUTPUT |
|
||
|
DBG_FAILURE_FILENAME_ONLY;
|
||
|
m_uFlags[DBG_OUTPUT_FLAGS] = 0;
|
||
|
m_uFlags[DBG_OUTPUT_MASK] = uOutputMask;
|
||
|
m_uFlags[DBG_USER_FLAGS] = uUserFlags;
|
||
|
|
||
|
ReadReg();
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::OutVa
|
||
|
//
|
||
|
// Base debug output method.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::OutVa(UINT uMask, char *pFmt, va_list Args)
|
||
|
{
|
||
|
if (m_uFlags[DBG_OUTPUT_FLAGS] & DBG_OUTPUT_SUPPRESS)
|
||
|
{
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
if ((uMask & DBG_MASK_NO_PREFIX) == 0)
|
||
|
{
|
||
|
OutputDebugStringA(m_pModule);
|
||
|
OutputDebugStringA(": ");
|
||
|
}
|
||
|
|
||
|
char chMsg[1024];
|
||
|
|
||
|
_vsnprintf(chMsg, sizeof(chMsg), pFmt, Args);
|
||
|
OutputDebugStringA(chMsg);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::Out
|
||
|
//
|
||
|
// Always-output debug output method.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::Out(char *pFmt, ...)
|
||
|
{
|
||
|
va_list Args;
|
||
|
|
||
|
va_start(Args, pFmt);
|
||
|
OutVa(0, pFmt, Args);
|
||
|
va_end(Args);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::AssertFailedVa
|
||
|
//
|
||
|
// Handles assertion failure output and interface.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::AssertFailedVa(char *pFmt, va_list Args, BOOL bNewLine)
|
||
|
{
|
||
|
if (m_uFlags[DBG_ASSERT_FLAGS] & DBG_FAILURE_OUTPUT)
|
||
|
{
|
||
|
if (OutPathFile("Assertion failed", m_uFlags[DBG_ASSERT_FLAGS]))
|
||
|
{
|
||
|
OutVa(DBG_MASK_NO_PREFIX, ":\n ", NULLVA);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
OutVa(DBG_MASK_NO_PREFIX, ": ", NULLVA);
|
||
|
}
|
||
|
|
||
|
OutVa(DBG_MASK_NO_PREFIX, pFmt, Args);
|
||
|
if (bNewLine)
|
||
|
{
|
||
|
OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (m_uFlags[DBG_ASSERT_FLAGS] & DBG_FAILURE_BREAK)
|
||
|
{
|
||
|
DebugBreak();
|
||
|
}
|
||
|
else if (m_uFlags[DBG_ASSERT_FLAGS] & DBG_FAILURE_PROMPT)
|
||
|
{
|
||
|
Prompt(NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::AssertFailed
|
||
|
//
|
||
|
// Handles simple expression assertion failures.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::AssertFailed(char *pExp)
|
||
|
{
|
||
|
AssertFailedVa(pExp, NULLVA, TRUE);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::AssertFailedMsg
|
||
|
//
|
||
|
// Handles assertion failures with arbitrary debug output.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::AssertFailedMsg(char *pFmt, ...)
|
||
|
{
|
||
|
va_list Args;
|
||
|
|
||
|
va_start(Args, pFmt);
|
||
|
AssertFailedVa(pFmt, Args, FALSE);
|
||
|
va_end(Args);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::HrFailure
|
||
|
//
|
||
|
// Handles HRESULT failures.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::HrFailure(HRESULT hr, char *pPrefix)
|
||
|
{
|
||
|
if (m_uFlags[DBG_HR_FLAGS] & DBG_FAILURE_OUTPUT)
|
||
|
{
|
||
|
OutPathFile(pPrefix, m_uFlags[DBG_HR_FLAGS]);
|
||
|
OutMask(DBG_MASK_FORCE_CONT, ": %s\n", HrString(hr));
|
||
|
}
|
||
|
|
||
|
if (m_uFlags[DBG_HR_FLAGS] & DBG_FAILURE_BREAK)
|
||
|
{
|
||
|
DebugBreak();
|
||
|
}
|
||
|
else if (m_uFlags[DBG_HR_FLAGS] & DBG_FAILURE_PROMPT)
|
||
|
{
|
||
|
Prompt(NULL);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::HrStmtFailed
|
||
|
//
|
||
|
// Handles statement-style HRESULT failures.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::HrStmtFailed(HRESULT hr)
|
||
|
{
|
||
|
HrFailure(hr, "HR test fail");
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::ReturnHr
|
||
|
//
|
||
|
// Handles expression-style HRESULT failures.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HRESULT DebugModule::HrExpFailed(HRESULT hr)
|
||
|
{
|
||
|
HrFailure(hr, "HR expr fail");
|
||
|
return hr;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::Prompt
|
||
|
//
|
||
|
// Allows control over debug options via interactive input.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::Prompt(char *pFmt, ...)
|
||
|
{
|
||
|
va_list Args;
|
||
|
|
||
|
if (pFmt != NULL)
|
||
|
{
|
||
|
va_start(Args, pFmt);
|
||
|
OutVa(0, pFmt, Args);
|
||
|
va_end(Args);
|
||
|
}
|
||
|
|
||
|
#if 0 // ndef WIN95
|
||
|
// This is DEADCODE, that is can be potentially used on NT ONLY to
|
||
|
// bring up a debugging prompt. It requires linking with NTDLL.LIB
|
||
|
char szInput[512];
|
||
|
char *pIdx;
|
||
|
int iIdx;
|
||
|
static char szFlagCommands[] = "ahomu";
|
||
|
|
||
|
for (;;)
|
||
|
{
|
||
|
ULONG uLen;
|
||
|
|
||
|
uLen = DbgPrompt("[bgaAFhHmMoOrRuU] ", szInput, sizeof(szInput) - 1);
|
||
|
if (uLen < 2)
|
||
|
{
|
||
|
Out("DbgPrompt failed\n");
|
||
|
DebugBreak();
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
// ATTENTION - Currently DbgPrompt returns a length that is two
|
||
|
// greater than the actual number of characters. Presumably this
|
||
|
// is an artifact of the Unicode/ANSI conversion and should
|
||
|
// really only be one greater, so attempt to handle both.
|
||
|
|
||
|
uLen -= 2;
|
||
|
if (szInput[uLen] != 0)
|
||
|
{
|
||
|
uLen++;
|
||
|
szInput[uLen] = 0;
|
||
|
}
|
||
|
|
||
|
if (uLen < 1)
|
||
|
{
|
||
|
Out("Empty command ignored\n");
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
switch(szInput[0])
|
||
|
{
|
||
|
case 'b':
|
||
|
DebugBreak();
|
||
|
break;
|
||
|
case 'g':
|
||
|
return;
|
||
|
|
||
|
case 'r':
|
||
|
WriteReg();
|
||
|
break;
|
||
|
case 'R':
|
||
|
ReadReg();
|
||
|
break;
|
||
|
|
||
|
case 'a':
|
||
|
case 'A':
|
||
|
case 'h':
|
||
|
case 'H':
|
||
|
case 'm':
|
||
|
case 'M':
|
||
|
case 'o':
|
||
|
case 'O':
|
||
|
case 'u':
|
||
|
case 'U':
|
||
|
char chLower;
|
||
|
|
||
|
if (szInput[0] >= 'A' && szInput[0] <= 'Z')
|
||
|
{
|
||
|
chLower = szInput[0] - 'A' + 'a';
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
chLower = szInput[0];
|
||
|
}
|
||
|
|
||
|
pIdx = strchr(szFlagCommands, chLower);
|
||
|
if (pIdx == NULL)
|
||
|
{
|
||
|
// Should never happen.
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
iIdx = (int)((ULONG_PTR)(pIdx - szFlagCommands));
|
||
|
if (szInput[0] == chLower)
|
||
|
{
|
||
|
// Set.
|
||
|
m_uFlags[iIdx] = ParseUint(szInput + 1, m_pModFlags[iIdx]);
|
||
|
}
|
||
|
|
||
|
// Set or Get.
|
||
|
OutUint(g_pFlagNames[iIdx], m_pModFlags[iIdx], m_uFlags[iIdx]);
|
||
|
break;
|
||
|
|
||
|
case 'F':
|
||
|
if (uLen < 2)
|
||
|
{
|
||
|
Out("'F' must be followed by a flag group specifier\n");
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
pIdx = strchr(szFlagCommands, szInput[1]);
|
||
|
if (pIdx == NULL)
|
||
|
{
|
||
|
Out("Unknown flag group '%c'\n", szInput[1]);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
iIdx = (int)((ULONG_PTR)(pIdx - szFlagCommands));
|
||
|
ShowFlags(g_pFlagNames[iIdx], m_pModFlags[iIdx]);
|
||
|
}
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
Out("Unknown command '%c'\n", szInput[0]);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
#else
|
||
|
OutUint("OutputMask", m_pModFlags[DBG_OUTPUT_MASK],
|
||
|
m_uFlags[DBG_OUTPUT_MASK]);
|
||
|
Out("Prompt not available\n");
|
||
|
DebugBreak();
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::OpenDebugKey
|
||
|
//
|
||
|
// Opens the Direct3D\Debug\m_pModule key.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
HKEY DebugModule::OpenDebugKey(void)
|
||
|
{
|
||
|
HKEY hKey;
|
||
|
char szKeyName[128];
|
||
|
|
||
|
strcpy(szKeyName, "Software\\Microsoft\\Direct3D\\Debug\\");
|
||
|
strcat(szKeyName, m_pModule);
|
||
|
if (RegOpenKeyExA(HKEY_LOCAL_MACHINE, szKeyName, 0, KEY_ALL_ACCESS,
|
||
|
&hKey) != ERROR_SUCCESS)
|
||
|
{
|
||
|
return NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return hKey;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::GetRegUint
|
||
|
//
|
||
|
// Gets a UINT value from the given key.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
UINT DebugModule::GetRegUint(HKEY hKey, char *pValue, UINT uDefault)
|
||
|
{
|
||
|
DWORD dwType, dwSize;
|
||
|
DWORD dwVal;
|
||
|
|
||
|
dwSize = sizeof(dwVal);
|
||
|
if (RegQueryValueExA(hKey, pValue, NULL, &dwType, (BYTE *)&dwVal,
|
||
|
&dwSize) != ERROR_SUCCESS ||
|
||
|
dwType != REG_DWORD)
|
||
|
{
|
||
|
return uDefault;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return (UINT)dwVal;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::SetRegUint
|
||
|
//
|
||
|
// Sets a UINT value for the given key.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL DebugModule::SetRegUint(HKEY hKey, char *pValue, UINT uValue)
|
||
|
{
|
||
|
return RegSetValueExA(hKey, pValue, NULL, REG_DWORD, (BYTE *)&uValue,
|
||
|
sizeof(uValue)) == ERROR_SUCCESS;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::ReadReg
|
||
|
//
|
||
|
// Reads settings from the registry.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::ReadReg(void)
|
||
|
{
|
||
|
HKEY hKey;
|
||
|
|
||
|
hKey = OpenDebugKey();
|
||
|
if (hKey != NULL)
|
||
|
{
|
||
|
int iIdx;
|
||
|
|
||
|
for (iIdx = 0; iIdx < DBG_FLAGS_COUNT; iIdx++)
|
||
|
{
|
||
|
m_uFlags[iIdx] = GetRegUint(hKey, g_pFlagNames[iIdx],
|
||
|
m_uFlags[iIdx]);
|
||
|
}
|
||
|
RegCloseKey(hKey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::WriteReg
|
||
|
//
|
||
|
// Writes values to the registry.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::WriteReg(void)
|
||
|
{
|
||
|
HKEY hKey;
|
||
|
|
||
|
hKey = OpenDebugKey();
|
||
|
if (hKey != NULL)
|
||
|
{
|
||
|
int iIdx;
|
||
|
|
||
|
for (iIdx = 0; iIdx < DBG_FLAGS_COUNT; iIdx++)
|
||
|
{
|
||
|
if (!SetRegUint(hKey, g_pFlagNames[iIdx], m_uFlags[iIdx]))
|
||
|
{
|
||
|
OutputDebugStringA("Error writing registry information\n");
|
||
|
}
|
||
|
}
|
||
|
RegCloseKey(hKey);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::ParseUint
|
||
|
//
|
||
|
// Parses a string for a numeric value or a set of flag strings.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
UINT DebugModule::ParseUint(char *pString, DebugModuleFlags *pFlags)
|
||
|
{
|
||
|
UINT uVal;
|
||
|
|
||
|
uVal = 0;
|
||
|
|
||
|
for (;;)
|
||
|
{
|
||
|
while (*pString != 0 &&
|
||
|
(*pString == ' ' || *pString == '\t'))
|
||
|
{
|
||
|
pString++;
|
||
|
}
|
||
|
|
||
|
if (*pString == 0)
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
char *pEnd;
|
||
|
int iStepAfter;
|
||
|
|
||
|
pEnd = pString;
|
||
|
while (*pEnd != 0 && *pEnd != ' ' && *pEnd != '\t')
|
||
|
{
|
||
|
pEnd++;
|
||
|
}
|
||
|
iStepAfter = *pEnd != 0 ? 1 : 0;
|
||
|
*pEnd = 0;
|
||
|
|
||
|
if (*pString >= '0' && *pString <= '9')
|
||
|
{
|
||
|
uVal |= strtoul(pString, &pString, 0);
|
||
|
if (*pString != 0 && *pString != ' ' && *pString != '\t')
|
||
|
{
|
||
|
Out("Unrecognized characters '%s' after number\n", pString);
|
||
|
}
|
||
|
}
|
||
|
else if (pFlags != NULL)
|
||
|
{
|
||
|
DebugModuleFlags *pFlag;
|
||
|
|
||
|
for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
|
||
|
{
|
||
|
if (!_stricmp(pString, pFlag->pName))
|
||
|
{
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pFlag->uFlag == 0)
|
||
|
{
|
||
|
Out("Unrecognized flag string '%s'\n", pString);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
uVal |= pFlag->uFlag;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Out("No flag definitions, unable to convert '%s'\n", pString);
|
||
|
}
|
||
|
|
||
|
pString = pEnd + iStepAfter;
|
||
|
}
|
||
|
|
||
|
return uVal;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::OutUint
|
||
|
//
|
||
|
// Displays a UINT as a set of flag strings.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::OutUint(char *pName, DebugModuleFlags *pFlags, UINT uValue)
|
||
|
{
|
||
|
if (pFlags == NULL || uValue == 0)
|
||
|
{
|
||
|
Out("%s: 0x%08X\n", pName, uValue);
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
Out("%s:", pName);
|
||
|
m_iStartCol = m_iModuleStartCol + strlen(pName) + 1;
|
||
|
m_iCol = m_iStartCol;
|
||
|
|
||
|
while (uValue != 0)
|
||
|
{
|
||
|
DebugModuleFlags *pFlag;
|
||
|
|
||
|
for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
|
||
|
{
|
||
|
if ((pFlag->uFlag & uValue) == pFlag->uFlag)
|
||
|
{
|
||
|
AdvanceCols(strlen(pFlag->pName) + 1);
|
||
|
OutMask(DBG_MASK_FORCE_CONT, " %s", pFlag->pName);
|
||
|
uValue &= ~pFlag->uFlag;
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (pFlag->uFlag == 0)
|
||
|
{
|
||
|
AdvanceCols(11);
|
||
|
OutMask(DBG_MASK_FORCE_CONT, " 0x%X", uValue);
|
||
|
uValue = 0;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::AdvanceCols
|
||
|
//
|
||
|
// Determines if there's enough space on the current line for
|
||
|
// the given number of columns. If not, a new line is started.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::AdvanceCols(int iCols)
|
||
|
{
|
||
|
static char szSpaces[] = " ";
|
||
|
|
||
|
m_iCol += iCols;
|
||
|
if (m_iCol >= 79)
|
||
|
{
|
||
|
int iSpace;
|
||
|
|
||
|
OutVa(DBG_MASK_NO_PREFIX, "\n", NULLVA);
|
||
|
// Force a prefix to be printed to start the line.
|
||
|
Out("");
|
||
|
|
||
|
m_iCol = m_iModuleStartCol;
|
||
|
while (m_iCol < m_iStartCol)
|
||
|
{
|
||
|
iSpace = (int)min(sizeof(szSpaces) - 1, m_iStartCol - m_iCol);
|
||
|
OutMask(DBG_MASK_FORCE_CONT, "%.*s", iSpace, szSpaces);
|
||
|
m_iCol += iSpace;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::ShowFlags
|
||
|
//
|
||
|
// Shows the given flag set.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
void DebugModule::ShowFlags(char *pName, DebugModuleFlags *pFlags)
|
||
|
{
|
||
|
DebugModuleFlags *pFlag;
|
||
|
|
||
|
Out("%s:\n", pName);
|
||
|
if (pFlags == NULL)
|
||
|
{
|
||
|
Out(" None defined\n");
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
for (pFlag = pFlags; pFlag->uFlag != 0; pFlag++)
|
||
|
{
|
||
|
Out(" 0x%08X - %s\n", pFlag->uFlag, pFlag->pName);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::PathFile
|
||
|
//
|
||
|
// Returns the trailing filename component or NULL if the path is
|
||
|
// only a filename.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
char *DebugModule::PathFile(char *pPath)
|
||
|
{
|
||
|
char *pFile, *pSlash, *pBack, *pColon;
|
||
|
|
||
|
pBack = strrchr(pPath, '\\');
|
||
|
pSlash = strrchr(pPath, '/');
|
||
|
pColon = strrchr(pPath, ':');
|
||
|
|
||
|
pFile = pBack;
|
||
|
if (pSlash > pFile)
|
||
|
{
|
||
|
pFile = pSlash;
|
||
|
}
|
||
|
if (pColon > pFile)
|
||
|
{
|
||
|
pFile = pColon;
|
||
|
}
|
||
|
|
||
|
return pFile != NULL ? pFile + 1 : NULL;
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// DebugModule::OutPathFile
|
||
|
//
|
||
|
// Outputs the given string plus a path and filename.
|
||
|
// Returns whether the full path was output or not.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
BOOL DebugModule::OutPathFile(char *pPrefix, UINT uFailureFlags)
|
||
|
{
|
||
|
char *pFile;
|
||
|
|
||
|
if (uFailureFlags & DBG_FAILURE_FILENAME_ONLY)
|
||
|
{
|
||
|
pFile = PathFile(m_pFile);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
pFile = NULL;
|
||
|
}
|
||
|
|
||
|
if (pFile == NULL)
|
||
|
{
|
||
|
Out("%s %s(%d)", pPrefix, m_pFile, m_iLine);
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
Out("%s <>\\%s(%d)", pPrefix, pFile, m_iLine);
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
//----------------------------------------------------------------------------
|
||
|
//
|
||
|
// Global debug module.
|
||
|
//
|
||
|
//----------------------------------------------------------------------------
|
||
|
|
||
|
DBG_DECLARE_ONCE(Global, G, NULL, 0, NULL, 0);
|
||
|
|
||
|
#endif // #if DBG
|