home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
PC World Komputer 1995 November
/
PCWK1195.iso
/
inne
/
podstawy
/
dos
/
4dos
/
4uzytki
/
4d24h20b.exe
/
4DOS24H2.ASM
< prev
next >
Wrap
Assembly Source File
|
1993-05-01
|
54KB
|
889 lines
PAGE 60,132
TITLE 4DOS24H2.ASM
SUBTTL Critical Error Handler for 4DOS
;
; Copenhagen, August 3. 1992 (revised May 1992)
;
; The documentation, this source file and the compiled program are released
; to the Public Domain. Nobody is authorized to charge any amount of money
; for the included files. Feel free to modify the code but please don't put
; my name under if redistributed.
;
; As a common convention the comments in this source file are Pascal-like
; statements to allow for a better overwiev of the program.
;
; The code is highly optimized to minimize use of memory but without
; compromising the user interface. I don't think it is possible to squeeze
; this code much more than a few bytes, but I would like to hear from
; everybody who succeeds in making this program use less memory (without
; loosing features). Also any other comments about bugs or whatever it might
; be would be very appreciated.
;
; You can reach me with E-mail at the following Internet address:
;
; ehlig@ask.diku.dk
;
; please use subject: 4DOS24H2
;
; If you cannot reach me through E-mail you can write to the following address:
;
; Niels Jensen
; Vaerebrovej 40,7,3
; 2880 Bagsvaerd
; Denmark DK
;
; Niels Jensen
;
; --------------------------------------
;
;
; To re-assemble using Microsoft Macro Assembler (MASM) or Borlands Turbo
; Assembler (TASM):
;
; TASM or MASM 4DOS24H2;
; LINK 4DOS24H2;
; EXE2BIN 4DOS24H2 4DOS24H2.COM
; DEL 4DOS24H2.EXE
; DEL 4DOS24H2.OBJ
;
; If you want 4DOS24H2 to be compatible with the old 40 columns modes change
; the define option on the command line to reflect:
;
; /Dshadow=1
;
; If you hate shadow simulation change the define option of the command to:
;
; /Dshadow=0
;
;--- Conditional defines ------------------------+------------------------------
; The following code causes two shadow columns as default in case nothing or
; a wrong value is specified on the command line.
;------------------------------------------------+------------------------------
IF1 ;
IFDEF shadow ;
IF (shadow GT 2) + (shadow LT 0) ; Default num. of shadow cols.
shadow = 2 ; if not defined.
ENDIF ;
ELSE ;
shadow = 2 ; Default num. of shadow cols.
ENDIF ; if value outside prop. range.
ENDIF ;
;
;--- Boolean constants --------------------------+------------------------------
False EQU 0 ;
True EQU 1 ;
;
;--- Bit constants ------------------------------+------------------------------
Bit7 EQU 80h ;
Bit6 EQU 40h ;
Bit5 EQU 20h ;
Bit4 EQU 10h ;
Bit3 EQU 08h ;
Bit2 EQU 04h ;
Bit1 EQU 02h ;
Bit0 EQU 01h ;
;
;--- Colour constants ---------------------------+------------------------------
Black EQU 00h ; Low intensity colours
Blue EQU 01h ;
Green EQU 02h ;
Cyan EQU 03h ;
Red EQU 04h ;
Magenta EQU 05h ;
Brown EQU 06h ;
LightGray EQU 07h ;
;------------------------------
Gray EQU 08h ; High intensity colours
LightBlue EQU 09h ;
LightGreen EQU 0Ah ;
LightCyan EQU 0Bh ;
LightRed EQU 0Ch ;
LightMagenta EQU 0Dh ;
Yellow EQU 0Eh ;
White EQU 0Fh ;
;
;--- Key Definitions ----------------------------+------------------------------
Enter EQU 0Dh ; Enter-key
Escape EQU 1Bh ; Escape-key
CtrlC EQU 03h ; Ctrl-C (Ctrl-Break)
CtrlP EQU 10h ; Ctrl-P (Printer on/off)
;
;--- Interrupt constants ------------------------+------------------------------
Video EQU 10h ; BIOS Video service
Equipmnt EQU 11h ; BIOS Equipment service
KeyBoard EQU 16h ; BIOS Keyboard service
ReadKey EQU 00h ; BIOS Keyboard: Read key
TestKey EQU 01h ; BIOS Keyboard: Test for key
Quit EQU 20h ; DOS Service: Terminate
DOS EQU 21h ; DOS Service Interrupt
GetKeyPress EQU 07h ; DOS Service: Get key (raw)
DosReadKey EQU 08h ; DOS Service: Read keystroke
PrintStr EQU 09h ; DOS Service: Print String
SetVector EQU 25h ; DOS Service: Set int. vector
GetVector EQU 35h ; DOS Service: Get int. vector
FreeMem EQU 49h ; DOS Service: Free memory blk.
BreakInt EQU 23h ; Interrupt 23h (Ctrl-Break)
CritErrInt EQU 24h ; Interrupt 24h (Crit. Err.)
TSR EQU 27h ; Terminate and stay resident
MultiPlex EQU 2Fh ; Multiplex interrupt
IDvector EQU 61h ; Vector used for identification
;
;--- Screen related addresses -------------------+------------------------------
MonoSeg EQU 0B000h ; Segment adr. for mono-scr.
ColrSeg EQU 0B800h ; Segment adr. for colour-scr.
ScrRows EQU 0484h ; Ofs. adr. of screen rows
ScrCols EQU 044Ah ; Ofs. adr. of screen columns
RegenBufLen EQU 044Ch ; Ofs. adr. of regen.buf.length
;
;--- Response constants -------------------------+------------------------------
IgnoreOK EQU Bit5 ; Set if ignore allowed
RetryOK EQU Bit4 ; Set if retry allowed
FailOK EQU Bit3 ; Set if fail allowed
IgnoreResp EQU 0 ; Response in case of ignore
RetryResp EQU 1 ; Response in case of retry
AbortResp EQU 2 ; Response in case of abort
FailResp EQU 3 ; Response in case of fail
;
;--- Window constants ---------------------------+------------------------------
WinLins EQU 14 ; Num. of lines in window
IF shadow EQ 0
WinCols EQU 39 ; Num. of columns in window
ELSE
IF shadow EQ 1
WinCols EQU 40 ; Num. of columns in window
ELSE
WinCols EQU 41 ; Num. of columns in window
ENDIF
ENDIF
WinSize EQU WinLins*(WinCols-2) ; Num. of chars in window
TopLines EQU 4 ; Num. of lines over window
TxtAttr EQU Yellow+(Blue SHL 4) ; Attribute of the window text
;
; Note: Remember to change the colour of the abort-message in the
; window accordingly if you change TxtAttr
;
;--- Misc. Program Constants --------------------+------------------------------
IDsign EQU '4D' ; Identification letters
MemSwc EQU 'M' ; Memory information switch
;
;------------------------------------------------+------------------------------
;
; M A C R O S
;
;------------------------------------------------+------------------------------
PushM MACRO regs ;; Push Multiple registers
IRP register,<regs> ;; - Pushes all registers
push register ;; between "<" and ">"
ENDM ;; separated by commas.
ENDM ;; Ex. PushM <ax,bx,cx>
;;
PopM MACRO regs ;; Pop Multiple registers
IRP register,<regs> ;; - Pops all registers
pop register ;; between "<" and ">"
ENDM ;; separated by commas.
ENDM ;; Ex. PopM <cx,bx,ax>
;------------------------------------------------+------------------------------
;
; C O D E S T A R T
;
;------------------------------------------------+------------------------------
Code SEGMENT
ASSUME CS:Code, DS:Code, ES:Code, SS:Code
;--- PSP addresses ------------------------------+------------------------------
ORG 12h ; - Offset address of old 24h
PSP24hOfs LABEL WORD ; handler.
ORG 14h ; - Segment address of old 24h
PSP24hSeg LABEL WORD ; handler.
ORG 16h ; - Segment address of parent
ParentPSP LABEL WORD ; PSP.
ORG 2Ch ; - Segment address of
EnvSegm LABEL WORD ; environment block.
ORG 5Ch ; - Offset where resident code
FreePSP LABEL WORD ; overlays unused part of PSP.
ORG 80h ; - Field indicating parameter
ParLen LABEL BYTE ; length
ORG 81h ; - Start of command line
ParmStr LABEL BYTE ; parameter string
ORG 100h ; - Starting offset for COM-prgs.
;------------------------------------------------+------------------------------
Start: JMP Begin ; Go to installation process
ORG 100h+FreePSP ; Start offset address 15Ch
IDintOfs LABEL NEAR ; If ID-int goto old vect. adr.
DB 0EAh ; JMP Far Ptr OldIDvector
OldIDvectOfs DW ? ; { Original content of the }
OldIDvectSeg DW ? ; { ID-vector. }
;
;--- Variables ----------------------------------+------------------------------
IDword DW IDsign ; Identification word
ScrSeg DW ColrSeg ; Screen address.
DevHdr LABEL DWORD ; Device Header Pointer
DevHdrOfs DW ? ; Address of the device
DevHdrSeg DW ? ; in error from BP:SI.
Errcode DW ? ; Error code from DI.
;
;--- Error message strings ----------------------+------------------------------
ClrStr DB (WinCols-7) DUP(' '),0 ; Clear string for erasing
Msg0 DB 'Disk is write protected',0 ; Disk write protected
Msg1 DB 'Unknown unit',0 ; Device not known
Msg2a DB 'Disk drive not ready',0 ; Disk drive not ready
Msg2b DB 'Device not ready',0 ; Device not ready
Msg3 DB 'Unknown command',0 ; Device command unrecognized
Msg4 DB 'Data error (CRC)',0 ; Disk data error
Msg5 DB 'Bad request struc. length',0; Device call format wrong
Msg6 DB 'Seek error',0 ; Disk seek error
Msg7 DB 'Unknown media type',0 ; Disk not recognized
Msg8 DB 'Sector not found',0 ; Disk sector not found
Msg9 DB 'Printer out of paper',0 ; Device out of paper
MsgA DB 'Write fault',0 ; Device write fault
MsgB DB 'Read fault',0 ; Device read fault
MsgC DB 'General failure',0 ; Disk general error
MsgF DB 'Invalid disk change',0 ; Disk is replaced
Msg10h DB 'FCB unavailable',0 ; Device error
Msg11h DB 'Sharing buffer overflow',0 ; Device error
MsgU DB 'Unknown error',0 ; Wrong error code
;
ErrMsg DW Msg0, Msg1, Msg2a, Msg3, Msg4; String pointer table with
DW Msg5, Msg6, Msg7, Msg8, Msg9 ; pointers to the error
DW MsgA, MsgB, MsgC, MsgU, MsgU ; messages
DW MsgF, Msg10h, Msg11h ;
;
;--- Disk error message parts -------------------+------------------------------
DskMsg1 DB 'Disk ',0 ;
DskMsg2A DB 'read ',0 ;
DskMsg2B DB 'write ',0 ;
DskMsg3 DB 'error on drive ' ;
Drive DB 'A: in ',0 ;
DskMsg4A DB 'DOS system area',0 ;
DskMsg4B DB 'FAT-area (File Allocation Table)',0
DskMsg4C DB 'the root directory area',0 ;
DskMsg4D DB 'the data area',0 ;
DskMsg4 DW DskMsg4A,DskMsg4B,DskMsg4C,DskMsg4D
;
;--- Device error message parts -----------------+------------------------------
DevMsg1 DB 'Device error on device ',0 ;
DevMsg2 DB 'Memory copy of FAT is bad',0;
;
;--- Basic message window -----------------------+------------------------------
IF shadow EQ 0
MsgBuf DB '┌──── DOS Critical Error Handler ────┐'
DB '│ Version 2.00 │'
DB '│ │'
DB '│ '
MsgPos1 DB ' │'
DB '│ '
MsgPos2 DB ' │'
DB '│ │'
DB '│ Error: '
MsgPos3 DB ' │'
DB '│ │'
DB '│ Please hit: │'
DB '│ A - to Abort current operation │'
DB '│ R - to Retry the operation │'
DB '│ '
MsgPos5 DB ' │'
DB '│ '
MsgPos6 DB ' │'
DB '└─────────────────────────────────────┘'
ELSE
IF shadow EQ 1
MsgBuf DB '┌──── DOS Critical Error Handler ────┐'
DB '│ Version 2.00 │ '
DB '│ │ '
DB '│ '
MsgPos1 DB ' │ '
DB '│ '
MsgPos2 DB ' │ '
DB '│ │ '
DB '│ Error: '
MsgPos3 DB ' │ '
DB '│ │ '
DB '│ Please hit: │ '
DB '│ A - to Abort current operation │ '
DB '│ R - to Retry the operation │ '
DB '│ '
MsgPos5 DB ' │ '
DB '│ '
MsgPos6 DB ' │ '
DB '└─────────────────────────────────────┘ '
DB ' '
ELSE
MsgBuf DB '┌──── DOS Critical Error Handler ────┐'
DB '│ Version 2.00 │ '
DB '│ │ '
DB '│ '
MsgPos1 DB ' │ '
DB '│ '
MsgPos2 DB ' │ '
DB '│ │ '
DB '│ Error: '
MsgPos3 DB ' │ '
DB '│ │ '
DB '│ Please hit: │ '
DB '│ A - to Abort current operation │ '
DB '│ R - to Retry the operation │ '
DB '│ '
MsgPos5 DB ' │ '
DB '│ '
MsgPos6 DB ' │ '
DB '└─────────────────────────────────────┘ '
DB ' '
ENDIF
ENDIF
;
;--- Response message parts ---------------------+------------------------------
; RetryMsg DB 'R - to Retry the operation',0;
; RetryMsgLen EQU $-RetryMsg-1 ;
IgnoreMsg DB 'I - to Ignore the error ',0;
IgnoreMsgLen EQU $-IgnoreMsg-1 ;
FailMsg DB 'F - to Fail the operation',0;
;
;------------------------------------------------+------------------------------
;
; S U B R O U T I N E S
;
;-------------------------------------------------------------------------------
; S w a p
;-------------------------------------------------------------------------------
; Does : Swaps the buffer containing the message window with the data on
; the screen located where the window is to be displayed.
; On call : DS:SI = Source; ES:DI = Destination (MsgBuf/Screen)
; Uses : BX, BP, CX, SI, DI
; Changes : BX, BP, CX, SI, DI
;
;--- Start of Swap ------------------------------+------------------------------
Swap PROC NEAR ; Procedure Swap;
; begin
MOV SI, Offset MsgBuf ; ds:si:= MsgBuf;
MOV DI, DX ; es:di:= Scr;
IF shadow EQ 0
MOV CX, WinLins ; cx:= WinLins;
ELSE
MOV CX, WinLins+1 ; cx:= WinLins+1;
ENDIF
Loop1: PUSH CX ; for cx1:= WinLins+1 downto 1 do
IF shadow NE 0
MOV AX, CX ;
DEC AX ; ax:= cx1 - 1;
ENDIF
MOV CL, WinCols ; if (cx1 = WinLins+1) or
IF shadow NE 0
JE NoShadC ; (cx1 = 1)
CMP AL, WinLins-1 ; then tmp:= WinCols
JBE Loop11 ; else tmp:= WinCols+1;
IF shadow EQ 1
NoShadC: DEC CX ;
ELSE
NoShadC: SUB CL, 2 ; for cx2:= tmp downto 1 do begin
ENDIF
ENDIF
Loop11: MOV BX, ES:[DI] ; bx:= Scr[ds:si];
IF shadow NE 0
CMP AL, WinLins-1 ; if (cx1 <= WinLins)
JA NoShade ; then
OR AX, AX ; if (cx2 <= 2) or
JZ Shade ; (cx1 = 1)
IF shadow EQ 1
CMP CL, 1 ;
JNE NoShade ;
ELSE
CMP CL, 2 ;
JA NoShade ;
ENDIF
Shade: MOV [SI], BL ; then Buf[si]:= bl;
ENDIF
NoShade: MOVSW ; Scr[di]:= Buf[si];
MOV [SI-2], BX ; di:= di+2; si:= si+2;
LOOP Loop11 ; Buf[si-2]:= bx
; end; (* for cx2 ... *)
IF shadow NE 0
CMP AL, WinLins ; if (ax = WinLins) or
JE Adj ; (ax = 1)
CMP AL, 1 ;
JNE NoAdj ; then
IF shadow EQ 1
Adj: INC DI ;
INC DI ; di:= di + 2;
ELSE
Adj: ADD DI, 4 ; di:= di + 4;
ENDIF
ENDIF
NoAdj: ADD DI, BP ; di:= di + bp;
POP CX ;
LOOP Loop1 ; end (* for cx1 ... *)
RET ; end;
Swap ENDP ;
;------------------------------------------------+------------------------------
; P u t S t r
;-------------------------------------------------------------------------------
; Does : Displays a null-teminated string. Length must be greater than 0.
; On call : AH = Attribute Byte;
; DS:SI = ^Source;
; ES:DI = ^Destination (Screen memory)
; Uses : AX, SI, DI, DS, ES
; Changes : AL, SI, DI
;
;------------------------------------------------+------------------------------
PutStr PROC NEAR ; Procedure PutStr;
again: LODSB ; begin
STOSW ; repeat
CMP Byte Ptr [SI], 0 ; al:= Buf[si]; write(ax);
JNE again ; Inc(si)
RET ; until Buf[si] = 0
PutStr ENDP ; end;
;------------------------------------------------+------------------------------
;
; N e w i n t e r r u p t h a n d l e r
;
;-------------------------------------------------------------------------------
;
; In case of a critical error during a graphics session this handler would
; not behave normaly because the information window is written directly to
; the screen memory. Instead the handler checks for graphics modes and
; calls the old critical error handler in case the current mode is not a
; text mode.
;
; Graphics modes are detected automatically by checking the length of the
; screen regenerate buffer and compare it against the (last) text screen
; solution. This is only tested on a Tseng ET4000 based Super VGA card and
; therefore NOT garanteed to work with other display adapters.
;
;
; Special register use:
;
; BP: Holds the constant 2*(ScrCols-WinCols) used during swapping of
; the message window and the screen. The constant expresses the
; byte distance in display memory from the end of a line in the
; message window to the beginning of the next.
;
; DX: Holds the constant (TopLines*2*ScrCols + 2*Indent) which is the
; offset from the start of display memory to the upper left corner
; of the message window.
;
;------------------------------------------------+------------------------------
New24h:
PushM <BX,CX,DX,SI,DI,BP,DS,ES>; Save(registers);
PUSH AX ; {AX = error locus info}
PUSH CS ; ds:= cs;
POP DS ; {BP:SI => dev. drv. header}
MOV DevHdrOfs, SI ; DevHdrOfs:= si;
MOV DevHdrSeg, BP ; DevHdrSeg:= bp;
AND DI, 001Fh ; di:= di and 001Fh;
MOV ErrCode, DI ; ErrCode:= di;
XOR DX, DX ; dx:= 0;
MOV ES, DX ; es:= dx;
;--- Check for graphics mode ---------------------------------------------------
Patch1 LABEL WORD ; { Address for patching }
MOV AL, 24 ; {$IF EGA} al:= ScrRows-1;
NOP ; {$ELSE} al:= 24;
NOP ; {$ENDIF}
INC AX ; al:= al+1;
MUL Byte Ptr ES:ScrCols ; ax:= ScrRows*ScrCols;
SHL AX, 1 ; ax:= ax*2;
MOV DX, ES:RegenBufLen ; dx:= RegenBufLength;
SHR DX, 1 ; dx:= dx/2;
JZ OldHandler ; if (dx=0) or (ax<=dx)
CMP AX, DX ; then begin
JA TxtMode ; { Jump to old handler }
OldHandler: PopM <AX,ES,DS,BP,DI,SI,DX,CX,BX>; Rest(regs);
DB 0EAh ; JMP Far Ptr OldHandler
OldInt24hOfs DW ? ; { Pointer to original }
OldInt24hSeg DW ? ; { int 24h handler }
; end;
;--- Calculate top margin and window start position ----------------------------
TxtMode: MOV AX, ES:ScrCols ; ax:= ScrCols;
MOV BP, AX ; bp:= ax;
SUB BP, WinCols ; bp:= ScrCols - WinCols;
MOV AH, TopLines*2 ; {Calc. byte cnt for topmarg}
MUL AH ; ax:= TopLines * 2*ScrCols;
ADD AX, BP ; ax:= ax + Indent;
SHL BP, 1 ; bp:= 2 * bp;
MOV DX, AX ; dx:= ax; { Window start pos }
IF (WinCols AND 1) ; if Odd(WinCols)
DEC DX ; then dx:= dx - 1;
ENDIF ;
PUSH CS ; { Setup ES }
POP ES ; es:= cs;
;--- Test bit 7 for disk error -------------------------------------------------
POP BX ; { Get org. AX in BX }
PUSH BX ; bx:= ErrInfo;
MOV AH, TxtAttr ; ah:= TxtAttr;
MOV DI, Offset MsgPos1 ; di:= MsgPos1;
TEST BH, Bit7 ; if DiskError
JNZ GetName ; then begin
;--- Put disk error message ----------------------------------------------------
MOV ErrMsg[2*2], Offset Msg2a; ErrMsg[2]:= Msg2a;
MOV SI, Offset DskMsg1 ; si:= ^DskMsg1;
CALL PutStr ; PutStr(si,di);
;--- Get error type info from bit 0 --------------------------------------------
TEST BH, Bit0 ; if WriteError
MOV SI, Offset DskMsg2A ; then si:= ^DskMsg2B
JZ ReadError ; else si:= ^DskMsg2A;
MOV SI, Offset DskMsg2B ; PutStr(si,di);
ReadError: CALL PutStr ; { Patch drive letter }
ADD Drive, BL ; Inc(DskMsg3[Drv],cl);
MOV SI, Offset DskMsg3 ; si:= ^DskMsg3;
CALL PutStr ; PutStr(si,di);
MOV Drive, 'A' ; DskMsg3[Drv]:= 'A';
;--- Get error area info from bits 1 and 2 -------------------------------------
MOV DI, Offset MsgPos2 ; di:= MsgPos2;
PUSH DI ;
MOV BL, BH ;
AND BX, 0006h ; bx:= bx mod 7;
MOV SI, Offset ClrStr ; si:= Ofs(ClrStr);
CALL PutStr ; PutStr(si,di);
POP DI ; di:= MsgPos2;
MOV SI, DskMsg4[BX] ; si:= DskMsg4[bx];
CALL PutStr ; PutStr(si,di)
JMP Short GetError ; end
;--- Device error - test bit 15 of device attribute for char/blok device -------
GetName:
MOV ErrMsg[2*2], Offset Msg2b; else begin
PUSH ES ; ErrMsg[2]:= Msg2b;
LES SI, DevHdr ; es:si:= ^DeviceHeader;
MOV CX, ES:[SI+4] ; cx:= DeviceAttr;
MOV SI, Offset DevMsg1 ;
TEST CH, Bit7 ; if CharDevice
JNZ CharDev ; then si:= DevMsg1
MOV SI, Offset DevMsg2 ; else si:= DevMsg2;
CharDev: POP ES ;
CALL PutStr ; PutStr(si,di);
TEST CH, Bit7 ;
JZ ClrMsgPos2 ; if CharDevice
PUSH DS ; then begin {Get dev. name}
LDS SI, DevHdr ; ds:si:= ^DeviceName;
ADD SI, 10 ; for cx1:= 1 to 8 do begin
MOV CX, 8 ; Win[di]:= DevName[si+10];
GetLoop1: LODSB ; Inc(di); Inc(si)
STOSW ; end
LOOP GetLoop1 ; end;
POP DS ; si:= ClrStr;
ClrMsgPos2: MOV SI, Offset ClrStr ; di:= MsgPos2;
MOV DI, Offset MsgPos2 ; PutStr(si,di)
CALL PutStr ; end;
;--- Generate specific error information ---------------------------------------
GetError:
MOV DI, Offset MsgPos3 ; di:= MsgPos3;
MOV SI, Offset ClrStr+6 ; si:= SubStr(6,ClrStr);
CALL PutStr ; PutStr(si,di);
MOV DI, Offset MsgPos3 ; di:= MsgPos3;
MOV SI, Offset MsgU ;
CMP ErrCode, 0011h ;
JA NoValidCode ; if ErrCode > 11h
MOV SI, ErrCode ; then si:= MsgU { Unkn. err. }
SHL SI, 1 ; else si:= ErrMsg[ErrCode];
MOV SI, ErrMsg[SI] ;
NoValidCode: CALL PutStr ; PutStr(si,di);
;--- Find out what response is allowed -----------------------------------------
MOV SI, Offset ClrStr ; si:= ClrStr;
MOV DI, Offset MsgPos6 ; di:= MsgPos6;
CALL PutStr ; PutStr(si,di);
POP BX ; bx:= errlocus;
MOV DI, Offset MsgPos5 ; { Test for retry }
; MOV DI, Offset MsgPos4 ; { Test for retry }
;TestRetry: ;
; TEST BH, RetryOK ; if RetryOK
; JZ TestIgnore ; then begin
; MOV SI, Offset RetryMsg ; PutStr(RetryMsg);
; CALL PutStr ; di:= NextPos
; ADD DI, 2*(WinCols-RetryMsgLen);
TestIgnore: ; end;
TEST BH, IgnoreOK ; if IgnoreOK
JZ TestFail ; then begin
MOV SI, Offset IgnoreMsg ; PutStr(IgnoreMsg);
CALL PutStr ; di:= NextPos
ADD DI, 2*(WinCols-IgnoreMsgLen);
TestFail: ; end;
MOV SI, Offset ClrStr+3 ; if FailOK
TEST BH, FailOK ; then si:= FailMsg
JZ EndRespTst ; else si:= ClrStr;
MOV SI, Offset FailMsg ;
EndRespTst: CALL PutStr ; PutStr(SI,DI);
;--- Show message window -------------------------------------------------------
MOV ES, ScrSeg ; es:= ScrSeg;
PUSH BX ;
CALL Swap ; Swap(Screen,MsgBuf);
POP BX ;
;--- Get user response ---------------------------------------------------------
GetKey: MOV AH, TestKey ; { Get keystroke }
INT KeyBoard ; repeat
JZ GetKey ; while not KeyPrs do
CMP AL, CtrlP ; TestKey(al);
JNE NormalKey ; if al = '^P'
MOV AH, DosReadKey ; then
INT Dos ; DosReadKey(al)
JMP Short GetKey ; until al <> '^P';
NormalKey: MOV AH, ReadKey ;
INT Keyboard ; ReadKey(al);
SUB AL, 'A' ;
CMP AL, ('Z'-'A') ; if al in ['A'..'Z']
JA ProcessIgnore ; then
ADD AL, 20h ; al:= LowCase(al);
;--- Process response ----------------------------------------------------------
; case al of
ProcessIgnore: CMP AL, ('i'-'A') ; 'i': begin {** Ignore **}
JNE ProcessRetry ; if Not IgnoreOK
TEST BH, Bit5 ; then goto GetKey;
JZ GetKey ; al:= 0;
MOV AL, IgnoreResp ; end;
ProcessRetry: CMP AL, ('r'-'A') ; 'r',
JE RetryAct ;
CMP AL, (Enter-'A') ; Enter,
JE RetryAct ;
CMP AL, (' '-'A') ; ' ': begin {** Retry **}
JNE ProcessFail ; al:= 1
RetryAct: MOV AL, RetryResp ; end;
;TEST BH, Bit4 ; if Not RetryOK
;JZ GetKey ; then goto GetKey;
ProcessFail: CMP AL, ('f'-'A') ; 'f': begin {** Fail **}
JNE ProcessAbort ; if Not IgnoreOK
TEST BH, Bit3 ; then goto GetKey
JZ GetKey ; al:= 3;
MOV AL, FailResp ; end;
ProcessAbort: CMP AL, ('a'-'A') ; 'a',
JE AbortAct ;
CMP AL, ('q'-'A') ; 'q',
JE AbortAct ;
CMP AL, ('x'-'A') ; 'x',
JE AbortAct ;
CMP AL, (CtrlC-'A') ; ^C ,
JE AbortAct ;
CMP AL, (Escape-'A') ; Esc: begin {** Abort **}
JNE ElseCase ; AL:= 2
AbortAct: MOV AL, AbortResp ; end;
ElseCase: CMP AL, FailResp ; else goto GetKey
JA GetKey ; end; { case }
;--- Restore screen and exit ---------------------------------------------------
PUSH AX ;
CALL Swap ; Swap(MsgBuf,Screen);
POP AX ;
XOR AH, AH ; ah:= 0;
POPM <ES,DS,BP,DI,SI,DX,CX,BX>; Rest(regs)
IRET ; end;
EndOfCode EQU $ ;
;----------------------------------------------+--------------------------------
;
; E N D O F R E S I D E N T C O D E
;
;-------------------------------------------------------------------------------
; L o a d e r - p r o g r a m
;
; This part of the code is responsible for:
; - loading the handler
; - high load without trouble under 386Max or QEMM if required
; - detection of screen hardware
; - the handler being continuously active during shells
;
;------------------------------------------------+------------------------------
; P R O C E D U R E D E C L A R A T I O N S
;------------------------------------------------+------------------------------
; Procedure WriteInt (ax: int);
;------------------------------------------------+------------------------------
WriteInt PROC NEAR ; Procedure WriteInt (ax:int);
PushM <AX,BX,CX,DX,BP> ; { Writes int w/o leading 0 }
MOV BX, 0007h ; begin
MOV BP, 10000 ; bp:= 10000;
XOR CX, CX ; cx:= 0;
WriteLoop: XOR DX, DX ; repeat
DIV BP ; dx:= ax mod bp;
PUSH DX ; ax:= ax div bp;
ADD CL, AL ; cl:= cl + al;
JZ LeadZero ; if cl > 0
ADD AL, '0' ; then begin
MOV AH, 0Eh ; al:= Char(al);
INT Video ; write(al)
LeadZero: MOV AX, BP ; end;
MOV BP, 10 ;
XOR DX, DX ; dx:= 0;
DIV BP ; bp:= bp div 10;
MOV BP, AX ;
POP AX ; ax:= dx
CMP BP, 0 ; until bp <= 0;
JG WriteLoop ; end;
PopM <BP,DX,CX,BX,AX> ;
RET ;
WriteInt ENDP ;
;------------------------------------------------+------------------------------
; Procedure WriteHex (ax: int);
;------------------------------------------------+------------------------------
WriteHex PROC NEAR ; Procedure WriteHex (ax:int);
PushM <BX,CX,DX,AX> ; begin
MOV AH, 2 ; ah:= 2;
MOV CX, 4 ; cx:= 4;
WriteLoop1: POP BX ; for i:= 1 to cx do begin
ROL BX, 1 ; bx:= Rotate(bx,1);
ROL BX, 1 ; bx:= Rotate(bx,1);
ROL BX, 1 ; bx:= Rotate(bx,1);
ROL BX, 1 ; bx:= Rotate(bx,1);
PUSH BX ;
AND BX, 000Fh ; bx:= bx mod 16;
MOV DL, HexCif[BX] ; dl:= HexCif[bx];
INT Dos ; write(dl);
LOOP WriteLoop1 ; end
PopM <AX,DX,CX,BX> ; end;
RET ;
;------------------------------------------------+ { Local constant }
HexCif DB '0123456789ABCDEF' ; const HexCif = '0..9ABCDEF';
WriteHex ENDP ;
;------------------------------------------------+------------------------------
;--- Test if already installed -------------------------------------------------
Begin: ; begin
MOV AL, CritErrInt ;
MOV AH, GetVector ;
INT Dos ; GetVect(CritErrInt,es:bx);
PUSH ES ; Save(Int24hSeg);
PUSH BX ; Save(Int24hOfs);
; { Install by modifying PSP }
MOV PSP24hOfs, Offset New24h ; PSP24hOfs:= Ofs(New24h);
MOV AH, GetVector ; { See if already installed }
MOV AL, IDvector ; GetVect(IDvector,es:bx);
INT Dos ;
CMP ES:IDword, IDsign ; if es:IDword = IDsign
JNE NotInst ; then begin
;--- Handler already installed -------------------------------------------------
; { Reinstall handler }
MOV PSP24hSeg, ES ; PSP24hSeg:= es;
; { Update stored address }
; { of old handler. }
POP ES:OldInt24hOfs ; Rest(es:OldInt24hOfs);
POP ES:OldInt24hSeg ; Rest(es:OldInt24hSeg);
MOV AX, 4C00h ; Halt(0)
INT Dos ; end;
;--- Handler not installed -----------------------------------------------------
NotInst: MOV DX, Offset ProgInfo ; { Print program info }
MOV AH, PrintStr ; write(ProgInfo);
INT Dos ;
MOV AX, 0D44Dh ; { Test if 4DOS is present }
XOR BX, BX ; ax:= 0D44Dh;
INT MultiPlex ; bx:= 0;
CMP AX, 44DDh ; MultiPlex(ax,bx);
JE Found4DOS ; if ax <> 44DDh
MOV DX, Offset LoadErr1 ; then begin
MOV AH, PrintStr ; { 4DOS not found }
INT Dos ; write(LoadErr1);
MOV AH, GetKeyPress ; { Wait for key press }
INT Dos ; GetKeyPress;
MOV AX, 4C01h ; Halt(1)
INT Dos ; end
Found4DOS: ; { Install by modifying PSP }
POP OldInt24hOfs ; OldInt24hOfs:= Int24hOfs;
POP OldInt24hSeg ; OldInt24hSeg:= Int24hSeg;
;
MOV BX, CS ; { Calc. new segm. value }
SUB BX, 10h ;
MOV PSP24hSeg, BX ; PSP24hSeg:= Seg(New24h);
;--- Release Environment Block -------------------------------------------------
MOV ES, CS:EnvSegm ; { Release environm. block }
MOV AH, FreeMem ; ES:= ^Env;
INT Dos ; FreeMem(ES);
;--- Screen-Detection ----------------------------------------------------------
MOV AH, 12h ; { Test for EGA+ adapter }
MOV BL, 10h ; bl:= 10h;
INT Video ; GetEGAinfo(bl);
CMP BL, 10h ; if bl <> 10h
JE TestCOorBW ; then begin
MOV Patch1, 0A026h ; PatchByte(Patch1);
MOV [Patch1+2], 0484h ; PatchByte(Patch1+2)
TestCOorBW: ; end;
INT Equipmnt ; BIOS(Equip);
TEST AX, Bit5+Bit4 ; if Bit4 and Bit5
JNP EndDetect ; then ScrSeg:= MonoSeg
MOV ScrSeg, MonoSeg ; else ScrSeg:= ColrSeg;
EndDetect: ;
;--- Test for memory info switch as paramter -----------------------------------
MOV SI, Offset ParmStr ; si:= Ofs(ParmStr);
XOR CX, CX ; cx:= Length(ParmStr);
MOV CL, ParLen ; if cx <> 0
JCXZ NoMemStat ; then begin
; { ParmStr[1] always space }
; { or switch char ('/'). }
ParTest: INC SI ; repeat
OR Byte Ptr [SI], 20h ; Inc(si); Dec(cx);
SwcTest: CMP Byte Ptr [SI], (MemSwc or 20h);LowCase([si]);
LOOPNE ParTest ; until ([si]=MemSwc)or(cx=0);
JNE NoMemStat ; if [si] = MemSwc
;--- Print Memory Statistics ---------------------------------------------------
MOV DX, Offset MemInfo ; then begin
MOV AH, PrintStr ; { Print memory status }
INT Dos ; write(MemInfo);
MOV AX, CS ; { Print load address }
CALL WriteHex ; WriteHex(CS);
MOV DX, Offset MemInfo1 ;
MOV AH, PrintStr ; { Print memory usage }
INT Dos ; write(MemInfo1);
MOV AX, Offset EndOfCode-100h;
CALL WriteInt ; WriteInt(EndOfCode-100);
MOV DX, Offset MemInfo2 ;
MOV AH, PrintStr ; writeln(MemInfo2);
INT Dos ; writeln;
; end
NoMemStat: ; end;
;--- Install Identification mark -----------------------------------------------
MOV AL, IDvector ; { Install identification }
MOV AH, GetVector ; GetVector(IDvect,es:bx);
INT Dos ; OldIDvectSeg:= es;
MOV OldIDvectOfs, BX ; OldIDvectOfs:= bx;
MOV OldIDvectSeg, ES ;
PUSH DS ; Save(ds); {!}
MOV DS, PSP24hSeg ; ds:= Seg(IDintSeg);
MOV DX, Offset IDintOfs ; dx:= Ofs(IDintOfs);
MOV AH, SetVector ; SetVect(IDvect,ds:dx);
INT Dos ;
;--- High Load precautions under QEMM and 386Max -------------------------------
PUSH DS ; { Modify parent PSP. }
MOV DS, CS:ParentPSP ; ds:= Seg(ParentPSP);
MOV PSP24hOfs, Offset New24h ; ds:PSP24hOfs:= Ofs(New24h);
POP PSP24hSeg ; ds:PSP24hSeg:= Seg(New24h);
POP DS ; Rest(ds);
;--- Move code to overlay unused part of PSP -----------------------------------
PUSH CS ; { Overlay FCB-area and
POP ES ; parameters to save mem. }
MOV DI, Offset FreePSP ; di:= Ofs(FreePSP);
MOV SI, Offset IDintOfs ; si:= Ofs(code);
MOV CX, Offset EndOfCode-IDintOfs; cx:= EndOfCode-IDintOfs;
CLD ; for i:= 0 to cx-1 do
REP MOVSB ; Mem[di+i]:= Mem[si+i];
;--- Terminate and Stay Resident ----------------+------------------------------
MOV DX, Offset EndOfCode-(IDintOfs-FreePSP)
INT TSR ; Keep
; end.
;----------------------------------------------+--------------------------------
ProgInfo DB '4DOS Critical Error Handler Version 2.00, rev. B',10,13
DB 'Written by Niels Jensen - May, 1993',13,10,'$'
MemInfo DB 'Resident at address $'
MemInfo1 DB ':0000 (hex) consuming $'
MemInfo2 DB ' bytes of memory.',13,10,'$'
LoadErr1 DB 10
DB 'The critical error handler is not installed due to an error.',13,10,10
DB 'The running command interpreter is not a version of 4DOS or NDOS.',10,13
DB 'You need the 4DOS or NDOS command interpreter from JP Software to',10,13
DB 'use this handler - it will not work under COMMAND.COM.',13,10,10
DB 'Press any key to continue . . .$'
;------------------------------------------------+------------------------------
Code ENDS
END Start