Handling OS/2 Error Codes
by Nico Mak
[LISTING ONE]
/* OS2ERR.H version 1.0, March, 1989 */ /* Include this file after including OS2.H or OS2DEF.H */ #ifdef OS2ERR 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()) #else #define os2chk(ErrCode) (ErrCode) #define os2(ErrCode) (ErrCode) #define poperr() #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 */ #define MAX_SAVE_ENTRIES 7 /* maximum number of threads that will use OS2ERR */ #include <stdio.h> /* definitions/declarations for standard I/O routines */ #define INCL_BASE /* to include all of OS/2 base */ #include "os2def.h" /* include OS/2 common definitions */ #include "bse.h" /* include OS/2 base definitions */ #define OS2ERR /* to include OS2ERR declarations and macros */ #include "os2err.h" /* include OS2ERR declarations */ 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 */ /* 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 */ }