1110 lines
26 KiB
C
1110 lines
26 KiB
C
|
//==========================================================================;
|
||
|
//
|
||
|
// 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
|
||
|
|