|
|
//==========================================================================;
//
// THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF ANY
// KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A PARTICULAR
// PURPOSE.
//
// Copyright (c) 1992-1995 Microsoft Corporation. All Rights Reserved.
//
//--------------------------------------------------------------------------;
//
// debug.c
//
// Description:
// This file contains code yanked from several places to provide debug
// support that works in win 16 and win 32.
//
//
//==========================================================================;
#include <windows.h>
#include <windowsx.h>
#include <stdarg.h>
#include "debug.h"
//
// since we don't UNICODE our debugging messages, use the ASCII entry
// points regardless of how we are compiled.
//
#ifdef _WIN32
#include <wchar.h>
#else
#define lstrcatA lstrcat
#define lstrlenA lstrlen
#define GetProfileIntA GetProfileInt
#define OutputDebugStringA OutputDebugString
#define wsprintfA wsprintf
#define MessageBoxA MessageBox
#endif
#ifdef USEDPF
//
//
//
BOOL __gfDbgEnabled = TRUE; // master enable
UINT __guDbgLevel = 0; // current debug level
#endif
#if defined(USERPF) || defined(USEDPF)
#define LOGSIZE 64000
char pStartOfBuffer[LOGSIZE]; static char* pEndOfBuffer = pStartOfBuffer+LOGSIZE; char* pHead = pStartOfBuffer; static char* pTail = pStartOfBuffer;
void listRemoveHead() { pHead += lstrlen(pHead) + 1 ; if (pHead >= pEndOfBuffer) { pHead = pStartOfBuffer ; } }
char* listGetHead() { return ( pHead ) ; } void listAddTail(char* lpszDebug) { int cchDebug ;
cchDebug = lstrlen(lpszDebug) ;
while (TRUE) { while ( (pTail < pHead) && ((pTail+(cchDebug+1)) > pHead) ) { listRemoveHead() ; }
if ((pTail+(cchDebug+1)+2) > pEndOfBuffer) { for ( ; pTail < pEndOfBuffer-1 ; pTail++ ) { *pTail = 'X' ; } *pTail = '\0' ; pTail = pStartOfBuffer ; } else { lstrcpyn(pTail, lpszDebug, pEndOfBuffer-pTail) ; pTail += (cchDebug+1) ; *pTail = '\0' ; break ; }
} }
//--------------------------------------------------------------------------;
//
// DbgDumpQueue
//
// Description:
//
// Arguments:
//
// Return (void):
// No value is returned.
//
//--------------------------------------------------------------------------;
VOID DbgDumpQueue() { char* pszDebug;
pszDebug = listGetHead() ;
while ('\0' != *pszDebug) { OutputDebugString(pszDebug) ; listRemoveHead() ; pszDebug = listGetHead() ;
} return; }
//--------------------------------------------------------------------------;
//
// void DbgQueueString
//
// Description:
//
//
// Arguments:
// LPSTR sz:
//
// Return (void):
// No value is returned.
//
//--------------------------------------------------------------------------;
void DbgQueueString(LPSTR pString) { listAddTail(pString); }
//--------------------------------------------------------------------------;
//
// void DbgVPrintF
//
// Description:
//
//
// Arguments:
// LPSTR szFormat:
//
// va_list va:
//
// Return (void):
// No value is returned.
//
//--------------------------------------------------------------------------;
void FAR CDECL DbgVPrintF ( LPSTR szFormat, va_list va ) { char ach[DEBUG_MAX_LINE_LEN]; BOOL fDebugBreak = FALSE; BOOL fPrefix = TRUE; BOOL fCRLF = TRUE; BOOL fQueue = FALSE; BOOL fDumpQueue = FALSE;
ach[0] = '\0';
for (;;) { switch (*szFormat) { case '!': fDebugBreak = TRUE; szFormat++; continue;
case '`': fPrefix = FALSE; szFormat++; continue;
case '~': fCRLF = FALSE; szFormat++; continue;
case ';': fQueue = TRUE; if (';' == *(szFormat+1)) { fQueue = FALSE; fDumpQueue = TRUE; szFormat++; } szFormat++; continue; }
break; }
if (fDebugBreak) { ach[0] = '\007'; ach[1] = '\0'; }
if (fPrefix) { lstrcatA(ach, DEBUG_MODULE_NAME ": "); }
#ifdef WIN95
{ char *psz = NULL; char szDfs[1024]={0}; strcpy(szDfs,szFormat); // make a local copy of format string
while (psz = strstr(szDfs,"%p")) // find each %p
*(psz+1) = 'x'; // replace each %p with %x
#ifdef _WIN32
wvsprintfA(ach + lstrlenA(ach), szDfs, va); // use the local format string
#else
wvsprintf(ach + lstrlenA(ach), szDfs, (LPSTR)va); // use the local format string
#endif
} #else
{ #ifdef _WIN32
wvsprintfA(ach + lstrlenA(ach), szFormat, va); #else
wvsprintf(ach + lstrlenA(ach), szFormat, (LPSTR)va); #endif
} #endif
if (fCRLF) { lstrcatA(ach, "\r\n"); }
if (fDumpQueue) { DbgDumpQueue(); }
if (fQueue) { DbgQueueString(ach); } else { OutputDebugStringA(ach); }
if (fDebugBreak) { DebugBreak(); } } // DbgVPrintF()
#endif // USERPF || USEDPF
#ifdef USEDPF
//--------------------------------------------------------------------------;
//
// void dprintf
//
// Description:
// dprintf() is called by the DPF() macro if DEBUG is defined at compile
// time. It is recommended that you only use the DPF() macro to call
// this function--so you don't have to put #ifdef DEBUG around all
// of your code.
//
// Arguments:
// UINT uDbgLevel:
//
// LPSTR szFormat:
//
// Return (void):
// No value is returned.
//
//--------------------------------------------------------------------------;
void FAR CDECL dprintf ( UINT uDbgLevel, LPSTR szFormat, ... ) { va_list va;
if (!__gfDbgEnabled || (__guDbgLevel < uDbgLevel)) return;
va_start(va, szFormat); DbgVPrintF(szFormat, va); va_end(va); } // dprintf()
//--------------------------------------------------------------------------;
//
// BOOL DbgEnable
//
// Description:
//
//
// Arguments:
// BOOL fEnable:
//
// Return (BOOL):
// Returns the previous debugging state.
//
//--------------------------------------------------------------------------;
BOOL WINAPI DbgEnable ( BOOL fEnable ) { BOOL fOldState;
fOldState = __gfDbgEnabled; __gfDbgEnabled = fEnable;
return (fOldState); } // DbgEnable()
//--------------------------------------------------------------------------;
//
// UINT DbgSetLevel
//
// Description:
//
//
// Arguments:
// UINT uLevel:
//
// Return (UINT):
// Returns the previous debugging level.
//
//--------------------------------------------------------------------------;
UINT WINAPI DbgSetLevel ( UINT uLevel ) { UINT uOldLevel;
uOldLevel = __guDbgLevel; __guDbgLevel = uLevel;
return (uOldLevel); } // DbgSetLevel()
//--------------------------------------------------------------------------;
//
// UINT DbgGetLevel
//
// Description:
//
//
// Arguments:
// None.
//
// Return (UINT):
// Returns the current debugging level.
//
//--------------------------------------------------------------------------;
UINT WINAPI DbgGetLevel ( void ) { return (__guDbgLevel); } // DbgGetLevel()
//--------------------------------------------------------------------------;
//
// UINT DbgInitialize
//
// Description:
//
//
// Arguments:
// BOOL fEnable:
//
// Return (UINT):
// Returns the debugging level that was set.
//
//--------------------------------------------------------------------------;
UINT WINAPI DbgInitialize ( BOOL fEnable ) { UINT uLevel;
uLevel = GetProfileIntA(DEBUG_SECTION, DEBUG_MODULE_NAME, (UINT)-1); if ((UINT)-1 == uLevel) { //
// if the debug key is not present, then force debug output to
// be disabled. this way running a debug version of a component
// on a non-debugging machine will not generate output unless
// the debug key exists.
//
uLevel = 0; fEnable = FALSE; }
DbgSetLevel(uLevel); DbgEnable(fEnable);
return (__guDbgLevel); } // DbgInitialize()
#endif // #ifdef USEDPF
//--------------------------------------------------------------------------;
//
// void _Assert
//
// Description:
// This routine is called if the ASSERT macro (defined in debug.h)
// tests and expression that evaluates to FALSE. This routine
// displays an "assertion failed" message box allowing the user to
// abort the program, enter the debugger (the "retry" button), or
// ignore the assertion and continue executing. The message box
// displays the file name and line number of the _Assert() call.
//
// Arguments:
// char * szFile: Filename where assertion occurred.
// int iLine: Line number of assertion.
//
//--------------------------------------------------------------------------;
#ifdef USEASSERT
#ifndef _WIN32
#pragma warning(disable:4704)
#endif
void WINAPI _Assert ( char * szFile, int iLine, char * szExpression ) { static char ach[400]; // debug output (avoid stack overflow)
int id; #ifndef _WIN32
int iExitCode; #endif
#ifdef DEBUG
if (__gfDbgEnabled) { wsprintfA(ach, "Assertion failed in file %s, line %d: (%s)", (LPSTR)szFile, iLine, (LPSTR)szExpression); OutputDebugString(ach); DebugBreak(); } else #endif
{ wsprintfA(ach, "Assertion failed in file %s, line %d: (%s) [Press RETRY to debug.]", (LPSTR)szFile, iLine, (LPSTR)szExpression);
id = MessageBoxA(NULL, ach, "Assertion Failed", MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE );
switch (id) {
case IDABORT: // Kill the application.
#ifndef _WIN32
iExitCode = 0; _asm { mov ah, 4Ch; mov al, BYTE PTR iExitCode; int 21h; } #else
FatalAppExit(0, TEXT("Good Bye")); #endif // WIN16
break;
case IDRETRY: // Break into the debugger.
DebugBreak(); break;
case IDIGNORE: // Ignore assertion, continue executing.
break; } } } // _Assert
#endif // #ifdef USEASSERT
//--------------------------------------------------------------------------;
//
// void rprintf
//
// Description:
// rprintf() is called by the RPF() macro. It is just like dprintf,
// except that there is no level defined. RPF statements always
// translate to a debug output, regardless of level.
//
// Arguments:
// LPSTR szFormat:
//
// Return (void):
// No value is returned.
//
//--------------------------------------------------------------------------;
#ifdef USERPF
void CDECL rprintf ( LPSTR szFormat, ... ) { va_list va;
va_start(va, szFormat); DbgVPrintF(szFormat, va); va_end(va); }
#endif // USERPF
#ifndef _WIN32
#pragma warning(default:4704)
#endif
|