;       SCCSID = @(#)d_sig.asm	6.1 91/02/15
;	SCCSID = @(#)d_sig.asm	6.2 90/01/22
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;***  D_SIG.ASM - API stub routine DosSetSigHandler
;
;	Member of API library
;	David Silverstein
;	Copyright MicroSoft Corporation, 1986
;	August 1986
;
;	library routine for API simulator
;
;	Called from dos 2.x,3.x compatible dos 5.x applications
;
;	Special Information
;		none
;
;	Modification History
;
;	2-Dec-1986 (billme): minor repairs according to ptm 229
;	and a bit of cleanup (code improvement)
;
;	31-Dec-1986 (billme): change code to accomodate signal
;	handlers written in C ... this was done by postponing
;	the execution of the handler until just before or just
;	after the execution of a "top level" FAPI routine (i.e.
;	NOT the execution of a FAPI routine called from within
;	another FAPI routine) ... NOTE that this requires that
;	any FAPI routine which calls another FAPI routine MUST
;	USE THE __api_begin/__api_end CONVENTION!
;
;
;	22-Sep-1987 (robertc): change errorcode
;
;	13-Oct-1987 (robertc): Use signal equates in ..\..\..\dos\sigdef.inc

include dos2equ.inc
include error.inc
include error2.inc
include api.inc
; Use commom signal equates
include sigdef.inc

	EXTRN	__api_begin:near
	EXTRN	__api_end:near

CGRP	group	_TEXT,SIGCHECK

	assume	CS:CGRP, DS:nothing


;***	DosSetSigHandle - stub to emulate function call
;
;	simulates DOS 5.0 call from DOS 2.x,3.x environment
;
;	This module currently supports ONLY ctrl-C signal.
;
;	SIGTERM (program termination):	This doesn't make sense
;	in Dos 2.x and 3.x since there is only one process.
;
;
;	errorcode = unsigned far pascal
;	DosSetSigHandler(RoutineAddress, PrevAddress, PrevAction,
;			Action, SigNumber);
;
;	ENTRY:
;		RoutineAddress - Signal handler address
;		PrevAddress    - Address of previous handler
;		PrevAction     - Address of previous action
;		Action	       - Indicate request type
;		SigNumber      - Signal number of interest
;
;	RETURN:
;		AX = 0 if no error, else error code (see DOS 5 spec)
;
;	EFFECTS:
;		This call will cause CtrlC to get hooked (unless
;		hooked already). CtrlC will remain hooked for the
;		duration of the process.
;

	title	DOSSETSIGHANDLER
;
;	EXTRN	DOSSETSIGHANDLER:FAR
;
;	PUSH	DWORD RoutineAddress
;	PUSH	@ DWORD PrevAddress
;	PUSH	@ WORD PrevAction
;	PUSH	WORD Action
;	PUSH	WORD SigNumber
;	CALL	DOSSETSIGHANDLER
;

_TEXT	segment byte public 'CODE'


	public	DOSSETSIGHANDLER

	extrn	FapiAddSigCatch :FAR
	extrn	FapiSubSigCatch :FAR


RoutineAddress	equ	[bp + 18]
PrevAddress	equ	[bp + 14]
PrevAction	equ	[bp + 10]
Action		equ	[bp + 8]
SigNumber	equ	[bp + 6]

;SIGINTR	 equ	 1	 ; Ctrl-C	  ;@@ REMOVED ----
;SIGBREAK	 equ	 3	 ;@@ Ctrl-Break	  ;@@ Use SIGDEF.INC

SYSTEM_DEFAULT	equ	0	; system default action
IGNORE_SIGNAL	equ	1	; ignore signal
INSTALL_SIGNAL	equ	2	; install signal handler at RoutineAddress
NO_FLAGPROCESS	equ	3	; error if DOSFLAGPROCESS issued to this process
RENABLE_REC	equ	4	; reenable signal recognition

HandlerAddress	dd	0
ActionSaved	dw	0
CurrentSignal	dw	SIGINTR
SigEnabled	db	1
SigFlag		db	0
SigDataSeg	dw	0

DOSSETSIGHANDLER	proc	far

IFDEF api_debug_pause
	int	3	; included ONLY IF api_debug_pause is defined
ENDIF

	push	bp
	mov	bp, sp
	push	ds
	push	bx
	push	cx
	push	dx
	push	si

	mov	ax,ds			; save data segment for handler
	mov	SigDataSeg,ax

	xor	ax,ax			       ;@@ no error
	cmp	word ptr [SigNumber], SIGBREAK	;@@ we ignore this one
	jne	chkintr
	jmp	ErrorExit		       ;@@ get out
chkintr:
	cmp	word ptr [SigNumber], SIGINTR	; is the signal number valid?
	mov	ax, error_invalid_signal_number ;@@ change error code ptm704
	jne	ErrorExit

	mov	ax, error_invalid_function
	mov	cx, [Action]		; get action code
	or	ch,ch			; if high byte set
	jnz	ErrorExit		; then function must be erroneous
	mov	bx, SETSIGHANDLER	; set up library parameter for
					; FapixxxSigCatch
	cmp	cl, SYSTEM_DEFAULT
	jne	IgnoreSignal
	call	FapiSubSigCatch		; remove signal handling
	jmp	short okExit

IgnoreSignal:
	cmp	cl, IGNORE_SIGNAL
	jne	InstallSignal
	mov	dx, SEG CGRP		; ds:dx <= address of ignore sig handler
	mov	ds, dx
	mov	dx, offset CGRP:IgnSigHandler
	call	FapiAddSigCatch		; install ignore signal handler
	jmp	short okExit

InstallSignal:
	cmp	cl, INSTALL_SIGNAL
	jne	RenableRecognition
	lds	si, [PrevAddress]			; return previous
	mov	ax, word ptr CGRP:[HandlerAddress]	; handler address
	mov	[si], ax
	mov	ax, word ptr CGRP:[HandlerAddress + 2]
	mov	[si + 2], ax

	lds	si, [RoutineAddress]		; save new handler addrs

	mov	word ptr CGRP:[HandlerAddress], si
	mov	word ptr CGRP:[HandlerAddress + 2], ds

	mov	ax, SEG CGRP			; ds:dx <= address of
	mov	ds, ax				; new signal handler
	mov	dx, offset CGRP:SigHandler
	call	FapiAddSigCatch			; install new signal handler
	mov	CGRP:[SigEnabled], 1		; allow a new signal
	jmp	short okExit

RenableRecognition:
	cmp	cl, RENABLE_REC
	jne	ErrorExit
	mov	CGRP:[SigEnabled], 1		; allow a new signal

okExit:
	lds	bx, [PrevAction]		; return the previous action
	mov	ax, CGRP:[ActionSaved]
	mov	[bx], ax
	mov	CGRP:[ActionSaved], cx		; save the current action
	xor	ax, ax				; clear error return code

ErrorExit:
	pop	si
	pop	dx
	pop	cx
	pop	bx
	pop	ds
	pop	bp
	ret	16

DOSSETSIGHANDLER	endp


;**	SigHandler - routine that receives actual interrupt
;
;	called only by hooked interrupt (see above)
;
;	ENTRY:
;
;	RETURN:
;

SigHandler	proc	far

	cmp	CGRP:[SigEnabled], 1	; is the signal enabled?
	jne	han1			; ignore it

	mov	CGRP:[SigEnabled], 0	; disable signal
	mov	CGRP:[SigFlag],1	; set signal flag
	push	ax			; preserve AX
	call	__api_begin		; null call to api begin/end which
	call	__api_end		;  will fire handler if possible
	pop	ax			; restore AX
han1:
	iret

SigHandler	endp


;**	IgnSigHandler - used to ignore a signal
;
;	called only by hooked interrupt (see above)
;
;	ENTRY:
;
;	RETURN:
;

IgnSigHandler	proc	far

	iret

IgnSigHandler	endp


_TEXT	ends



SIGCHECK	segment byte common 'CODE'

; See notes IN i_versio.asm.

TopCall dw	0
temp	dw	0				; for return address


; See notes IN i_versio.asm.

SHORT_JMP_OP	equ	0EBh

SignalCheck	proc	near

	db	SHORT_JMP_OP
	db	1			; jump to ExecSignalCheck
	ret				; one byte - doesn't matter

SignalCheck	endp


;**    ExecSignalCheck
;
;	errorcode = unsigned near pascal
;	ExecSignalCheck();
;
;	ENTRY:
;
;	RETURN:
;		all registers preserved
;		flags are corrupted
;
;	NOTE:
;		Should be called only when entering (before registers
;		are altered) or leaving (after registers are restored)
;		an FAPI routine.
;

;	EXTRN	ExecSignalCheck:near
;
;	CALL	ExecSignalCheck
;

ExecSignalCheck proc	near

	cmp	CGRP:[SigFlag],1	; if signal flag not set
	jne	sigchkx			; then return
	cmp	CGRP:[TopCall],0	; if top-call is not zero
	jne	sigchkx			; then return
					; else fire the user's routine
	inc	CGRP:[TopCall]		; increment - to avoid infinite loop

	push	ax			; save ax (others saved by __api_begin)
	mov	ax,SigDataSeg
	mov	ds,ax			; set DS to correct value

						; fire signal handler...
	xor	ax, ax
	push	ax				; push 0 where SigArg would be
	push	CGRP:[CurrentSignal]		; signal being processed
	call	dword ptr CGRP:[HandlerAddress] ; call users signal handler

	pop	ax			; restore ax

	dec	CGRP:[TopCall]		; decrement topcall
	mov	CGRP:[SigFlag],0	; reset signal flag
sigchkx:
	ret

ExecSignalCheck endp

SIGCHECK	ends


	end

