|
|
/*** 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
}
|