Handling OS/2 Error Codes

by Nico Mak
 * 1990-07-10

Source code for OS2ERR, an error tracking utility for OS/2's (somtimes) cryptic error messages. When a function returns an error the utility displays a pop-up screen with info on the program name, process ID, thread ID, error code and error ID. The utility also recommends an action to be taken and gives you the choice of continuing or aborting the offending program.

[LISTING ONE]

/* OS2ERR.H version 1.0, March, 1989 */ /* Include this file after including OS2.H or OS2DEF.H */

USHORT APIENTRY xos2chk(PSZ, USHORT, PSZ, USHORT); USHORT APIENTRY xos2(PSZ, USHORT, PSZ, USHORT); VOID  APIENTRY xpoperr(VOID); #define os2chk(ErrCode) (xos2chk(__FILE__, __LINE__, #ErrCode, ErrCode)) #define os2(ErrCode) (xos2(__FILE__, __LINE__, #ErrCode, ErrCode)) #define poperr (xpoperr) #define os2chk(ErrCode) (ErrCode) #define os2(ErrCode) (ErrCode) #define poperr
 * 1) ifdef OS2ERR
 * 1) else
 * 1) endif

[LISTING TWO] /* OS2ERR.C version 1.1, April 1989 by Nico Mak */ /* These functions are called by the macros in OS2ERR.H */ /* Compile this program with the options you use for the rest of */ /* your application, and link your application with OS2ERR.OBJ */ typedef struct _SAVEINFO {                 /* save */ TID tid; PSZ pszFileName; USHORT usLineNumber; PSZ pszLineSource; USHORT usErrCode; } SAVEINFO, FAR *PSAVEINFO; SAVEINFO save[MAX_SAVE_ENTRIES]; USHORT cSavedEntries = 0;  /* number of threads that have used OS2ERR */ BOOL fOverFlow = 0;        /* 1 when all entries in "save" table are full */ /* DosErrClass error classifications */ PSZ pszClass[] = { "",   "Out of Resource", "Temporary Situation", "Permission problem", "Internal System Error", "Hardware Failure", "System Failure", "Application Error", "Not Found", "Bad Format", "Locked", "Media Failure", "Collision with Existing Item", "Unknown/other", "Can't perform requested action", "Time-out", }; /* DosErrClass recommended actions */ PSZ pszAction[] = { "",   "Retry immediately", "Delay and retry", "User error, get new values", "Abort in orderly manner", "Abort immediately", "Ignore this error", "Retry after user intervention", }; /* DosErrClass locus */ PSZ pszLocus[] = { "",   "Unknown", "Disk", "Network", "Serial device", "Memory parameter", }; CHAR szWaitMsg[] = "\nPress Esc to abort process or any other key to continue"; CHAR szErrTID[] = "\npoperr error: no information saved for this thread\n\r"; CHAR szErrOverFlow[] = "\npoperr error: thread storage area overflowed\n\r"; CHAR szBuffer[400]; USHORT PASCAL PszLen(PSZ psz); /* function returns length of a far string */ PSAVEINFO PASCAL FindSaveEntry(TID); /* function returns PSAVEINFO for TID */
 * 1) define MAX_SAVE_ENTRIES 7 /* maximum number of threads that will use OS2ERR */
 * 1) include      /* definitions/declarations for standard I/O routines */
 * 2) define INCL_BASE      /* to include all of OS/2 base */
 * 3) include "os2def.h"    /* include OS/2 common definitions */
 * 4) include "bse.h"       /* include OS/2 base definitions */
 * 5) define OS2ERR         /* to include OS2ERR declarations and macros */
 * 6) include "os2err.h"    /* include OS2ERR declarations */

/* xos2chk - handle error (if any) and return error code */ USHORT APIENTRY xos2chk(PSZ pszFileName, USHORT usLineNumber, PSZ pszLineSource, USHORT usErrCode) {   if (xos2(pszFileName, usLineNumber, pszLineSource, usErrCode)) xpoperr; return usErrCode; } /* xos2 - save error information and return error code */ USHORT APIENTRY xos2(PSZ pszFileName, USHORT usLineNumber, PSZ pszLineSource, USHORT usErrCode) {   PSAVEINFO psave; PIDINFO pidi; if (usErrCode) {       DosGetPID(&pidi); if ((psave = FindSaveEntry(pidi.tid)) == NULL) {           DosEnterCritSec; if (cSavedEntries < MAX_SAVE_ENTRIES) psave = save + cSavedEntries++; else fOverFlow = 1; DosExitCritSec; }       if (psave) {           psave->tid = pidi.tid; psave->pszFileName = pszFileName; psave->usLineNumber = usLineNumber; psave->pszLineSource = pszLineSource; psave->usErrCode = usErrCode; }       }    return usErrCode; } /* xpoperr - display pop-up screen with error information, return error code */ VOID APIENTRY xpoperr(VOID) {   KBDKEYINFO kbci; PIDINFO pidi; PSZ psz; USHORT usClass, usAction, usLocus, usWait, usEnviron, usOffsetCmd, cbMsg; PSAVEINFO psave; /* open a pop-up screen */ usWait = VP_WAIT | VP_OPAQUE; VioPopUp(&usWait, 0); DosGetPID(&pidi); if ((psave = FindSaveEntry(pidi.tid)) == NULL) {       VioWrtTTY(szErrTID, sizeof(szErrTID), 0); if (fOverFlow) VioWrtTTY(szErrOverFlow, sizeof(szErrOverFlow), 0); }   else {       /* display error code, command name, and command tail */ sprintf(szBuffer, "Error Code:  %u\n\r", psave->usErrCode); VioWrtTTY(szBuffer, PszLen(szBuffer), 0); DosGetEnv(&usEnviron, &usOffsetCmd); for (psz = MAKEP(usEnviron, 0); *psz; psz += PszLen(psz) + 1) ;       psz += 1; sprintf(szBuffer, "Command:     %Fs\n\r", psz); VioWrtTTY(szBuffer, PszLen(szBuffer), 0); psz += PszLen(psz) + 1; psz += PszLen(psz) + 1; sprintf(szBuffer, "Command tail: %Fs\n\r", psz); VioWrtTTY(szBuffer, PszLen(szBuffer), 0); /* display process id, thread id, and DosErrClass information */ sprintf(szBuffer, "Process ID:  %u\n\rThread ID:    %u\n\r",         pidi.pid, pidi.tid); VioWrtTTY(szBuffer, PszLen(szBuffer), 0); DosErrClass(psave->usErrCode, &usClass, &usAction, &usLocus); sprintf(szBuffer,        "Action:       %Fs\n\rLocus:        %Fs\n\rClass:        %Fs\n\r",         pszAction[usAction], pszLocus[usLocus], pszClass[usClass]); VioWrtTTY(szBuffer, PszLen(szBuffer), 0); /* display source filename, line number, and source code */ sprintf(szBuffer, "Source name: %Fs\n\rSource line: %d (%Fs)\n\r\n\r",        psave->pszFileName, psave->usLineNumber, psave->pszLineSource); VioWrtTTY(szBuffer, PszLen(szBuffer), 0); /* display system message (if any) */ if (!DosGetMessage(0, 0, szBuffer, sizeof(szBuffer), psave->usErrCode, "OSO001.MSG", &cbMsg)) VioWrtTTY(szBuffer, cbMsg, 0); }   /* wait for a keypress */ VioWrtTTY(szWaitMsg, sizeof(szWaitMsg), 0); do { KbdCharIn(&kbci, IO_WAIT, 0); } while (!(kbci.fbStatus & 0x40)); /* close the pop-up screen and abort if requested */ VioEndPopUp(0); if (kbci.chChar == 27 && kbci.chScan == 1) DosExit(EXIT_PROCESS, 1); } /* PszLen - return length of a far string */ USHORT PASCAL PszLen(PSZ psz) {   PSZ pszSearch = psz; while (*pszSearch) pszSearch++; return pszSearch - psz; } /* FindSaveEntry - return pointer to SAVEINFO for a thread ID */ PSAVEINFO PASCAL FindSaveEntry(TID tid) {   PSAVEINFO psave; for (psave = save; psave < save + cSavedEntries; ++psave) if (psave->tid == tid) return psave; return NULL; }

[Example 1: Examples of OS/2chk macro]

os2err(DosClose(hanConfig));   /* display pop-up screen w/error info */ os2err(VioGetFont(&viofi, 0)); /* if system calls return error codes */

[Example 2: Examples of OS/2 and poperr macros] SubCommandProcess {

if (!setjmp(jmpbuf)) {                        /* set up error handler */

/* ... processing ... */

err == os2(VioGetFont(&viofi, 0));       /* get current font info */ if (err == ERROR_VIO_EXTENDED_SG)   /* if running in a VIO window */ InVioWindow = YES;                /* remember we're in window */ else if (err)                    /* if any other VioGetFont error */ poperr;            /* display pop-up screen with error info */

/* ... more processing ... */

if (os2(DosClose(hanConfig)) /* if DosClose returns an error code */           longjmp(jmpbuf);       /* skip to application's error handler */

/* ... yet more processing ... */

}   else poperr; /* error handler - display pop-up screen with error info */ }