;       SCCSID = @(#)d_gtdbcs.asm	6.1 91/02/15
;	SCCSID = @(#)d_gtdbcs.asm	1.4 90/01/22
; ****************************************************************************
; *									     *
; *			  IBM/Microsoft Confidential			     *
; *									     *
; *		    Copyright (c) IBM Corporation  1987, 1990		     *
; *		    Copyright (c) Microsoft Corp.  1987, 1990		     *
; *			      All Rights Reserved			     *
; *									     *
; ****************************************************************************
;
;	06-Jan-87 (billme): Replace initial pushes and final pops
;	with calls to __api_begin and __api_end resp.  This will
;	reduce the size of FAPI and allow support for signals.
;
;	04-May-87 (robertc): Install hooks for DOSErrorClass Support.
;	All int 21h errors are passed through api_get_extended to get the
;	extended errorcode and to provide the class, action, and locus for
;	the dynamic error FIFO queue.
;
;	14-July-87 (Tarng): Initialize truncate_flag for each entry.
;
;	12-Aug-87 (Tarng): Support Japanese version.
;
;	2-Sep-87 (robertc): fix version checking.
;
;      22-Oct-87 (robertc): P1074 int 21h func 65h only valid in 3xb
;
;/*************** START OF SPECIFICATIONS ******************************/
;/*								       */
;/* SUBROUTINE NAME: DosGetDBCSEv				       */
;/*								       */
;/* SOURCE FILE NAME: D_GtDBCS.ASM				       */
;/*								       */
;/* DESCRIPTIVE NAME: Dos Get DBCS Environment			       */
;/*								       */
;/* FUNCTION:  Gets the DBCS Environment			       */
;/*								       */
;/* NOTES:  @@ DosGetDBCSEv is a new routine to the 1.10 Family API    */
;/*	    Library.						       */
;/*								       */
;/* ENTRY POINT:						       */
;/*	    LINKAGE:  EXTRN DosGetDBCSEv:FAR			       */
;/*								       */
;/* INPUT:  PUSH     WORD    Length	  ;Length of data area provided*/
;/*	    PUSH@    OTHER   Structure	  ;Address of country code     */
;/*					  ;and code page	       */
;/*	    PUSH@    OTHER   MemoryBuffer ;Pointer to the data area    */
;/*					  ;to be filled		       */
;/*	    call  DosGetDBCSEv					       */
;/*								       */
;/*								       */
;/* EXIT-NORMAL:  AX = 0					       */
;/*								       */
;/* EXIT-ERROR:	 AX = Error Code				       */
;/*								       */
;/*    ReturnCode Value = 1, Error_invalid_function		       */
;/*			  ?, Country code not found in file	       */
;/*			  ?, DBCS Ev information not found	       */
;/*			  ?, Error_NLS_Table_Truncated		       */
;/*			  ?, Code page value not found		       */
;/*								       */
;/* EFFECTS:  BP, ES, DS, DI, SI, BX, CX, and DX, registers are saved. */
;/*								       */
;/* PSUEDO CODE:						       */
;/*								       */
;/*	save registers						       */
;/*								       */
;/*	get DOS version						       */
;/*								       */
;/*	If version < 3.20					       */
;/*	    then AX=invalid DOS version and goto DosGetDBCSExit	       */
;/*								       */
;/*	use BP as pointer to stack parameters			       */
;/*								       */
;/*	If version >= 3.20  && < 3.4				       */
;/*								       */
;/*	    Begin						       */
;/*	      Preset the carry flag				       */;@@1
;/*	      load registers for int 21 call			       */
;/*	      ah = 63h = DBCS control				       */
;/*	      al = 00h = get pointer to DBCS table		       */;@@1
;/*	    execute int 21 with function 6300H			       */
;/*	    if carry flag set goto DOSGetDBCSExit		       */
;/*								       */
;/*	    At this point DS:SI points at DBCS table.  Copy the	       */
;/*	    contents of the table into the caller's buffer.            */
;/*								       */
;/*	    Counter1=length					       */
;/*	    While (Counter1 > 0) and (Buffer not yet copied)	       */;@@1
;/*		Begin						       */
;/*		Copy pairs of bytes to the caller's buffer             */;@@1
;/*		End						       */
;/*								       */
;/*	    If we got here without getting to double zero terminator   */;@@1
;/*	    in table.  Set AX=Error_NLS_Table_Truncated		       */;@@1
;/*	    Goto DOSGetDBCSExit					       */
;/*								       */
;/*	    Goto Exit_no_error					       */
;/*	    End							       */
;/*								       */
;/*	    Else   (Version >= 3.40)				       */
;/*								       */
;/*	    Begin						       */
;/*	    load registers for int 21 call			       */
;/*	      ah = 65h = Get extended country information	       */
;/*	      al = 07 = Get DBCS environment			       */
;/*	      bx = codepage					       */
;/*	      dx = country_id					       */
;/*	      cx = length					       */
;/*	      es:di = address of country_info (internal buffer)	       */
;/*	    execute int 21 with function 6507H			       */
;/*	    if carry flag set goto DOSGetDBCSExit		       */
;/*	    goto Copy_into_app_buffer				       */
;/*	    End							       */
;/*								       */
;/*								       */
;/*Copy_into_app_buffer:					       */
;/*								       */
;/*	CX = Lower of caller's Length or length of DBCS table.         */
;/*	Length of table is first word of table.			       */
;/*	If caller's buffer length is less than length of               */
;/*	table then truncate flag = 1				       */
;/*								       */
;/*	At this point, the address of the DBCS table is in the	       */
;/*	buffer filled in by the get exteneded country info call.       */
;/*	We will move CX bytes from that buffer, into the caller's      */
;/*	buffer.							       */
;/*								       */
;/*	If truncate flag = 1 then AX=Error_NLS_Table_Truncated and     */
;/*	goto DOSGetDBCSExit					       */
;/*								       */
;/*Exit_no_error:						       */
;/*								       */
;/*	AX=0							       */
;/*								       */
;/*DosGetDBCSExit:						       */
;/*								       */
;/*	restore registers					       */
;/*								       */
;/*	return clearing stack frame				       */
;/*								       */
;/*								       */
;/* INTERNAL REFERENCES:					       */
;/*    ROUTINES:						       */
;/*								       */
;/* EXTERNAL REFERENCES:					       */
;/*    ROUTINES:    INT 21H FUNCTION 6507H    GET DBCS CHARACTER SET   */
;/*		    INT 21H FUNCTION 3000H    GET DOS VERSION	       */
;/*		    INT 21H FUNCTION 6301H    DBCS CONTROL	       */
;/*								       */
;/*************** END OF SPECIFICATIONS ********************************/
;
;
; LIBRARIES
;
.XLIST
include error2.inc
include error.inc
include struc.inc			;@@1

	EXTRN	api_get_extended:far	;@@ added support for DOSErrorClass
	EXTRN	__api_begin:near
	EXTRN	__api_end:near
	EXTRN	_api_getvrsn:near
.LIST
;
; PUBLIC SYMBOLS
;
	PUBLIC	DosGetDBCSEv

	PAGE

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

country_info	db	5  dup (0)		; Buffer for returning from
						; Get Extended Country Info call
country_id	dw	0			; Country to return info for
						; Environment
size_cntry_info dw	5			; Size of country_info
truncate_flag	db	0			; DBCS table truncate flag
;
; stack frame:
; +0	bp
; +2	ip
; +4	cs
; +6	ptr_membuffer
; +10	ptr_structure
; +14	length
;
str	struc
old_bp		dw	?
return		dd	?
ptr_membuffer	dd	?
ptr_structure	dd	?
strlength	dw	?
str	ends
;
DosGetDBCSEv	PROC	FAR

	call	__api_begin	; init bp and save bp,ds,bx,cx,dx,si,di,es
				; required to save: bp,es,ds,di,si,bx,cx,dx
		push	cs			; Set DS to CS so we can get to
		pop	ds			; our own variables
		mov	cs:truncate_flag,0	; initialize truncate flag
;
;
; Check DOS version to make sure PC DOS 3.20 or higher
;
		call	_api_getvrsn		;@@ AH <- major, AL <- minor
		cmp	ax,0328h		;@@ if version >= 3.4
		jae	DOS_340_gtdbcs		;@@ do DOS 3.4+
		cmp	ax,0314h		;@@ if version >=3.2 & < 3.4
		jae	DOS_320_gtdbcs		;@@ do DOS 3.2
		jmp	DOS_version_error	;@@ else return invalid function


DOS_320_gtdbcs:

; Set up interrupt for Japanese version of PC DOS 3.20.  Use int 21h
; function 63h/00h.

	push	ds			;@@Japan save DS, SI
	push	si			;@@Japan

	mov	ax,6300h		; DOS 3.20 DBCS, get table ;@@1
	push	bp			;@@1
	int	21h			;Get DS:SI = DBCS table ptr ;@@1
	pop	bp			;@@1

; Check if it is Japanese version of PC DOS 3.20.
; If not, set carry
	pop	ax			;@@ restore orginal DS, SI
	pop	bx			;@@ into AX,BX
	mov	cx,ds
	.if <ax eq si > and		;Is DS or SI updated?
	.if <bx eq cx >
	 stc				;No->Not Japanese version
	.else
	 clc				;Yes->Japanese version;@@1
	.endif

; Copy DBCS table into caller's buffer.  DS:SI will point to DBCS table.
; ES:DI will point to caller's buffer.

	pushf				;@@1
	xor	ax,ax			;Preset good return code ;@@1
	les	di,[bp].ptr_membuffer	; ES:DI = caller's buffer ;@@1
	mov	cx,[bp].strlength	; Loop counter in bytes ;@@1
	shr	cx,1			;@@1
	.if	z			;Not enough room for any data ;@@1
	    inc	    ax			;@@1
	.endif				;@@1
	popf				;@@1

	.if	nc			;Call was successful ;@@1
	    .if	    ncxz		;Some data to move ;@@1
		.repeat			;@@1
		    lodsw		;@@1
		    and	    ax,ax	;@@1
		.until	z or		;Double zero terminated ;@@1
		    stosw		;@@1
		    dec	    cx		;@@1
		.until	z		;End of buffer ;@@1
	    .endif			;@@1
	.endif				;@@1

	and	ax,ax			;@@1
	.if	z			;Double zero terminated or no table ;@@1
	    stosw			;@@1
	.else				;Stop by end of buffer ;@@1
	    mov	    ax,Error_NLS_Table_Truncated ;Return truncate err ;@@1
	.endif				;@@1
	jmp	NormalExit		;End of DOS 3.2 code ;@@1
					;@@ added support for DOSErrorClass
DOS_340_gtdbcs:
;
; Now set up get DBCS environment interrupt for PC DOS 3.40 and greater
; and CP DOS
;
		push	ds			; Save DS
		lds	di,[bp].ptr_structure	; Ptr_structure points to a
		mov	dx,word ptr ds:[di]	; double word.  First word is
		mov	bx,word ptr ds:[di+2]	; country code of interest.
						; Second word is code page of
						; interest.
		pop	ds			; Restore DS
		or	dx,dx			; If country code = 0, then
		jnz	not_default_cntrycode	; default is used, in PC DOS
		dec	dx			; 3.40, -1 says use active
not_default_cntrycode:
		or	bx,bx			; If code page = 0, then
		jnz	not_default_codepage	; current is used, in PC DOS
		dec	bx			; 3.40, -1 says use active
not_default_codepage:
		mov	cx,size_cntry_info	; CX = Size of cntry_info
		push	ds
		pop	es
		mov	di,offset country_info	; ES:DI = buffer to fill
		mov	ax,6507H		; Get DBCS environment
		int	21h
		jnc	Copy_into_app_buffer	; Copy into app buffer if no
						; error, else exit
		jmp	ErrorExit      ;@@ added support for DOSErrorClass
;
Copy_into_app_buffer:
;
; The PC DOS Get Extended Country Info call returns in the buffer provided:
;     First byte = item requested (in this case 07 for get DBCS table)
;     Bytes 2 and 3 = Offset of DBCS table
;     Bytes 4 and 5 = Segment of DBCS table
;
		push	ds			; Save DS
		mov	di,offset country_info
		mov	si,word ptr ds:[di+1]	; Get address of move source
		mov	ds,word ptr ds:[di+3]
		mov	cx,ds:word ptr [si]	; First word of list is length
		add	si,2			; Get ptr past size
		cmp	cx,[bp].strlength	; See if list fits in caller's
						; buffer
		jna	No_truncate_DBCS_list	; If yes then no truncate
		mov	truncate_flag,1		; else set truncate flag and
		mov	cx,[bp].strlength	; set counter to Length
No_truncate_DBCS_list:
		les	di,[bp].ptr_membuffer	; Destination of move is app's
						; buffer
rep		movs	es:byte ptr[di],ds:byte ptr[si]
		pop	ds			; Restore DS
		cmp	truncate_flag,1
		je	List_too_small_error
Exit_no_error:
		xor	ax,ax			; No errors returned
	jmp	short NormalExit	;@@ Added support for DOSErrorClass
List_too_small_error:
		mov	ax,Error_NLS_Table_Truncated  ; Return list truncate err
	jmp	short NormalExit	;@@ Added support for DOSErrorClass
Dos_version_error:
		mov	ax,error_invalid_function ; Return invalid function

	jmp	short NormalExit	;@@ Added support for DOSErrorClass
ErrorExit:				;@@ added support for DOSErrorClass
	call	api_get_extended	;@@ added support for DOSErrorClass
NormalExit:				;@@ added support for DOSErrorClass

	call	__api_end	; check sigs & restore es,di,si,dx,cx,bx,ds,bp

		ret	size str - 6		; Clear stack frame
DosGetDBCSEv	ENDP
_TEXT	ends
		END

;@@1 = 03/06/87 STJ, Correct the code for DOS 3.20
