;       SCCSID = @(#)d_eclass.asm	6.1 91/02/15
;	SCCSID = @(#)d_eclass.asm	1.4 90/01/22
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;
;
;	10-Oct-87 (robertc) refreshed error table from dosio.asm
;	09-Dec-87 (microsoft!johnfr) removed CHILD_ALIVE_NOWAIT
;	08-Mar-88 (robertc) refreshed error table from dosio.asm
;
;/*************** START OF SPECIFICATIONS ******************************/
;/*								       */
;/* SUBROUTINE NAME: DosErrClass				       */
;/*								       */
;/* SOURCE FILE NAME: D_ERRCLS.ASM				       */
;/*								       */
;/* DESCRIPTIVE NAME: Dos Error Class				       */
;/*								       */
;/* FUNCTION:  Retrieves the class, action, and locus after a Family   */
;/*	       API error.					       */
;/*								       */
;/*								       */
;/* NOTES:  @@ DosErrClass is a new routine to the 1.10 Family API     */
;/*	    Library.						       */
;/*								       */
;/* ENTRY POINT:						       */
;/*	    LINKAGE:  EXTRN DosErrClass:FAR			       */
;/*								       */
;/* INPUT:  PUSH     WORD    Code	  ;Error code to lookup	       */
;/*	    PUSH@    WORD    Class	  ;pointer to class	       */
;/*	    PUSH@    WORD    Action	  ;pointer to action	       */
;/*	    PUSH@    WORD    Locus	  ;pointer to locus	       */
;/*	    call  DosErrClass					       */
;/*								       */
;/*								       */
;/* EXIT-NORMAL:  AX = 0					       */
;/*								       */
;/* EXIT-ERROR:	 AX = 0						       */
;/*								       */
;/* EFFECTS:  BP, ES, DS, DI, SI, BX, CX, and DX, registers are saved. */
;/*								       */
;/* PSUEDO CODE:						       */
;/*								       */
;/* INTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*								       */
;/* EXTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*								       */
;/*************** END OF SPECIFICATIONS ********************************/
;
;
.XLIST
include error2.inc
include error.inc
include basemaca.inc
INCLUDE dos2equ.inc

	.LFCOND				; Show false conditionals
	.SALL				; Supress macro expansion

.LIST
;
; PUBLIC SYMBOLS
;
PUBLIC	DosErrClass
PUBLIC	_indices
PUBLIC	_list
PUBLIC	DosErrAdd

	PAGE

_TEXT	segment byte public 'CODE'
	assume	CS:_TEXT,DS:NOTHING

; EXTRN's moved into code segment to force CS override

	EXTRN	__api_begin:near
	EXTRN	__api_end:near
	EXTRN	_api_getvrsn : near
	EXTRN	crit_err_set:near

	EXTRN	crit_err_AX:word
	EXTRN	crit_err_BX:word
	EXTRN	crit_err_CX:word
	EXTRN	crit_err_flag:word




errcode		equ	[BP+18]		; offsets for input parameters
class		equ	[BP+14]
action		equ	[BP+10]
locus		equ	[BP+6]

list_len	equ	 5
list_width	equ	 5
not_used	equ	 0
not_found	equ	 0
is_used		equ	 1
is_found	equ	 1
fail_on_int_24	equ	83
int_24_mapping	equ	19

found	DW	?

_indices	DW	00H		;******IMPORTANT
		DW	01H		; _indices MUST be as long
		DW	02H		; as list_len and be initialized
		DW	03H		; to 0 to list_len-1
		DW	04H

_list	DW	(list_len * list_width) dup (0)

stash	dw	?
; Must define emit_error_table to make errtab.inc generate data

emit_error_table equ 0ffffh

etab	  label	  word
include errtab.inc		;Include table giving class, action and locus
				; for each error.
etablen =	($-etab)/SIZE ErrEntry



DosErrClass    PROC FAR

	call	__api_begin	; init bp and save bp,ds,bx,cx,dx,si,di,es
				; required to save: bp,bx
;* find an entry matching code *
	xor	cx,cx			; set up index to zero
	jmp	look			; start the match lookup

bumpi:
	inc	cx			; i++

check_lim:
	cmp	cx,list_len		; table and indices is 5 deep
	jb	look			; keep looking
	jmp	err_unk			; table exhausted

look:
	mov	bx,cx
	shl	bx,1			; set up a WORD index
	mov	si,WORD PTR _indices[bx]; si has index of table entry

;** look for a valid table entry with a matching code

	mov	bx,si			; set bx to point at the valid flag
	mov	ax,bx
	shl	bx,1
	shl	bx,1
	add	bx,ax
	shl	bx,1
	cmp	WORD PTR _list[bx+8],is_used  ; is valid flag set to 1
	je	valid			; yes
	jmp	bumpi			; no

valid:
	mov	ax,[errcode]		;get the passed in code
	cmp	WORD PTR _list[bx],ax	;and compare it to valid entries
	je	get_data		;got a match
	jmp	bumpi			;no match

get_data:
	les	bx,[class]		;fill in class for caller
	mov	di,si
	mov	ax,di
	shl	di,1
	shl	di,1
	add	di,ax
	shl	di,1
	mov	ax,WORD PTR _list[di+2]
	mov	es:[bx],ax

	les	bx,[action]		;fill in action for caller
	mov	ax,WORD PTR _list[di+4]
	mov	es:[bx],ax

	les	bx,[locus]		;fill in locus for caller
	mov	ax,WORD PTR _list[di+6]
	mov	es:[bx],ax

	mov	WORD PTR _list[di+8],not_used ; mark this entry as invalid

;* reshuffle the indices *

	mov	dx,cx	    ;		 ; j = i
	jmp	checkj

bumpj:
	inc	dx			 ; point to next index

checkj:
	cmp	dx,list_len-1		; last index ?
	jb	loopj			; no
	jmp	donej			; yes

loopj:
	mov	bx,dx			 ;shift indices to the left
	shl	bx,1
	mov	di,dx
	shl	di,1
	mov	ax,WORD PTR _indices[di+2]
	mov	WORD PTR _indices[bx],ax
	jmp	bumpj

donej:
	mov	bx,dx			; and now move the found index
	shl	bx,1			;; to the end.
	mov	WORD PTR _indices[bx],si
	jmp	doneget

;;; error not found in dynamic FIFO queue, look in static table
err_unk:
	push	es
	mov	ax,[errcode]
	mov	cx,etablen
	mov	si,OFFSET CS:etab

;	Search for error code

dec1:	cmp	ax,cs:ErrorCode.[si]
	jz	dec3			; got it
	add	si,SIZE ErrEntry
	loop	dec1			; try each one

;	We fell off the end of the table (Bad Ecode)

	sub	si, SIZE ErrEntry	; move pointer back

;	(CS:SI) = address of record


dec3:	sub	ah,ah
	mov	al,cs:ErrClass.[si]		; (ax) = classification
	les	di,[class]
	stosw
	mov	al,cs:ErrAction.[si]		; (ax) = action
	les	di,[action]
	stosw
	mov	al,cs:ErrLocus.[si]		; (ax) = locus
	les	di,[locus]
	stosw
	pop	es

doneget:
	xor	ax,ax		; return 0
	call	__api_end	; check sigs & restore es,di,si,dx,cx,bx,ds,bp
	ret	14	; clear stack of entry parameters (bytes)
DosErrClass    ENDP

;;;;*********************************************************************

;; on entry  AX = extended errorcode
;;	     BH = Error class
;;	     BL = Suggested action
;;	     CH = Locus

;; on exit   all registers preserved


DosErrAdd   PROC FAR
	push	ax
	push	bx
	push	cx
	push	dx
	push	si
	push	di


	push	cx
	push	bx
	push	ax

;* find empty slot
	xor	dx,dx			; set up found flag
	xor	cx,cx			; set up index to zero
	jmp	a_checki		; start the match lookup

a_bumpi:
	inc	cx			 ; i++

a_checki:
	cmp	cx,list_len		; table and indices is 5 deep
	jb	a_look			; keep looking
	jmp	a_donei			; table exhausted

a_look:
	mov	bx,cx
	shl	bx,1			; set up word index
	mov	si,WORD PTR _indices[bx]; si has index of table entry

	mov	bx,cx			 ;set up to point at the valid flag
	shl	bx,1
	mov	bx,WORD PTR _indices[bx]
	mov	ax,bx
	shl	bx,1
	shl	bx,1
	add	bx,ax
	shl	bx,1
	cmp	WORD PTR _list[bx+8],not_used  ;is valid flag set to 0
	je	a_found			;Yes, found an empty slot
	jmp	a_bumpi			;No, not yet

a_found:
	mov	dx,is_found		; set match flag


; we get here either by finding an empty or running out of slots

a_donei:
	cmp	dx,not_found		;did we find an empty
	je	noneopen		;none found
	jmp	adddata			;found one

noneopen:
	mov	si,WORD PTR _indices	 ; we will replace the oldest
	xor	cx,cx			 ;start at beginning of indices
	jmp	a_checki2

a_bumpi2:
	inc	cx			 ;next index

a_checki2:
	cmp	cx,list_len-1		 ;have we gone to far
	jb	a_look2
	jmp	a_donei2

a_look2:
	mov	bx,cx			  ; indices[i] = indices[i+1];
	shl	bx,1
	mov	di,cx
	shl	di,1
	mov	ax,WORD PTR _indices[di+2]
	mov	WORD PTR _indices[bx],ax
	jmp	a_bumpi2

a_donei2:
	mov	bx,cx			 ;and now set the end index
	shl	bx,1
	mov	WORD PTR _indices[bx],si

adddata:
	mov	bx,si			 ; add the code to table
	mov	ax,bx
	shl	bx,1
	shl	bx,1
	add	bx,ax
	shl	bx,1
	pop	ax			; get errorcode off stack
	mov	WORD PTR _list[bx],ax

	pop	dx			; get class and action off stack
	xor	ax,ax
	mov	al,dh			; ax = class
	mov	WORD PTR _list[bx+2],ax

	mov	al,dl			; ax = action
	mov	WORD PTR _list[bx+4],ax

	pop	dx			; get locus off stack
	mov	al,dh			; ax = locus
	mov	WORD PTR _list[bx+6],ax

	mov	WORD PTR _list[bx+8],is_used  ;set the table entry to VALID

	pop	di			; clean up stack
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ax			; get back the errorcode
	ret
DosErrAdd    ENDP




;;;common call for all fapi to get extended error code and
;; fill in DOSERRCLASS table.
;; on entry  AX = errorcode
;;
;; on return AX = extended errorcode
;;	     BH = Error class
;;	     BL = Suggested action
;;	     CH = Locus
;;
;; NOTE: the int 21H function 59H destroys the contents of DX,SI,DI,ES,CL,DS

	public	api_get_extended

api_get_extended  proc	  far
	mov	stash,ax		; save original errorcode
	call	_api_getvrsn		; AH <- major, AL <- minor version
					; version comes from stubloader
	cmp	ah,3
	jge	get_ext
	jmp	fake_it
get_ext:
;; NOTE: the int 21H function 59H destroys the contents of DX,SI,DI,ES,CL,DS
	push	si
	push	di
	push	es
	push	ds
	push	dx
	push	cx

	mov	ah,59h			;Get Extended Error
	xor	bx,bx
	int	21h

	pop	dx
	mov	cl,dl
	pop	dx
	pop	ds
	pop	es
	pop	di
	pop	si

check_crit:
	cmp	ax,83			; we already hooked crit error
	jne	normal			; no
	cmp	crit_err_flag,0ffh	; have we used our critical error
					; handler
	jne	normal			; not really normal but 83 is best.

	mov	ax,crit_err_AX		; restore data from crit error
	mov	bx,crit_err_BX
	mov	cx,crit_err_CX
	mov	crit_err_flag,0		; reset crit_err_flag
	jmp	exit			; but do not add to table

normal:
	mov	stash,ax		; save extended code for return
	jmp	add_it
fake_it:
	mov	ax,stash		; get original errorcode
	mov	bx,(ERRCLASS_UNK SHL 8) + ERRACT_ABORT
	mov	ch,ERRLOC_UNK
add_it:
	call	DosErrAdd
	mov	ax,stash		; retreive the code
exit:
	ret

api_get_extended endp

_TEXT	ENDS
END
