Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1109 lines
26 KiB

//==========================================================================;
//
// Copyright (c) 1991-1995 Microsoft Corporation
//
// You have a royalty-free right to use, modify, reproduce and
// distribute the Sample Files (and/or any modified version) in
// any way you find useful, provided that you agree that
// Microsoft has no warranty obligations or liability for any
// Sample Application Files which are modified.
//
//--------------------------------------------------------------------------;
//
// debug.c
//
// Description:
// This file contains code yanked from several places to provide debug
// support that works in win 16 and win 32.
//
// History:
// 11/23/92 cjp [curtisp]
//
//==========================================================================;
#ifdef DEBUG
#include <windows.h>
#include <windowsx.h>
#include <mmsystem.h>
#include <stdarg.h>
#include "debug.h"
#ifdef WIN32
#define BCODE
#else
#define BCODE __based(__segname("_CODE"))
#endif // End #ifdef WIN32
#ifdef WIN32
#define GlobalSmartPageLock(a) (TRUE)
#endif // End #ifdef WIN32
#define WSPRINTF_LIMIT 1024
typedef struct tagLOG
{
LPTSTR lpszQueue; // TCHAR Representation
UINT cchBuffer; // Size of Log in TCHAR's
UINT idxRead; // Read index
UINT idxWrite; // Write index
} LOG, FAR *LPLOG;
#define LOG_INCIDX(pl,x) ((++x >= pl->cchBuffer) ? x = 0 : x)
void FAR CDECL DbgVPrintF (LPTSTR szFmt, va_list va);
BOOL NEAR PASCAL LogInit (LPLOG lpLog, UINT ckBuffer);
void NEAR PASCAL LogWrite (LPLOG lpLog, LPTSTR lpstrEvent);
BOOL NEAR PASCAL LogRead (LPLOG lpLog, LPTSTR lpstrBuffer, UINT cchBuffer);
#ifdef ISRDEBUG
int wivsprintf (LPTSTR lpOut, LPCTSTR lpFmt, VOID FAR* lpParms) ;
LPCTSTR NEAR PASCAL SP_GetFmtValue (LPCTSTR lpch, UINT * lpw) ;
UINT NEAR PASCAL SP_PutNumber (LPTSTR lpb, DWORD n, UINT limit, UINT radix, UINT icase) ;
VOID NEAR PASCAL SP_Reverse (LPTSTR lpFirst, LPTSTR lpLast) ;
UINT NEAR PASCAL ilstrlen (LPTSTR lpstr) ;
VOID NEAR PASCAL ilstrcat (LPTSTR lpstrDest, LPTSTR lpstrSrc) ;
#endif
//
// Use interruptable versions of functions
//
#ifdef ISRDEBUG
#define wvsprintf wivsprintf
#define lstrcat ilstrcat
#define lstrlen ilstrlen
#endif
//
//
//
BOOL __gfDbgEnabled = TRUE; // master enable
UINT __guDbgLevel = 0; // current debug level
BOOL __gfLogging = 0; // Are we logging as well?
HWND ghWndCB = (HWND)NULL;
LOG gLog;
WORD wDebugLevel = 0;
//************************************************************************
//**
//** WinAssert();
//**
//** DESCRIPTION:
//**
//**
//** ARGUMENTS:
//** LPSTR lpstrExp
//** LPSTR lpstrFile
//** DWORD dwLine
//**
//** RETURNS:
//** void
//**
//** HISTORY:
//**
//************************************************************************
VOID WINAPI WinAssert(
LPSTR lpstrExp,
LPSTR lpstrFile,
DWORD dwLine)
{
static TCHAR szWork[256];
static TCHAR BCODE szFormat[] =
TEXT ("Assertion failed!\n\nFile:\t%s\nLine:\t%lu\n\n[%s]");
static TCHAR BCODE szOops[] =
DEBUG_MODULE_NAME TEXT (" is confused");
// Use regular wsprintf here; assert's can't be at interrupt time
// anyway.
//
#ifdef UNICODE
static TCHAR szFile[256];
static TCHAR szMsg[256];
// Convert File to UNICODE
INT cLen = lstrlenA (lpstrFile);
if (cLen >= 255)
cLen = 255;
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
lpstrFile, cLen, szFile, 256);
szFile[cLen] = 0;
// Convert Message to UNICODE
cLen = lstrlenA (lpstrExp);
if (cLen >= 255)
cLen = 255;
MultiByteToWideChar (CP_ACP, MB_PRECOMPOSED,
lpstrExp, cLen, szMsg, 256);
szMsg[cLen] = 0;
// Create Assert String
wsprintf (szWork, szFormat, szFile, dwLine, szMsg);
#else
wsprintf (szWork, szFormat, lpstrFile, dwLine, lpstrExp);
#endif
if (IDCANCEL == MessageBox(NULL, szWork, szOops, MB_OKCANCEL|MB_ICONEXCLAMATION))
DebugBreak();
}
//************************************************************************
//**
//** DbgVPrintF();
//**
//** DESCRIPTION:
//**
//**
//** ARGUMENTS:
//** LPSTR szFmt
//** LPSTR va
//**
//** RETURNS:
//** void
//**
//** HISTORY:
//**
//************************************************************************
void FAR CDECL DbgVPrintF(
LPTSTR szFmt,
va_list va)
{
TCHAR ach[DEBUG_MAX_LINE_LEN];
BOOL fDebugBreak = FALSE;
BOOL fPrefix = TRUE;
BOOL fCRLF = TRUE;
ach[0] = TEXT ('\0');
for (;;)
{
switch(*szFmt)
{
case '!':
fDebugBreak = TRUE;
szFmt++;
continue;
case '`':
fPrefix = FALSE;
szFmt++;
continue;
case '~':
fCRLF = FALSE;
szFmt++;
continue;
}
break;
}
if (fDebugBreak)
{
ach[0] = TEXT ('\007');
ach[1] = TEXT ('\0');
}
if (fPrefix)
lstrcat (ach, DEBUG_MODULE_NAME TEXT (": "));
wvsprintf (ach + lstrlen(ach), szFmt, va);
if (fCRLF)
lstrcat (ach, TEXT ("\r\n") );
if (__gfLogging)
{
LogWrite (&gLog, ach);
if (ghWndCB)
PostMessage (ghWndCB, WM_DEBUGUPDATE, 0, 0);
}
OutputDebugString (ach);
if (fDebugBreak)
DebugBreak();
} //** DbgVPrintF()
//************************************************************************
//**
//** dprintf();
//**
//** DESCRIPTION:
//** dprintf() is called by the DPF macro if DEBUG is defined at compile
//** time.
//**
//** The messages will be send to COM1: like any debug message. To
//** enable debug output, add the following to WIN.INI :
//**
//** [debug]
//** ICSAMPLE=1
//**
//**
//** ARGUMENTS:
//** UINT uDbgLevel
//** LPCSTR szFmt
//** ...
//**
//** RETURNS:
//** void
//**
//** HISTORY:
//** 06/12/93 [t-kyleb]
//**
//************************************************************************
void FAR CDECL dprintf(
UINT uDbgLevel,
LPTSTR szFmt,
...)
{
va_list va;
if (!__gfDbgEnabled || (__guDbgLevel < uDbgLevel))
return;
va_start (va, szFmt);
DbgVPrintF (szFmt, va);
va_end (va);
} //** dprintf()
//************************************************************************
//**
//** DbgEnable();
//**
//** DESCRIPTION:
//**
//**
//** ARGUMENTS:
//** BOOL fEnable
//**
//** RETURNS:
//** BOOL
//**
//** HISTORY:
//** 06/12/93 [t-kyleb]
//**
//************************************************************************
BOOL WINAPI DbgEnable(
BOOL fEnable)
{
BOOL fOldState;
fOldState = __gfDbgEnabled;
__gfDbgEnabled = fEnable;
return (fOldState);
} //** DbgEnable()
//************************************************************************
//**
//** DbgSetLevel();
//**
//** DESCRIPTION:
//**
//**
//** ARGUMENTS:
//** UINT uLevel
//**
//** RETURNS:
//** UINT
//**
//** HISTORY:
//** 06/12/93 [t-kyleb]
//**
//************************************************************************
UINT WINAPI DbgSetLevel(
UINT uLevel)
{
UINT uOldLevel;
uOldLevel = __guDbgLevel;
__guDbgLevel = wDebugLevel = uLevel;
return (uOldLevel);
} //** DbgSetLevel()
//--------------------------------------------------------------------------;
//
// UINT DbgInitialize(void)
//
// Description:
//
//
// Arguments:
//
// Return (UINT):
//
//
// History:
// 11/24/92 cjp [curtisp]
//
//--------------------------------------------------------------------------;
UINT WINAPI DbgInitialize(BOOL fEnable)
{
TCHAR szTemp[64];
LPTSTR pstr;
UINT uLevel;
UINT uLogMem;
GetProfileString (DEBUG_SECTION, DEBUG_MODULE_NAME, TEXT (""), szTemp, sizeof(szTemp));
pstr = szTemp;
uLevel = 0;
while (*pstr >= TEXT ('0') && *pstr <= TEXT ('9'))
{
uLevel = uLevel*10 + (UINT)(*pstr - TEXT ('0'));
pstr++;
}
__gfLogging = FALSE;
if (*pstr == TEXT (','))
{
pstr++;
uLogMem = 0;
while (*pstr >= TEXT ('0') && *pstr <= TEXT ('9'))
{
uLogMem = uLogMem*10 + (UINT)(*pstr - TEXT ('0'));
pstr++;
}
if (0 == uLogMem)
uLogMem = K_DEFAULT_LOGMEM;
if (uLogMem > K_MAX_LOGMEM)
uLogMem = K_MAX_LOGMEM;
__gfLogging = TRUE;
}
if (__gfLogging)
__gfLogging = LogInit(&gLog, uLogMem);
DbgSetLevel (GetProfileInt(DEBUG_SECTION, DEBUG_MODULE_NAME, 0));
DbgEnable (fEnable);
return (__guDbgLevel);
} // DbgInitialize()
void WINAPI DbgRegisterCallback (HWND hWnd)
{
ghWndCB = hWnd;
}
BOOL WINAPI DbgGetNextLogEntry (LPTSTR lpstrBuffer, UINT cchBuffer)
{
if (!__gfLogging)
return FALSE;
return LogRead (&gLog, lpstrBuffer, cchBuffer);
}
BOOL NEAR PASCAL LogInit (LPLOG lpLog, UINT ckMem)
{
DWORD cbMem = 1024L * ckMem;
LPTSTR lpszQueue = GlobalAllocPtr (GPTR, cbMem);
if (NULL == lpszQueue)
return FALSE;
if (! GlobalSmartPageLock (HIWORD(lpszQueue)))
{
GlobalFreePtr (lpszQueue);
return FALSE;
}
lpLog->lpszQueue = (LPTSTR)lpszQueue;
lpLog->cchBuffer = (UINT)cbMem/sizeof(TCHAR);
lpLog->idxRead = 0;
lpLog->idxWrite = 0;
return TRUE;
}
void NEAR PASCAL LogWrite (LPLOG lpLog, LPTSTR lpstrEvent)
{
if (!*lpstrEvent)
return;
while (*lpstrEvent)
{
lpLog->lpszQueue[lpLog->idxWrite] = *lpstrEvent++;
LOG_INCIDX (lpLog,lpLog->idxWrite);
}
lpLog->idxRead = lpLog->idxWrite;
while (lpLog->lpszQueue[lpLog->idxRead])
{
lpLog->lpszQueue[lpLog->idxRead] = TEXT ('\0');
LOG_INCIDX(lpLog,lpLog->idxRead);
}
LOG_INCIDX(lpLog,lpLog->idxRead);
LOG_INCIDX(lpLog,lpLog->idxWrite);
}
BOOL NEAR PASCAL LogRead(LPLOG lpLog, LPTSTR lpstrBuffer, UINT cchBuffer)
{
TCHAR ch;
UINT idx;
if (!cchBuffer)
return FALSE;
idx = lpLog->idxRead;
while (TEXT ('\0') == lpLog->lpszQueue[idx])
{
LOG_INCIDX(lpLog,idx);
if (idx == lpLog->idxRead)
return FALSE;
}
cchBuffer--;
while (0 != (ch = lpLog->lpszQueue[idx]))
{
if (cchBuffer)
{
*lpstrBuffer++ = ch;
cchBuffer--;
}
lpLog->lpszQueue[idx] = TEXT ('\0');
LOG_INCIDX(lpLog,idx);
}
*lpstrBuffer = TEXT ('\0');
LOG_INCIDX (lpLog,idx);
lpLog->idxRead = idx;
return TRUE;
}
//--------------------------------------------------------------------------;
//
// The rest of the code is only needed if we're in Win16 and need to be
// interrupt callable.
//
//--------------------------------------------------------------------------;
#ifdef ISRDEBUG
#define OUT(ch) if (--cchLimit) *lpOut++=(ch); else goto error_Out
//************************************************************************
//**
//** wivsprintf();
//**
//** DESCRIPTION:
//** Interrupt callable version of wvsprintf()
//**
//**
//** ARGUMENTS:
//** LPTSTR lpOut - Buffer to format into.
//** LPCTSTR lpFmt - Format string.
//** VOID FAR* lpParms - Points to the first of args
//** described by lpFmt.
//**
//** RETURNS:
//** int - Number of characters stored.
//**
//** HISTORY:
//** 3/28/93 jfg [jimge]
//**
//************************************************************************
int wivsprintf(
LPTSTR lpOut,
LPCTSTR lpFmt,
VOID FAR* lpParms)
{
int left ;
TCHAR prefix ;
int width ;
int prec ;
TCHAR fillch ;
int size ;
int sign ;
int radix ;
int upper ;
int cchLimit = WSPRINTF_LIMIT;
int cch ;
LPTSTR lpT ;
union
{
long l ;
unsigned long ul ;
TCHAR sz[sizeof(long)] ;
} val;
while (*lpFmt)
{
if (*lpFmt==TEXT ('%'))
{
//
// Read the format flags.
//
left = 0 ;
prefix = 0 ;
while (*++lpFmt)
{
if (*lpFmt==TEXT ('-'))
{
left++;
}
else if (*lpFmt==TEXT ('#'))
{
prefix++;
}
else
{
break;
}
}
//
// Find the fill character (either '0' or ' ')
//
if (*lpFmt==TEXT ('0'))
{
fillch = TEXT ('0') ;
lpFmt++ ;
}
else
{
fillch = TEXT (' ') ;
}
//
// Now parse [width[.precision]]
//
lpFmt = SP_GetFmtValue(lpFmt,&cch);
width = cch;
if (*lpFmt==TEXT ('.'))
{
lpFmt = SP_GetFmtValue(++lpFmt,&cch);
prec = cch;
}
else
{
prec = (UINT)-1 ;
}
//
// Get the operand size modifier
//
if (*lpFmt==TEXT ('l'))
{
size = 1 ;
lpFmt++ ;
}
else
{
size = 0 ;
if (*lpFmt==TEXT ('h'))
{
lpFmt++ ;
}
}
//
// We've gotten all the modifier; now format the output
// based on the type (which should now be pointed at
// by lpFmt).
//
upper = 0 ;
sign = 0 ;
radix = 10 ;
switch (*lpFmt)
{
case 0:
goto error_Out ;
case TEXT ('i') :
case TEXT ('d') :
sign++ ;
case TEXT ('u'):
//
// Don't show a prefix for decimal formats
//
prefix=0 ;
do_Numeric:
//
// Special cases to act like MSC v5.10
//
if (left || prec>=0)
{
fillch = TEXT (' ');
}
//
// Get value from parm list into val union
//
if (size)
{
val.l=*((long far *)lpParms)++;
}
else
{
if (sign)
{
val.l=(long)*((short far *)lpParms)++;
}
else
{
val.ul=(unsigned long)*((unsigned far *)lpParms)++;
}
}
//
// Save sign of val.l in sign and set val.l positive.
//
if (sign && val.l<0L)
{
val.l=-val.l;
}
else
{
sign=0;
}
//
// Save start of output stream for later reverse
//
lpT = lpOut;
//
// Blast the number backwards into the user buffer
//
cch = SP_PutNumber(lpOut,val.l,cchLimit,radix,upper) ;
if (!(cchLimit-=cch))
goto error_Out ;
lpOut += cch ;
width -= cch ;
prec -= cch ;
if (prec>0)
{
width -= prec ;
}
//
// Fill in up to precision
//
while (prec-- > 0)
{
OUT(TEXT ('0')) ;
}
if (width>0 && !left)
{
//
// If we're filling with spaces, put sign first
//
if (fillch != '0')
{
if (sign)
{
sign = 0 ;
OUT(TEXT ('-')) ;
width-- ;
}
if (prefix)
{
OUT(prefix) ;
OUT(TEXT ('0')) ;
prefix = 0 ;
}
}
if (sign)
{
width-- ;
}
//
// Now fill to width
//
while (width-- > 0)
{
OUT(fillch) ;
}
//
// Still have a sign?
//
if (sign)
{
OUT(TEXT ('-')) ;
}
if (prefix)
{
OUT(prefix) ;
OUT(TEXT ('0')) ;
}
//
// Now reverse the string in place
//
SP_Reverse(lpT,lpOut-1);
}
else
{
//
// Add the sign character
//
if (sign)
{
OUT(TEXT ('-')) ;
width-- ;
}
if (prefix)
{
OUT(prefix);
OUT(TEXT ('0'));
}
//
// Now reverse the string in place
//
SP_Reverse(lpT,lpOut-1);
//
// Pad to the right of the string in case left aligned
//
while (width-- > 0)
{
OUT(fillch) ;
}
}
break ;
case TEXT ('X'):
upper++ ;
//
// Falling through...
//
case TEXT ('x'):
radix=16 ;
if (prefix)
{
prefix = upper ? TEXT ('X') : TEXT ('x') ;
}
goto do_Numeric ;
case TEXT ('c'):
//
// Save as one character string and join common code
//
val.sz[0] = *((TCHAR far*)lpParms) ;
val.sz[1] = 0 ;
lpT = val.sz ;
cch = 1 ;
// Note: this may need to be fixed for UNICODE
(BYTE far*)lpParms += sizeof(WORD) ;
goto put_String ;
case 's':
lpT = *((LPTSTR FAR *)lpParms)++ ;
cch = ilstrlen(lpT) ;
put_String:
if (prec>=0 && cch>prec)
{
cch = prec ;
}
width -= cch ;
if (left)
{
while (cch--)
{
OUT(*lpT++) ;
}
while (width-->0)
{
OUT(fillch) ;
}
}
else
{
while (width-- > 0)
{
OUT(fillch) ;
}
while (cch--)
{
OUT(*lpT++) ;
}
}
break ;
default:
//
// An unsupported type character was given. We just
// print the character and go on.
//
OUT(*lpFmt) ;
break ;
} // switch(*lpfmt)
} // if (*lpfmt == '%')
else
{
//
// Normal not-format character
//
OUT(*lpFmt) ;
}
lpFmt++ ;
} // while (*lpFmt)
error_Out:
*lpOut = 0 ;
return WSPRINTF_LIMIT-cchLimit ;
} //** wivsprintf()
//************************************************************************
//**
//** SP_GetFmtValue();
//**
//** DESCRIPTION:
//** Parse a decimal integer forming part of a format string.
//**
//**
//** ARGUMENTS:
//** LPCSTR lpch - Points to the string to parse.
//** LPWORD lpw - Points to a word where the value will be
//** returned.
//**
//** RETURNS:
//** LPCSTR - Pointer of first character past the format value.
//**
//** HISTORY:
//** 3/28/93 jfg [jimge]
//**
//************************************************************************
LPCTSTR NEAR PASCAL SP_GetFmtValue(
LPCTSTR lpch,
UINT * lpw)
{
UINT i = 0 ;
while (*lpch>=TEXT ('0') && *lpch<=TEXT ('9'))
{
i *= 10;
i += (UINT)(*lpch++-TEXT ('0'));
}
*lpw = i;
return(lpch);
} //** SP_GetFmtValue()
//************************************************************************
//**
//** SP_PutNumber();
//**
//** DESCRIPTION:
//** Formats the given number in the given radix into the buffer
//** *backwards*. The entire string will be reversed after printf
//** has added sign, prefix, etc. to it.
//**
//**
//** ARGUMENTS:
//** LPSTR lpb - Points to the output buffer.
//** DWORD n - Number to convert.
//** UINT limit - Maximum number of characters to store.
//** UINT radix - Base to format in.
//** UINT icase - Non-zero if the string should be upper case (hex).
//**
//** RETURNS:
//** UINT - Number of characters output.
//**
//** HISTORY:
//**
//************************************************************************
UINT NEAR PASCAL SP_PutNumber(
LPTSTR lpb,
DWORD n,
UINT limit,
UINT radix,
UINT icase)
{
TCHAR bTemp;
UINT cchStored = 0;
//
// Set icase to the offset to add to the character if it
// represents a value > 10
//
icase = (icase ? TEXT ('A') : TEXT ('a')) - TEXT ('0') - 10 ;
while (limit--)
{
bTemp = TEXT ('0') + (TCHAR)(n%radix);
if (bTemp > TEXT ('9'))
{
bTemp += icase ;
}
*lpb++ = bTemp;
++cchStored;
n /= radix;
if (n == 0)
{
break ;
}
}
return cchStored ;
} //** SP_PutNumber()
//************************************************************************
//**
//** SP_Reverse();
//**
//** DESCRIPTION:
//** Reverse string in place.
//**
//** ARGUMENTS:
//** LPSTR pFirst
//** LPSTR pLast
//**
//** RETURNS:
//** VOID
//**
//** HISTORY:
//**
//************************************************************************
VOID NEAR PASCAL SP_Reverse(
LPTSTR pFirst,
LPTSTR pLast)
{
UINT uSwaps = (pLast - pFirst + sizeof(TCHAR)) / (2 * sizeof(TCHAR));
TCHAR bTemp;
while (uSwaps--)
{
bTemp = *pFirst;
*pFirst = *pLast;
*pLast = bTemp;
pFirst++, pLast--;
}
} //** SP_Reverse()
//************************************************************************
//**
//** ilstrlen();
//**
//** DESCRIPTION:
//** Interrupt callable version of strlen().
//**
//** ARGUMENTS:
//** LPSTR pstr
//**
//** RETURNS:
//** UINT
//**
//** HISTORY:
//**
//************************************************************************
UINT NEAR PASCAL ilstrlen(
LPTSTR pstr)
{
UINT cch = 0 ;
while (*pstr++)
++cch;
return(cch);
} //** ilstrlen()
//************************************************************************
//**
//** ilstrcat();
//**
//** DESCRIPTION:
//** Interrupt callable version of lstrcat().
//**
//** ARGUMENTS:
//** LPSTR pstrDest
//** LPSTR pstrSrc
//**
//** RETURNS:
//** VOID
//**
//** HISTORY:
//**
//************************************************************************
VOID NEAR PASCAL ilstrcat(
LPTSTR pstrDest,
LPTSTR pstrSrc)
{
while (*pstrDest)
pstrDest++;
while (*pstrDest++ = *pstrSrc++)
;
} //** ilstrcat()
#endif // #ifdef ISRDEBUG
#endif // #ifdef DEBUG