Contributor: FRANK HECKENBACH

UNIT BPTrap;  { see DEMO at the bottom !! }

{ Trap runtime errors, Version 1.0
  Copyright (C) 1991-1996 by Frank Heckenbach, heckenb@mi.uni-erlangen.de

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, version 1, for NON-COMMERCIAL use.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. }

{$IFNDEF VER70}
This unit was tested only with Borland Pascal 7.0. You can use it with other
versions by commenting these two lines, but at your own risk!
{$ENDIF}

INTERFACE

FUNCTION  Trap:Boolean; FAR;
{* Returns False on installation.
 * After trapping a runtime error it jumps back to where the function was
   called returning True.
 * The procedure that calls Trap must NOT return as long as Trap is installed
   (so it is safest to call Trap from the main program, if possible)!
 * You must call this function AFTER installing all other Exitprocs (if any).
 * In Real mode: You must NOT call it from an overlayed unit.
 * In Protected mode and Windoze: You must call it from a code segment with
   the following attributes: FIXED PRELOAD PERMANENT. (I am not sure if this
   is really necessary...).}

FUNCTION UnTrap:Boolean;
{Returns True iff Trap could be uninstalled.}

IMPLEMENTATION

TYPE ptrrec=RECORD ofs,sgm:Word END;

CONST
  addrsave:Pointer=NIL;
  codesave:Word=0;

VAR
  exitsave,trapaddr:Pointer;
  trapsp,trapbp:Word;

{$S-}
PROCEDURE Trapexit; FAR;
BEGIN
  IF Erroraddr<>NIL
    THEN {Trapping runtime error}
      BEGIN
        {Install Trapexit again (in case another runtime error occurs later)!}
        Exitproc:=@Trapexit;

        {Keep error address and exit code and reset these variables}
        addrsave:=Erroraddr;
        codesave:=Exitcode;
        Erroraddr:=NIL;
        Exitcode:=0;

        {If you want, you can do something here to indicate the user that an
         error occurred. You could e.g. pop up a message telling the user to
         quit the program asap and report the error to the programmer.}

        ASM
          {Load the saved SP and BP registers}
          MOV  SP,trapsp
          MOV  BP,trapbp

          {Continue at saved address returning True}
          MOV  AL,1
          JMP  [trapaddr]
        END
      END

    ELSE {Programm finished without an error}
      BEGIN
        {Continue with other exit procs}
        Exitproc:=exitsave;

        {Restore error address and exit code of the last trapped error, if any}
        IF addrsave<>NIL THEN
          BEGIN
            Erroraddr:=addrsave;
            Exitcode:=codesave
          END
      END
END;

FUNCTION Trap:Boolean; ASSEMBLER;
ASM
   {Install Trapexit as an Exitproc}
   MOV  AX,OFFSET Trapexit
   MOV  DX,SEG Trapexit
   CMP  Exitproc.ptrrec.ofs,AX
   JNE  @1
   CMP  Exitproc.ptrrec.sgm,DX
   JE   @2
@1:XCHG Exitproc.ptrrec.ofs,AX
   XCHG Exitproc.ptrrec.sgm,DX
   MOV  exitsave.ptrrec.ofs,AX
   MOV  exitsave.ptrrec.sgm,DX

   {Save SP and BP registers and the return address}
@2:MOV  trapbp,BP
   MOV  SI,SP
   {$IFDEF WINDOWS}
   ADD  SI,4
   ADD  trapbp,6
   {$ENDIF}
   LES  DI,SS:[SI]
   MOV  trapaddr.ptrrec.ofs,DI
   MOV  trapaddr.ptrrec.sgm,ES
   ADD  SI,4
   MOV  trapsp,SI

   {Return False}
   XOR  AX,AX
END;

FUNCTION UnTrap:Boolean;
BEGIN
  IF Exitproc=@Trapexit
    THEN
      BEGIN
        Exitproc:=exitsave;
        UnTrap:=True
      END
    ELSE UnTrap:=False
END;
END.


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

PROGRAM TrapDemo;
{ Demo program for BPTrap unit, Version 1.0
  Copyright (C) 1996 by Frank Heckenbach, heckenb@mi.uni-erlangen.de

  This program is free software; you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, version 1, for NON-COMMERCIAL use.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program; if not, write to the Free Software
  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. }

{$C FIXED PRELOAD PERMANENT} {Not necessary for real mode.}

USES BPTrap{$IFDEF WINDOWS},Wincrt{$ENDIF};

VAR a,b:Byte;

BEGIN
  Writeln;
  Writeln('TrapDemo version 1.0, Copyright (C) 1996 by Frank Heckenbach');
  Writeln('TrapBP and TrapDemo come with ABSOLUTELY NO WARRANTY.');
  Writeln('This is free software, and you are welcome to redistribute it');
  Writeln('under certain conditions for NON-COMMERCIAL use.');
  Writeln('For details see the file COPYING.');
  Writeln;
  Writeln('Before the trap...');
  Writeln;
  Randomize;
  IF NOT Trap THEN
    REPEAT
      a:=Random(10);
      b:=Random(10);
      Writeln(a,'/',b,'=',a/b)
    UNTIL False;
  Writeln('Infinity.');
  Write('Press Enter.');
  Readln;
  Write('The program caused a... ')
END.