;    File              : $Workfile: CRIT.ASM$
;
;    Description       :
;
;    Original Author   : DIGITAL RESEARCH
;
;    Last Edited By    : $CALDERA$
;
;-----------------------------------------------------------------------;
;    Copyright Work of Caldera, Inc. All Rights Reserved.
;      
;    THIS WORK IS A COPYRIGHT WORK AND CONTAINS CONFIDENTIAL,
;    PROPRIETARY AND TRADE SECRET INFORMATION OF CALDERA, INC.
;    ACCESS TO THIS WORK IS RESTRICTED TO (I) CALDERA, INC. EMPLOYEES
;    WHO HAVE A NEED TO KNOW TO PERFORM TASKS WITHIN THE SCOPE OF
;    THEIR ASSIGNMENTS AND (II) ENTITIES OTHER THAN CALDERA, INC. WHO
;    HAVE ACCEPTED THE CALDERA OPENDOS SOURCE LICENSE OR OTHER CALDERA LICENSE
;    AGREEMENTS. EXCEPT UNDER THE EXPRESS TERMS OF THE CALDERA LICENSE
;    AGREEMENT NO PART OF THIS WORK MAY BE USED, PRACTICED, PERFORMED,
;    COPIED, DISTRIBUTED, REVISED, MODIFIED, TRANSLATED, ABRIDGED,
;    CONDENSED, EXPANDED, COLLECTED, COMPILED, LINKED, RECAST,
;    TRANSFORMED OR ADAPTED WITHOUT THE PRIOR WRITTEN CONSENT OF
;    CALDERA, INC. ANY USE OR EXPLOITATION OF THIS WORK WITHOUT
;    AUTHORIZATION COULD SUBJECT THE PERPETRATOR TO CRIMINAL AND
;    CIVIL LIABILITY.
;-----------------------------------------------------------------------;
;
;    *** Current Edit History ***
;    *** End of Current Edit History ***
;
;    $Log$
;    CRIT.ASM 1.11 94/12/01 10:05:21
;    Changed critical error message display so that the default message
;    is 'I/O error' and that all share-related codes are converted to
;    'File sharing conflict'
;    
;    CRIT.ASM 1.9 93/09/10 15:56:08 
;    Use device driver header at BP:SI instead of AH to determine if disk/char device
;    That way we get "device NETWORK" rather than "drive D" on VLM critical errors
;    ENDLOG
;
; 19/Sep/88 Move the messages into a separate module
; 15/Dec/88 Critical Error messages processed by STDERR
; 06/Apr/89 DR DOS version taken from PCMODE & put in COMMAND.COM
; 10/Aug/89 Issue INT 2F's so application can give it's own error message
; 08/Sep/89 'No FCBs' message
; 02/Nov/89 abort_char etc become ABS rather than CHAR (saves a few bytes)
; 13/Nov/89 Reduced number of external messages referenced to one
;		(crit_top) to aid Dual Language Support.
; 12/Feb/90 Changed code to avoid problems with double byte character sets.
;  8/Mar/90 Remove extra pair of CR/LF's that were output after error
; 20/Apr/90 DLS data into R_TEXT for Watcom C v7.0
;  9/May/90 Critical errors go to STDERR on command PSP, not current_psp

	include msdos.equ
	include mserror.equ
	include	driver.equ
;
dataOFFSET	equ offset DGROUP:


PSP_XFTPTR	equ	es:dword ptr 34h	; from i:PSP.DEF

;	Critical Error responses from the default INT 24 handler and
;	the DO_INT24 routine.
;
ERR_IGNORE	equ	0		; Ignore Error
ERR_RETRY	equ	1		; Retry the Operation
ERR_ABORT	equ	2		; Terminate the Process
ERR_FAIL	equ	3		; Fail Function
;
OK_FAIL		equ	00001000b	; Fail is a Valid Response
OK_RETRY	equ	00010000b	; Retry is a Valid Response
OK_IGNORE	equ	00100000b	; Ignore is a valid Response
OK_RIF		equ	00111000b	; All Responsese are Valid
OK_RI		equ	00110000b	; Retry and Ignore are Valid
OK_RF		equ	00011000b	; Retry and Fail are Valid
;
;
;	The following equates allow us to access the users registers
;	and flags during normal system call emulation.
;
;NOTE:-	The users INT21 structure is not normally available because of the
;	stack switch which occurs on entry and only the general purpose
;	registers are copied to the new stack.
;
dos_AX		equ	word ptr 0[bp]
dos_BX		equ	word ptr 2[bp]
dos_CX		equ	word ptr 4[bp]
dos_DX		equ	word ptr 6[bp]
dos_SI		equ	word ptr 8[bp]
dos_DI		equ	word ptr 10[bp]
dos_BP		equ	word ptr 12[bp]
dos_DS		equ	word ptr 14[bp]
dos_ES		equ	word ptr 16[bp]
;
;
;
ifdef CDOSTMP
DGROUP	GROUP	R_TEXT

R_TEXT		SEGMENT byte public 'CDOS_DATA'

else

DGROUP	GROUP	_DATA, R_TEXT, ED_TEXT

R_TEXT		SEGMENT byte public 'CDOS_DATA'
R_TEXT		ENDS

_DATA		SEGMENT byte public 'DATA'

endif
	extrn	_country:WORD
	extrn	__psp:WORD

ifdef DLS
TEXT_LEN	equ	320		; it needs to be this size for Japanese

	Public	_crit_msgs

	; crit_table gives offset into crit_msgs table.

crit_table	db	0		; (00) Write to Read Only Disk
		db	2		; (01) Unknown Unit
		db	4		; (02) Drive Not Ready
		db	2		; (03) Unknown Command
		db	6		; (04) Data Error (CRC)
		db	2		; (05) Bad Request Length Structure
		db	8		; (06) Seek Error
		db	10		; (07) Unknown Media Type
		db	12		; (08) Sector Not Found
		db	14		; (09) Printer Out Of Paper
		db	2		; (0A) Write Fault
		db	2		; (0B) Read Fault
		db	2		; (0C) General Failure
		db	16		; (0D) File Sharing Error
		db	16		; (0E) Locking Error
		db	18		; (0F) FCB Unavailable

_crit_msgs	dw	TEXT_LEN	; size of this message buffer
crit_top	dw	0,0,0,0,0,0,0,0,0,0
msg_crlf	dw	0	
readmsg		dw	0
writemsg	dw	0
drivemsg	dw	0
charmsg		dw	0
abort_char	dw	0
abort_msg	dw	0
retry_char	dw	0
retry_msg	dw	0
ignore_char	dw	0
ignore_msg	dw	0
fail_char	dw	0
fail_msg	dw	0
prompt_msg	dw	0
		dw	0	; end of list

public	_crit_text
_crit_text	db	TEXT_LEN dup(?)	; message text is placed here

CRIT_LEN	equ	$-crit_top


else

	extrn	msg0:byte, msg2:byte, msg3:byte, msg4:byte
	extrn	msg6:byte, msg7:byte, msg8:byte
	extrn	msg20:byte, msg21:byte, msg22:byte

crit_top	dw	offset DGROUP:msg0	; (00) Write to Read Only Disk
		dw	offset DGROUP:msg3	; (01) Unknown Unit
		dw	offset DGROUP:msg2	; (02) Drive Not Ready
		dw	offset DGROUP:msg3	; (03) Unknown Command
		dw	offset DGROUP:msg4	; (04) Data Error (CRC)
		dw	offset DGROUP:msg3	; (05) Bad Request Length Structure
		dw	offset DGROUP:msg6	; (06) Seek Error
		dw	offset DGROUP:msg7	; (07) Unknown Media Type
		dw	offset DGROUP:msg8	; (08) Sector Not Found
		dw	offset DGROUP:msg21	; (09) Printer Out Of Paper
		dw	offset DGROUP:msg3	; (0A) Write Fault
		dw	offset DGROUP:msg3	; (0B) Read Fault
		dw	offset DGROUP:msg3	; (0C) General Failure
		dw	offset DGROUP:msg20	; (0D) File Sharing Error
		dw	offset DGROUP:msg20	; (0E) Locking Error
		dw	offset DGROUP:msg22	; (0F) FCB Unavailable


	Extrn	msg_crlf:byte
	Extrn	readmsg:byte, writemsg:byte, drivemsg:byte, charmsg:byte
	Extrn	abort_char:byte, abort_msg:byte
	Extrn	retry_char:byte, retry_msg:byte
	Extrn	ignore_char:byte, ignore_msg:byte
	Extrn	fail_char:byte, fail_msg:byte, prompt_msg:byte
endif
ifndef CDOSTMP
_DATA	ends
ED_TEXT		SEGMENT para public 'CDATA'
endif

	assume cs:DGROUP, ds:nothing, es:nothing, ss:nothing
;
;	This is the default critical error handler which will prompt
;	the user with an error message and wait for a response. This handler
;	is usually replaced by the DOS application
;
;	+++++++++++++++++++++++++++++++
;	Int 24 - Critical Error Handler
;	+++++++++++++++++++++++++++++++
;
;	INT 24 Critical Error:-
;	    On Entry:-	AH/7	0 = Disk Device
;			AH/5	0 = IGNORE is an Invalid Response
;			AH/4	0 = RETRY in an Invalid Response
;			AH/3	0 = FAIL is an Invalid Response
;			AH/2-1	00= DOS Area
;				01= File Allocation Table
;				10= Directory
;				11= Data
;			AH/0	0 = Read, 1 = Write
;
;			AL	Failing Disk Drive if AH/7 == 0
;			BP:SI	Device Header Control Block
;			DI	High Byte DRNET server (inverted, CDOS only)
;				Low Byte Error Code 
;
;	    On Exit:-	AL	0 = IGNORE Error
;				1 = RETRY the Operation
;				2 = TERMINATE using INT 23
;				3 = FAIL the current DOS function
;
;

	Public	com_criterr	
com_criterr:
;
;	This is called by the int24 handler 'critical_error', in CSTART.ASM.
;
	sti
	cld
	push	es
	push	ds
	push	bp
	push	di
	push	si
	push	dx
	push	cx
	push	bx
	push	ax
	
	mov	bp,sp
	mov	ah,MS_P_GETPSP
	int	DOS_INT			; Get PSP into DS
	mov	ds,cs:__psp	
	mov	al,ds:byte ptr 1ah	; use COMMAND STDERR for Console INPUT
	mov	ah,al			;  and OUTPUT
	mov	es,bx
	lds	bx,PSP_XFTPTR		; Get the handle table pointer
	push	word ptr [bx]		; Save the current Values
	mov	word ptr [bx],ax

	push	cs
	pop	ds			; DS == CS
	call	i24_crlf		;output carriage return - line feed

	mov	ah,MS_F_ERROR
	xor	bx,bx
	int	DOS_INT			; Get extended error code
	mov	cx,ax			; Get the Real Error Code (ie INT21/59)
	mov	bx,0Fh			; assume FCB unavailable
	cmp	al,-(ED_NOFCBS)		; if FCB exhausted/closed then generate
	 je	int24_e10		;  a more appropriate error message
	dec	bx
    dec bx          
	cmp	al,-(ED_SHAREFAIL)	;  check for sharing failure which
	 je	int24_e10		;  is forced to be a DRIVE NOT READY
	cmp	al,-(ED_NOLOCKS)	; check for sharing buffer overflow
	 je	int24_e10
	dec	bx			; BX = 0Ch, default error
	mov	ax,dos_DI		; get the REAL error code
	cmp	ax,0Eh			; is it a sensible value ?
	 ja	int24_e10		; no, return GENERAL FAILURE
	xchg	ax,bx			; yes, use it
int24_e10:
	call	int24_errmsg		; print out the offending error msg
	call	i24_crlf		; Print CR/LF

;
;	This section of the Critical Error handler prints the correct
;	prompt repeatedly until the user responds with a correct
;	response. This value is returned to the PCMODE.
;
i24_query:
ifdef DLS
	mov dx,abort_msg		; Print "Abort" as this is always
else
	mov dx,dataOFFSET abort_msg	; Print "Abort" as this is always
endif
	call i24_print			; a valid response

	test bh,OK_RETRY
	 jz i24_q10			; Display ", Retry" if RETRY 
ifdef DLS
	mov	dx,retry_msg		; is a Valid Response
else
	mov	dx,dataOFFSET retry_msg	; is a Valid Response
endif
	call	i24_print

i24_q10:
	test bh,OK_IGNORE
	 jz i24_q20			; Display ", Ignore" if IGNORE
ifdef DLS
	mov	dx,ignore_msg		; is a valid response
else
	mov	dx,dataOFFSET ignore_msg ; is a valid response
endif
	call	i24_print

i24_q20:
	test bh,OK_FAIL
	 jz i24_q30			; Display ", Fail" if FAIL is
ifdef DLS
	mov	dx,fail_msg		; a valid response
else
	mov	dx,dataOFFSET fail_msg	; a valid response
endif
	call	i24_print

i24_q30:
ifdef DLS
	mov	dx,prompt_msg
else
	mov	dx,dataOFFSET prompt_msg
endif
	call	i24_print

	mov	ah,MS_C_FLUSH		; Clear type ahead buffer
	mov	al,MS_C_READ		; and then get a character
	int	DOS_INT

; In case we get double byte characters...
; If we had access to the dbcs_lead() routine (in the non-resident code)
; we could test for a double byte character and consume the second byte.
; Since we can't do this I have used the following code, which simply
; consumes and displays all bytes in type-ahead buffer.
	push	ax			; save first character received
dbcs_loop:
	mov	ah, MS_C_RAWIO		; char in type-ahead buffer?
	mov	dl, 0FFh
	int	DOS_INT
	 jz	dbcs_exit		;  no - exit loop
	mov	dl, al
	mov	ah, MS_C_WRITE		;  yes - display char
	int	DOS_INT
	jmp short dbcs_loop		; loop until type-ahead buffer empty
dbcs_exit:
	pop	ax			; restore the first character

; Check that character lies in the range 'a' <= ch <= 'z' before anding it
; with 5Fh to uppercase it (incase the character is a DBCS lead byte).

	cmp	al, 'a'			; ch < 'a' ?
	 jb	uc_done			;  yes - skip upper casing
	cmp	al, 'z'			; ch > 'z' ?
	 ja	uc_intl			;  yes - may be intl
	and	al, 5Fh			; uppercase ch
	jmp short uc_done
uc_intl:
	cmp	al, 80h			; international char?
	 jb	uc_done
; ch >= 80h  -- call international routine
UCASE	equ	18			; offset of dword ptr to uppercase func
	call	dword ptr [_country+UCASE]
uc_done:

	push	ax
	call	i24_crlf
	pop	dx

	mov	ah,bh
	xor	al,al			; AL == 0 IGNORE Error
ifdef DLS
	test	ah,OK_IGNORE
	 jz	i24_q40			; Is it a valid response
	mov	bx,ignore_char
	cmp	dl,[bx]
else
	test	bh,OK_IGNORE
	 jz	i24_q40			; Is it a valid response
	cmp	dl,ignore_char
endif
	 jz 	i24_exit

i24_q40:
	inc	ax			; AL == 1 RETRY Function
ifdef DLS
	test	ah,OK_RETRY
	 jz	i24_q50			; Is it a valid response
	mov	bx,retry_char
	cmp	dl,[bx]
else
	test	bh,OK_RETRY
	 jz	i24_q50			; Is it a valid response
	cmp	dl,retry_char
endif
	 jz	i24_exit

i24_q50:
	inc	ax			; AL == 2 ABORT Process
ifdef DLS
	mov	bx,abort_char
	cmp	dl,[bx]
else
	cmp	dl,abort_char
endif
	 jz	i24_exit

	inc	ax			; AL == 3 FAIL Function
ifdef DLS
	test	ah,OK_FAIL
	 jz	i24_query_again		; Is it a valid response
	mov	bx,fail_char
	cmp	dl,[bx]
	 jz	i24_exit
i24_query_again:
	mov	bh, ah			; restore valid response bit set
	jmp	i24_query
else
	test	bh,OK_FAIL
	 jz	i24_query_again		; Is it a valid response
	cmp	dl,fail_char
	 jz	i24_exit
i24_query_again:
	jmp	i24_query
endif


i24_exit:
	mov	dos_AX,ax
	mov	ah,MS_P_GETPSP
	int	DOS_INT			; Get PSP into DS
	mov	es,bx
	lds	bx,PSP_XFTPTR		; the handle table pointer
	pop	word ptr [bx]		; Restore the original handle Values
	
	pop	ax
	pop	bx
	pop	cx
	pop	dx
	pop	si
	pop	di
	pop	bp
	pop	ds
	pop	es

	ret

int24_errmsg:
; Print out an appropriate error message (eg. "Drive not ready")
; Call INT 2F functions in case system extentions (eg. CDROM) wish to
; give another error message.
	push	bx			; save error code
	push	cx
	mov	ax,500h
	int	2fh			; query if user msg handler installed
	cmp	al,0ffh			; yes if FF returned
	pop	cx
	pop	bx
	 jne	int24_errmsg10
	push	bx
	push	cx
if 0
; the DOS 3 way
	mov	ah,5			; OK. now we ask for a message
	mov	al,cl			;  with the error code in AL
else
; the DOS 5 way
	mov	ax,501h
	mov	bx,cx
endif
	int	2fh			; ES:DI -> msg
	pop	cx
	pop	bx
	 jc	int24_errmsg10		; did they give us a msg ?
	mov	si,di			; ES:SI -> msg
	mov	ah,MS_C_WRITE		; write it out
int24_errmsg1:
	lods	es:byte ptr [si]	; get a character
	test	al,al			; until end of an ASCIIZ string
	 jz	int24_errmsg2
	mov	dl,al			; character into DL
	int	DOS_INT			; write it
	jmp short int24_errmsg1
int24_errmsg2:
	mov	bx,dos_AX		; get original AX for Abort/Retry etc
	ret
	
int24_errmsg10:
; No-one wants to supply a message - we'd better generate one ourselves
;
	xor	bh,bh			 
ifdef	DLS
	mov	bl, crit_table[bx]
else
	shl	bx,1
endif
	mov	dx, crit_top[bx]	
	call	i24_print		

	mov	bx,dos_AX		; Get the Original AX
	test 	bh,01h			; check to see if the error occured 
	jnz 	prwrite			; while reading or writing
ifdef DLS
	mov 	dx,readmsg 		; print 'reading'
else
	mov 	dx,dataOFFSET readmsg 	; print 'reading'
endif
	jmp short prread
prwrite:
ifdef DLS
	mov 	dx,writemsg		; print 'writing'
else
	mov 	dx,dataOFFSET writemsg	; print 'writing'
endif
prread:
	call	i24_print		; appropriate string
;;	test	bh,80h
	mov	es,dos_BP		; ES:SI = driver header
	test	es:DH_ATTRIB[si],DA_CHARDEV
	 jz	disk_error		; Was this a DISK error

;
;	For Character Device errors print the failing Device Name
;	and then prompt the user for a valid response.
;
;character_error:
ifdef DLS
	mov	dx,charmsg
else
	mov	dx,dataOFFSET charmsg
endif
	call	i24_print

;;	mov	es,dos_BP		; ES:SI = driver header
	mov	cx,8			; Print the 8 Character device name
char_name:
	mov	dl,DH_NAME[si]		; Get the next character and
	mov	ah,MS_C_WRITE		; display on the console
	int 	DOS_INT
	inc	si			; Increment the character pointer
	loop	char_name		; and Loop till complete name displayed
	ret				; Now query the user

;
;	For DISK errors print the failing drive code and then
;	prompt the user for a valid response.
;
disk_error:
ifdef DLS
	mov	dx,drivemsg		;
else
	mov	dx,dataOFFSET drivemsg	;
endif
	call	i24_print		; print 'drive d'
	mov	dl,bl			; Get the Drive Code
	add 	dl,'A'			; convert drive to ascii 
	mov 	ah,MS_C_WRITE		; print the drive
	int	DOS_INT
	ret

i24_crlf:
ifdef DLS
	mov	dx,msg_crlf
else
	mov	dx,dataOFFSET msg_crlf
endif

i24_print:
	mov 	ah,MS_C_WRITESTR
	int	DOS_INT
	ret

ifdef CDOSTMP
R_TEXT	ENDS
else
ED_TEXT	ENDS
endif
	end
