741 lines
17 KiB
C
741 lines
17 KiB
C
/*** error.c - error handling functions
|
|
*
|
|
* Copyright <C> 1989, Microsoft Corporation
|
|
*
|
|
* Purpose:
|
|
* This module contains all error message functions and variuos
|
|
* functions that check if errror condition has occured.
|
|
*
|
|
* This Module contains Proprietary Information of Microsoft
|
|
* Corporation and should be treated as Confidential.
|
|
*
|
|
* Revision History:
|
|
*
|
|
* [WJK] 28-Jun-1990 Created
|
|
*
|
|
*************************************************************************/
|
|
|
|
#include <minlit.h> /* Types, constants */
|
|
#include <bndtrn.h> /* More types and constants */
|
|
#include <bndrel.h> /* Types and constants */
|
|
#include <lnkio.h> /* Linker I/O definitions */
|
|
#include <lnkmsg.h> /* Error messages */
|
|
#include <nmsg.h> /* Near message strings */
|
|
#include <extern.h> /* External declarations */
|
|
#include <string.h>
|
|
#if (defined(WIN_NT) OR defined(DOSX32)) AND (NOT defined( _WIN32 ))
|
|
#define i386
|
|
#endif
|
|
#include <stdarg.h>
|
|
#if EXE386
|
|
#include <exe386.h>
|
|
#endif
|
|
#if WIN_3
|
|
#include <windows.h>
|
|
#endif
|
|
#if NEWIO
|
|
#include <errno.h> /* System error codes */
|
|
#endif
|
|
|
|
#define DEBUG_WIN FALSE
|
|
#if DEBUG_WIN
|
|
char szDebugBuffer[80];
|
|
#define DEBUGW(parm1,parm2)\
|
|
{\
|
|
wsprintf(szDebugBuffer,parm1,(char far*)parm2);\
|
|
OutputDebugString(szDebugBuffer);\
|
|
}
|
|
#else
|
|
#define DEBUGW(parm1,parm2)
|
|
#endif
|
|
|
|
|
|
#if OSEGEXE AND NOT QCLINK
|
|
extern int yylineno; /* Current line in definitions file */
|
|
#else
|
|
#define yylineno -1
|
|
#endif
|
|
|
|
|
|
#if AUTOVM
|
|
extern BYTE FAR * NEAR FetchSym1(RBTYPE rb, WORD Dirty);
|
|
#define FETCHSYM FetchSym1
|
|
#else
|
|
#define FETCHSYM FetchSym
|
|
#endif
|
|
|
|
|
|
LOCAL char chErr = 'L'; /* Error message prefix */
|
|
|
|
|
|
/*
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*/
|
|
|
|
LOCAL void cdecl NEAR ErrSub(MSGTYPE msg, WORD fWarn, va_list pArgList);
|
|
LOCAL void vFmtPrint(char *fmt, va_list pArgList);
|
|
|
|
|
|
/*** ChkInput - check input file for I/O errors
|
|
*
|
|
* Purpose:
|
|
* Check if there were any I/O errors on input file.
|
|
*
|
|
* Input:
|
|
* No explicit value is passed. The global input file bsInput is
|
|
* used.
|
|
*
|
|
* Output:
|
|
* If everything is OK function returns, otherwise it calls Fatal
|
|
* with appropriate error message.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void ChkInput(void)
|
|
{
|
|
if (feof(bsInput))
|
|
Fatal(ER_eofobj);
|
|
else if (ferror(bsInput))
|
|
Fatal(ER_ioerr, strerror(errno));
|
|
}
|
|
|
|
// Comment : GetMsg and __NMSG_TEXT are generated by MKMSG [jp]
|
|
|
|
/*** ErrPrefix - write error message prefix
|
|
*
|
|
* Purpose:
|
|
* Write out error message prefix. If we are parsinf .DEF file or reading
|
|
* .OBJ files then the error message prefix takes form "<filename> : "
|
|
* otherwise this is "LINK : ".
|
|
*
|
|
* Input:
|
|
* No explicit value is passed.
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void ErrPrefix(void)
|
|
{
|
|
DisplayBanner();
|
|
if (fDrivePass || yylineno > 0)
|
|
OutFileCur(bsErr);
|
|
else
|
|
FmtPrint(lnknam);
|
|
FmtPrint(" : ");
|
|
}
|
|
|
|
#pragma check_stack(on)
|
|
|
|
/*** OutFileCur - write out current input file name
|
|
*
|
|
* Purpose:
|
|
* Write out current input file name. Used by error message functions.
|
|
* File name is written in the following formats:
|
|
* <filename>(nnn)
|
|
* <filename>(<modulename>)
|
|
* <filename>
|
|
*
|
|
* Input:
|
|
* bs - file to which current input file name is written
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void OutFileCur(BSTYPE bs)
|
|
{
|
|
APROPFILEPTR apropFile; /* Pointer to file property cell */
|
|
AHTEPTR ahte; /* Pointer symbol name */
|
|
BSTYPE bsTmp; /* Temporary file pointer */
|
|
SBTYPE fileName; /* File name buffer */
|
|
SBTYPE moduleName; /* Object module name */
|
|
int n; /* String length counter */
|
|
|
|
#if OSEGEXE
|
|
if (yylineno > 0)
|
|
{
|
|
apropFile = (APROPFILEPTR) FETCHSYM(rhteDeffile,FALSE);
|
|
ahte = GetHte(rhteDeffile);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
apropFile = (APROPFILEPTR ) FETCHSYM(vrpropFile,FALSE);
|
|
ahte = GetHte(vrpropFile);
|
|
}
|
|
bsTmp = bsErr;
|
|
bsErr = bs;
|
|
|
|
// Copy file name
|
|
|
|
n = (ahte->cch[0] < sizeof(fileName) - 1) ? ahte->cch[0] : sizeof(fileName) - 1;
|
|
FMEMCPY((char FAR *) fileName, &ahte->cch[1], n);
|
|
fileName[n] = '\0';
|
|
if (yylineno > 0)
|
|
FmtPrint("%s(%d)", fileName, yylineno);
|
|
else if (apropFile->af_rMod)
|
|
{
|
|
// Get object module name
|
|
|
|
ahte = (AHTEPTR ) FETCHSYM(apropFile->af_rMod,FALSE);
|
|
while(ahte->attr != ATTRNIL)
|
|
ahte = (AHTEPTR ) FETCHSYM(ahte->rhteNext,FALSE);
|
|
n = (ahte->cch[0] < sizeof(moduleName) - 1) ? ahte->cch[0] : sizeof(moduleName) - 1;
|
|
FMEMCPY((char FAR *) moduleName, &ahte->cch[1], n);
|
|
moduleName[n] = '\0';
|
|
FmtPrint("%s(%s)", fileName, moduleName);
|
|
|
|
}
|
|
else
|
|
FmtPrint("%s", fileName);
|
|
bsErr = bsTmp;
|
|
}
|
|
|
|
#pragma check_stack(off)
|
|
|
|
#if (QCLINK OR OSEGEXE) AND NOT EXE386
|
|
typedef int (cdecl FAR * FARFPTYPE)(char FAR *buf);
|
|
/* Far function pointer type */
|
|
extern FARFPTYPE FAR *pfQTab; /* Table of addresses */
|
|
#endif
|
|
|
|
/*** vFmtPrint - print formated message
|
|
*
|
|
* Purpose:
|
|
* Print on bsErr formated error or warning message.
|
|
* Check for any I/O errors.
|
|
*
|
|
* Input:
|
|
* fmt - error message format string
|
|
* pArgList - pointer to variable number of parameters desrcibing error message
|
|
* bsErr - error file - global variable
|
|
* bsLst - listing file - global variable
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* I/O errors. If error detected and stdout is an error file then silently
|
|
* exit to system with return code 4 (something must be terribly wrong
|
|
* if stdout is not working). If we are writing to listing file and
|
|
* error was detected then close listing file and notify user.
|
|
*
|
|
* Notes:
|
|
* This function handles output to QC enviroment.
|
|
*
|
|
*************************************************************************/
|
|
|
|
LOCAL void vFmtPrint(char *fmt, va_list pArgList)
|
|
{
|
|
#if WIN_3
|
|
char buf[512];
|
|
vsprintf(buf, fmt, pArgList);
|
|
ErrMsgWin(buf);
|
|
#if DEBUG_WIN2
|
|
OutputDebugString((char far*)"\r\nDebS: ");
|
|
OutputDebugString((char far*)buf);
|
|
#endif
|
|
#else
|
|
|
|
#if (QCLINK) AND NOT EXE386
|
|
SBTYPE buf;
|
|
if (fZ1)
|
|
{
|
|
// Output via QC call-back
|
|
|
|
vsprintf(buf, fmt, pArgList);
|
|
(*pfQTab[0])((char far *) buf);
|
|
}
|
|
else
|
|
#endif
|
|
{
|
|
vfprintf(bsErr, fmt, pArgList);
|
|
if (ferror(bsErr))
|
|
{
|
|
if (bsErr == stdout)
|
|
{
|
|
#if USE_REAL
|
|
RealMemExit();
|
|
#endif
|
|
exit(4);
|
|
}
|
|
else if (bsErr == bsLst)
|
|
{
|
|
fclose(bsLst);
|
|
fLstFileOpen = FALSE;
|
|
bsErr = stdout;
|
|
}
|
|
ExitCode = 4;
|
|
Fatal(ER_spclst);
|
|
}
|
|
fflush(bsErr);
|
|
}
|
|
#endif // WIN_3
|
|
}
|
|
|
|
/*** FmtPrint - print formated message
|
|
*
|
|
* Purpose:
|
|
* Print on bsErr formated error or warning message.
|
|
* Check for any I/O errors.
|
|
*
|
|
* Input:
|
|
* fmt - error message format string
|
|
* ... - variable number of parameters desrcibing error message
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* I/O errors.
|
|
*
|
|
* Notes:
|
|
* The actual job is done by the vFmtPrint.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void cdecl FmtPrint(char *fmt, ...)
|
|
{
|
|
va_list pArgList;
|
|
|
|
|
|
va_start(pArgList, fmt);
|
|
vFmtPrint(fmt, pArgList);
|
|
}
|
|
|
|
|
|
#if OSMSDOS AND NOT WIN_3
|
|
/*
|
|
* PromptStd : Standard prompt routine
|
|
*
|
|
* Display a warning message and prompt, with optional arguments.
|
|
* Optionally read a response into a given buffer. If the given
|
|
* buffer is null, get a yes/no response with <ENTER> being yes.
|
|
*
|
|
* Returns:
|
|
* TRUE if yes or response read.
|
|
* FALSE if no.
|
|
*/
|
|
int cdecl PromptStd (sbNew,msg,msgparm,pmt,pmtparm)
|
|
BYTE *sbNew; /* Buffer for response */
|
|
MSGTYPE msg; /* Error message */
|
|
int msgparm; /* Message parameter */
|
|
MSGTYPE pmt; /* Prompt */
|
|
int pmtparm; /* Prompt parameter */
|
|
{
|
|
register BYTE *p;
|
|
int ch;
|
|
int n;
|
|
|
|
if(msg)
|
|
OutWarn(msg, msgparm);
|
|
if(!pmt)
|
|
return(TRUE);
|
|
fprintf(stderr,GetMsg(pmt),pmtparm);
|
|
fflush(stderr); /* Flush stderr */
|
|
#if CPU286
|
|
flskbd(); /* Flush DOS keyboard buffer */
|
|
#endif
|
|
fflush(stdin); /* Flush console input */
|
|
if(sbNew != NULL)
|
|
{
|
|
/* Read response */
|
|
for(p = &sbNew[1], n = 0;
|
|
(ch = fgetc(stdin)) != '\n' && ch != EOF && n < sizeof(SBTYPE); )
|
|
{
|
|
#if CRLF
|
|
if(ch == '\r')
|
|
continue;
|
|
#endif
|
|
*p++ = (BYTE) ch;
|
|
n++;
|
|
}
|
|
sbNew[0] = (BYTE) n;
|
|
return(TRUE);
|
|
}
|
|
#if CRLF
|
|
if(fgetc(stdin) != '\r')
|
|
return(FALSE);
|
|
#endif
|
|
if(fgetc(stdin) != '\n')
|
|
return(FALSE);
|
|
return(TRUE);
|
|
}
|
|
#endif /* OSMSDOS */
|
|
|
|
/*
|
|
* CputcStd : standard console character output routine.
|
|
* Call fputc to stdout. Will be called through pfCputc.
|
|
*/
|
|
void CputcStd (ch)
|
|
int ch;
|
|
{
|
|
putc(ch,stdout);
|
|
if (ferror(stdout))
|
|
exit(4);
|
|
}
|
|
|
|
/*
|
|
* CputsStd : standard console string output routine
|
|
* Call fputs to stdout. Will be called through pfCputs.
|
|
*/
|
|
void CputsStd (str)
|
|
char *str;
|
|
{
|
|
fputs(str,stdout);
|
|
if (ferror(stdout))
|
|
{
|
|
#if USE_REAL
|
|
RealMemExit();
|
|
#endif
|
|
exit(4);
|
|
}
|
|
fflush(stdout);
|
|
}
|
|
|
|
/*** ErrSub - write out nonfatal error message
|
|
*
|
|
* Purpose:
|
|
* Fromat and write out nonfatal error message. If error message number
|
|
* is equal to zero then we treat it as a prompt.
|
|
*
|
|
* Input:
|
|
* msg - error message number
|
|
* fWarn - TRUE if this warnnig
|
|
* ... - variable number of parameters for message
|
|
* bsErr - error file - global variable
|
|
* bsLst - listing file - global variable
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
LOCAL void cdecl NEAR ErrSub(MSGTYPE msg, WORD fWarn, va_list pArgList)
|
|
{
|
|
|
|
if (fLstFileOpen && bsErr == bsLst && vgsnLineNosPrev)
|
|
{ /* If we've listed line numbers */
|
|
NEWLINE(bsErr); /* Newline */
|
|
vgsnLineNosPrev = 0; /* Reset */
|
|
}
|
|
if (msg)
|
|
{
|
|
/* If there is any message to print */
|
|
#if WIN_3
|
|
if(fWarn)
|
|
fSeverity=SEV_WARNING;
|
|
else
|
|
fSeverity=SEV_ERROR;
|
|
#endif
|
|
|
|
|
|
#if MSGMOD AND NOT WIN_3
|
|
if (msg >= 1000)
|
|
{
|
|
#endif
|
|
/* Error or warning */
|
|
|
|
ErrPrefix();
|
|
#if MSGMOD
|
|
FmtPrint("%s %c%04d: ",
|
|
fWarn ? __NMSG_TEXT(N_warning) : __NMSG_TEXT(N_error),
|
|
(int) chErr, msg);
|
|
#else
|
|
FmtPrint("%s: ",fWarn ? "warning" : "error");
|
|
#endif
|
|
vFmtPrint(GetMsg(msg), pArgList);
|
|
#if NOT WIN_3
|
|
#if QCLINK
|
|
if (fZ1)
|
|
FmtPrint("\n");
|
|
else
|
|
#endif
|
|
NEWLINE(bsErr);
|
|
#else
|
|
FmtPrint("\r\n");
|
|
// for the second part of the message
|
|
fSeverity = SEV_WARNING;
|
|
#endif
|
|
|
|
if (fDrivePass && !fWarn
|
|
#if MSGMOD
|
|
&& (msg >= 2005 && msg < 2022) || msg == 1101
|
|
#endif
|
|
)
|
|
FmtPrint("%s: %lx %s: %02x\r\n",
|
|
__NMSG_TEXT(N_pos),ftell(bsInput),
|
|
__NMSG_TEXT(N_rectyp),rect & 0xff);
|
|
|
|
#if MSGMOD AND NOT WIN_3
|
|
}
|
|
else
|
|
{
|
|
/* Prompt */
|
|
#if QCLINK
|
|
if (fZ1)
|
|
(*pfPrompt)(NULL, msg, (int) pArgList, 0, 0);
|
|
else
|
|
{
|
|
#endif
|
|
vFmtPrint(GetMsg(msg), pArgList);
|
|
NEWLINE(bsErr);
|
|
#if QCLINK
|
|
}
|
|
#endif
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/*** OutError - write out nonfatal error message
|
|
*
|
|
* Purpose:
|
|
* Top level function called when error message has to be displayed.
|
|
* Bumps the error counter and calls ErrSub to do the job.
|
|
*
|
|
* Input:
|
|
* msg - error message number
|
|
* ... - variable number of error parameters
|
|
*
|
|
* Output:
|
|
* No explicit value is returned. Global error counter cErrors is
|
|
* incremented.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void cdecl OutError(MSGTYPE msg, ...)
|
|
{
|
|
va_list pArgList;
|
|
|
|
va_start(pArgList, msg);
|
|
++cErrors; /* Increment error count */
|
|
ErrSub(msg, FALSE, pArgList);
|
|
}
|
|
|
|
/*** OutWarn - write out warning message
|
|
*
|
|
* Purpose:
|
|
* Top level function called when warning message has to be displayed.
|
|
* Calls ErrSub to do the job.
|
|
*
|
|
* Input:
|
|
* msg - error message number
|
|
* ... - variable number of error parameters
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
* incremented.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void cdecl OutWarn (MSGTYPE msg, ...)
|
|
{
|
|
va_list pArgList;
|
|
DEBUGW("\r\nOutWarn entered",0);
|
|
va_start(pArgList, msg);
|
|
ErrSub(msg, TRUE, pArgList);
|
|
}
|
|
|
|
/*** KillRunFile - delete .EXE file
|
|
*
|
|
* Purpose:
|
|
* Delete the .EXE file created by the linker.
|
|
*
|
|
* Input:
|
|
* No explicit value is passed.
|
|
* bsRunfile - output file handle - global variable.
|
|
* psbRun - output file name - global variable.
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void KillRunfile(void)
|
|
{
|
|
if (bsRunfile != NULL)
|
|
{
|
|
CloseFile(bsRunfile);
|
|
_unlink(&psbRun[1]);
|
|
}
|
|
}
|
|
|
|
/*** Fatal - write out fatal error message
|
|
*
|
|
* Purpose:
|
|
* Format and write out fatal error message. Terminate linker.
|
|
*
|
|
* Input:
|
|
* msg - error message number
|
|
* ... - variable number of message parameters
|
|
* bsLst - listing file - global variable
|
|
*
|
|
* Output:
|
|
* No explicit value is returned. Linker terminates.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* None.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void cdecl Fatal (MSGTYPE msg, ...)
|
|
{
|
|
static WORD cInvoked =0;
|
|
va_list pArgList;
|
|
|
|
va_start(pArgList, msg); /* Get start of argument list */
|
|
|
|
if (++cInvoked > 1) // Fatal during Fatal
|
|
{
|
|
#if USE_REAL
|
|
RealMemExit();
|
|
#endif
|
|
if (ExitCode)
|
|
EXIT(ExitCode);
|
|
else
|
|
EXIT(2); /* Program error */
|
|
}
|
|
|
|
/* If msg is nonzero then print a message */
|
|
|
|
if (msg)
|
|
{
|
|
if (fLstFileOpen)
|
|
fflush(bsLst);
|
|
ErrPrefix();
|
|
#if MSGMOD
|
|
FmtPrint("%s %c%04d: ", __NMSG_TEXT(N_fatal), chErr, msg);
|
|
#else
|
|
FmtPrint("fatal error: ");
|
|
#endif
|
|
vFmtPrint(GetMsg(msg), pArgList);
|
|
#if WIN_3
|
|
fSeverity = SEV_ERROR; // Send as error to QCwin
|
|
FmtPrint("\r\n");
|
|
#else
|
|
NEWLINE(stderr);
|
|
#endif
|
|
if(fDrivePass && ftell(bsInput)
|
|
#if MSGMOD
|
|
&& msg >= 2005 && msg < 2022 || msg == 1101
|
|
#endif
|
|
)
|
|
FmtPrint("%s: %lx %s: %02x\r\n",
|
|
__NMSG_TEXT(N_pos),ftell(bsInput),
|
|
__NMSG_TEXT(N_rectyp),rect & 0xff);
|
|
}
|
|
KillRunfile();
|
|
if (fLstFileOpen) fclose(bsLst);
|
|
#if OWNSTDIO
|
|
FlsStdio();
|
|
#endif
|
|
|
|
// If someone else assigned the exit code, use it. Otherwise,
|
|
// assume program error.
|
|
|
|
if (ExitCode)
|
|
EXIT(ExitCode);
|
|
else
|
|
EXIT(2); /* Program error */
|
|
}
|
|
|
|
/*** CtrlC - display Ctrl-C error message and die
|
|
*
|
|
* Purpose:
|
|
* Do minimal work required to display error message and die.
|
|
*
|
|
* Input:
|
|
* No explicit value is passed.
|
|
*
|
|
* Output:
|
|
* No explicit value is returned.
|
|
*
|
|
* Exceptions:
|
|
* None.
|
|
*
|
|
* Notes:
|
|
* This function doesn't return.
|
|
*
|
|
*************************************************************************/
|
|
|
|
void CtrlC(void)
|
|
{
|
|
#if USE_REAL
|
|
RealMemExit();
|
|
#endif
|
|
#ifdef OS2
|
|
if (_osmode == OS2_MODE)
|
|
fputs("\r\n", stdout);
|
|
#endif
|
|
|
|
#if DOSEXTENDER AND NOT WIN_NT
|
|
if (!_fDosExt)
|
|
{
|
|
#endif
|
|
if (fLstFileOpen)
|
|
fflush(bsLst);
|
|
ErrPrefix();
|
|
FmtPrint("%s %c%04d: %s", __NMSG_TEXT(N_fatal), chErr, ER_intrpt, GetMsg(ER_intrpt));
|
|
KillRunfile();
|
|
if (fLstFileOpen)
|
|
fclose(bsLst);
|
|
#if OWNSTDIO
|
|
FlsStdio();
|
|
#endif
|
|
EXIT(4);
|
|
#if DOSEXTENDER AND NOT WIN_NT
|
|
}
|
|
else
|
|
_exit(4);
|
|
#endif
|
|
}
|