/* common.c
 *
 * Common functions useful for Windows programs.
 */



#include <windows.h>
#include <stdarg.h>
#include <win32.h> 	// This must be included, for both versions

#ifdef DEBUG  // On NT, ntavi.h might do an undef debug...
#include "common.h"


/* globals */
int		giDebugLevel = 0;	// current debug level (0 = disabled)
int		gfhDebugFile = -1;	// file handle for debug output (or -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 = 0;
	gfhDebugFile = -1;

	/* get the debug output location */
        if ( (GetProfileStringA("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)
	{
                gfhDebugFile = _lopen(achLocation, OF_WRITE);
	}
        else
        if (lstrcmpiA(achLocation, "com2") == 0)
        {
                gfhDebugFile = _lopen(achLocation, OF_WRITE);
	}
	
	/* get the debug level */
	giDebugLevel = GetProfileIntA("debug", szAppName, 0);
}


/* TerminateDebugOutput()
 *
 * Terminate debug output for this application.
 */
void FAR PASCAL
TerminateDebugOutput(void)
{
	if (gfhDebugFile >= 0)
		_lclose(gfhDebugFile);
	gfhDebugFile = -1;
	giDebugLevel = 0;
}


/* _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)
#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, "(%s)\nFile %s, line %d", (LPSTR)szExp, (LPSTR)szFile, iLine);
        else
            wsprintfA(ach, "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>.
 */
void FAR CDECL
_DebugPrintf(LPSTR szFormat, ...)
{
	static char	ach[300];	// debug output (avoid stack overflow)
	int		cch;		// length of debug output string
        NPSTR           pchSrc, pchDst;

#ifndef WIN32
        wvsprintf(ach, szFormat, (LPVOID)(&szFormat+1));
#else
        va_list va;

        va_start(va, szFormat);
        wvsprintfA(ach, szFormat, va);
        va_end(va);
#endif

	/* 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';

	/* output the debug string */
	if (gfhDebugFile > 0)
		_lwrite(gfhDebugFile, ach, cch);
	else
		OutputDebugStringA(ach);
}

#endif