home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Zodiac Super OZ
/
MEDIADEPOT.ISO
/
FILES
/
13
/
COMMIO0B.ZIP
/
_EXIT.PAS
next >
Wrap
Pascal/Delphi Source File
|
1996-05-14
|
6KB
|
146 lines
unit _exit;
{
This unit is a companion to the COMMIO communications unit.
Written by Jason Morriss a.k.a. Lief O'Pardy
Copyright (C) 1995,1996 by Jason Morriss
This unit should be placed before ALL other unitnames in the "uses" statment
in your main program source. This assures that the New Handlers below are
Installed before anything else. But if you have a unit that must go before
this one than thats ok, but if that unit allocates any memory in its "init"
section, it cannot rely on the memory handler that this unit creates.
This unit will do the following:
Θ Installs a new exit procedure. If your program is halted by some sort of
internal error (ie: IO error, etc) this will bypass the TP [ugly] exit
procedure and display a better discription of the error. This just looks
much more professional then TP's "runtime error: blabla".
Θ Saves and restores the HEAP marker automatically. This means that you
don't have to use dispose or freemem before your program exits, because
this will free the entire heap that was used, and you don't have to do a
thing! ***(this is the main reason why this unit should go before anything
else. If you have a unit before this, and that unit uses some of the heap
this unit will not know about it, and will not be able to restore the heap
it used)
this feature might be useless. i think tp does this automatically... but
i'm not sure...
Θ Installs a new memory handler. If you try to allocate a chunk of memory
to something and there's not enough heap, instead of halting with an
out of memory error like TP does, this will continue normally with the
program, but the variable that you tried to assign the memory to, will
have the value NIL. This makes it easier to do error checks when
allocating memory. You use it like this:
getmem(myptr,myptrsize);
if myptr=nil then <not enough memory>
..
if myptr<>nil then freemem(myptr,myptrsize);
*NOTE* everything is handled AUTOMATICALLY by this unit, you don't have to
do ANYTHING for the handlers, etc... enjoy.
}
interface
const
MAX_ExitProcs = 256;
type
TExitProc = procedure;
TProcAry = array[1..Max_ExitProcs] of TExitProc; {ary=1024 bytes}
Function AddtoExitChain(proc:TExitProc):boolean;
{^ This adds a procedure to the "Exit Chain". Any procedures in the Exit
Chain are called when your program ends, automatically... No matter how
the program gets terminated (normally, HALT(), ^C). (unless something
drastic happens, and the whole system gets fucked because of it ;)
proc = procedure to add. The procedure cannot have any parameters,
and MUST be compiled FAR. And to be safe, the location of the
procedure should not be an Overlayed unit. (i'm not sure what
would happen though; probably nothing)
The procedures are called in a "LIFO" (last in, first out) fasion. This
is so that the Comport routines will be the very last thing to DeInit
itself. For 2 reasons. 1) So you don't have to worry about Calling
"DeInitComport" at the end of your program. COMMIO adds its own procedure
to the ExitChain, to DeInit itself for you. (and its always the very
first procedure in the chain) 2) Since COMMIO is last to be "shut down",
any of your procedures in the Exit Chain can use the comport still, if
you need/want to. (as long as you don't call DeInitComport yourself!)
NOTE: once you add a procedure, you cannot remove it. (this could be
changed easily, but i have no need to remove procedures [yet], so i
don't feel like adding the code for it, sorry; live with it)
}
Implementation
type
string10 = string[10];
const
ChainNum : integer = 0;
var
ExitChain : TProcAry;
SavedExitProc:pointer;
hp:pointer;
const
hx : array[0..15] of char='0123456789ABCDEF'; {needed for the Hex() funcs}
{───────────────────────────────────────────────────────────────────────────}
Function AddtoExitChain;
begin
AddtoExitChain:=false;
if (ChainNum<MAX_ExitProcs)and(@proc<>nil) then begin
inc(ChainNum);
ExitChain[ChainNum]:=proc;
AddtoExitChain:=true;
end;
end;
{───────────────────────────────────────────────────────────────────────────}
function hex2(b:byte):string10;
begin
hex2 := hx[(b shr 4) and 15]+hx[b and 15];
end;
{───────────────────────────────────────────────────────────────────────────}
function hex4(w:word):string10;
begin
hex4 := hex2(hi(w))+hex2(lo(w));
end;
{───────────────────────────────────────────────────────────────────────────}
Function CustomHeapError(Size : word) : integer; far; {MUST BE FAR}
begin
CustomHeapError := 1; {forces New & Getmem to return NIL}
end;
{───────────────────────────────────────────────────────────────────────────}
Procedure CustomExit; far; {MUST BE FAR}
var i:integer;
begin
if ErrorAddr<>nil then begin
asm mov ax,3; int 10h end; { make sure we go back to text mode }
writeln('■ An unknown error has occured. -Program halted');
writeln(' Address = ',hex4(seg(erroraddr^)),'h:',hex4(ofs(erroraddr^)),'h');
writeln(' ExitCode = ',ExitCode);
reset(input);
ErrorAddr:=nil; {This is so TP will not display its error}
ExitCode:=0; { message.}
end;
for i := ChainNum downto 1 do
if @ExitChain[i]<>nil then ExitChain[i];
release(hp); { release all remaining heap }
ExitProc:=SavedExitProc; { This should be done so the TP's exit
procedure (and any others that might be
installed from other units) can take
over after this one. }
end;
{───────────────────────────────────────────────────────────────────────────}
begin
SavedExitProc := ExitProc;
ExitProc := @CustomExit;
HeapError := @CustomHeapError;
mark(hp); { get current heap amount }
end.