235 lines
5.4 KiB
C
235 lines
5.4 KiB
C
/* common.c
|
|
*
|
|
* Common functions useful for Windows programs.
|
|
*/
|
|
|
|
|
|
|
|
//#include <windows.h>
|
|
#include <stdarg.h>
|
|
#include "graphic.h"
|
|
#include "profile.h"
|
|
|
|
#ifdef DEBUG // On NT, ntavi.h might do an undef debug...
|
|
#include "common.h"
|
|
|
|
/* globals */
|
|
int giDebugLevel = -1; // current debug level (0 = disabled)
|
|
int gfhDebugFile = -1; // file handle for debug output (or -1)
|
|
int giTimingLevel = -1;
|
|
|
|
|
|
/* InitializeDebugOutput(szAppName)
|
|
*
|
|
* Read the current debug level of this application (named <szAppName>)
|
|
* from the [debug] section of win.ini, as well as the current location
|
|
* for debug output.
|
|
*/
|
|
void FAR PASCAL
|
|
InitializeDebugOutput(LPSTR szAppName)
|
|
{
|
|
char achLocation[300]; // debug output location
|
|
|
|
/* debugging is disabled by default (and if an error occurs below) */
|
|
giDebugLevel = -1;
|
|
gfhDebugFile = -1;
|
|
|
|
/* get the debug output location */
|
|
if ( (mmGetProfileStringA("debug", "Location", "", achLocation,
|
|
sizeof(achLocation)) == sizeof(achLocation)) ||
|
|
(achLocation[0] == 0) )
|
|
return;
|
|
|
|
if (achLocation[0] == '>')
|
|
{
|
|
/* <achLocation> is the name of a file to overwrite (if
|
|
* a single '>' is given) or append to (if '>>' is given)
|
|
*/
|
|
if (achLocation[1] == '>')
|
|
gfhDebugFile = _lopen(achLocation + 2, OF_WRITE);
|
|
else
|
|
gfhDebugFile = _lcreat(achLocation + 1, 0);
|
|
|
|
if (gfhDebugFile < 0)
|
|
return;
|
|
|
|
if (achLocation[1] == '>')
|
|
_llseek(gfhDebugFile, 0, SEEK_END);
|
|
}
|
|
else
|
|
if (lstrcmpiA(achLocation, "aux") == 0)
|
|
{
|
|
/* use OutputDebugString() for debug output */
|
|
}
|
|
else
|
|
if ((lstrcmpiA(achLocation, "com1") == 0)
|
|
|| (lstrcmpiA(achLocation, "com2") == 0))
|
|
{
|
|
gfhDebugFile = _lopen(achLocation, OF_WRITE);
|
|
}
|
|
else
|
|
{
|
|
/* invalid "location=" -- keep debugging disabled */
|
|
return;
|
|
}
|
|
|
|
/* get the debug level */
|
|
giDebugLevel = mmGetProfileIntA("debug", szAppName, 0);
|
|
giTimingLevel = mmGetProfileIntA("debug", "Timing", 0);
|
|
}
|
|
|
|
|
|
/* TerminateDebugOutput()
|
|
*
|
|
* Terminate debug output for this application.
|
|
*/
|
|
void FAR PASCAL
|
|
TerminateDebugOutput(void)
|
|
{
|
|
if (gfhDebugFile >= 0)
|
|
_lclose(gfhDebugFile);
|
|
gfhDebugFile = -1;
|
|
giDebugLevel = -1;
|
|
}
|
|
|
|
|
|
/* _Assert(szExpr, szFile, iLine)
|
|
*
|
|
* If <fExpr> is TRUE, then do nothing. If <fExpr> is FALSE, then display
|
|
* an "assertion failed" message box allowing the user to abort the program,
|
|
* enter the debugger (the "Retry" button), or igore the error.
|
|
*
|
|
* <szFile> is the name of the source file; <iLine> is the line number
|
|
* containing the _Assert() call.
|
|
*/
|
|
#ifndef _WIN32
|
|
#pragma optimize("", off)
|
|
#define ASSERTPREFIX
|
|
#else
|
|
#define ASSERTPREFIX "(NT) "
|
|
#endif
|
|
|
|
void FAR PASCAL
|
|
_Assert(char *szExp, char *szFile, int iLine)
|
|
{
|
|
static char ach[300]; // debug output (avoid stack overflow)
|
|
int id;
|
|
int iExitCode;
|
|
void FAR PASCAL DebugBreak(void);
|
|
|
|
/* display error message */
|
|
|
|
if (szExp)
|
|
wsprintfA(ach, ASSERTPREFIX "(%s)\nFile %s, line %d", (LPSTR)szExp, (LPSTR)szFile, iLine);
|
|
else
|
|
wsprintfA(ach, ASSERTPREFIX "File %s, line %d", (LPSTR)szFile, iLine);
|
|
|
|
MessageBeep(MB_ICONHAND);
|
|
id = MessageBoxA(NULL, ach, "Assertion Failed",
|
|
#ifdef BIDI
|
|
MB_RTL_READING |
|
|
#endif
|
|
MB_SYSTEMMODAL | MB_ICONHAND | MB_ABORTRETRYIGNORE);
|
|
|
|
/* abort, debug, or ignore */
|
|
switch (id)
|
|
{
|
|
|
|
case IDABORT:
|
|
|
|
/* kill this application */
|
|
iExitCode = 0;
|
|
#ifndef _WIN32
|
|
_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 the assertion failure */
|
|
break;
|
|
}
|
|
}
|
|
#ifndef _WIN32
|
|
#pragma optimize("", on)
|
|
#endif
|
|
|
|
/* _DebugPrintf(szFormat, ...)
|
|
*
|
|
* If the application's debug level is at or above <iDebugLevel>,
|
|
* then output debug string <szFormat> with formatting codes
|
|
* replaced with arguments in the argument list pointed to by <szArg1>.
|
|
*/
|
|
#define MODNAME "MCIAVI"
|
|
void FAR CDECL
|
|
_DebugPrintf(LPSTR szFormat, ...)
|
|
{
|
|
static char ach[300]; // debug output (avoid stack overflow)
|
|
int cch; // length of debug output string
|
|
|
|
#ifndef _WIN32
|
|
NPSTR pchSrc, pchDst;
|
|
if (*szFormat == '!') {
|
|
++szFormat;
|
|
}
|
|
wvsprintf(ach, szFormat, (LPVOID)(&szFormat+1));
|
|
#else
|
|
UINT n;
|
|
va_list va;
|
|
|
|
va_start(va, szFormat);
|
|
if (*szFormat == '!') {
|
|
++szFormat;
|
|
n=0;
|
|
} else if (*szFormat=='.') {
|
|
n=0;
|
|
} else {
|
|
n = wsprintfA(ach, MODNAME ": (tid %x) ", GetCurrentThreadId());
|
|
}
|
|
wvsprintfA(ach+n, szFormat, va);
|
|
va_end(va);
|
|
#endif
|
|
|
|
#ifndef _WIN32
|
|
/* expand the newlines into carrige-return-line-feed pairs;
|
|
* first, figure out how long the new (expanded) string will be
|
|
*/
|
|
for (pchSrc = pchDst = ach; *pchSrc != 0; pchSrc++, pchDst++)
|
|
if (*pchSrc == '\n')
|
|
pchDst++;
|
|
|
|
/* is <ach> large enough? */
|
|
cch = pchDst - ach;
|
|
Assert(cch < sizeof(ach));
|
|
*pchDst-- = 0;
|
|
|
|
/* working backwards, expand \n's to \r\n's */
|
|
while (pchSrc-- > ach)
|
|
if ((*pchDst-- = *pchSrc) == '\n')
|
|
*pchDst-- = '\r';
|
|
|
|
#else
|
|
cch = strlen(ach);
|
|
#endif //no expansion on Win32
|
|
/* output the debug string */
|
|
if (gfhDebugFile > 0)
|
|
_lwrite(gfhDebugFile, ach, cch);
|
|
else {
|
|
OutputDebugStringA(ach);
|
|
}
|
|
}
|
|
|
|
#endif
|
|
|