;       SCCSID = @(#)inicp.asm  6.1 90/11/17
        page    78,132
        title   inicp,  Code Page Initialization

SCCSID  equ     "@(#)inicp.asm  1.12 90/09/17"

;
;                 IBM/Microsoft Confidential
;
;           Copyright (c) IBM Corporation  1987, 1990
;           Copyright (c) Microsoft Corp.  1987, 1990
;                     All Rights Reserved
;

;
; SOURCE FILE NAME:     INICP.ASM
;
; DESCRIPTIVE NAME:     CODEPAGE INITIALIZATION
;
; FUNCTION:     INITIALIZE THE CDIB SEGMENT, ACTIVATE CODEPAGE/FONT
;               SUPPORT
;
; NOTES:
;   DEPENDENCIES:
;   RESTRICTIONS:
;
; ENTRY POINTS:
;               SYICPACTIVATE
;               SYICODEPAGE
;
; EXTERNAL REFERENCES:
;               DosAllocSeg:FAR
;               DosClose:FAR
;               DosChgFilePtr:FAR
;               DosFreeSeg:FAR
;               DosGlobalSeg:FAR
;               DosOpen:FAR
;               DosRead:FAR
;               DosReallocSeg:FAR
;               DosSetCp:FAR
;               KbdSetCp:FAR
;               syiAbortR3:NEAR
;               syiSaveMessageR3:NEAR
;               VioSetCp:FAR
;

        subttl  Data Structures
        page
        .xlist
        .xcref
        include country.inc             ;country.sys structure
        include inicfg.inc              ;config parameters structure
        include basemaca.inc            ;cp/dos macros
        include fnoinit.inc
        include osmaca.inc              ;cp/dos macros
        include dosseg.inc              ;cp/dos kernel segments
        include cdib.inc                ;cp/dos codepage structures
        include inisms.inc              ;sysinit message structures
        include error.inc               ;cp/dos error codes
        include error2.inc              ;cp/dos error codes
        include filemode.inc            ;filemode equates
        include struc.inc               ;structured assembler macros
        include basemid.inc
        include curdir.inc              ;includes MAXPATHLEN
        include infoseg.inc             ;information segment
        include mi.inc
        .cref
        .list

        ModName  , FNO_INICP_ASM

;
;       CodePage Initialization Local Data Area
;

;       external references

        extrn   pDosAllocSeg:dword
        extrn   pDosChgFilePtr:dword
        extrn   pDosClose:dword
        extrn   pDosFreeSeg:dword
        extrn   pDosGlobalSeg:dword
        extrn   pDosOpen:dword
        extrn   pDosRead:dword
        extrn   pDosReallocSeg:dword
        extrn   pDosSetCp:dword
        extrn   pKbdSetCp:dword
        extrn   pVioSetCp:dword
        extrn   Config_Sys_Data:word
        extrn   SISData:byte
        extrn   syiAbortR3:near
        extrn   syiSaveMessageR3:near
        extrn   StrTransPathCharR3:near
        ReferGlobal     CDIB_selector,WORD

INITDATA segment
cdibglobseg db  '\SHAREMEM\DOS\CDIB',0
ct_default_drive db ?                 ; must be in front of ct_file
ct_file db      ':\COUNTRY.SYS',0
ctf_len equ     $-ct_file
ct_tag  db      0ffh,'COUNTRY'
ct_len  equ     $-ct_tag
fmt_tag db      0ffh,'CTYINFO'
fmt_len equ     $-fmt_tag
col_tag db      0ffh,'COLLATE'
col_len equ     $-col_tag
cas_tag db      0ffh,'UCASE  '
cas_len equ     $-cas_tag
dbcs_tag db     0ffh,'DBCS   '
dbcs_len equ    $-dbcs_tag
sys_cp_flag     db      0
SYS_CP_WARN     equ     00000001b       ;warning error
SYS_CP_FATAL    equ     00000010b       ;fatal error
SYS_CP_SEG      equ     00000100b       ;CDIB segment present
        public  cdibseg                 ;hook for unit test
cdibseg dw      0
cfgid_size equ  size CFG_Packet4a
cfg_id_size db  cfgid_size
cpid_size equ   size CDIB_cp_id_section
cp_id_size db   cpid_size
cp_err_vio_cp  SMT     <MSG_SYSINIT_VIO_CP,1>
                SMT_Var <DOSINITDATA:CP_DEC> ;asciiz decimal codepage pointer
cp_err_kbd_cp  SMT     <MSG_SYSINIT_KBD_CP,1>
                SMT_Var <DOSINITDATA:CP_DEC> ;asciiz decimal codepage pointer
cp_err_fail_CDIB SMT   <MSG_SYSINIT_MORE_MEM,0>
cp_err_no_fileu SMT    <MSG_SYSINIT_UFILE_NOT_FND,3>
                SMT_Var <line_number>
                SMT_Var <command>
                SMT_Var <file_spec>
cp_err_no_files SMT    <MSG_SYSINIT_SFILE_NOT_FND,1>
                SMT_Var <ct_default_drive>
cp_err_bad_fileu SMT   <MSG_SYSINIT_UCFILE_INVAL,3>
                SMT_Var <line_number>
                SMT_Var <command>
                SMT_Var <file_spec>
cp_err_bad_files SMT   <MSG_SYSINIT_SCFILE_INVAL,1>
                SMT_Var <ct_default_drive>
cp_err_bad_devinfo SMT    <MSG_SYSINIT_UFILE_NOT_FND,3>
                SMT_Var <line_number>
                SMT_Var <command>
                SMT_Var <file_spec>
cp_err_no_entry SMT    <MSG_SYSINIT_INVAL_PARM,3>
cp_line_no      SMT_Var <>              ;store the line number pointer
cp_command      SMT_Var <>              ;store the command pointer
                SMT_Var <DOSINITDATA:CP_DEC> ;asciiz decimal codepage pointer
cp_err_bad_cty SMT     <MSG_SYSINIT_INVAL_PARM,3>
                SMT_Var <line_number>
                SMT_Var <command>
                SMT_Var <DOSINITDATA:CT_DEC> ;asciiz decimal country pointer
cp_err_bad_layout SMT   <MSG_SYSINIT_INVAL_PARM,3>
                SMT_Var <line_number>
                SMT_Var <command>
                SMT_Var <DOSINITDATA:KBD_LAYOUT> ; keyboard layout code
cp_err_cp_fatal SMT    <MSG_SYSINIT_CP_FATAL,0>
INITDATA ends

INITBSS segment
CT_DEC  db      6 dup (0)
CP_DEC  db      12 dup (0)
cpsize  equ     $-CP_DEC
KBD_LAYOUT  db  9 dup(0)
kbd_devinfo dw  0                     ; offset to KBD devinfo packet
line_number db  6 dup(?)              ; line number of failing command
command     db  MAXPATHLEN dup(?)     ; failing command name
file_spec   db  1024 dup(?)           ; failing file specification
no_file     dw  ?                     ; message for missing file
bad_file    dw  ?                     ; message for bad file
INITBSS ends


;
; SUBROUTINE NAME:      syicpInit
;
; DESCRIPTIVE NAME:     CODEPAGE INITIALIZATION CONTROL ROUTINE
;
; FUNCTION:     CONTROL CODEPAGE PROCESSING
;
; NOTES:
;
; ENTRY POINT:  syicpInit
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               No Input
;
; EXIT-NORMAL:
;               No Output
;
; EXIT-ERROR:
;               No Output
;
; EFFECTS:
;               Allocates & Initializes CDIB Segment
;               Makes CDIB Global & Shared
;               Activates proper codepages & fonts
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicpAscii:NEAR
;               syicpCountry:NEAR
;               syicpDevInfo:NEAR
;               syiAbortR3:NEAR
;               syicpID:NEAR
;               syicpWarning:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;               DosAllocSeg:FAR
;               DosGlobalSeg:FAR
;               DosReallocSeg:FAR
;               DosSetCp:FAR
;               syiAbortR3:NEAR
;
;
;       Procedure SYICP
;
;       allocate a 64k CDIB segment via DosAllocSeg
;       if (DosAllocSeg returns in error) then
;         call syiAbortR3
;       else
;         process 'CODEPAGE =' statement via syicpID
;         process 'COUNTRY =' statement via syicp_Country
;         if (syicp_Country returns without a fatal error) then
;           process 'DEVINFO =' statements via syicp_DevInfo
;           resize the CDIB segment via DosReallocSeg
;           if (DosReallocSeg returns in error) then
;             call syiAbortR3
;           else
;             convert CDIB segment read-only, global, shared via DosGlobalSeg
;             if (DosGlobalSeg returns in error) then
;               call syiAbortR3
;             else
;               if (CODEPAGE not specified) then
;                 set good return code
;               else
;                 activate primary code page via DosSetCp
;               endif
;             endif
;           endif
;         endif
;       endif
;       return
;
;       End Procedure SYICP

        FARCODE INITR3
INITR3CODE segment

Procedure syicpInit,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        LocalVar sci_globsel,WORD

        EnterProc

        SaveReg <ds,es,di,si,bx,cx,dx>        ;save register state

;       set up ds reference

        DosInitContext  ds

;       allocate a 64k CDIB segment via DosAllocSeg

        push    0                       ;allocate a 64k segment
        push    ds                      ;selector &
        push    offset cdibseg          ; offset of storage for selector
        push    0                       ;do not share
        call    [pDosAllocSeg]          ;entry point for DosAllocSeg
        .if     <ax ne 0>
          mov   si,offset cp_err_fail_CDIB ;load error message offset
          call  syiAbortR3             ;process internal error error
        .endif
        or      [sys_cp_flag],SYS_CP_SEG;indicate CDIB segment presence

;       obtain addressing for the 'CODEPAGE' statement processing

        mov     es,Config_Sys_Data      ;obtain the config data selector
        mov     di,es:[0].CFG_CodePage.CFG_Tail ;load offset of final cp pkt

;       process the 'CODEPAGE' parms

        call    syicpID                 ;codepage processing routine

;       obtain addressing for the 'COUNTRY' statement processing

        mov     di,es:[0].CFG_Country.CFG_Tail ;point to the final CTY pkt

;       process the 'COUNTRY' parms

        call    syicpCountry ;country processing routine
        .if <bit [sys_cp_flag] and SYS_CP_FATAL> ;if error
          jmp   exit                    ;  quit
        .endif

;       process the 'DEVINFO' statement

        mov     di,es:[0].CFG_DevInfo.CFG_Tail ;point to the devinfo pkt
        .if     <nonzero di>            ;any DEVINFOs present?
          call    syicpDevInfo ;devinfo processing routine
        .endif

;       obtain the size of the CDIB

        mov     es,[cdibseg]            ;es:di point
        mov     ax,es:[0].CDIB_length  ;load segment size

;       resize the CDIB via DosReallocSeg

        push    ax                      ;requested size
        push    es                      ;CDIB selector
        call    [pDosReallocSeg]        ;DosReallocSeg entry point
        .if <ax ne 0>
          mov   si,offset cp_err_fail_CDIB;load error message offset
          call  syiAbortR3              ;process internal error
        .endif

;       convert the CDIB via DosGlobalSeg

        push    ds                      ;selector &
        push    offset cdibglobseg      ;  offset of shared name
        push    es                      ;current selector
        xor     ax,ax
        mov     es,ax                   ;don't leave freed selector
        push    ss                      ;selector &
        lea     ax,[sci_globsel]        ;  offset of new selector storage
        push    ax                      ;
        call    [pDosGlobalSeg]         ;DosGlobalSeg entry point
        .if <ax ne 0>
          mov   si,offset cp_err_fail_CDIB;load error message offset
          call  syiAbortR3              ;process internal error
        .endif
        and     [sys_cp_flag],not SYS_CP_SEG ;clear the SYS_CP_SEG flag

;       store global selector for future use

        DosContext ds
        mov     ax,[sci_globsel]
        mov     CDIB_selector,ax
        DosInitContext ds

;       check if codepage specified

        mov     es,[sci_globsel]        ;load CDIB
        mov     di,es:[0].CDIB_codepage_ptr ;
        .if     <es:[di].CDIB_cp_number_codepages eq 0> ;codepage not specified
          mov   es,Config_Sys_Data      ;check if codepages were specified
          .if   <es:[0].CFG_CodePage.CFG_Tail ne 0> ;if cp's were specified
            mov si,offset cp_err_cp_fatal;codepage switching was disabled
            call syicpWarning ;load message
          .endif
          jmp   exit                    ;  & quit
        .endif

;       obtain primary codepage

        mov     ax,es:[di].CDIB_cp_first_id.CDIB_cp_id ;first cp id

;       convert to asciiz for error messages

        push    es                      ;save
        push    di                      ;  registers
        DosInitContext es               ;address of storage
        mov     di,offset CP_DEC        ;initialize count
        call    syicpAscii              ;load asciiz field
        pop     di                      ;restore
        pop     es                      ;registers

;       activate primary codepage

        push    ax                      ;primary codepage
        push    0                       ;reserved parm
        call    [pDosSetCp]             ;entry point for DosSetCp

exit:
        RestoreReg <dx,cx,bx,si,di,es,ds>     ;restore register state
        LeaveProc
        ret

EndProc syicpInit


;
; SUBROUTINE NAME:      SYICPID
;
; DESCRIPTIVE NAME:     CODEPAGE STATEMENT PROCESSING ROUTINE
;
; FUNCTION:     PLACE 'CODEPAGE =' INFORMATION IN THE CDIB
;
; NOTES:
;
; ENTRY POINT:  syicpID
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ES:DI   @codepage packet
;               DS:CDIBSEG cdib selector
;
; EXIT-NORMAL:
;               No Output
;
; EXIT-ERROR:
;               No Output
;
; EFFECTS:
;               Assign CDIB structure in CDIB Segment
;               Assign CDIB_codepage_section structure
;                 in CDIB segment
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPID
;
;       place CDIB structure at offset 0 of CDIB segment
;       set CDIB_length = size of CDIB structure
;       initialize codepage structure
;       update CDIB_length
;       set CDIB_codepage_ptr = size of CDIB structure
;       set CDIB_cp_length = (4 * count) + 4
;       set CDIB_cp_number_codepages = count
;       if (count == 0)
;         load dummy id = 0
;       else
;         for each codepage id
;           repeat
;             compare new codepage id against loaded ids
;           until (current list examined or match found)
;           if (new id is unique) then
;             set cp_id = codepage id
;           else
;             decrement CDIB_cp_number_codepages
;           endif
;         endfor
;       endif
;       return
;
;       End Procedure SYICPID

Procedure syicpID,near,local
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        EnterProc

        SaveReg <ds,es,di,si,bx,cx>

;       Fill in message items if a CODEPAGE command was specified

        .if     <nonzero di>
          lea   ax,es:[di].CFG_LineNumber ; fill in pointer to line
          mov   [cp_line_no].Segmt,es     ;   number
          mov   [cp_line_no].Offst,ax
          mov   ax,es:[di].CFG_Command.Segmt ; fill in pointer to
          mov   bx,es:[di].CFG_Command.Offst ;   command name
          mov   [cp_command].Segmt,ax
          mov   [cp_command].Offst,bx
        .endif

;       initialize CDIB structure

        push    ds                      ;save initdata
        mov     ds,[cdibseg]            ;load cdib
        mov     ds:[0].CDIB_length,size CDIB ;
        mov     ds:[0].CDIB_codepage_ptr,size CDIB ;
        mov     ds:[0].CDIB_country_ptr,0 ;
        mov     ds:[0].CDIB_screen_ptr,0 ;
        mov     ds:[0].CDIB_keyboard_ptr,0 ;
        mov     ds:[0].CDIB_lpt1_ptr,0  ;
        mov     ds:[0].CDIB_lpt2_ptr,0  ;
        mov     ds:[0].CDIB_lpt3_ptr,0  ;
        pop     ds                      ;restore initdata

;       define codepage section

        .if     <zero di>               ;was codepage specified?
          xor   ax,ax                   ;no
        .else
          mov     ax,es:[di].CFG_nIDs   ;load codepage count
        .endif
        mov     cx,ax                   ;save count
        mul     [cp_id_size]            ;equals count * size of id struc
        add     ax,size CDIB_codepage_section ;(no bounds checking on count)

;       determine presence of codepage ids

        .if     <zero cx>               ;no codepage ids specified
          add   ax,size CDIB_cp_id_section ;compensate for dummy entry
        .endif
        mov     ds,[cdibseg]            ;load cdib
        add     ds:[0].CDIB_length,ax   ;update segment length
        mov     si,ds:[0].CDIB_codepage_ptr ;point to codepage section
        mov     ds:[si].CDIB_cp_length,ax ;store codepage length
        mov     ds:[si].CDIB_cp_number_codepages,cx ;store count
        add     si,offset CDIB_cp_first_id ;point to first codepage in CDIB
        mov     bx,si                   ;bx = offset of first cp id

;       store the codepage ids

        .if     <zero cx>               ;no codepage ids specified
          mov   ds:[si].CDIB_cp_id,0    ;dummy id
        .else
          add   di,offset CFG_IDs       ;point to first codepage in Config Data
          .repeat
            mov ax,es:[di]              ;move codepage id from Config Seg...
            push bx                     ;save base address of cp ids
            .while      <bx b si> and   ;all entries scanned?
            .while      <ax ne ds:[bx].CDIB_cp_id> ;cp ids match?
              add       bx,size CDIB_cp_id_section ;point at next entry
            .endwhile                   ;
            .if <bx ae si>              ;no match found (ok)
              mov       ds:[si].CDIB_cp_id,ax ;store cp id
            .else                       ;match found (duplicate cp ids)
              mov       bx,ds:[0].CDIB_codepage_ptr ;offset of cp section base
              dec       ds:[bx].CDIB_cp_number_codepages ;adjust count
            .endif
            pop bx                      ;restore base address of cp ids
            add si,size CDIB_cp_id_section ;point to next codepage in CDIB
            add di,size CFG_IDs         ;point to next codepage in Config Data
          .loop
        .endif

exit_id:
        RestoreReg <cx,bx,si,di,es,ds>
        LeaveProc
        ret

EndProc syicpID


;
; SUBROUTINE NAME:      SYICPCOUNTRY
;
; DESCRIPTIVE NAME:     COUNTRY STATEMENT PROCESSING ROUTINE
;
; FUNCTION:     PLACE 'COUNTRY =' INFORMATION IN THE CDIB
;
; NOTES:
;
; ENTRY POINT:  syicp_Country
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ES:DI   @country packet
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               AX != 0
;
; EFFECTS:
;               Assign CDIB_country_section structure
;                 in CDIB structure_section structure
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicp_Ascii:NEAR
;               syicp_Data:NEAR
;               syiAbortR3:NEAR
;               syicp_Save_Data:NEAR
;               syicp_Validate_Country:NEAR
;               syicp_Warning:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;               DosAllocSeg:FAR
;               DosClose:FAR
;               DosChgFilePtr:FAR
;               DosFreeSeg:FAR
;               DosOpen:FAR
;               DosRead:FAR
;
;
;       Procedure SYICPCOUNTRY
;
;       set CDIB_country_ptr = current size of CDIB
;       set default country code and filename
;       if (country statement present) then
;         call syiSaveData to save line number, command, and
;               file specification from the COUNTRY command
;         set ct_code = country code
;         if (country filename present) then
;           set ct_filename = country file
;         endif
;       endif
;       insure filename is word rounded
;       set ct_length
;       update CDIB_length
;       open the country file via DosOpen
;       if (DosOpen returns in error) then
;         call syiAbortR3
;       else
;         obtain file size via DosChgFilePtr
;         if (DosChgFilePtr returns in error) then
;           call syiAbortR3
;         else
;           reset file pointer via DosChgFilePtr
;           if (DosChgFilePtr returns in error) then
;             call syiAbortR3
;           else
;             if (country file > 64k size) then
;               call syiAbortR3
;             else
;               allocate a segment for country data via DosAllocSeg
;               if (DosAllocSeg returns in error) then
;                 call syiAbortR3
;               else
;                 read in the file via DosRead
;                 if (DosRead returns in error or bytes read not ok) then
;                   call syiAbortR3
;                 else
;                   if (invalid file tag) then
;                     call syiAbortR3
;                   else
;                     if (COUNTRY was specified)
;                       Call syicpValidateCountry
;                     endif
;                     if (COUNTRY wasn't specified or is invalid)
;                       set country code = default country from the file
;                     endif
;                     fill the Ascii country code string
;                     if (codepages specified)
;                       for cx = 1 to # codepages
;                         call syicpData
;                         if (fatal error) then
;                           free buffer segment via DosFreeSeg
;                           close country file via DosClose
;                         endif
;                       next
;                     endif
;                     if (any errors occurred) or
;                     if (no codepages specified) then
;                       search for any codepage via syicp_Data
;                       if (syicp_Data returns not ok) then
;                         call syiAbortR3
;                         free buffer segment via DosFreeSeg
;                         close country file via DosClose
;                         return
;                       endif
;                     endif
;                   endif
;                 endif
;               endif
;             endif
;           endif
;         endif
;       endif
;       free buffer segment via DosFreeSeg
;       close country file via DosClose
;       return
;
;       End Procedure SYICPCOUNTRY

Procedure syicpCountry,near,local
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing
        LocalVar ct_eos,WORD
        LocalVar ct_fhnd,WORD
        LocalVar ct_fact,WORD
        LocalVar ct_fsize,DWORD
        LocalVar ct_reset,DWORD
        LocalVar ct_bufsel,WORD
        LocalVar ct_bytrd,WORD
        LocalVar ct_flag,BYTE
        LocalVar ct_errdata,WORD
        LocalVar ct_ctycode,WORD

        CT_CP_OK        equ     00000001b
        CT_CP_ERR       equ     00000010b

        EnterProc

        SaveReg <ds,es,di,si,bx,cx,dx>

;       obtain country pointer

        push    di                      ;move config pointer from di...
        mov     es,[cdibseg]            ;load cdib
    assume es:nothing
        push    ds
        DosContext ds
        mov     ax,[SISData].SIS_BootDrv ;load default drive
        pop     ds
    assume ds:DOSINITDATA
        add     al,'A' - 1
        mov     ct_default_drive,al     ;save it for messages
        pop     si                      ;    ...to si
        mov     di,es:[0].CDIB_length   ;current length of segment...
        mov     es:[0].CDIB_country_ptr,di ;  ...becomes country pointer

;       initialize country filename

        push    si                      ;save pointers
        push    di                      ;
        mov     cx,[ctf_len]            ;load length
        push    cx                      ;save length
        mov     si,offset ct_file       ;load source offset
        add     di,offset CDIB_ct_filename ;point to ct_filename
        stosb                           ;store drive
        rep     movsb                   ;move the string
        pop     cx                      ;restore length
        inc     cx                      ;include drive letter
        mov     ct_eos,di               ;save eos offset
        pop     di                      ;restore country pointers
        pop     si                      ;restore country pointers

;       Set up for default country information file in messages

        mov     [no_file],offset cp_err_no_files
        mov     [bad_file],offset cp_err_bad_files

;       check for presence of country statement

        .if     <zero si>               ;no statement
          mov   [ct_ctycode],0          ;change to zero, load default later
        .else
          push  ds                      ;save initdata
          mov   ds,[Config_Sys_Data]    ;load Config_Sys_Data selector
    assume ds:nothing

;         Save line number, command name, and file specification from
;         the COUNTRY command

          call  syiSaveData

;       set country code

          mov   ax,ds:[si].CFG_CountryCode ;store country code...
          mov   es:[di].CDIB_ct_code,ax ;  ...into the CDIB
          mov   [ct_ctycode],ax         ;save for use

;       check for presence of country file

          .if   <ds:[si].CFG_FileSpec ne 0>

;         Set up for user specified country information file in messages

            SaveReg <ds>
            DosInitContext ds
            mov [no_file],offset cp_err_no_fileu
            mov [bad_file],offset cp_err_bad_fileu
            RestoreReg <ds>
        assume ds:nothing

;       set country filename

            push di                     ;save country pointers
            push si                     ;
            add di,offset CDIB_ct_filename ;point to ct_filename
            mov si,ds:[si].CFG_FileSpec ;load source offset
            xor   cx,cx                 ;set counter
            .repeat                     ;
              inc cx                    ;keep count
              lodsb                     ;move byte es:[di] to
              stosb                     ;  ds:[si] via al
            .until <zero al>
            mov [ct_eos],di             ;save eos offset
            pop si                      ;
            pop di                      ;restore country pointer
          .endif
          pop   ds                      ;restore initdata
        assume ds:DOSINITDATA
        .endif

;       word round the ASCIIZ file string

        .if   <bit cx and 1>            ;if count is odd
          mov bx,[ct_eos]               ;load offset
          mov byte ptr es:[bx],0        ;add another 0
          inc [ct_eos]                  ;bump the offset
        .endif

;       set ct_length

        mov     bx,[ct_eos]
        mov     ax,bx                   ;load eos
        sub     ax,di                   ;calculate length
        mov     es:[di].CDIB_ct_length,ax ;store length

;       update CDIB length

        mov     es:[0].CDIB_length,bx   ;store segment size

;       open country file

        push    es                      ;filename pointer
        lea     bx,es:[di].CDIB_ct_filename ;
        push    bx                      ;
        push    ss                      ;handle storage pointer
        lea     ax,[ct_fhnd]            ;
        push    ax
        push    ss                      ;action taken storage pointer
        lea     ax,[ct_fact]            ;
        push    ax
        push    0                       ;size (dword)
        push    0                       ;
        push    0                       ;file attribute
        push    1                       ;openflag
        push    open_for_read+sharing_deny_write+open_no_inherit+open_autofail
                                        ;openmode
        push    0                       ;reserved (dword)
        push    0                       ;
        call    [pDosOpen]              ;entry point for DosOpen call

;       if an error actually occurred

        .if     <nonzero ax>
          mov   si,[no_file]
          call  syiAbortR3              ;fatal
          jmp   exit_ct                 ;
        .endif

;       obtain size via DosChgFilePtr

        push  [ct_fhnd]                 ;file handle
        push  0                         ;distance to move
        push  0                         ;
        push  2                         ;move method
        push  ss                        ;new
        lea   ax,[ct_fsize]             ;  pointer
        push  ax
        call  [pDosChgFilePtr]          ;entry point for DosChgFilePtr
        .if   <nonzero ax>              ;error
exit_file_prob:                         ;common file problem
          mov   si,[bad_file]           ;load error offset
          call  syiAbortR3              ;fatal
          jmp   exit_ct_1               ;
        .endif

;       reset pointer via DosChgFilePtr

        push [ct_fhnd]                  ;file handle
        push 0                          ;distance to move
        push 0                          ;
        push 0                          ;move method
        push ss                         ;reset
        lea  ax,[ct_reset]              ;  storage
        push ax
        call [pDosChgFilePtr]           ;entry point for DosChgFilePtr
        .if   <nonzero ax>              ;error
          jmp exit_file_prob            ;  with file
        .endif

;       insure country file < 64k

        mov ax,[ct_fsize].hiword        ;load most significant word
        .if   <nonzero ax>              ;error
          jmp exit_file_prob            ;  with file
        .endif

;       allocate a buffer segment

        mov     bx,[ct_fsize].loword    ;(bx) = size
        push    bx                      ;size
        push    ss                      ;storage for
        lea     ax,[ct_bufsel]          ;    selector
        push    ax
        push    0                       ;local only
        call    [pDosAllocSeg]          ;entry point for DosAllocSeg
        .if   <nonzero ax>              ;error
          mov   si,offset cp_err_fail_CDIB;load msg pointer
          call  syiAbortR3              ;process internal error
        .endif

;       read in the file
;       (BX) = size

        push  [ct_fhnd]                 ;file handle
        push  [ct_bufsel]               ;buffer selector
        push  0                         ;  offset 0
        push  bx                        ;buffer length
        push  ss                        ;storage for
        lea   ax,[ct_bytrd]             ;  bytes read
        push  ax
        call  [pDosRead]                ;entry point for DosRead
        .if   <nonzero ax> or           ;error
        .if   <bx ne ct_bytrd>          ;wrong # bytes read
exit_file_prob1:                        ;common file problem
          mov   si,[bad_file]           ;load error offset
          call  syiAbortR3              ;fatal
          jmp   exit_ct_2               ;
        .endif

;       check for valid file tag

        mov  si,offset ct_tag           ;source pointer
        push es                         ;save
        push di                         ;  es:di
        mov  es,[ct_bufsel]             ;load tag
    assume es:nothing
        xor  di,di                      ;  & offset
        mov  cx,[ct_len]                ;load count
        repe cmpsb                      ;compare
        pop  di                         ;restore
        pop  es                         ;  es:di
    assume es:nothing
        .if <nz>
          jmp exit_file_prob1           ;strings don't match - bad tag
        .endif

;       if a country code was specified, make sure it exists

        mov     ax,[ct_ctycode]
        .if     <nonzero ax>
          mov   bx,[ct_bufsel]          ;country file segment
          call  syicpValidateCountry  ;
      assume es:nothing
          .if   <bit [sys_cp_flag] and SYS_CP_FATAL> ;if fatal error occurred...
            jmp exit_ct_2       ;quit
          .endif                ;
          mov   es,[cdibseg]    ;reload cdib selector
      assume es:nothing
          mov   [ct_ctycode],ax
        .endif

;       if a valid country code was not specified, default to
;       the first country found in the country information file

        .if     <ct_ctycode eq 0>
          mov   ds,[ct_bufsel]          ;buffer selector
      assume ds:nothing
          mov   si,size cty_hdr         ;point at first C/C header
          mov   ax,ds:[si].cty_cc_ptr.hiword ;obtain offset
          .if   <nonzero ax>            ;offset too large
            DosInitContext ds           ;reset ds
            jmp exit_file_prob1         ;quit with error
          .endif
      assume ds:nothing
          mov   si,ds:[si].cty_cc_ptr.loword ;obtain actual offset
          add   si,size cty_cc_cnt      ;point at first cty/cp entry
          mov   ax,ds:[si].cty_cp_cty   ;obtain the first country id
          mov   di,es:[0].CDIB_country_ptr ;obtain pointer
          mov   es:[di].CDIB_ct_code,ax ;store default country code
          mov   [ct_ctycode],ax         ;country code = default code
          DosInitContext ds             ;reset ds
        .endif

;       perform country processing for all codepage ids

        mov [ct_flag],0                 ;clear the flag
        mov [ct_errdata],0              ;clear the error holder
        mov di,es:[0].CDIB_codepage_ptr ;
        mov bx,es:[di].CDIB_cp_number_codepages ;est. loop count
        add di,size CDIB_cp_id_section  ;first codepage id
        .if     <nonzero bx>
          mov   dx,di                   ;save offset of first cp id
          .for  cx = 1 to bx
            mov ax,es:[di].CDIB_cp_id   ;codepage id
            push [ct_bufsel]            ;source sel
            push [ct_fsize].loword      ;load buffer size
            push [ct_ctycode]           ;load country code
                                        ;es:di = CDIB:cp_id
                                        ;ax = codepage id
            call syicpData              ;load the id tables

;         what kind of result?

            .if <ax eq 0>               ;no error occurred
              or        ct_flag,CT_CP_OK ;indicate ok
            .else
              .if       <bit [sys_cp_flag] and SYS_CP_FATAL> ;fatal error occur.
                jmp     exit_ct_2       ;quit
              .endif
              or        ct_flag,CT_CP_ERR ;warning error
              .leave
            .endif
            add di,size CDIB_cp_id_section ;next codepage id
          .next cx
          mov   di,dx                   ;restore first id
        .endif

;       attempt country with any codepage

        .if     <bit ct_flag and CT_CP_ERR> or
        .if     <zero bx>
          mov  ax,0                     ;no/any codepage id
          push [ct_bufsel]              ;source sel
          push [ct_fsize].loword        ;load buffer size
          push [ct_ctycode]             ;load country code
                                        ;es:di = CDIB:cp_id
                                        ;ax = codepage id
          call syicpData                ;load the id tables

;       what kind of result?

          .if       <ax eq 0>           ;no error occurred
exit_ct_load:
            or      ct_flag,CT_CP_OK    ;indicate ok
          .endif
        .endif

;       free the buffer via DosFreeSeg

exit_ct_2:
        DosInitContext ds               ;INSURE!! that ds ne buffer selector
        push  [ct_bufsel]               ;buffer selector
        call  [pDosFreeSeg]             ;entry point for DosFreeSeg

;       close the file via DosClose

exit_ct_1:
        push  [ct_fhnd]                 ;file
        call  [pDosClose]               ;entry point for DosClose

exit_ct:
        RestoreReg <dx,cx,bx,si,di,es,ds>
        LeaveProc
        ret
EndProc syicpCountry


;
; SUBROUTINE NAME:      SYICPVALIDATECOUNTRY
;
; DESCRIPTIVE NAME:     VALIDATE COUNTRY CODE
;
; FUNCTION:     VALIDATE THE VALUE SPECIFIED ON A COUNTRY STATEMENT
;
; NOTES:
;
; ENTRY POINT:  syicp_Validate_Country
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:        AX =    country code
;               BX =    selector for country file segment
;
; EXIT-NORMAL:
;               AX =    country code
;
; EXIT-ERROR:
;               AX =    0
;               flag set in [sys_cp_flag]
;
; EFFECTS:
;               ES destroyed
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicp_Ascii:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;               None
;
;
;       Procedure SYICPVALIDATECOUNTRY
;
;       call syicpAscii to convert country to ASCII string
;
;       obtain first country/codepage header
;       if (offset too large) then
;         call syiAbortR3
;       else
;         repeat
;         until (country matches or list scanned)
;         if (country not found) then
;           call syicpWarning
;           return
;         endif
;       return
;
;       End Procedure SYICPVALIDATECOUNTRY

Procedure syicpValidateCountry,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        LocalVar data_country,WORD

        EnterProc

        SaveReg <ds,di,si,bx,cx,dx>

        mov     data_country,ax         ;save country code

;       set ASCIIZ country string for error message

        DosInitContext <ds,es>
        mov     di,offset CT_DEC        ;offset
        mov     ax,[data_country]       ;value
        call    syicpAscii              ;set string

;       obtain codepage/country entry
;       (commented out lines indicate for future use)

        mov     ds,bx                   ;load address of buffer segment
;       mov     cx,ds:[0].cty_cnt       ;obtain count pointers in header
        mov     si,size cty_hdr         ;point at first C/C header
;       dec     cx                      ;adjust count for looping
;         .for  ax = 1 to cx
;           add si,size cty_cc_hdr      ;point at next C/C header
;         .next ax
;         .if   <si gt data_bufsiz>
;           mov si,[bad_file]               ;load error code
;           call syiAbortR3
;           xor ax,ax
;           jmp exit_validate           ;quit
;         .endif

        mov     bx,word ptr ds:[si].cty_cc_ptr ;obtain offset
        mov     ax,word ptr ds:[si].cty_cc_ptr+2 ;
        .if     <nonzero ax>            ;bad offset too large
          DosInitContext ds
          mov   si,[bad_file]
          call  syiAbortR3              ;
          xor   ax,ax
          jmp exit_validate             ;quit
        .endif
        mov     ax,data_country         ;load country code
        mov     si,bx                   ;load offset
        xor     di,di                   ;clear index reg
        mov     bx,ds:[si].cty_cc_cnt   ;load cty/cp count
        xor     cx,cx                   ;initialize loop
        add     si,size cty_cc_cnt      ;point at first cty/cp entry
        .repeat                         ;examine each entry
          .if   <ax eq ds:[si].cty_cp_cty> ;check for country match
            xor ax,ax                   ;indicate country found in file
          .endif
          inc   cx                      ;increment count
          add   si,size cty_cp_hdr      ;point at next entry
        .until  <zero ax> or            ;country code found
        .until  <cx ae bx>              ;scanned entire list
        xor     ax,data_country         ;restore country code to AX
                                        ;  (or zero if invalid)
        .if     <ax eq 0>               ;country could not be found
          DosInitContext ds
          mov   si,offset cp_err_bad_cty
          call  syicpWarning ;
          xor   ax,ax
        .endif

;       return to caller

exit_validate:
        RestoreReg <dx,cx,bx,si,di,ds>
        LeaveProc
        ret

EndProc syicpValidateCountry


;
; SUBROUTINE NAME:      SYICPDATA
;
; DESCRIPTIVE NAME:     COUNTRY DATA LOADING ROUTINE
;
; FUNCTION:     PLACE COUNTRY/CODEPAGE INFORMATION INTO CDIB SEGMENT
;
; NOTES:
;
; ENTRY POINT:  syicpData
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ES:DI   CDIB:cp_id
;               AX      codepage id
;               On Stack:
;               DW      buffer selector
;               DW      buffer size
;               DW      country code
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               AX != 0
;               flag set in [sys_cp_flag]
;
; EFFECTS:
;               Defines Codepage Data Section
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicpCaseMap:NEAR
;               syicpCollate:NEAR
;               syicpDBCS:NEAR
;               syicpFormat:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPDATA
;
;       if (codepage specified) then
;         set codepage string via syicpAscii
;       endif
;       offset codepage data section = CDIB_length
;       obtain first country/codepage header
;       if (offset too large) then
;         call syiAbortR3
;       else
;         repeat
;           if (country matches) then
;             if (codepage matches) then
;               if (any codepage acceptable) then
;                 set CDIB_cp_first_id = codepage
;                 deactivate switching, set CDIB_cp_number_codepages = 0
;                 set codepage string via syicp_Ascii
;               endif
;               if (offset too large) then
;                 call syiAbortR3
;                 return
;               endif
;             endif
;           endif
;         until (entry found or list scanned)
;         if (entry not found) then
;           call syicpWarning
;           return
;         endif
;         for (# entries in country data)
;           if (entry is valid) then
;             case
;               call syicpFormat
;               call syicpCollate
;               call syicpCaseMap
;               call syicpDBCS
;             endcase
;             if (error) then
;               call syiAbortR3
;               return
;             endif
;           endif
;         next entry
;         if (no tables selected) then
;           call syicpWarning
;           return
;         endif
;       endif
;       store codepage data section pointer
;       update CDIB_length
;       return
;
;       End Procedure SYICPDATA

Procedure syicpData,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        ArgVar  data_ctycode,WORD
        ArgVar  data_bufsiz,WORD
        ArgVar  data_src,WORD

        LocalVar data_newlen,WORD
        LocalVar data_cpid_ptr,WORD
        LocalVar data_id_ptr,WORD
        LocalVar data_tblflg,BYTE
        LocalVar data_cpid,WORD

        data_fmt_tbl    equ     00000001b
        data_col_tbl    equ     00000010b
        data_case_tbl   equ     00000100b
        data_dbcs_tbl   equ     00001000b


        EnterProc

        SaveReg <ds,es,di,si,bx,cx,dx>

        mov     data_cpid,ax            ;save codepage id
        mov     data_cpid_ptr,di        ;save the cp id pointer

;       set up ascii codepage if specified

        .if     <nonzero ax>
          DosInitContext ds
          push  es                      ;save
          push  di                      ;  registers
          DosInitContext es             ;segment
          mov     di,offset CP_DEC      ;address of storage
          call    syicpAscii ;fill ASCIIZ field
          pop   di                      ;restore
          pop   es                      ;  registers
        .endif

;       save starting CDIB length

        mov     bx,es:[0].CDIB_length   ;
        mov     data_id_ptr,bx          ;offset of codepage_data_section
        mov     es:[bx].CDIB_cpd_length,size CDIB_codepage_data_section
                                        ;set length of codepage data section
        add     bx,size CDIB_codepage_data_section ;
        mov     [data_newlen],bx        ;store new length

;       obtain codepage/country entry
;       (commented out lines indicate for future use)

        mov     ds,data_src             ;load address of buffer segment
;       mov     cx,ds:[0].cty_cnt       ;obtain count pointers in header
        mov     si,size cty_hdr         ;point at first C/C header
;       dec     cx                      ;adjust count for looping
;         .for  ax = 1 to cx
;           add si,size cty_cc_hdr      ;point at next C/C header
;         .next ax
;         .if   <si gt data_bufsiz>
;           mov si,[bad_file]           ;load error code
;           call syiAbortR3
;           jmp exit_data1              ;quit
;         .endif

        mov     bx,word ptr ds:[si].cty_cc_ptr ;obtain offset
        mov     ax,word ptr ds:[si].cty_cc_ptr+2 ;
        .if     <nonzero ax>            ;bad offset too large
data_file_prob1:
          DosInitContext ds
          mov   si,[bad_file]
          call  syiAbortR3              ;
          jmp exit_data1                ;quit
        .endif
        mov     si,bx                   ;load offset
        xor     di,di                   ;clear index reg
        mov     bx,ds:[si].cty_cc_cnt   ;load cty/cp count
        xor     cx,cx                   ;initialize loop
        add     si,size cty_cc_cnt      ;point at first cty/cp entry
        .repeat                         ;examine each entry
          mov   ax,data_ctycode         ;load country code
          .if   <ax eq ds:[si].cty_cp_cty> ;check for country match
            mov ax,data_cpid            ;load codepage id
;
; @149209 Remove special code to check codepage 1004
;                                       ;### DCR 946
;           .if <ax eq 1004>            ;### Codepage 1004 is not a valid value
;               jmp data_file_prob2     ;### at init time
;           .endif                      ;### DCR 946
            .if <ax eq ds:[si].cty_cp_cp> or ;check for codepage match...
            .if <ax eq 0>               ;     ...or dummy entry

;       set up the actual ascii codepage

              .if     <ax eq 0>
                mov     ax,ds:[si].cty_cp_cp ;load codepage value found
                mov     di,es:[0].CDIB_codepage_ptr ;point to cp section

;       set count to zero to insure no codepage switching

                mov     es:[di].CDIB_cp_number_codepages,0 ;set count = 0
                mov     es:[di].CDIB_cp_first_id,ax ;store cp value
                push  es                ;save
                push  di                ;  registers
                DosInitContext es       ;segment
                mov     di,offset CP_DEC;address of storage
                call    syicpAscii ;fill ASCIIZ field (ax = cp)
                pop     di                      ;restore
                pop     es                      ;  registers
              .endif
              mov     di,word ptr ds:[si].cty_cp_ptr ;obtain offset
              mov     ax,word ptr ds:[si].cty_cp_ptr+2 ;
              .if     <nonzero ax>      ;bad offset
                jmp   data_file_prob1
              .endif
            .endif
          .endif
          inc   cx                      ;increment count
          add   si,size cty_cp_hdr      ;point at next entry
        .until  <nonzero di> or         ;found an entry
        .until  <cx ae bx>              ;scanned entire list

        .if     <zero di>               ;no entry found
data_file_prob2:
          DosInitContext ds
          mov   si,offset cp_err_no_entry
          call  syicpWarning
          jmp exit_data1                 ;quit
        .endif

;       scan for the different tables

        mov     si,di                   ;point to country data header
        mov     cx,ds:[si].cty_dat_cnt  ;load looping count
        add     si,size cty_dat_hdr     ;point at first entry
        .for    dx = 1 to cx near
          mov   al,ds:[si].cty_dat_inf  ;obtain cty info type

;       select the proper entries

          .if   <al eq setcountryinfo> or  ;a
          .if   <al eq setucase> or        ;  valid
          .if   <al eq setcollate> or      ;    table?
          .if   <al eq setdbcs>            ;

;       examine the pointer

            mov di,word ptr ds:[si].cty_dat_ptr ;obtain offset
            mov bx,word ptr ds:[si].cty_dat_ptr+2 ;
            .if <nonzero bx>            ;offset too large
              jmp   data_file_prob1
            .endif

;       load parms

            push si                     ;save country data header
            push cx                     ;save looping count
            mov  si,di                  ;ds:si offset in buffer
            mov  di,data_cpid_ptr       ;es:di = CDIB:cp_id
            push ds                     ;buffer seg
            push ss                     ;address
            lea  bx,[data_newlen]       ;  of
            push bx                     ;    newlen storage
            mov  bx,data_id_ptr         ;offset of codepage_data_section
            mov  cx,data_bufsiz         ;size of buffer segment

;       case select the proper routine

            .if   <al eq setcountryinfo> ;
              call syicpFormat ;
              or  data_tblflg,data_fmt_tbl ;indicate formatting
            .elseif   <al eq setucase>  ;
              call syicpCasemap ;
              or  data_tblflg,data_case_tbl ;indicate casemap
            .elseif   <al eq setcollate> ;
              call syicpCollate ;
              or  data_tblflg,data_col_tbl ;indicate collate
            .else                       ;must be DBCS
              call syicpDBCS ;
              or  data_tblflg,data_dbcs_tbl ;indicate DBCS
            .endif

;       restore

            pop  cx                     ;restore
            pop  cx                     ;  stack
            pop  ds                     ;
            pop  cx                     ;
            pop  si                     ;

;       check for error

            .if  <nonzero ax>           ;error occurred
              jmp   data_file_prob1
            .endif
          .endif
          add   si,size cty_dat_ent     ;point at next entry
        .next   dx

;       insure a table has been included

        .if <data_tblflg eq 0>
          jmp   data_file_prob2
        .endif
        mov     di,data_cpid_ptr        ;store
        mov     ax,data_id_ptr          ;  cp_data_ptr
        mov     es:[di].CDIB_cp_data_ptr,ax ;
        mov     ax,[data_newlen]        ;  new
        mov     es:[0].CDIB_length,ax   ;    CDIB_length
        xor     si,si                   ;no msg, no error

;       errors

exit_data1:
          mov   ax,si                   ;ax nonzero

;       errors have been processed

exit_data:
        RestoreReg <dx,cx,bx,si,di,es,ds>
        LeaveProc
        ret     6

EndProc syicpData


;
; SUBROUTINE NAME:      SYICPFORMAT
;
; DESCRIPTIVE NAME:     LOAD FORMAT TABLE FOR THIS CODEPAGE/COUNTRY
;
; FUNCTION:     PLACE COUNTRY/CODEPAGE FORMAT INFO INTO CDIB SEGMENT
;
; NOTES:
;
; ENTRY POINT:  syicpFormat
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ds:si   sel:offset in buffer segment
;               bx      offset of codepage data section
;               cx      size of buffer segment
;               On Stack:
;               DD      @newlen storage
;               DW      buffer selector
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               AX != 0
;
; EFFECTS:
;               Assign format structure in CDIB Segment
;               set format pointer in cp data section
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPFORMAT
;
;       locate format table
;       check table size versus segment limit
;       if (table exceeds segment/i.e. bad file structure) then
;         indicate error
;       else
;         check format tag
;         if (tag is improper) then
;           indicate error
;         else
;           allocate format table in CDIB segment
;           load format table into CDIB segment
;           set fmt_length
;           set cpd_format_ptr = offset of format table
;         endif
;       endif
;       return
;
;       End Procedure SYICPFORMAT

Procedure syicpFormat,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing
        ArgVar  fmt_newlen,DWORD
        ArgVar  fmt_bufsel,WORD

        EnterProc

        SaveReg <ds,es,di,si,cx>

;       insure that table size does not exceed segment size

        mov     ax,si                   ;
        add     ax,size cty_info_tbl    ;ax = end of cty inf tbl
        .if     <ax a cx>               ;if table exceeds seg limit @149475
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_fmt                ;    & quit
        .endif

;       check for a valid tag

        push    es                      ;save
        push    si                      ;  regs
        DosInitContext ds,ax
        mov     cx,[fmt_len]            ;load count
        mov     es,[fmt_bufsel]         ;load buffer sel
        mov     di,si                   ;di = buffer offset
        mov     si,offset fmt_tag       ;load address of check tag
        repe    cmpsb                   ;compare the strings
        pop     di                      ;di = offset in buffer segment
        pop     es                      ;
        .if     <nz>                    ;if tags do not match
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_fmt                ;    & quit
        .endif

;       obtain the offset of the new format table

        lds     si,fmt_newlen           ;address of newlen
        mov     ax,[si]                 ;newlen value

;       update the newlen variable

        add     word ptr [si],size CDIB_format_section ;update newlen

;       store the offset of the new table

        mov     es:[bx].CDIB_cpd_format_ptr,ax ;offset of cty info section

;       load in the table

        mov     si,di                   ;si = offset in buffer segment
        mov     di,ax                   ;load offset of new cty info table
        mov     ds,fmt_bufsel           ;ds:si = address of buffer cty info
        mov     es:[di].CDIB_fmt_length,size CDIB_format_section ; store len
        add     di,offset CDIB_fmt_date_format ;point at proper offsets
        add     si,offset cty_info_date_fmt ; for block transfer of table
        mov     cx,size CDIB_format_section-2 ;load count
        rep     movsb                   ;transfer the country info
        xor     ax,ax                   ;set good return

exit_fmt:
        RestoreReg <cx,si,di,es,ds>
        LeaveProc
        ret

EndProc syicpFormat


;
; SUBROUTINE NAME:      SYICPCOLLATE
;
; DESCRIPTIVE NAME:     LOAD COLLATE TABLE FOR THIS CODEPAGE/COUNTRY
;
; FUNCTION:     PLACE COUNTRY/CODEPAGE COLLATE INFO INTO CDIB SEGMENT
;
; NOTES:
;
; ENTRY POINT:  syicpCollate
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ds:si   sel:offset in buffer segment
;               bx      offset of codepage data section
;               cx      size of buffer segment
;               On Stack:
;               DD      @newlen storage
;               DW      buffer selector
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               AX != 0
;
; EFFECTS:
;               Assign collate structure in CDIB Segment
;               set collate pointer in cp data section
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPCOLLATE
;
;       locate collate table
;       check table size versus segment limit
;       if (table exceeds segment/i.e. bad file structure) then
;         indicate error
;       else
;         check collate tag
;         if (tag is improper) then
;           indicate error
;         else
;           allocate collate table in CDIB segment
;           load collate table into CDIB segment
;           set collate length
;           set cpd_collate_ptr = offset of collate table
;         endif
;       endif
;       return
;
;       End Procedure SYICPCOLLATE

Procedure syicpCollate,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        ArgVar  col_newlen,DWORD
        ArgVar  col_bufsel,WORD

        EnterProc

        SaveReg <ds,es,di,si,cx>

;       insure that table size does not exceed segment size

        mov     ax,si                   ;
        add     ax,size cty_col_tbl     ;ax = ending offset of collate tbl
        .if     <ax a cx>               ;if table exceeds seg limit @149475
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_col                ;    & quit
        .endif

;       check for a valid tag

        push    es                      ;save
        push    si                      ;  regs
        DosInitContext ds,ax
        mov     cx,[col_len]            ;load count
        mov     es,[col_bufsel]         ;load bufsel
        mov     di,si                   ;di = buffer offset
        mov     si,offset col_tag       ;load address of check tag
        repe    cmpsb                   ;compare the strings
        pop     di                      ;di = offset in buffer segment
        pop     es                      ;
        .if     <nz>                    ;if tags do not match
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_col                ;    & quit
        .endif

;       obtain the offset of the new format table

        lds     si,col_newlen           ;address of newlen
        mov     ax,ds:[si]              ;newlen value

;       update the newlen variable

        add     word ptr [si],size CDIB_collate_section ;update newlen

;       store the offset of the new table

        mov     es:[bx].CDIB_cpd_collate_ptr,ax ;offset of collate section

;       load in the table

        mov     si,di                   ;si = offset in buffer segment
        mov     di,ax                   ;load offset of new collate table
        mov     ds,col_bufsel           ;ds:si = address of buffer cty info
        mov     es:[di].CDIB_col_length,size CDIB_collate_section ;load length
        add     si,offset cty_col_lst   ; for block transfer of table
        add     di,offset CDIB_col_weight ;destination for table
        mov     cx,size cty_col_lst     ;load count
        rep     movsb                   ;transfer the collate info
        xor     ax,ax                   ;set good return

exit_col:
        RestoreReg <cx,si,di,es,ds>
        LeaveProc
        ret

EndProc syicpCollate


;
; SUBROUTINE NAME:      SYICPCASEMAP
;
; DESCRIPTIVE NAME:     LOAD CASEMAP TABLE FOR THIS CODEPAGE/COUNTRY
;
; FUNCTION:     PLACE COUNTRY/CODEPAGE CASEMAP INFO INTO CDIB SEGMENT
;
; NOTES:
;
; ENTRY POINT:  syicpCasemap
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ds:si   sel:offset in buffer segment
;               bx      offset of codepage data section
;               cx      size of buffer segment
;               On Stack:
;               DD      @newlen storage
;               DW      buffer selector
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               AX != 0
;               Error Status Flag Set
;
; EFFECTS:
;               Assign casemap structure in CDIB Segment
;               Set Casemap pointer in cp data section
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPCASEMAP
;
;       locate casemap table
;       check table size versus segment limit
;       if (table exceeds segment/i.e. bad file structure) then
;         indicate error
;       else
;         check casemap tag
;         if (tag is improper) then
;           indicate error
;         else
;           allocate casemap table in CDIB segment
;           load casemap table into CDIB segment
;           set casemap length
;           set cpd_casemap_ptr = offset of casemap table
;         endif
;       endif
;       return
;
;       End Procedure SYICPCASEMAP

Procedure syicpCasemap,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        ArgVar  cas_newlen,DWORD
        ArgVar  cas_bufsel,WORD

        EnterProc

        SaveReg <ds,es,di,si,cx>

;       insure that table size does not exceed segment size

        mov     ax,si                   ;
        add     ax,size cty_ucase_tbl   ;ax = ending off. of casemap tbl
        .if     <ax a cx>               ;if table exceeds seg limit @149475
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_cas                ;    & quit
        .endif

;       check for a valid tag

        push    es                      ;save
        push    si                      ;  regs
        DosInitContext ds,ax
        mov     cx,[cas_len]            ;load count
        mov     es,[fmt_bufsel]         ;load buffer sel
        mov     di,si                   ;di = buffer offset
        mov     si,offset cas_tag       ;load address of check tag
        repe    cmpsb                   ;compare the strings
        pop     di                      ;di = offset in buffer segment
        pop     es                      ;
        .if     <nz>                    ;if tags do not match
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_cas                ;    & quit
        .endif

;       obtain the offset of the new casemap table

        lds     si,cas_newlen           ;address of newlen
        mov     ax,[si]                 ;newlen value

;       update the newlen variable

        add     word ptr [si],size CDIB_casemap_section ;update newlen

;       store the offset of the new table

        mov     es:[bx].CDIB_cpd_casemap_ptr,ax ;offset of casemap section

;       load in the table

        mov     si,di                   ;si = offset in buffer segment
        mov     di,ax                   ;load offset of new casemap table
        mov     ds,cas_bufsel           ;ds:si = address of buffer casemap tbl
        mov     es:[di].CDIB_cm_length,size CDIB_casemap_section ;load length
        add     di,offset CDIB_cm_data  ;destination offset
        add     si,offset cty_ucase_char; for block transfer of table
        mov     cx,size cty_ucase_char  ;load count
        rep     movsb                   ;transfer the casemap info
        xor     ax,ax                   ;set good return

exit_cas:
        RestoreReg <cx,si,di,es,ds>
        LeaveProc
        ret

EndProc syicpCasemap


;
; SUBROUTINE NAME:      SYICPDBCS
;
; DESCRIPTIVE NAME:     LOAD DBCS TABLE FOR THIS CODEPAGE/COUNTRY
;
; FUNCTION:     PLACE COUNTRY/CODEPAGE DBCS INFO INTO CDIB SEGMENT
;
; NOTES:
;
; ENTRY POINT:  syicpDBCS
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ds:si   sel:offset in buffer segment
;               bx      offset of codepage data section
;               cx      size of buffer segment
;               On Stack:
;               DD      @newlen storage
;               DW      buffer sel
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               AX != 0
;
; EFFECTS:
;               Assign DBCS structure in CDIB Segment
;               set DBCS pointer in cp data section
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPDBCS
;
;       locate DBCS table
;       check table size versus segment limit
;       if (table exceeds segment/i.e. bad file structure) then
;         indicate error
;       else
;         check DBCS tag
;         if (tag is improper) then
;           indicate error
;         else
;           allocate DBCS table in CDIB segment
;           load DBCS table into CDIB segment
;           set DBCS length
;           set cpd_DBCS_ptr = offset of DBCS table
;         endif
;       endif
;       return
;
;       End Procedure SYICPDBCS

Procedure syicpDBCS,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        ArgVar  dbcs_newlen,DWORD
        ArgVar  dbcs_bufsel,WORD

        LocalVar dbcs_size,WORD

        EnterProc

        SaveReg <ds,es,di,si,cx>

;       insure that table size does not exceed segment size

        mov     ax,si                   ;
        add     ax,size cty_dbcs_hdr    ;ax = ending offset
        add     ax,ds:[si].cty_dbcs_len ;  of DBCS table
        .if     <ax a cx>               ;if table exceeds seg limit @149475
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_dbcs               ;    & quit
        .endif
        mov     ax,ds:[si].cty_dbcs_len ;save length of vector section
        mov     dbcs_size,ax            ;

;       check for a valid tag

        push    es                      ;save
        push    si                      ;  regs
        DosInitContext ds,ax
        mov     cx,[dbcs_len]           ;load count
        mov     es,[dbcs_bufsel]        ;
        mov     di,si                   ;di = buffer offset
        mov     si,offset dbcs_tag      ;load address of check tag
        repe    cmpsb                   ;compare the strings
        pop     di                      ;di = offset in buffer segment
        pop     es                      ;
        .if     <nz>                    ;if tags do not match
          mov   ax,MSG_SYSINIT_SCFILE_INVAL; load error code
          jmp   exit_dbcs               ;    & quit
        .endif

;       obtain the offset of the new dbcs table

        lds     si,dbcs_newlen          ;address of newlen
        mov     ax,[si]                 ;newlen value

;       update the newlen variable

        mov     cx,dbcs_size            ;size of vector section +
        add     cx,size cty_dbcs_len    ;  length storage = size of CDIB_DBCS
        add     word ptr [si],cx        ;update newlen variable

;       store the offset of the new table

        mov     es:[bx].CDIB_cpd_DBCS_ptr,ax ;offset of DBCS section

;       load in the table

        mov     si,di                   ;si = offset in buffer segment
        mov     di,ax                   ;load offset of new DBCS table
        mov     ds,dbcs_bufsel          ;ds:si = address of buffer casemap tbl
        mov     es:[di].CDIB_DBCS_length,cx ;store DBCS section size
        add     di,size CDIB_DBCS_section ;destination offset for vectors
        mov     cx,ds:[si].cty_dbcs_len ;load transfer count
        add     si,size cty_dbcs_hdr    ;source offset of vectors
        rep     movsb                   ;transfer the dbcs info
        xor     ax,ax                   ;set good return

exit_dbcs:
        RestoreReg <cx,si,di,es,ds>
        LeaveProc
        ret

EndProc syicpDBCS


;
; SUBROUTINE NAME:      SYICPDEVINFO
;
; DESCRIPTIVE NAME:     LOAD DEVICE INFORMATION
;
; FUNCTION:     PLACE DEVICE INFORMATION INTO CDIB SEGMENT
;
; NOTES:
;
; ENTRY POINT:  syicpDevInfo
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               ES:DI   Devinfo tail packet
;
; EXIT-NORMAL:
;               AX = 0
;
; EXIT-ERROR:
;               None
;
; EFFECTS:
;               Allocate device section structures in CDIB segment
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syiSaveData:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;               DosClose:FAR
;               DosOpen:FAR
;               syiSaveMessageR3:NEAR
;               StrTransPathCharR3:NEAR
;
;
;       Procedure SYICPDEVINFO
;
;       repeat
;         Call syiSaveData to save the line number, command name,
;             and file specification from the DEVINFO command
;         verify proper file via DosOpen
;         if (no error) then
;           close file via DosClose
;         else
;           load error message via syiSaveMessageR3
;           break to end of loop
;         endif
;         examine device pointer
;         if (device pointer = zero) then
;           store device subtype field
;           if (packet is a KBD type)
;             save the address of the KBD devinfo packet
;             save the KBD layout code
;           endif
;           dev_number_ROM_fonts = number of ROM fonts
;           allocate font storage of 4 * font count
;           set dev_filename_ptr = offset at end of font table
;           load fonts
;           set dev_filename = ASCIIZ \path\file string, word rounded
;           set dev_length field
;           set device pointer to offset of device section
;           update CDIB_length
;         endif
;       until (all devinfos processed)
;       endif
;       return
;
;       End Procedure SYICPDEVINFO

Procedure syicpDevInfo,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        LocalVar dev_newptr,WORD
        LocalVar dev_fhnd,WORD
        LocalVar dev_fact,WORD

        EnterProc

        SaveReg <ds,es,di,si,bx,cx>

;       initialize starting addresses to:
;       di = offset 0 (of CDIB)
;       si = offset of final devinfo packet (in Config_Sys_Data)

        mov     si,di                   ;load offset of last packet
        xor     di,di                   ;offset zero

;       repeat for each statement, start with last packet

        .repeat

          DosInitContext ds             ;adjust segregs for devinfo
          mov   es,Config_Sys_Data      ;  filespec checking logic

;         Save the line number, command name, and file specification
;         from the DEVINFO command packet

          SaveReg <ds>
          push  es
          pop   ds

          SaveReg <si>
          mov   si,es:[si].CFG_FileSpec ; ds:si -> filespec
          call  StrTransPathCharR3      ; make sure filespec has only \ as
          RestoreReg <si>               ; path separator char

          call  syiSaveData
          RestoreReg <ds>

;       open device file

          push  es                      ;filename pointer
          mov   bx,es:[si].CFG_FileSpec ;
          push  bx                      ;
          push  ss                      ;handle storage pointer
          lea   ax,[dev_fhnd]           ;
          push  ax                      ;
          push  ss                      ;action taken storage pointer
          lea   ax,[dev_fact]           ;
          push  ax                      ;
          push  0                       ;size (dword)
          push  0                       ;
          push  0                       ;file attribute
          push  1                       ;openflag
          push  open_for_read+sharing_deny_write+open_no_inherit+open_autofail
                                        ;openmode
          push  0                       ;reserved (dword)
          push  0                       ;
          call  [pDosOpen]              ;entry point for DosOpen call

;       if ok, close and continue

          .if     <ax eq 0>
            push        [dev_fhnd]      ;file handle
            call        [pDosClose]     ;

;       if not ok, load message and break

          .else
            push        si              ;save register
            mov         si,offset cp_err_bad_devinfo;offset of msg structure
            call        syiSaveMessageR3           ;load message
            pop         si              ;restore register
            mov         es,[cdibseg]       ;adjust segregs
            mov         ds,Config_Sys_Data ;  for break
            jmp         dev_end_loop    ;break to end of loop
          .endif

;       adjust segregs ; es = CDIB , ds = Config_Sys_Data

          mov   es,[cdibseg]            ;adjust segregs
          mov   ds,Config_Sys_Data      ;  for break

;       examine device type

          mov   bx,ds:[si].CFG_DevType  ;load for efficient checking
          add   bx,bx                   ;shift to word index
          .if   <es:[bx].CDIB_screen_ptr-2 ne 0>
            jmp dev_end_loop
          .endif
          add   bx,offset CDIB_screen_ptr-2 ;store address
          mov   [dev_newptr],bx         ;       of ptr storage

;       store subtype field

          mov   cx,size CDIB_dev_subtype ;load count
          mov   bx,es:[0].CDIB_length  ;load destination offset
          lea   di,es:[bx].CDIB_dev_subtype ;load source offset
          push  si                      ;save CFG packet pointer
          add   si,offset CFG_SubType   ;load source offset
          rep   movsb                   ;move string
          pop   si                      ;restore pointer

;       Save the address of the KBD devinfo packet and save the
;       keyboard layout code

          .if   <ds:[si].CFG_DevType eq CFG_DevType_KBD>
            SaveReg <es,si>
            DosInitContext es
            mov es:kbd_devinfo,si
            mov cx,size CDIB_dev_subtype ;load count
            mov di,offset KBD_LAYOUT    ;load destination offset
            add si,offset CFG_SubType   ;load source offset
            rep movsb                   ;move string
            std                         ;set for auto-decrement
            dec di                      ;point at last byte
            mov al,' '                  ;load scan value
            mov cx,size CDIB_dev_subtype ;load count
            repe scasb                  ;scan for last non-blank
            mov byte ptr es:[di+2],0    ;asciiz the string
            cld                         ;reset for auto-increment
            RestoreReg <si,es>
        assume es:nothing
          .endif

;       obtain  number of rom fonts

          mov   ax,ds:[si].CFG_nIDpairs ;ax = # ROM_fonts
          mov   es:[bx].CDIB_dev_number_ROM_fonts,ax ;store count

;       obtain CDIB_dev_filename_ptr (assumes # rom fonts < 255)

          DosInitContext ds             ;reference initdata
          mul   cfg_id_size             ;obtain size of ROM_fonts storage
          mov   di,bx                   ;start
          add   di,size CDIB_device_section ;  of ROM_fonts
          push  di                      ;save offset
          add   di,ax                   ;di = offset of filename storage
          mov   es:[bx].CDIB_dev_filename_ptr,di ;store it
          pop   di                      ;restore offset
          mov   ds,Config_Sys_Data      ;restore ds to config parms

;       load in font table
;       (es,ds,di,cld already set)

          mov   cx,ax                   ;move count
          push  si                      ;save packet offset
          add   si,offset CFG_IDpairs   ;load source offset
          rep   movsb                   ;load font table
          pop   si                      ;retore packet offset

;       load in filespec

          mov   di,es:[bx].CDIB_dev_filename_ptr ;destination offset
          push  si                      ;save pointer
          mov   si,ds:[si].CFG_FileSpec ;source offset
          xor   cx,cx                   ;set counter
          .repeat                       ;
            lodsb                       ;move byte es:[di] to
            stosb                       ;  ds:[si] via al
            inc cx                      ;update count
          .until        <zero al>
          .if   <bit cx and 1>          ;if count is odd
            stosb                       ;add another 0
          .endif
          pop   si                      ;restore pointer

;       update for new device

        push    di                      ;save size
        sub     di,bx                   ;store
        mov     es:[bx].CDIB_dev_length,di ;  device section size
        pop     di                      ;restore size
        mov     es:[0].CDIB_length,di   ;segment size
        mov     di,dev_newptr           ;store new
        mov     es:[di],bx              ;  device pointer

dev_end_loop:

;       point at next packet

        mov     si,ds:[si].CFG_Prev     ;moving toward head

;       until all packets processed...

        .until  <zero si> near

        xor     ax,ax                   ;set good return

exit_dev:
        RestoreReg <cx,bx,si,di,es,ds>
        LeaveProc
        ret

EndProc syicpDevInfo


;
; SUBROUTINE NAME:      SYICPFATAL
;
; DESCRIPTIVE NAME:     HANDLE ALL FATAL CONDITIONS
;
; FUNCTION:     RECOVER FROM ALL FATAL CONDITIONS
;
; NOTES:
;
; ENTRY POINT:  syicpFatal
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               SI      offset of error message table
;
; EXIT-NORMAL:
;               No value
;
; EFFECTS:
;               sets fatal flag
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicpError:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPFATAL
;
;       set fatal flag
;       handle error via syicpError
;       return
;
;       End Procedure SYICPFATAL


Procedure syicpFatal,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        EnterProc

        SaveReg <ds,si>

;       set up ds reference

        DosInitContext ds

;       set fatal flag

        or      [sys_cp_flag],SYS_CP_FATAL ;fatal flag value set

;       handle error

        call    syicpError      ;

        RestoreReg <si,ds>
        LeaveProc
        ret

EndProc syicpFatal


;
; SUBROUTINE NAME:      SYICPWARNING
;
; DESCRIPTIVE NAME:     HANDLE ALL WARNING CONDITIONS
;
; FUNCTION:     RECOVER FROM ALL WARNING CONDITIONS
;
; NOTES:
;
; ENTRY POINT:  syicpWarning
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               SI      offset of error message table
;
; EXIT-NORMAL:
;               No value
;
; EFFECTS:
;               sets warning flag
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicpError:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPWARNING
;
;       set warning flag
;       handle error via syicpError
;       return
;
;       End Procedure SYICPWARNING


Procedure syicpWarning,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        EnterProc

        SaveReg <ds,si>

;       set up ds reference

        DosInitContext ds

;       set warning flag

        or      [sys_cp_flag],SYS_CP_WARN ;warning flag value set

;       handle error

        call    syicpError      ;

        RestoreReg <si,ds>
        LeaveProc
        ret

EndProc syicpWarning


;
; SUBROUTINE NAME:      SYICPERROR
;
; DESCRIPTIVE NAME:     HANDLE ALL ERROR CONDITIONS
;
; FUNCTION:     RECOVER FROM ALL ERROR CONDITIONS
;
; NOTES:
;
; ENTRY POINT:  syicpError
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               SI      offset of error message table
;
; EXIT-NORMAL:
;               No value
;
; EFFECTS:
;               Prints appropriate message(s)
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;               DosFreeSeg:FAR
;               DosGetMessage:FAR
;               DosPutMessage:FAR
;
;
;       Procedure SYICPERROR
;
;       call to load message value - TBD
;       if (error was fatal) then
;         if (CDIB segment present flag) then
;           free the CDIB via DosFreeSeg
;         endif
;         call to load fatal message value - TBD
;       endif
;       return
;
;       End Procedure SYICPERROR


Procedure syicpError,near,local
    assume ds:DOSINITDATA, es:nothing, fs:nothing, gs:nothing, ss:nothing

        EnterProc

;       store the error message

        call    syiSaveMessageR3

;       fatal error logic

        .if     <bit [sys_cp_flag] and SYS_CP_FATAL>

;       free the CDIB segment

          .if   <bit [sys_cp_flag] and SYS_CP_SEG>
            push        [cdibseg]       ;buffer selector
            call        [pDosFreeSeg]   ;entry point for DosFreeSeg
          .endif
        .endif

        LeaveProc
        ret

EndProc syicpError


;
; SUBROUTINE NAME:      SYICPASCII
;
; DESCRIPTIVE NAME:     ASCII DECIMAL ROUTINE
;
; FUNCTION:     FILL ASCIIZ DECIMAL FIELDS
;
; NOTES:        (COURTESY OF E. RASMUSSEN)
;
; ENTRY POINT:  syicpAscii
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               AX      Numeric value (less than 64k)
;               ES:DI   Address of asciiz field
;
; EXIT-NORMAL:
;               No value
;
; EFFECTS:
;               Fills ASCIIZ decimal buffer
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicpInt2Ascii
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;
;       Procedure SYICPASCII
;
;       call syicpInt2Ascii
;       load binary zero after ascii string to make asciiz
;       return
;       End Procedure SYICPASCII
;
;
;       Procedure SYICPINT2ASCII
;
;       save remainder
;       divide ax by 10
;       if (ax ne 0)
;         call syicpInt2Ascii
;       endif
;       convert remainder to ascii
;       store character
;       restore remainder
;       return
;       End Procedure SYICPINT2ASCII
;

Procedure syicpAscii,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        EnterProc

        push    es                      ;save
        push    di                      ;  affected
        push    ax                      ;    registers
        call    syicpInt2Ascii ;perform conversion
        mov     byte ptr es:[di],0      ;asciiz the string
        pop     ax                      ;restore
        pop     di                      ;  affected
        pop     es                      ;    registers
        LeaveProc                       ;
        ret                             ;

EndProc syicpAscii


Procedure syicpInt2Ascii,near,local
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        push    dx                      ;
        xor     dx,dx                   ;clear for division
        push    cx                      ;
        mov     cx,10                   ;load divisor
        div     cx                      ;(dx:ax)/10 = ax rem dx
        pop     cx                      ;
        .if     <nonzero ax>            ;if quotient > 0
          call  syicpInt2Ascii ;perform recursively
        .endif                          ;
        add     dl,'0'                  ;convert digit to ascii
        mov     al,dl                   ;store digit
        stosb                           ;  in buffer
        pop     dx                      ;
        ret                             ;

EndProc syicpInt2Ascii


;
; SUBROUTINE NAME: syiSaveData
;
; DESCRIPTIVE NAME: Copy CONFIG.SYS common data
;
; FUNCTION:      To copy the ASCIIZ string which contains the
;                line number, the ASCIIZ string which contains the
;                command, and the ASCIIZ string which contains
;                the file specification from the CONFIG.SYS data
;                packet
;
; NOTES:         This is an internal subroutine within syicpInit
;
; ENTRY POINT: syiSaveData
;    LINKAGE:    Call (near)
;
; INPUT:         DS:SI = Address of CONFIG.SYS data packet
;
; EXIT-NORMAL: line_number contains the line number string
;                command contains the command name
;                file_spec contains the file specification (if any)
;
; EXIT-ERROR:    None
;
; EFFECTS:       All registers are preserved
;
; INTERNAL REFERENCES:
;    ROUTINES: None
;
; EXTERNAL REFERENCES:
;    ROUTINES: None
;
;
; Procedure syiSaveData(CONFIG.SYS data packet)
;
; copy the line number from the data packet
; copy the command from the data packet
; copy the file specification from the data packet
;
; Return
;
; End syiSaveData

Procedure syiSaveData,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es>
        pusha

;       Copy the line number from the data packet

        SaveReg <si>
        add     si,offset CFG_LineNumber  ; DS:SI = address of line
                                          ;         number string in
                                          ;         CONFIG.SYS data
                                          ;         packet

        DosInitContext <es>
        mov     di,offset line_number      ; ES:DI = address of line_number

        .repeat                       ; copy the string (until the
          lodsb                       ;   terminating null is found)
          stosb
        .until  <al eq 0>
        RestoreReg <si>

;       Copy the command from the data packet

        SaveReg <ds,si>
        lds     si,ds:[si].CFG_Command; DS:SI = address of command name

        mov     di,offset command      ; ES:DI = address of command

        .repeat                       ; copy the string (until the
          lodsb                       ;   terminating null is found)
          stosb
        .until  <al eq 0>
        RestoreReg <si,ds>

;       Copy the file specification from the data packet

        mov     si,ds:[si].CFG_FileSpec ; DS:SI = address of file
                                      ;         specification string
                                      ;         in CONFIG.SYS data
                                      ;         packet

        .if     <zero si>
          mov   [file_spec],0         ; no file specification
        .else                         ; copy the file specification
          mov   di,offset file_spec   ; ES:DI = address of file_specification
          .repeat                     ; copy the string (until the
            lodsb                     ;   terminating null is found)
            stosb
          .until <al eq 0>
        .endif

;       Return to caller

        popa
        RestoreReg <es,ds>
    assume ds:nothing,es:nothing
        ret

EndProc syiSaveData


;
; SUBROUTINE NAME:      SYICPACTIVATE
;
; DESCRIPTIVE NAME:     ACTIVATE PRIMARY CODEPAGE
;
; FUNCTION:     ACTIVATE THE PRIMARY CODEPAGE
;
; NOTES:
;
; ENTRY POINT:  syicpActivate
;    LINKAGE:           NEAR AT PL 3
;
; INPUT:
;               No Input
;
; EXIT-NORMAL:
;               No Output
;
; EXIT-ERROR:
;               No Output
;
; EFFECTS:
;               Activates proper codepages & fonts
;
; INTERNAL REFERENCES:
;    ROUTINES:
;               syicpAscii:NEAR
;               syicpWarning:NEAR
;               syiSaveData:NEAR
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;               DosSetCp:FAR
;               KbdSetCp:FAR
;               VioSetCp:FAR
;
;
;       Procedure SYICPACTIVATE
;
;       if (CODEPAGE was specified)
;         activate primary code page via DosSetCp
;         load appropriate display font(s) via VioSetCp
;         if (VioSetCp returns in error) then
;           call syicpWarning
;         endif
;
;         Call syiSaveData to retrieve the information
;             about the KBD devinfo statement (if any)
;         load appropriate keyboard code page(s) via KbdSetCp
;         if (KbdSetCp returns in error) then
;           call syicpWarning
;         endif
;       endif
;       return
;
;       End Procedure SYICPACTIVATE

Procedure syicpActivate,near
    assume ds:nothing, es:nothing, fs:nothing, gs:nothing, ss:nothing

        SaveReg <ds,es,di,si,bx,cx,dx>        ;save register state

;       check if codepage specified

        DosContext ds
        .if     <CDIB_selector eq 0>    ; make sure there is a CDIB
          jmp   exit_act_cp
        .endif
        mov     es,CDIB_selector        ; point to the CDIB
        mov     di,es:[0].CDIB_codepage_ptr
        .if     <es:[di].CDIB_cp_number_codepages eq 0> ;codepage not specified
          jmp   exit_act_cp             ;  & quit
        .endif

;       obtain primary codepage

        DosInitContext ds
        mov     ax,es:[di].CDIB_cp_first_id.CDIB_cp_id ;first cp id
        mov     dx,ax                   ;save since ax is destroyed in ascii

;       convert to asciiz for error messages

        push    es                      ;save
        push    di                      ;  registers
        DosInitContext es               ;address of storage
        mov     di,offset CP_DEC        ;initialize count
        call    syicpAscii              ;load asciiz field
        pop     di                      ;restore
        pop     es                      ;registers

;       activate primary codepage

        push    dx                      ;primary codepage
        push    0                       ;reserved parm
        call    [pDosSetCp]             ;entry point for DosSetCp

;       load appropriate display fonts via VioSetCp

        push    0                       ;reserved parm
        push    dx                      ;primary codepage
        push    0                       ;reserved parm
        call    [pVioSetCp]             ;entry point for VioSetCp
        .if <ax ne 0> and
        .if <ax ne ERROR_VIO_NO_CP>
          mov   si,offset cp_err_vio_cp ;error msg
          call  syicpWarning ;process error
        .endif

;       Retrieve the information from the original KBD
;       devinfo statement (if any)

        SaveReg <ds>
        mov     si,kbd_devinfo
        mov     ds,Config_Sys_Data
        .if     <nonzero si>
          call  syiSaveData
        .endif
        RestoreReg <ds>

;       load appropriate keyboard translation tables via KbdSetCp

        push    0                       ;reserved parm
        push    dx                      ;primary codepage
        push    0                       ;reserved parm
        call    [pKbdSetCp]             ;entry point for KbdSetCp
        .if <ax ne 0>
          .if <ax eq ERROR_KBD_CODEPAGE_LOAD_INCOMPL> and
          .if <nonzero si>            ; select appropriate
            mov si,offset cp_err_bad_layout  ; error message
          .else

; insure that both codepages are printed (if present)

            .if         <es:[di].CDIB_cp_number_codepages eq 2> ;multiple codepages
              push      es                      ;save
              push      di                      ;  affected
              push      ax                      ;    registers
              push      bx                      ;
              push      cx                      ;

;       point to second codepage in CDIB

              add       di,offset CDIB_cp_first_id + size CDIB_cp_id_section
              mov       bx,es:[di].CDIB_cp_id   ;obtain 2nd cp id
              DosInitContext es                 ;es for scan and ascii call
              mov       di,offset CP_DEC        ;point to beginning of field
              mov       cx,cpsize               ;size of field
              mov       al,0                    ;scan for
              repne     scasb                   ;  binary zero
              mov       byte ptr es:[di-1],','  ;seperate cp ids with comma
              mov       ax,bx                   ;ax = cp id value
              call      syicpAscii      ;load asciiz field
              pop       cx                      ;restore
              pop       bx                      ;  affected
              pop       ax                      ;    registers
              pop       di                      ;
              pop       es                      ;
            .endif
            mov si,offset cp_err_kbd_cp
          .endif
          call  syicpWarning            ;process error
        .endif

exit_act_cp:
        RestoreReg <dx,cx,bx,si,di,es,ds>     ;restore register state
        ret

EndProc syicpActivate

INITR3CODE ends
        end
