;/*
; *                      Microsoft Confidential
; *                      Copyright (C) Microsoft Corporation 1987 - 1991
; *                      All Rights Reserved.
; */
	PAGE	,132
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;                                           
; MS-DOS 5.00 - NLS Support - KEYB Command
;
; File Name:  KEYBTBBL.ASM
; ----------
;
; Description:
; ------------
;	Build SHARED_DATA_AREA with parameters specified
;	in KEYBCMD.ASM
;
; Documentation Reference:
; ------------------------
;	None
;
; Procedures Contained in This File:
; ----------------------------------
;	TABLE_BUILD: Build the header sections of the SHARED_DATA_AREA
;	STATE_BUILD: Build the state sections in the table area
;	FIND_CP_TABLE: Given the language and code page parm, determine the
;		offset of the code page table in KEYBOARD.SYS
;
; Include Files Required:
; -----------------------
;	KEYBSHAR.INC
;	KEYBSYS.INC
;	KEYBDCL.INC
;	KEYBI2F.INC
;
; External Procedure References:
; ------------------------------
;	None
;
; Change History:
; ---------------
;

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

	PUBLIC TABLE_BUILD
	PUBLIC FIND_CP_TABLE
	PUBLIC CPN_INVALID
	PUBLIC SD_LENGTH

CODE	SEGMENT PUBLIC 'CODE'

	INCLUDE KEYBEQU.INC
	INCLUDE KEYBSHAR.INC
	INCLUDE KEYBSYS.INC
	INCLUDE KEYBCMD.INC
	INCLUDE KEYBDCL.INC
	INCLUDE COMMSUBS.INC
	INCLUDE KEYBCPSD.INC

	ASSUME  cs:CODE,ds:CODE

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Module: TABLE_BUILD
;
; Description:
;	Create the table area within the shared data structure. Each
;	table is made up of a descriptor plus the state sections.
;	Translate tables are found in the Keyboard definition file and are
;	copied into the shared data area by means of the STATE_BUILD
;	routine.
;
; Input Registers:
;	ds - points to our data segment
;	es - points to our data segment
;	bp - points at beginning of CMD_PARM_LIST
;
;	SHARED_DATA_STR must be allocated in memory
;
;	The following variables must also be passed from KEYB_COMMAND
;	 KEYBSYS_FILE_HANDLE is set to file handle after opening file
;	 CP_TAB_OFFSET is the offset of the CP table in the SHARED_DATA_AREA
;	 STATE_LOGIC_OFFSET is the offset of the state section in the SHARED_DATA_AREA
;	 SYS_CODE_PAGE is the binary representation of the system CP
;	 KEYBCMD_LANG_ENTRY_PTR is a pointer to the lang entry in KEY DEF file
;	 DESIG_CP_BUFFER is the buffer which holds a list of designated CPs
;	 DESIG_CP_OFFSET:WORD is the offset of that list
;	 NUM_DESIG_CP is the number of CPs designated
;	 FILE_BUFFER is the buffer to read in the KEY DEF file
;**********CNS ***************************************
;	 ID_PTR_SIZE is the size of the ID ptr structure
;**********CNS ***************************************
;	 LANG_PTR_SIZE is the size of the lang ptr structure
;	 CP_PTR_SIZE is the size of the CP ptr structure
;	 NUM_CP is the number of CPs in the KEYB DEF file for that lang
;	 SHARED_AREA_PTR segment and offset of the SHARED_DATA_AREA
;
;
; Output Registers:
;	cx - RETURN_CODE :=  0  - Table build successful
;			  1  - Table build unsuccessful - ERROR 1
;					(Invalid language parm)
;			  2  - Table build unsuccessful - ERROR 2
;					(Invalid Code Page parm)
;			  3  - Table build unsuccessful - ERROR 3
;					(Machine type unavaliable)
;			  4  - Table build unsuccessful - ERROR 4
;					(Bad or missing keyboard def file)
;			  5  - Table build unsuccessful - ERROR 5
;					(Memory overflow occurred)
; Logic:
;	Calculate Offset difference between TEMP and SHARED_DATA_AREAs
;	Get LANGUAGE_PARM and CODE_PAGE_PARM from parm list
;	Call FIND_CP_TABLE := Determine whether CP is valid for given language
;	IF CP is valid THEN
;	Store them in the SHARED_DATA_AREA
;	Prepare to read Keyboard definition file by LSEEKing to the top
;	READ the header
;	Store maximum table values for calculation of RES_END
;	Set di to point at TABLE_AREA within SHARED_DATA_AREA
;	FOR the state logic section of the specified language:
;		IF STATE_LOGIC_PTR is not -1 THEN
;		LSEEK to state logic section in keyboard definition file
;		READ the state logic section into the TABLE_AREA
;		Set the hot keyb scan codes
;		Set the LOGIC_PTR in the header
;	FOR the common translate section:
;		IF Length parameter is not 0 THEN
;		Build state
;		Set the COMMON_XLAT_PTR in the header
;	FOR the specific translate sections:
;	Establish addressibility to list of designated code pages
;	FOR each code page
;		IF CP_ENTRY_PTR is not -1 THEN
;		Determine offset of CP table in Keyb Def file
;		IF CP table not avaliable THEN
;			Set CPN_INVALID flag
;		ELSE
;			LSEEK to CPn state section in keyboard definition file
;			IF this is the invoked code page THEN
;			Set ACTIVE_XLAT_PTR in SHARED_DATA_AREA
;			Update RESIDENT_END ptr
;			Build state
;	Update RESIDENT_END ptr
;	End
;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FB		EQU	FILE_BUFFER
KB_MASK		EQU	02H

FIRST_XLAT_TAB	DW	0
NEXT_SECT_PTR	DW	-1

MAX_COM_SIZE	DW	?
MAX_SPEC_SIZE	DW	?
MAX_LOGIC_SIZE	DW	?

RESIDENT_END_ACC DW	0
SA_HEADER_SIZE	DW	SIZE SHARED_DATA_STR;
PARM_LIST_OFFSET DW	?
;********************CNS*************************
TB_ID_PARM	DW	0
;********************CNS*************************
TB_LANGUAGE_PARM DW	0
TB_CODE_PAGE_PARM DW	0

CPN_INVALID	DW	0

KEYB_INSTALLED	DW	0
SD_AREA_DIFFERENCE DW	0
SD_LENGTH	DW	2000

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  Program Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TABLE_BUILD	  PROC NEAR

	mov	ax,OFFSET SD_SOURCE_PTR	; Setup the difference
	sub	ax,OFFSET SD_DesT_PTR	; value used to calculate
	mov	SD_AREA_DIFFERENCE,ax	; new ptr values for
					;  SHARED_DATA_AREA
	mov	ax,[bp].ID_PARM		; Get id parameter
	mov	TB_ID_PARM,ax
	mov	ax,[bp].LANGUAGE_PARM	; Get language parameter
	mov	TB_LANGUAGE_PARM,ax
	mov	bx,[bp].CODE_PAGE_PARM	; Get code page parameter
	mov	TB_CODE_PAGE_PARM,bx
					; Make sure code page is
	call	FIND_CP_TABLE		;   valid for the language
	jcxz	TB_CHECK_CONTINUE1	; IF code page is found
	jmp	TB_ERROR6		;  for language THEN

TB_CHECK_CONTINUE1:
	mov	bp,OFFSET SD_SOURCE_PTR	; Put language parm and
	mov	ax,TB_ID_PARM		;  id parm and..
	mov	es:[bp].INVOKED_KBD_ID,ax
	mov	bx,TB_CODE_PAGE_PARM
	mov	es:[bp].INVOKED_CP_TABLE,bx	; code page parm into the
	mov	ax,TB_LANGUAGE_PARM		;  SHARED_DATA_AREA
	mov	word ptr es:[bp].ACTIVE_LANGUAGE,ax

	mov	bx,KEYBSYS_FILE_HANDLE	; Get handle
	xor	dx,dx			; LSEEK file pointer
	xor	cx,cx			;  back to top of file
	mov	ax,4200h		; If no problem with
	int	21H			;  Keyboard Def file THEN
	jnc	TB_START
	jmp	TB_ERROR4

TB_START:				; Else
	xor	di,di			; Set number
;M006	LEA	cx,[di].KH_MAX_LOGIC_SZ+2 ;	bytes to read header
	lea	cx,[di].KH_NUM_ID+2	; M006 -- read a few extra entries
	mov	dx,OFFSET FILE_BUFFER	; Move contents into file buffer
	mov	ah,3FH			;  READ
	push	cs
	pop	ds
	int	21H			;  File
	jnc	TB_CONTINUE1
	jmp	TB_ERROR4

TB_CONTINUE1:
	cmp	cx,ax
	je	TB_ERROR_CHECK1
;M002	mov	cx,4
;M002	jmp	TB_CPN_INVALID
tb_err4_j:				; M006
	jmp	TB_ERROR4		; M002

TB_ERROR_CHECK1:
	cmp	FB.KH_NUM_ID,0		; M006 -- is it an old KEYBOARD.SYS?
	jz	tb_err4_j		; M006 --  bomb out if so

	mov	cx,FB.KH_MAX_COM_SZ	; Save values for RESIDENT_END
	mov	MAX_COM_SIZE,cx		;  calculation
	mov	cx,FB.KH_MAX_SPEC_SZ
	mov	MAX_SPEC_SIZE,cx
	mov	cx,FB.KH_MAX_LOGIC_SZ
	mov	MAX_LOGIC_SIZE,cx


	LEA	di,[bp].TABLE_AREA	; Point at beginning of table area
					;		di ---> TABLE_AREA

;	M002 -- begin added section
;
;	Before we go ANY further, let's see if we actually have room
;	   for our worst case memory allocation needs.  Notice that
;	   we're actually trusting the MAX fields from the KEYBOARD
;	   definition file.  If it lies to us and has fields bigger
;	   than these MAX values, we may crash over memory we don't
;	   own during initialization.

	mov	ax,NUM_DESIG_CP
	mul	MAX_SPEC_SIZE
	or	dx,dx			; error if overflowed 16 bits
	jnz	mem_alloc_err

	add	ax,SA_HEADER_SIZE
	jc	mem_alloc_err
	add	ax,MAX_LOGIC_SIZE
	jc	mem_alloc_err
	add	ax,MAX_COM_SIZE
	jc	mem_alloc_err

;	Note that ax could be used for the RESIDENT_END_ACC value,
;	  but since this check is being added late in the testing
;	  cycle, we'll leave that calculation alone.

	add	ax,di			; get the ending offset of temp buffer
	jc	mem_alloc_err

	add	ax,15
	jc	mem_alloc_err
	mov	cl,4			; convert to paragraph
	shr	ax,cl
	mov	cx,ax
	mov	ax,cs			; get our code segment
	add	ax,cx			; this is our ending segment
	cmp	ax,cs:[2]		; compare against psp:2
	jb	mem_alloc_ok
mem_alloc_err:
	jmp	TB_ERROR5
mem_alloc_ok:

;	M002 -- end added section

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	** FOR STATE LOGIC SECTION FOR LANG **
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TB_STATE_BEGIN:
	mov	bx,KEYBSYS_FILE_HANDLE		; Get handle
	mov	cx,word ptr STATE_LOGIC_OFFSET+2
	mov	dx,word ptr STATE_LOGIC_OFFSET	; Get LSEEK file pointer

	cmp	dx,-1			; If no language table then
	jnz	TB_STATE_CONTINUE1	;  jump to code page begin
	jmp	TB_CP_BEGIN

TB_STATE_CONTINUE1:			; Else
	mov	ax,4200h		; LSEEK to begin of state logic sect
	int	21H			;	Keyboard Def file THEN
	jnc	TB_STATE_CONTINUE2
	jmp	TB_ERROR4

TB_STATE_CONTINUE2:
	mov	dx,ax
	mov	word ptr SB_STATE_OFFSET+2,cx	;  Save the offset of the
	mov	word ptr SB_STATE_OFFSET,dx	;	states in Keyb Def file

	sub	di,SD_AREA_DIFFERENCE	; Adjust for relocation
	mov	es:[bp].LOGIC_PTR,di	; Set because this is state
	add	di,SD_AREA_DIFFERENCE	; Adjust for relocation

	mov	cx,4			; Set number bytes to read length and
					;	special features
	mov	dx,OFFSET FILE_BUFFER	; Set the buffer address
	mov	ah,3FH			; Read from the Keyb Def file
	int	21H
	jnc	TB_STATE_CONTINUE3
	jmp	TB_ERROR4

TB_STATE_CONTINUE3:
	cmp	cx,ax
	je	TB_ERROR_CHECK2
;M002	mov	cx,4
;M002	jmp	TB_CPN_INVALID
	jmp	TB_ERROR4

TB_ERROR_CHECK2:
	mov	ax,FB.KT_SPECIAL_FEATURES	; Save the special features in the
	mov	es:[bp].SPECIAL_FEATURES,ax	;	SHARED_DATA_AREA


	mov	es:[bp].HOT_KEY_ON_SCAN,F1_SCAN
	mov	es:[bp].HOT_KEY_OFF_SCAN,F2_SCAN

HOT_KEY_SET:
	mov	cx,FB.KT_LOGIC_LEN	; Set length of section to read
	or	cx,cx
	jnz	TB_STATE_CONTINUE4

	dec	cx			; cx = -1
	mov	es:[bp].LOGIC_PTR,cx
	jmp	short SB_COMM_BEGIN

TB_STATE_CONTINUE4:
	mov	es:[di],cx		; Store length parameter in
	add	di,2			;	  SHARED_DATA_AREA
	mov	cx,FB.KT_SPECIAL_FEATURES ; Save the special features
	mov	es:[di],cx
	add	di,2
	mov	cx,FB.KT_LOGIC_LEN	; Set length of section to read
	sub	cx,4			; Adjust for what we have already read
	mov	dx,di			; Set the address of SHARED_DATA_AREA
	push	es
	pop	ds
	mov	ah,3FH			; Read logic section from the
	int	21H			;	Keyb Def file
	push	cs
	pop	ds
	jnc	TB_STATE_CONTINUE5
	jmp	TB_ERROR4

TB_STATE_CONTINUE5:
	cmp	cx,ax
	je	TB_ERROR_CHECK3
;M002	mov	cx,4
;M002	jmp	TB_CPN_INVALID
	jmp	TB_ERROR4

TB_ERROR_CHECK3:
	add	di,cx			; Set di at new beginning of area
					;		TABLE_AREA
					;		STATE_LOGIC
	mov	cx,RESIDENT_END_ACC	;	di --->
	add	cx,SA_HEADER_SIZE
	add	cx,MAX_LOGIC_SIZE
	mov	RESIDENT_END_ACC,cx	;  Refresh Resident end size

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	** FOR COMMON TRANSLATE SECTION FOR LANG **
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

SB_COMM_BEGIN:
	mov	cx,SIZE KEYBSYS_XLAT_SECT-1 ; Set number bytes to read header
	mov	dx,di			; Set the SHARED_DATA_AREA address
	push	es
	pop	ds
	mov	ah,3FH			; Read from the Keyb Def file
	int	21H
	push	cs
	pop	ds
	jnc	TB_STATE_CONTINUE6
	jmp	TB_ERROR4

TB_STATE_CONTINUE6:
	mov	cx,es:[di].KX_SECTION_LEN; Set length of section to read
	jcxz	TB_CP_BEGIN

	mov	cx,word ptr SB_STATE_OFFSET	;  Save the offset of the
	add	cx,FB.KT_LOGIC_LEN
	mov	word ptr SB_STATE_OFFSET,cx	;  Save the offset of the
	sub	di,SD_AREA_DIFFERENCE		;   Adjust for relocation
	mov	es:[bp].COMMON_XLAT_PTR,di
	add	di,SD_AREA_DIFFERENCE		;   Adjust for relocation

	call	STATE_BUILD
					; di set at new beginning of area
					;		TABLE_AREA
					;		STATE_LOGIC
					;		COMMON_XLAT_SECTION
	mov	cx,RESIDENT_END_ACC
	add	cx,MAX_COM_SIZE
	mov	RESIDENT_END_ACC,cx	;  Refresh resident end size

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;	FOR alL DESIGNATED OR INVOKED CODE PAGES
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TB_CP_BEGIN:						; Get the offset to
	mov	cx,OFFSET DESIG_CP_BUFFER.DESIG_CP_ENTRY ; the beginning of the
	mov	DESIG_CP_OFFSET,cx			; table of designated
							; code pages
TB_CPN_BEGIN:
	mov	ax,word ptr es:[bp].ACTIVE_LANGUAGE  ; Get the active language
	mov	cx,NUM_DESIG_CP		; Get the number of CPs
	or	cx,cx			; IF we have done all requested CPs
	jnz	TB_CPN_VALID1
	jmp	TB_DONE			;	Then done

TB_CPN_VALID1:
	mov	si,[DESIG_CP_OFFSET]
	mov	bx,[si]			; Get the CP
	cmp	bx,-1
	jnz	TB_CPN_CONTINUE1
	jmp	short TB_CPN_REPEAT

TB_CPN_CONTINUE1:			; ELSE
	push	di
	call	FIND_CP_TABLE		;	Find offset of code page table
	pop	di

	jcxz	TB_CPN_VALID		;  brif valid code page for language
	mov	CPN_INVALID,cx		;	Set flag and go to next CP
	jmp	short TB_CPN_REPEAT	; Else

TB_CPN_VALID:
	mov	bx,KEYBSYS_FILE_HANDLE	; Get handle
	mov	cx,word ptr CP_TAB_OFFSET+2  ; Get offset of the code page
	mov	dx,word ptr CP_TAB_OFFSET ;	in the Keyb Def file

	cmp	dx,-1			; Test if code page is blank
	jnz	TB_CPN_CONTINUE2
	jmp	short TB_CPN_REPEAT	; If it is then go get next CP

TB_CPN_CONTINUE2:
	mov	ax,4200h		; LSEEK to table in Keyb Def file
	int	21H			;	Keyb Def file Then
	jnc	TB_CPN_CONTINUE3
	jmp	TB_ERROR4

TB_CPN_CONTINUE3:
	mov	dx,ax
	mov	word ptr SB_STATE_OFFSET+2,cx	;  Save the offset of the
	mov	word ptr SB_STATE_OFFSET,dx	;	states in Keyb Def file

	mov	cx,TB_CODE_PAGE_PARM	;  If this code page is the
	mov	si,[DESIG_CP_OFFSET]	;	invoked code page
	cmp	cx,[si]
	jnz	TB_CPN_CONTINUE4	;  Then

	sub	di,SD_AREA_DIFFERENCE	;  Adjust for relocation
	mov	es:[bp].ACTIVE_XLAT_PTR,di ;  Set active xlat section
	add	di,SD_AREA_DIFFERENCE	;  Adjust for relocation

TB_CPN_CONTINUE4:
	sub	di,SD_AREA_DIFFERENCE	;  Adjust for relocation
	mov	es:[bp].FIRST_XLAT_PTR,di ;	  Set flag
	add	di,SD_AREA_DIFFERENCE	;  Adjust for relocation

TB_CPN_CONTINUE5:
	CALL	STATE_BUILD		;  Build state
					;		TABLE_AREA
	jcxz	TB_CPN_REPEAT		;    COMMON_XLAT_SECTION,SPECIFIC...
	jmp	short TB_ERROR4	;M006	;	di --->
;M006	jmp	TB_ERROR4		;	di --->

TB_CPN_REPEAT:
	mov	cx,RESIDENT_END_ACC
	add	cx,MAX_SPEC_SIZE	;  Refresh resident end size
	mov	RESIDENT_END_ACC,cx

	mov	cx,DESIG_CP_OFFSET
	add	cx,2			; Adjust offset to find next code page
	mov	DESIG_CP_OFFSET,cx

	mov	cx,NUM_DESIG_CP		; Adjust the number of code pages left
	dec	cx
	mov	NUM_DESIG_CP,cx

	jmp	TB_CPN_BEGIN
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

TB_DONE:
	mov	cx,RESIDENT_END_ACC	;  Set final calculated value
	add	cx,bp
	sub	cx,SD_AREA_DIFFERENCE		;  Adjust for relocation
	mov	es,word ptr SHARED_AREA_PTR	;	Set segment
	mov	bp,word ptr SHARED_AREA_PTR+2
	cmp	cx,es:[bp].RESIDENT_END
	JNA	TB_DONE_CONTINUE1
	jmp	short TB_ERROR5

TB_DONE_CONTINUE1:
	cmp	es:[bp].RESIDENT_END,-1
	jnz	DONT_REPLACE
	push	cs
	pop	es
	mov	bp,OFFSET SD_SOURCE_PTR
	mov	es:[bp].RESIDENT_END,cx ;  Save resident end
	jmp	short CONTINUE_2_END

DONT_REPLACE:
	push	cs
	pop	es
	mov	bp,OFFSET SD_SOURCE_PTR

CONTINUE_2_END:
	sub	cx,OFFSET SD_DesT_PTR	;  Calculate # of bytes to copy
	mov	SD_LENGTH,cx

	xor	cx,cx			;  Set valid completion return code
	mov	TB_RETURN_CODE,cx
	ret

;	M002 -- dead code deleted.  The following label was only
;		branched to with cx==4.  Those calls were all
;		replaced with direct JMPs to TB_ERROR4, which was
;		assumed to set cx=4 in other places anyway.

;M002	TB_CPN_INVALID:
;M002		cmp	cx,1			;  Set error 1 return code
;M002		jnz	TB_ERROR2
;M002		mov	TB_RETURN_CODE,cx
;M002		ret
;M002	
;M002	TB_ERROR2:
;M002		cmp	cx,2			;  Set error 2 return code
;M002		jnz	TB_ERROR3
;M002		mov	TB_RETURN_CODE,cx
;M002		ret
;M002	
;M002	TB_ERROR3:
;M002		cmp	cx,3			;  Set error 3 return code
;M002		jnz	TB_ERROR4
;M002		mov	TB_RETURN_CODE,cx
;M002		ret
;M002	

TB_ERROR4:
;M002	cmp	cx,4			;  Set error 4 return code
;M002	jnz	TB_ERROR5
	mov	cx,4		; M002	; set error 4 return code
	mov	TB_RETURN_CODE,cx
	ret

TB_ERROR5:
	mov	cx,5			;  Set error 5 return code
	mov	TB_RETURN_CODE,cx
	ret

TB_ERROR6:
	mov	bx,TB_CODE_PAGE_PARM
	mov	cx,6
	mov	TB_RETURN_CODE,cx	;  Set error 6 return code
	ret

TABLE_BUILD	  ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Module: STATE_BUILD
;
; Description:
;	Create the state/xlat section within the specific translate section.
;
; Input Registers:
;	ds - points to our data segment
;	es - points to our data segment
;	SB_STATE_OFFSET - offset to the beginning of the info in Keyb Def SYS
;	di - offset of the beginning of the area used to build states
;
;	KEYBSYS_FILE_HANDLE - handle of the KEYBOARD.SYS file
;
; Output Registers:
;	di  - offset of the end of the area used by STATE_BUILD
;
;	cx - Return Code := 0  -  State build successful
;			    4  -  State build unsuccessful
;				    (Bad or missing Keyboard Def file)
;
; Logic:
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

END_OF_AREA_PTR	DW	0
SB_FIRST_STATE	DW	0
SB_STATE_LENGTH	DW	0
SB_STATE_OFFSET	DD	0
STATE_LENGTH	DW	0
RESTORE_BP	DW	?

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  Program Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

STATE_BUILD	  PROC NEAR

	mov	si,di			;  Get the tally pointer
	mov	END_OF_AREA_PTR,di	;  Save pointer

	mov	RESTORE_bp,bp		;  Save the base pointer

	mov	bx,KEYBSYS_FILE_HANDLE	; Get handle
	mov	dx,word ptr SB_STATE_OFFSET	; LSEEK file pointer
	mov	cx,word ptr SB_STATE_OFFSET+2	;	back to top of XLAT table
	mov	ax,4200h		; If no problem with
	int	21H			;   Keyboard Def file THEN
	jnc	SB_FIRST_HEADER
	jmp	SB_ERROR4

SB_FIRST_HEADER:
	xor	bp,bp
	LEA	cx,[bp].KX_FIRST_STATE	; Set number of bytes to read header
	mov	dx,di
	push	es
	pop	ds
	mov	ah,3FH			; read in the header
	int	21H
	push	cs
	pop	ds
	jnc	SB_HEAD_CONTINUE1
	jmp	SB_ERROR4

SB_HEAD_CONTINUE1:
	mov	dx,NEXT_SECT_PTR
	cmp	dx,-1
	je	SB_HEAD_CONTINUE2
	sub	dx,SD_AREA_DIFFERENCE	;  Adjust for relocation

SB_HEAD_CONTINUE2:
	mov	es:[di].XS_NEXT_SECT_PTR,dx
	cmp	dx,-1
	je	SB_HEAD_CONTINUE3
	add	dx,SD_AREA_DIFFERENCE	;  Adjust for relocation

SB_HEAD_CONTINUE3:
	add	di,cx			; Update the di pointer

SB_NEXT_STATE:
	xor	bp,bp			;  Set number
	LEA	cx,[bp].KX_STATE_ID	;	bytes to read state length
	mov	dx,di			;  Read the header into the
	mov	bx,KEYBSYS_FILE_HANDLE	;	SHARED_DATA_AREA
	push	es
	pop	ds
	mov	ah,3FH
	int	21H

SB_CONTINUE1:
	push	cs			; Reset the data segment
	pop	ds
	mov	cx,es:[di].KX_STATE_LEN ; If the length of the state section
	mov	STATE_LENGTH,cx
	add	di,2			;  is zero then done
	jcxz	SB_DONE

	xor	bp,bp			;  Set number
	LEA	cx,[bp].KX_FIRST_XLAT-2 ;	bytes to read state length
	mov	dx,di			;  Read the header into the
	mov	bx,KEYBSYS_FILE_HANDLE	;	SHARED_DATA_AREA
	push	es
	pop	ds
	mov	ah,3FH
	int	21H

SB_CONTINUE1A:
	push	cs			; Reset the data segment
	pop	ds
	sub	di,2
	mov	ax,es:[di].XS_KBD_TYPE	; Get the keyboard type def
	test	ax,HW_TYPE		; Does it match our hardware?
	JNZ	SB_CONTINUE2
	mov	dx,es:[di].XS_STATE_LEN ; No, then
	LEA	cx,[bp].KX_FIRST_XLAT
	sub	dx,cx
	xor	cx,cx
	mov	ah,42H			;  LSEEK past this state
	mov	al,01H
	int	21H
	jmp	SB_NEXT_STATE

SB_CONTINUE2:				; Yes, then
	mov	ax,SIZE STATE_STR-1
	add	di,ax			; Set PTR and end of header

SB_XLAT_TAB_BEGIN:			; Begin getting xlat tables
	mov	bx,KEYBSYS_FILE_HANDLE
	LEA	dx,[bp].KX_FIRST_XLAT	; Adjust for what we have already read
	mov	cx,STATE_LENGTH
	sub	cx,dx
	mov	dx,di
	push	es
	pop	ds
	mov	ah,3FH			; Read in the xlat tables
	int	21H
	push	cs
	pop	ds
	jnc	SB_CONTINUE4
	jmp	short SB_ERROR4

SB_CONTINUE4:
	cmp	cx,ax
	je	SB_ERROR_CHECK1
	jmp	short SB_ERROR4

SB_ERROR_CHECK1:
	add	di,cx			; Update the end of area ptr

	mov	si,di
	jmp	SB_NEXT_STATE

SB_DONE:
	mov	ax,-1
	mov	si,END_OF_AREA_PTR
	mov	NEXT_SECT_PTR,si

	mov	bp,RESTORE_bp
	ret

SB_ERROR1:
	mov	cx,1
	ret

SB_ERROR2:
	mov	cx,2
	ret

SB_ERROR3:
	mov	cx,3
	ret

SB_ERROR4:
	mov	cx,4
	ret


STATE_BUILD	  ENDP

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;
; Module: FIND_CP_TABLE
;
; Description:
;	Determine the offset of the specified code page table in KEYBOARD.SYS
;
; Input Registers:
;	ds - points to our data segment
;	es - points to our data segment
;	ax - ASCII representation of the language parm
;	bx - binary representation of the code page
;
;	KEYBSYS_FILE_HANDLE - handle of the KEYBOARD.SYS file
;
; Output Registers:
;	CP_TAB_OFFSET - offset of the CP table in KEYBOARD.SYS
;
;	cx - Return Code := 0  -  State build successful
;			    2  -  Invalid Code page for language
;			    4  -  Bad or missing Keyboard Def file
; Logic:
;
;	READ language table
;	IF error in reading file THEN
;	 Display ERROR message and EXIT
;	ELSE
;	 Use table to verify language parm
;	 Set pointer values
;	 IF code page was specified
;		READ language entry
;		IF error in reading file THEN
;		  Display ERROR message and EXIT
;		ELSE
;		  READ Code page table
;		  IF error in reading file THEN
;			Display ERROR message and EXIT
;		  ELSE
;			Use table to get the offset of the code page parm
;	ret
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FIND_CP_PARM	  DW	?

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;  Program Code
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

FIND_CP_TABLE	  PROC  NEAR


	mov	FIND_CP_PARM,bx	  ; Save Code page

	mov	bx,KEYBSYS_FILE_HANDLE	; Get handle
	mov	dx,word ptr KEYBCMD_LANG_ENTRY_PTR ; LSEEK file pointer
	mov	cx,word ptr KEYBCMD_LANG_ENTRY_PTR+2 ;  to top of language entry
	mov	ax,4200h		; If no problem with
	int	21H			;   Keyb Def file Then
	jnc	FIND_BEGIN
	jmp	short FIND_CP_ERROR4

FIND_BEGIN:
	mov	di,ax
	mov	cx,SIZE KEYBSYS_LANG_ENTRY-1	; Set number
						;	bytes to read header
	mov	dx,OFFSET FILE_BUFFER
	mov	ah,3FH			; Read language entry in
	int	21H			;	KEYBOARD.SYS file
	jnc	FIND_VALID4		; If no error in opening file then
	jmp	short FIND_CP_ERROR4

FIND_VALID4:

;****************************** CNS ****************************************
	xor	ah,ah
	mov	al,FB.KL_NUM_CP
;****************************** CNS ****************************************

	mov	NUM_CP,ax		; Save the number of code pages
	MUL	CP_PTR_SIZE		; Determine # of bytes to read
	mov	dx,OFFSET FILE_BUFFER	; Establish beginning of buffer
	mov	cx,ax
	cmp	cx,FILE_BUFFER_SIZE	; Make sure buffer is not to small
	jbe	FIND_VALID5
	jmp	short FIND_CP_ERROR4

FIND_VALID5:
	mov	ah,3FH			; Read code page table from
	int	21H			;	KEYBOARD.SYS file
	jnc	FIND_VALID6		; If no error in opening file then
	jmp	short FIND_CP_ERROR4

FIND_VALID6:
	mov	cx,NUM_CP		;  Number of valid codes
	mov	di,OFFSET FILE_BUFFER	;  Point to correct word in table

F_SCAN_CP_TABLE:			; FOR code page parm
	mov	ax,FIND_CP_PARM		;	Get parameter
	cmp	[di].KC_CODE_PAGE,ax	;	Valid Code ??
	je	F_CODE_PAGE_FOUND	; If not found AND more entries THEN
	add	di,LANG_PTR_SIZE	;	Check next entry
	loop	F_SCAN_CP_TABLE		;    Decrement count & loop


	jmp	short FIND_CP_ERROR2	;  Display error message

F_CODE_PAGE_FOUND:
	mov	ax,word ptr [di].KC_ENTRY_PTR
	mov	word ptr CP_TAB_OFFSET,ax
	mov	ax,word ptr [di].KC_ENTRY_PTR+2
	mov	word ptr CP_TAB_OFFSET+2,ax

	xor	cx,cx
	ret

FIND_CP_ERROR1:
	mov	cx,1
	ret

FIND_CP_ERROR2:
	mov	cx,2
	ret

FIND_CP_ERROR3:
	mov	cx,3
	ret

FIND_CP_ERROR4:
	mov	cx,4
	ret

FIND_CP_TABLE	 ENDP
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
CODE	ENDS
	END	TABLE_BUILD
