;       SCCSID = @(#)ansiinj.asm	6.1 90/11/16
;	SCCSID = @(#)ansiinj.asm	6.4 90/02/12
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
	PAGE	60,132
	TITLE	ANSIINJ.ASM - Inject ANSI DSR

;********************** START OF SPECIFICATIONS *******************************
;*
;*   Subroutine Name:  AnsiInject
;*
;*   Descriptive Name:	Inject ANSI DSR output to KbdHandler buffer
;*
;*   Function:	When AnsiInterp requests a Device Status Report (DSR), the
;*		character string forming the CURSOR POSITION REPORT (CPR) is
;*		output to a buffer (dsrBuff).  Whenever a CPR is pending, the
;*		GetStringIn function returns these characters instead of
;*		calling the keyboard driver.
;*
;*   Notes:  When called with the BUILD action a CPR string (bvs_cprTemp) is
;*	     updated with the current position.  This is per-screen-group data.
;*	     When called with the READ action, the characters are read from
;*	     bvs_cprTemp and copied to the calling routine's In_String buffer.
;*	     A maximum of 9 characters are moved to In_String.	Upon exit,
;*	     In_Length contains the number of characters AnsiInject copied
;*	     to InputData.In_String.  The address of In_String is not changed.
;*
;*   Entry Point:  AnsiInject
;*	 Linkage:  CALL FAR - PUBLIC dynamic link routine
;*
;*   INPUT:
;*     SYMBOLIC NAME:  InputData     TYPE:  selector-offset
;*
;*     DESCRIPTION:  Address of caller's parameter block with the
;*		     following structure:
;*
;*	 InputData     STRUC
;*	 In_String     DD    ?	  ; address [off, sel] of caller's inject buff
;*	 In_Length     DB    ?	  ; length of CPR string (0 if none pending)
;*				  ; (ignored on entry)
;*	 In_Action     DB    ?	  ; requested action for AnsiInject
;*	 In_Char       DW    ?	  ; (ignored on entry)
;*	 InputData     ENDS
;*
;*     WHERE:
;*	 Action = 0   BUILD CPR string into bvscb.bvs_cprTemp.
;*	 Action = 1   READ CPR string from bvs_cprTemp to InputData.In_String.
;*
;*   Exit - NORMAL:  AX = 0
;*
;*   Exit - ERROR:   any error returned by external routines
;*
;*   Internal References:  ANSIDAT	; Per process data segment
;*			   ANSIGSEG	; Global data segment
;*	      Routines:    AnsiGetShr	; Routine to set up selectors for the
;*					;   shared segments (BVSCB & KEYDEF)
;*
;*   External References:  BVSCB	; Shared PSG data area (from BVS)
;*	      Routines:    DOSGETSHRSEG
;*
;***********************  END OF SPECIFICATIONS  ******************************
;
;   Uses the shared PSG data area "BVSCB" allocated in Base Video Subsystem
;   Uses this defined 9-character string as a template for the CPR:
;     .bvs_cprTemp    DB     ASCII_ESC,'[00;00R',ASCII_CR
;
;******************************************************************************

.xlist
INCLUDE 	struc.inc		; Structure macro file
INCLUDE 	infoseg.inc		; Information segment structures
INCLUDE 	bvscb.inc		; BVS structure definitions
INCLUDE 	ansidecl.inc		; ANSI common data declarations
INCLUDE 	error.inc		; DOS ERROR declarations
INCLUDE 	ansiextr.inc		; External declarations
.list
	.386p				; Assemble for iAPX-386 processor

	EXTRN	BinToHx:NEAR		; Convert binary to Hex ASCII

	EXTRN	DOSGETSHRSEG:FAR	; Get shared segment(s)
	EXTRN	DOSGETINFOSEG:FAR	;

	EXTRN	InfoSegL:WORD		;				;@T52
	EXTRN	CPIndex:WORD		;				;@T52

ANSIDAT SEGMENT WORD PUBLIC 'DATA' USE16 ; Instance data segment        ;@T52
ANSIDAT ENDS

ANSIGSEG SEGMENT WORD PUBLIC 'FAR_DATA' Use16 ; Global data segment     ;@T52
ANSIGSEG ENDS				;   among all processes in the system

ANSI1	SEGMENT BYTE  PUBLIC 'CODE' USE16                               ;@T52
ANSI1	ENDS


ANSI1	SEGMENT BYTE  PUBLIC 'CODE' USE16                               ;@T52

	PUBLIC	AccessBVSCB
	PUBLIC	ANSIINJECT
	PUBLIC	cprRead

	ASSUME	CS:ANSI1,DS:NOTHING,ES:NOTHING

AccessBVSCB PROC NEAR
;
;   This routine is responsible for establishing addressability to a
;   named share segment specified
;
;	On entry:   DS:DI = pointer to returned selector
;		    BX = offset of ASCIIZ string in ANSIGSEG
;
;	On exit:    DS:DI -> returned selector
;		    AX = return code
;
;	Effect	    AX, ES
;
	mov	es,ds:InfosegL		    ;			    ;@T52
	mov	ax,es:[LIS_CurScrnGrp]	    ; Get current session # ;@T52
	call	BinToHx 		    ; Convert binary to Hex ;@T52
	push	ANSIGSEG		    ;			    ;@T52
	pop	es			    ; Setup ES		    ;@T52
	mov	WORD PTR es:[bx+LNOFF],ax   ;			    ;@T52

	push	es			    ;			    ;@T52
	push	bx			    ;			    ;@T52
	push	ds			    ;			    ;@T52
	push	di			    ;			    ;@T52
	call	DOSGETSHRSEG		    ;			    ;@T52
	ret

AccessBVSCB ENDP



ANSIINJECT PROC FAR
;
;	int	3			; ******** BUG-BUG ********
;
	pusha
	mov	bp,sp
	mov	bp,[bp].SP_REG
	push	ds
	push	es
	push	gs							;@T52

	mov	ax,ANSIDAT		; establish addressibility
	mov	ds,ax			; (DS) = ANSI data segment selector
	xor	ax,ax			; clear AX
;
;  In ANSI, the present screen group's BVSCB is accessed via ES:[SI].
;  First, check if this process already has the selector for bvscb:
;
	.if	<ds:BvscbSel e ax>	; Don't have access to BVSCB?   ;@T52
	    mov     di,OFFSET BvscbSel	; (CX) = offset of selector save word
	    mov     bx,OFFSET bvsSegLabel;(BX) = offset of selector label
	    call    AccessBVSCB 	; get the shared segment selector
	    .if     <nonzero ax>	; Error?			;@T52
		jmp	cprx		; exit
	    .endif			;				;@T52
	.endif				;				;@T52
;
;   Now the selector of the BVSCB is in "BvscbSel".
;   Get address (offset;selector) of InputData from stack:
;
	mov	gs,ds:BvscbSel		; (ES) = selector of bvscb	;@T52
	les	di,[bp].DataBlock	; (DI) = offset of InputData block
					; (ES) = selector of InputData block
	mov	ch,es:[di].In_Action	; (CH) = action requested for Inject
	cmp	ch,BUILD		; check ACTION requested
	jg	cprRead 		; if ACTION = 1, then READ the CPR
;
;   The inject ACTION is BUILD.
;
	mov	cl,10			; (CL)= 10, divisor to convert to ASCII
	mov	ax,gs:[Bvs_CursorRow]	; convert the Row # to chars	;@T52
	inc	al			; make row start from 1 (top row)
	div	cl			; (AL) = tens digit
					; (AH) = ones digit
	add	ax,'00'                 ; convert to ASCII character codes
	mov	WORD PTR gs:[bvs_cprTemp+2],ax ; move 2 chars to cprTemp;@T52
	mov	ax,gs:[Bvs_CursorCol]	; convert the column # to chars ;@T52
	inc	al			; make column start from 1 (left col)
	div	cl			; (AL) = tens digit
					; (AH) = ones digit
	add	ax,'00'                 ; convert to ASCII character codes
	mov	WORD PTR gs:[bvs_cprTemp+5],ax ; move 2 chars to cprTemp;@T52
	or	gs:[bvs_flags],bvs_f_ansicprs  ; reset cpr state	;@T52
	xor	ax,ax			; clear AX before return
	jmp	SHORT cprx		; goto common exit
;
;   The inject ACTION is READ
;
cprRead:
	test	gs:[bvs_flags],bvs_f_ansicprs ; IF ansicprs flag is set ;@T52
	jnz	cpr1			; THEN continue to read CPR
	mov	es:[di].In_Length,0	; ELSE set length to zero
	jmp	SHORT cprx		;    go to exit
cpr1:
	mov	cl,es:[di].In_Length	; (CL) = length of output buffer
	xor	ch,ch			; (CX) = length of output buffer
	cmp	cl,9			; IF output buffer length <= 9
	jb	cpr2			; THEN copy In_Length characters
	mov	cl,9			; ELSE limit length to 9
cpr2:
	mov	es:[di].In_Length,cl	; save length of string transferred
	les	di,es:[di].In_String	; (DI) = offset of destination string
					; (ES) = selector of destination string
	mov	ds,BvscbSel		; (DS) = Selector of bvscb
	lea	si,ds:[bvs_cprTemp]	; (SI) = offset of cprTemp in bvscb

	cld				; clear DF to auto-increment
	rep	movsb			; move (CX) bytes
	and	ds:[bvs_flags],NOT bvs_f_ansicprs   ; clear ansicprs flag
cprx:
	mov	WORD PTR [bp-2],ax
	pop	gs							;@T52
	pop	es			; restore caller's registers
	pop	ds
	popa
	ret	4			; return to caller (remove param)

ANSIINJECT ENDP

ANSI1	ENDS
	END
