
        PAGE    ,132
        TITLE   DOS KEYB Command  -  Transient Command Processing

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;; DOS - NLS Support - KEYB Command
;; (C) Copyright 1988 Microsoft
;;
;; 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             ;; WGR Get id parameter              ;AN000
        MOV   TB_ID_PARM,AX               ;; WGR                               ;AN000
        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
        CMP   CX,0                        ;; Test return codes
        JE    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    ;AN000
        MOV   AX,TB_ID_PARM                     ;; WGR id parm and..           ;AN000
        MOV   ES:[BP].INVOKED_KBD_ID,AX         ;; WGR
        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   AH,42H                   ;;
        MOV   AL,0                     ;; If no problem with
        INT   21H                      ;;     Keyboard Def file THEN
        JNC   TB_START                 ;;
        JMP   TB_ERROR4                ;;
                                       ;;
TB_START:                              ;; Else
        XOR   DI,DI                    ;; Set number
        LEA   CX,[DI].KH_MAX_LOGIC_SZ+2;;        bytes to read header
        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          ;;
        MOV   CX,4                     ;;
        JMP   TB_CPN_INVALID           ;;
                                       ;;
TB_ERROR_CHECK1:                       ;;
        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
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;   ** 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
        JNE   TB_STATE_CONTINUE1       ;;           jump to code page begin
        JMP   TB_CP_BEGIN              ;;
                                       ;;
TB_STATE_CONTINUE1:                    ;; Else
        MOV   AH,42H                   ;; LSEEK to beginning of state logic sect
        MOV   AL,0                     ;; If no problem with
        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          ;;
        MOV   CX,4                     ;;
        JMP   TB_CPN_INVALID           ;;
                                       ;;;;;
TB_ERROR_CHECK2:                          ;;
        MOV   AX,FB.KT_SPECIAL_FEATURES   ;; Save the special features in the
        MOV   ES:[BP].SPECIAL_FEATURES,AX ;;  SHARED_DATA_AREA
                                          ;;
        CMP   HW_TYPE,JR_KB               ;;;;;;;;
        JNE   USE_F1_F2                         ;;
        TEST  AX,JR_HOT_KEY_1_2                 ;;
        JZ    USE_F1_F2                         ;;
        MOV   ES:[BP].HOT_KEY_ON_SCAN,ONE_SCAN  ;;
        MOV   ES:[BP].HOT_KEY_OFF_SCAN,TWO_SCAN ;;
        JMP   HOT_KEY_SET                       ;;
                                                ;;
USE_F1_F2:                                      ;;
        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
        CMP   CX,0                        ;;
        JNE   TB_STATE_CONTINUE4          ;;
        MOV   CX,-1                    ;;;;;
        MOV   ES:[BP].LOGIC_PTR,CX     ;;
        JMP   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          ;;
        MOV   CX,4                     ;;
        JMP   TB_CPN_INVALID           ;;
                                       ;;
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
        CMP   CX,0                     ;;
        JNE   TB_STATE_CONTINUE7       ;;
        JMP   TB_CP_BEGIN              ;;
                                       ;;;;;;;
TB_STATE_CONTINUE7:                         ;;
        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
        CMP   CX,0                     ;; IF we have done all requested CPs
        JNE   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                    ;;
        JNE   TB_CPN_CONTINUE1         ;;
        JMP   TB_CPN_REPEAT            ;;
                                       ;;
TB_CPN_CONTINUE1:                      ;; ELSE
        PUSH  DI                       ;;
        CALL  FIND_CP_TABLE            ;;   Find offset of code page table
        POP   DI                       ;;
                                       ;;
        CMP   CX,0                     ;; Test return codes
        JE    TB_CPN_VALID             ;; IF code page is not found for language
        MOV   CPN_INVALID,CX           ;;       Set flag and go to next CP
        JMP   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
        JNE   TB_CPN_CONTINUE2         ;;
        JMP   TB_CPN_REPEAT            ;; If it is then go get next CP
                                       ;;
TB_CPN_CONTINUE2:                      ;;
        MOV   AH,42H                   ;; LSEEK to table in Keyb Def file
        MOV   AL,0                     ;; If no problem with
        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]                       ;;
        JNE   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
        CMP   CX,0                     ;;             COMMON_XLAT_SECTION
        JE    TB_CPN_REPEAT            ;;             SPECIFIC_XLAT_SECTION(S)
        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   TB_ERROR5                ;;
                                       ;;
TB_DONE_CONTINUE1:                     ;;
        CMP   ES:[BP].RESIDENT_END,-1  ;;
        JNE   DONT_REPLACE             ;;
        PUSH  CS                       ;;
        POP   ES                       ;;
        MOV   BP,OFFSET SD_SOURCE_PTR  ;;
        MOV   ES:[BP].RESIDENT_END,CX  ;;  Save resident end
        JMP   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                            ;;
                                       ;;
TB_CPN_INVALID:                        ;;
        CMP   CX,1                     ;;  Set error 1 return code
        JNE   TB_ERROR2                ;;
        MOV   TB_RETURN_CODE,CX        ;;
        RET                            ;;
                                       ;;
TB_ERROR2:                             ;;
        CMP   CX,2                     ;;  Set error 2 return code
        JNE   TB_ERROR3                ;;
        MOV   TB_RETURN_CODE,CX        ;;
        RET                            ;;
                                       ;;
TB_ERROR3:                             ;;
        CMP   CX,3                     ;;  Set error 3 return code
        JNE   TB_ERROR4                ;;
        MOV   TB_RETURN_CODE,CX        ;;
        RET                            ;;
                                       ;;
TB_ERROR4:                             ;;
        CMP   CX,4                     ;;  Set error 4 return code
        JNE   TB_ERROR5                ;;
        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   AH,42H                          ;;
        MOV   AL,0                     ;;;;;;;;; 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
        CMP   CX,0                     ;;
        JE    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   SB_ERROR4                ;;
                                       ;;
SB_CONTINUE4:                          ;;
        CMP   CX,AX                    ;;
        JE    SB_ERROR_CHECK1          ;;
        JMP   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   AH,42H                               ;;
        MOV   AL,0                     ;;;;;;;;;;;;;; If no problem with
        INT   21H                      ;;     Keyb Def file Then
        JNC   FIND_BEGIN               ;;
        JMP   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   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   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   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
        DEC   CX                       ;;    Decrement count of entries
        JNE   F_SCAN_CP_TABLE          ;; Else
        JMP   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
