Contributor: SWAG SUPPORT TEAM        

{$I- $F+}
UNIT Errtrp;
INTERFACE

USES
crt,
dos;

CONST
ScrSeg : WORD = $B800;
FGNorm = lightgray;
BGNorm = blue;
FGErr = white;
BGErr = red;

VAR
SaveInt24 : POINTER;
ErrorRetry : BOOLEAN;
IOCode    : INTEGER;
version   : INTEGER;

PROCEDURE DisplayError (ErrNo : INTEGER);
PROCEDURE RuntimeError;
PROCEDURE DisableErrorHandler;
PROCEDURE ErrTrap (ErrNo : INTEGER);


IMPLEMENTATION


VAR
  ExitSave : POINTER;
  regs : REGISTERS;


(**************************************************************************)

CONST
 INT59ERROR  : INTEGER  = 0;
 ERRORACTION : BYTE = 0;
 ERRORTYPE   : BYTE = 0;
 ERRORAREA   : BYTE = 0;
 ERRORRESP   : BYTE = 0;
 ERRORRESULT : INTEGER = 0;

TYPE
errmsg         = ARRAY [0..89] OF STRING;
ermsgPtr       = ^errmsg;

VAR
Errs : ermsgPTR;

PROCEDURE HideCursor; Assembler;
Asm
  MOV   ax, $0100
  MOV   cx, $2607
  INT   $10
END;

PROCEDURE ShowCursor; Assembler;
Asm
  MOV   ax, $0100
  MOV   cx, $0506
  INT   $10
END;


PROCEDURE box;
VAR
 i : INTEGER;
BEGIN
  TEXTCOLOR (FGErr);
  TEXTBACKGROUND (BGErr);
  GOTOXY (1, 1);
  WRITELN ('ÚÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ  Critical Error  ÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄ¿');
    FOR i := 1 TO 5 DO
  WRITELN ('³                                                ³');
  WRITE  ('ÀÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÄÙ');
END;{box}

FUNCTION DosVer : INTEGER;
VAR
 Maj : shortint;
 Min : shortint;
 regs : REGISTERS;

BEGIN
 regs.ah := $30;
 MSDOS (Regs);
 Maj := regs.al;
 Min := regs.ah;
 DosVer := Maj;
END;

PROCEDURE InitErrs;
BEGIN
NEW (Errs);
Errs^ [0] :=   '             No error occured           ';
Errs^ [1] :=    '          Invalid function number       ';
Errs^ [2] :=    '              File not found            ';
Errs^ [3] :=    '              Path not found            ';
Errs^ [4] :=    '            No handle available         ';
Errs^ [5] :=    '              Access denied             ';
Errs^ [6] :=    '             Invalid handle             ';
Errs^ [7] :=    '     Memory control blocks destroyed    ';
Errs^ [8] :=    '           Insufficient memory          ';
Errs^ [9] :=    '      Invalid memory block address      ';
Errs^ [10] :=    '       Invalid SET command string       ';
Errs^ [11] :=    '             Invalid format             ';
Errs^ [12] :=    '          Invalid access code           ';
Errs^ [13] :=    '              Invalid data              ';
Errs^ [14] :=    '                Reserved                ';
Errs^ [15] :=    '       Invalid drive specification      ';
Errs^ [16] :=    '   Attempt to remove current directory  ';
Errs^ [17] :=    '             Not same device            ';
Errs^ [18] :=    '        No more files to be found       ';
Errs^ [19] :=    '          Disk write protected          ';
Errs^ [20] :=    '            Unknown unit ID             ';
Errs^ [21] :=    '          Disk drive not ready          ';
Errs^ [22] :=    '          Command not defined           ';
Errs^ [23] :=    '            Disk data error             ';
Errs^ [24] :=    '      Bad request structure length      ';
Errs^ [25] :=    '             Disk seek error            ';
Errs^ [26] :=    '         Unknown disk media type        ';
Errs^ [27] :=    '          Disk sector not found         ';
Errs^ [28] :=    '          Printer out of paper          ';
Errs^ [29] :=    '      Write error - Printer Error?      ';
Errs^ [30] :=    '               Read error               ';
Errs^ [31] :=    '            General failure             ';
Errs^ [32] :=    '         File sharing violation         ';
Errs^ [33] :=    '         File locking violation         ';
Errs^ [34] :=    '          Improper disk change          ';
Errs^ [35] :=    '             No FCB available           ';
Errs^ [36] :=    '         Sharing buffer overflow        ';
Errs^ [37] :=    '                Reserved                ';
Errs^ [38] :=    '                Reserved                ';
Errs^ [39] :=    '                Reserved                ';
Errs^ [40] :=    '                Reserved                ';
Errs^ [41] :=    '                Reserved                ';
Errs^ [42] :=    '                Reserved                ';
Errs^ [43] :=    '                Reserved                ';
Errs^ [44] :=    '                Reserved                ';
Errs^ [45] :=    '                Reserved                ';
Errs^ [46] :=    '                Reserved                ';
Errs^ [47] :=    '                Reserved                ';
Errs^ [48] :=    '                Reserved                ';
Errs^ [49] :=    '                Reserved                ';
Errs^ [50] :=    '      Network request not supported     ';
Errs^ [51] :=    '      Remote computer not listening     ';
Errs^ [52] :=    '        Duplicate name on network       ';
Errs^ [53] :=    '         Network name not found         ';
Errs^ [54] :=    '             Network busy               ';
Errs^ [55] :=    '      Network device no longer exists   ';
Errs^ [56] :=    '      NetBIOS command limit exceeded    ';
Errs^ [57] :=    '      Network adapter hardware error    ';
Errs^ [58] :=    '      Incorrect response from network   ';
Errs^ [59] :=    '        Unexpected network error        ';
Errs^ [60] :=    '      Incompatible remote adapter       ';
Errs^ [61] :=    '            Print queue full            ';
Errs^ [62] :=    '      Not enough space for print file   ';
Errs^ [63] :=    '         Print file was deleted         ';
Errs^ [64] :=    '        Network name was deleted        ';
Errs^ [65] :=    '             Access denied              ';
Errs^ [66] :=    '       Network device type incorrect    ';
Errs^ [67] :=    '          Network name not found        ';
Errs^ [68] :=    '        Network name limit exceeded     ';
Errs^ [69] :=    '      NetBIOS session limit exceeded    ';
Errs^ [70] :=    '           Temporarily paused           ';
Errs^ [71] :=    '       Network request not accepted     ';
Errs^ [72] :=    '  Print or disk re-direction is paused  ';
Errs^ [73] :=    '                Reserved                ';
Errs^ [74] :=    '                Reserved                ';
Errs^ [75] :=    '                Reserved                ';
Errs^ [76] :=    '                Reserved                ';
Errs^ [77] :=    '                Reserved                ';
Errs^ [78] :=    '                Reserved                ';
Errs^ [79] :=    '                Reserved                ';
Errs^ [80] :=    '           File already exists          ';
Errs^ [81] :=    '                Reserved                ';
Errs^ [82] :=    '              Cannot make               ';
Errs^ [83] :=    '     Critical-error interrupt failure   ';
Errs^ [84] :=    '          Too many redirections         ';
Errs^ [85] :=    '          Duplicate redirection         ';
Errs^ [86] :=    '           Duplicate password           ';
Errs^ [87] :=    '            Invalid parameter           ';
Errs^ [88] :=    '            Network data fault          ';
Errs^ [89] :=    '             Undefined Error            ';
END;

PROCEDURE CritError (Flags, CS, IP, AX, BX, CX, DX, SI, DI, DS, ES, BP : WORD);
 INTERRUPT;
TYPE
ScrPtr         = ^ScrBuff;
ScrBuff        = ARRAY [1..4096] OF BYTE;

VAR
  Display,
  SaveScr    : ScrPtr;

  c         : CHAR;
  ErrorPrompt,
  msg        : STRING;
  ErrNum     : BYTE;

  drive,
  area,
  al, ah      : BYTE;

  deviceattr : ^WORD;
  devicename : ^CHAR;
  ch,
  i          : shortint;
  actmsg,
  tmsg,
  amsg,
  dname      : STRING;
BEGIN
    ah := HI (ax);
    al := LO (ax);                            { in case DOS version < 3     }
    ErrNum := LO (DI) + 19;                     { save the error and add      }
    msg := Errs^ [ErrNum];                    { add 19 to convert to        }
                                           { standard DOS error          }
    tmsg := '';
    actmsg := '';                            { we can't suggest a response }

 IF (ah AND $80) = 0 THEN                    { if a disk error then        }
   BEGIN                                   { get the drive and area      }
     amsg := ' drive ' + CHR (al + 65) + ':';
     area := (ah AND 6) SHR 1;
     CASE area OF
     0 : amsg := amsg + ' dos communications area ';
     1 : amsg := amsg + ' disk directory area ';
     2 : amsg := amsg + ' files area ';
     END;
   END
ELSE                                       { else if a device error }
   BEGIN                                   { get type of device     }
     deviceattr := PTR (bp, si + 4);
     i := 0;
     IF (deviceattr^ AND $8000) <> 0 THEN     { if a character device }
       BEGIN                                { like a printer        }
         amsg := 'character device';
         ch := 0;
         REPEAT
         i := i + 1;
         devicename := PTR (bp, si + $0a + ch);      { get the device name  }
         dname [i] := devicename^;
         dname [0] := CHR (i);
         INC (ch);
         UNTIL (devicename^ = CHR (0) ) OR (ch > 7);
       END
    ELSE                                     { else }
      BEGIN                                  { just inform of the error }
        dname := 'disk in ' + CHR (al) + ':';
        msg := ' general failure ' ;
        END;
     amsg := amsg + ' ' + dname;
     END;

 INLINE ($FA);                           { Enable interrupts       }
 Display := PTR (ScrSeg, $0000);            { save the current screen }
 NEW (SaveScr);
 SaveScr^ := Display^;
 WINDOW (15, 10, 65, 16);                   { make a box to display the}
 TEXTCOLOR (FGErr);                      { error message            }
 TEXTBACKGROUND (BGErr);
 CLRSCR;
 box;

  IF Version >= 3 THEN                     { check the DOS version   }
  BEGIN                                  { major component         }
  regs.ah := $59;                          { and use DosExtErr since }
  regs.bx := $00;                          { it is available         }
  MSDOS (Regs);
  INT59ERROR := regs.ax;
  ERRORTYPE := regs.bh;
  ERRORACTION := regs.bl;
  ERRORAREA := regs.ch;
  msg := Errs^ [INT59ERROR];                { get the error information}
(*
  case ERRORAREA of
  1: amsg:='Unknown';
  2: amsg:='Block Device';               { usually disk access error}
  3: amsg:='Network Problem';
  4: amsg:='Serial Device';              { printer or COM problem   }
  5: amsg:='Memory';                     { corrupted memory         }
  end;
*)
  CASE ERRORTYPE OF
  1 : tmsg := 'Out of Resource';            { no channels, space       }
  2 : tmsg := 'Temporary situation';        { file locked for instance;}
                                          { not an error and will    }
                                          { clear eventually         }
  3 : tmsg := 'Authorization Violation';     { permission problem e.g.  }
                                          { write to read only file  }
  4 : tmsg := 'Internal Software Error';     { system software bug      }
  5 : tmsg := 'Hardware Error';              { serious trouble -- fix   }
                                          { the machine              }
  6 : tmsg := 'System Error';                { serious trouble software }
                                          { at fault -- e.g. missing }
                                          { CONFIG file              }
  7 : tmsg := 'Program Error';               { inconsistent request     }
                                          { from your program        }
  8 : tmsg := 'Not found';                   { as stated                }
  9 : tmsg := 'Bad Format';                  { as stated                }
  10 : tmsg := 'Locked';                      { interlock situation      }
  11 : tmsg := 'Media Error';                 { CRC error, wrong disk in }
                                          { drive, bad disk cluster  }
  12 : tmsg := 'Exists';                      { collision with existing  }
                                          { item, e.g. duplicate     }
                                          { device name              }
  13 : tmsg := 'Unknown Error';
  END;

  CASE ERRORACTION OF
  1 : actmsg := 'Retry';                     { retry a few times then   }
                                          { give user abort option   }
                                          { if not fixed             }
  2 : actmsg := 'Delay Retry';               { pause, retry, then give  }
                                          { user abort option        }
  3 : actmsg := 'User Action';               { ask user to reenter item }
                                          { e.g. bad drive letter or }
                                          { filename used            }
  4 : actmsg := 'Abort';                      { invoke an orderly shut   }
                                          { down -- close files, etc }
  5 : actmsg := 'Immediate Exit';             { don't clean up, you may  }
                                          { really screw something up}
  6 : actmsg := 'Ignore';
  7 : actmsg := 'Retry';                     { after user intervention: }
  END;                                    { let the user fix it first}

  END;
amsg := tmsg + amsg;
actmsg := 'Suggested Action: ' + actmsg;

GOTOXY ( (54 - LENGTH (msg) ) DIV 2, 3);
WRITE (msg);

GOTOXY ( (54 - LENGTH (amsg) ) DIV 2, 4);
WRITE (amsg);

GOTOXY ( (54 - LENGTH (actmsg) ) DIV 2, 6);
WRITE (actmsg);
                                          { display it              }

ErrorPrompt := ' I)gnore R)etry A)bort F)ail ? ';
GOTOXY ( (54 - LENGTH (ErrorPrompt) ) DIV 2, 5);
WRITE (ErrorPrompt);
REPEAT                                     { get the user response  }
c := READKEY;
c := UPCASE (c);
UNTIL c IN ['A', 'R', 'I', 'F'];
WINDOW (1, 1, 80, 25);                         { restore the screen     }
TEXTCOLOR (FGNorm);
TEXTBACKGROUND (BGNorm);
Display^ := SaveScr^;
DISPOSE (SaveScr);
CASE c OF
  'I' : BEGIN
        AX := 0;
        ERRORRETRY := FALSE;
      END;
  'R' : BEGIN
        AX := 1;
        ERRORRETRY := TRUE;
      END;
  'A' : BEGIN
        Ax := 2;
        ERRORRETRY := FALSE;
        Showcursor;
      END;
  'F' : BEGIN
        Ax := 3;
        ERRORRETRY := FALSE;
        Showcursor;
      END;
END;

END;{procedure CritError}

(**************************************************************************)
PROCEDURE DisplayError (ErrNo : INTEGER);
VAR
msg,
exitmsg : STRING;
BEGIN
    CASE ErrNo OF
    2 : exitmsg := 'File not found';
    3 : exitmsg := 'Path not found';
    4 : exitmsg := 'Too many open files';
    5 : exitmsg := 'Access denied';
    6 : exitmsg := 'Invalid file handle';
    12 : exitmsg := 'Invalid file access code';
    15 : exitmsg := 'Invalid drive';
    16 : exitmsg := 'Cannot remove current directory';
    17 : exitmsg := 'Cannot rename across drives';
    100 : exitmsg := 'Disk read error';
    101 : exitmsg := 'Disk write error - Disk Full ?';
    102 : exitmsg := 'File not assigned';
    103 : exitmsg := 'File not opened';
    104 : exitmsg := 'File not open for input';
    105 : exitmsg := 'File not open for output';
    106 : exitmsg := 'Invalid numeric format';
    150 : exitmsg := 'Disk is write protected';
    151 : exitmsg := 'Unknown unit';
    152 : exitmsg := 'Drive not ready';
    153 : exitmsg := 'Unkown command';
    154 : exitmsg := 'CRC error in data';
    155 : exitmsg := 'Bad drive request structure length';
    156 : exitmsg := 'Disk seek error';
    157 : exitmsg := 'Unknown media type';
    158 : exitmsg := 'Sector not found';
    159 : exitmsg := 'Printer out of paper';
    160 : exitmsg := 'Device write fault';
    161 : exitmsg := 'Device read fault';
    162 : exitmsg := 'Hardware failure';
    200 : exitmsg := 'Division by zero';
    201 : exitmsg := 'Range check error';
    202 : exitmsg := 'Stack overflow';
    203 : exitmsg := 'Heap overflow';
    204 : exitmsg := 'Invalid pointer operation';
    205 : exitmsg := 'Floating point overflow';
    206 : exitmsg := 'Floating point underflow';
    207 : exitmsg := 'Invalid floating point operation'
    ELSE exitmsg := 'Unknown Error # ';
    END;

  msg := exitmsg;

  TEXTCOLOR (FGErr);
  TEXTBACKGROUND (BGErr);
  GOTOXY ( (50 - LENGTH (msg) ) DIV 2, 3);
  WRITE (msg);

END;

PROCEDURE ErrTrap (ErrNo : INTEGER);
TYPE
ScrPtr         = ^ScrBuff;
ScrBuff        = ARRAY [1..4096] OF BYTE;

VAR
  Display,
  SaveScr    : ScrPtr;

  c         : CHAR;
  ErrorPrompt,
  msg : STRING;

BEGIN

 Display := PTR (ScrSeg, $0000);            { save the current screen }
 NEW (SaveScr);
 SaveScr^ := Display^;
 WINDOW (15, 10, 65, 16);                   { make a box to display the}
 TEXTCOLOR (FGErr);                      { error message            }
 TEXTBACKGROUND (BGErr);
 CLRSCR;
 box;

  ErrorRetry := TRUE;
  DisplayError (ErrNo);

                                          { display it              }

ErrorPrompt := ' I)gnore R)etry A)bort F)ail ? ';
GOTOXY ( (54 - LENGTH (ErrorPrompt) ) DIV 2, 5);
WRITE (ErrorPrompt);
REPEAT                                     { get the user response  }
c := READKEY;
c := UPCASE (c);
UNTIL c IN ['A', 'R', 'I', 'F'];
CASE c OF
  'I' : ErrorRetry := FALSE;
  'R' : ErrorRetry := TRUE;
  'A' : BEGIN
        ErrorRetry := FALSE;
        Showcursor;
      END;
  'F' : BEGIN
        ErrorRetry := FALSE;
        Showcursor;
      END;
  END;
  IF ErrorRetry = FALSE THEN
    BEGIN
      GOTOXY (4, 4);
      WRITE ('If you are unable to correct the error');
      GOTOXY (4, 5);
      WRITE ('please report the error ', #40, Errno, #41, ' and      ');
      GOTOXY (4, 6);
      WRITE ('exact circumstances when it occurred to us.');
      WINDOW (1, 1, 80, 25);                         { restore the screen     }
      TEXTCOLOR (FGNorm);
      TEXTBACKGROUND (BGNorm);
      Display^ := SaveScr^;
      DISPOSE (SaveScr);

      ErrorAddr := NIL;
      GOTOXY (1, 1);
      Showcursor;
      HALT;
    END;
WINDOW (1, 1, 80, 25);                         { restore the screen     }
TEXTCOLOR (FGNorm);
TEXTBACKGROUND (BGNorm);
Display^ := SaveScr^;
DISPOSE (SaveScr);
END;

PROCEDURE RuntimeError;

TYPE
ScrPtr         = ^ScrBuff;
ScrBuff        = ARRAY [1..4096] OF BYTE;

VAR
  Display,
  SaveScr    : ScrPtr;

  c         : CHAR;
  ErrorPrompt,
  msg : STRING;

BEGIN
  IF ErrorAddr <> NIL THEN
    BEGIN
      Display := PTR (ScrSeg, $0000);            { save the current screen }
      NEW (SaveScr);
      SaveScr^ := Display^;
      WINDOW (15, 10, 65, 16);                   { make a box to display the}
      TEXTCOLOR (FGErr);                      { error message            }
      TEXTBACKGROUND (BGErr);
      CLRSCR;
      box;
      GOTOXY (15, 1);
      WRITE ('   Fatal  Error   ');
      DisplayError (ExitCode);
      GOTOXY (20, 2);
      WRITE ('Run time error ', ExitCode);
      GOTOXY (4, 4);
      WRITE ('If you are unable to correct the error');
      GOTOXY (4, 5);
      WRITE ('Please report the error and exact');
      GOTOXY (4, 6);
      WRITE ('circumstances when it occurred to us.');
      GOTOXY (4, 7);
      WRITE ( ' Press a key to continue ');
      ErrorAddr := NIL;

      ExitProc := ExitSave;
      c := READKEY;
    END;
  WINDOW (1, 1, 80, 25);                         { restore the screen     }
  TEXTCOLOR (FGNorm);
  TEXTBACKGROUND (BGNorm);
  Display^ := SaveScr^;
  DISPOSE (SaveScr);

  ShowCursor;
  TEXTCOLOR (lightgray);
  TEXTBACKGROUND (black);

  SETINTVEC ($24, SaveInt24);
END;

PROCEDURE DisableErrorHandler;
BEGIN
  SETINTVEC ($24, SaveInt24);
  ExitProc := ExitSave;
END;

(**************************************************************************)
BEGIN
  InitErrs;
  Version := DosVer;
  Hidecursor;
  IF mem [$0000 : $0449] <> 7 THEN ScrSeg := $B800 ELSE ScrSeg := $B000;
  GETINTVEC ($24, SaveInt24);
  SETINTVEC ($24, @CritError);
  ExitSave := ExitProc;
  ExitProc := @RuntimeError;
END.

{ ---------------------   DEMO PROGRAM -------------------------- }

{$I-}  { THIS MUST BE HERE FOR THE ERROR TRAP TO WORK !! }
PROGRAM testerr;
USES dos, crt, printer, errtrp;
VAR
regs : REGISTERS;
fil : FILE;
Pchar : STRING;
BEGIN
CLRSCR;
(*COMMENT OUT THE FUNCTIONS NOT BEING TESTED*)
(*       USING THE CRITICAL ERROR HANDLER PROCEDURE CRITERR  *)

(* remove disc from A: drive to test this *)
(******************************************)

WRITE ('trying to write to drive a: ');

  ASSIGN (fil, 'A:filename.ext');
  REWRITE (fil);

DisableErrorHandler;

(*  USING THE ERRTRAP PROCEDURE *)

WRITE ('trying to write to drive a: using ERRTRAP');
REPEAT
ASSIGN (fil, 'A:filename.ext');
REWRITE (fil);
iocode := IORESULT;
IF IOCode <> 0 THEN ErrTrap (IOCode);
UNTIL ERRORRETRY = FALSE;

END.