;       SCCSID = @(#)codepg.asm 6.3 92/02/18                                                          00001  INSERT(NEW)  00001
        PAGE    ,132  ;\017 (CTRL-OH)   IBM PC PRINTER CONDENSED MODE

;;************************* START OF SPECIFICATIONS ******************/
;;                                                                   */
;;     SOURCE FILE NAME:  CODEPG                                     */
;;                                                                   */
;;     DESCRIPTIVE NAME:  Kernel Code Page Support Program           */
;;                        It contains two worker                     */
;;                        routines for DosSetCp, DosGetCp only       */
;;                                                                   */
;;     COPYRIGHT:  N/A                                               */
;;                                                                   */
;;     STATUS:  N/A                                                  */
;;                                                                   */
;;     FUNCTION: This program contains the worker routines that are  */
;;               called by DosSetCp  and DosGetCp.                   */
;;               Dynamic Link entry points for this programs's       */
;;               worker routines are defined in api2.asm.            */
;;                                                                   */
;;     NOTES:  1. This is a kernel routine runs at PL 0              */
;;             3. DosSetCp, DosGetCp is defined in api2.asm          */
;;                as Dynamic Link entry point (via SysEntry,         */
;;                EndEntry etc.).                                    */
;;            INCLUDE files used :                                   */
;;               . dossymb.inc                                       */
;;               . dosseg.inc                                        */
;;               . error.inc                                         */
;;               . struc.inc                                         */
;;                                                                   */
;;            @@ This modeule contains all new code for Release 1.1  */
;;                                                                   */
;;        DEPENDENCIES: Dynamic Link Handler - SysEntry, EndEntry    */
;;                                             macros and THOPs      */
;;        RESTRICTIONS: Runs in protect mode only                    */
;;                                                                   */
;;     ENTRY POINTS: w_SetCp, w_GetCp                                */
;;                                                                   */
;;                                                                   */
;;     EXTERNAL REFERENCES:                                          */
;;                          HYBRID, DosContext, Farcall              */
;;                          SuWord                                   */
;;                                                                   */
;;     MODIFICATION HISTORY:                                         */
;;                                                                   */
;;     CWY:  Added test in check_val_cp to see if CDIB segment       */
;;           is zero.  If so return invalid code page.               */
;;                                                                   */
;;     KCD:  Changed check_val_cp to return pointer to codepage      */
;;           found.  If CP is zero return first codepage in CDIB.    */
;;           Changed w_SetCP to setup CP_CaseMapTbl.  Codepage       */
;;           of zero is remapped to first codepage in CDIB.          */
;;                                                                   */
;;     CWY:  Changed get_val_cp to NOT return the default            */
;;           codepage if there is no CODEPAGE statement in           */
;;           CONFIG.SYS file                                         */
;;                                                                   */
;;     KCD:  Added code to set or reset CP_Flgs variable for         */
;;           DBCS support.                                           */
;;                                                                   */
;;     CWY:  Clear AX when normal exit for DOSSETCP and DOSGETCP     */
;;                                                                   */
;;     CWY:  PTM 2265                                                */
;;           If CP is zero then treated it as invalid CP.            */
;;           The changes is in Check_val_cp                          */
;;                                                                   */
;;     CWY: PTM  3283                                                */
;;          If there is no CODEPAGE statement in CONFIG.SYS, dont    */
;;          look for the default codepage in DOSSETCP, just return   */
;;          an error.                                                */
;;                                                                   */
;;     CWY: 5/7/87                                                   */
;;          Checking the reserved word in DOSSETCP is zero?  If      */
;;          it is not zero then return the error and terminate.      */
;;                                                                   */
;;************************** END OF SPECIFICATIONS *******************/
        .XLIST
include dosseg.inc
include basemaca.inc
include osmaca.inc
include mi.inc
include defdbug.inc
include dossymc.inc
include error.inc
include error2.inc
include struc.inc
include cdib.inc
        .LIST

ReferTask   codepage_tag,WORD        ;;   get to PTDA data segment
ReferTask   CP_CaseMapTbl,DWORD      ;;@@ case map table for current code page
ReferTask   CP_Flgs,BYTE             ;;@@ flags for current code page
ReferGlobal CDIB_selector,WORD       ;;   selector to CDIB
ReferGlobal DBCS_Codepg,WORD         ;;@@ code page with DBCS activity

EXTRNFAR SuWord                      ;; routine to copy word to user defined
                                     ;; area and check protection fault


;;  This is temporary defined error messages
;;*******************************************************
DATA    segment


DATA    ends
;;*******************************************************

            FARCODE     HIGH3
HIGH3CODE    SEGMENT
        ASSUME ds:nothing, es:nothing, ss:TASKAREA

;;*******************************************************/
;;                                                      */
;; SUBROUTINE NAME: DosSetCp                            */
;;                                                      */
;; DESCRIPTIVE NAME:    Dos Set Code Page               */
;;                                                      */
;; FUNCTION:   Setup dynamic call to DosSetCp worker    */
;;             routine which does the following:        */
;;             This routine will call w_SetCp           */
;;             to set the current code page             */
;;                                                      */
;; NOTES:                                               */
;;                                                      */
;; ENTRY POINT:         DosSetCp                        */
;;   LINKAGE:           CALL                            */
;;                                                      */
;; INPUT:     PUSH  WORD  CODEPAGE ;code page id        */
;;            PUSH  WORD  RESERVED ;reserved, set to 0  */
;;                                                      */
;; EXIT-NORMAL:    ax =0                                */
;;                 code page is set                     */
;;                                                      */
;; EXIT_ERROR:                                          */
;;               ax = Error_invalid_code_page           */
;;                                                      */
;;               The valid code pages are the code      */
;;               pages which were specified in the      */
;;               CODEPAGE statement in the CONFIG.SYS   */
;;               and the ROM code page identifier       */
;;               which is 0.                            */
;;                                                      */
;; EFFECTS:      contents of ax are destroyed           */
;;               all other registers are saved          */
;;                                                      */
;; INTERNAL REFERENCES:                                 */
;;     ROUTINES:                                        */
;;                                                      */
;; EXTERNAL REFERENCES:   w_SetCp                       */
;;     ROUTINES:          SCI - system call interpreter */
;;             SysEntry  - macro to indicate the start  */
;;                         of the dynamic link routine  */
;;             EndEntry  - macro to indicate the end of */
;;                         the dynamic link routine     */
;;             THOPS     - macro to interprete the      */
;;                         thread operator instruction  */
;;                                                      */
;;*******************************************************/


;;******************************************************
;;
;; SUBROUTINE NAME:     w_SetCp
;;
;; DESCRIPTIVE NAME:    Worker routine for DosSetCp
;;
;; FUNCTION:   This routine will validate the input
;;             parameters and call Check_val_cp
;;             which will get the code pages
;;             from CDIB.  If the input parameter
;;             is a valid code page then set the
;;             code page in the Per Task Data Area.
;;
;; NOTES:
;;
;; ENTRY POINT:         w_SetCp
;;   LINKAGE:           Far call (available to any
;;                               kernel routines)
;;
;; INPUT:   BX = Codepage ID
;;          CX = reserved
;;
;; EXIT-NORMAL:    CF will be set to 0
;;                 codepage is set
;;                 CP_CaseMapTbl point to casemap table
;;                 CP_Flgs in PTDA is set.
;;
;; EXIT_ERROR:     CF = 1  and
;;                 ax = Error_invalid_code_page
;;
;; EFFECTS:    no registers are saved
;;
;; INTERNAL REFERENCES: Check_Val_Cp
;;     ROUTINES:
;;
;; EXTERNAL REFERENCES: none
;;     ROUTINES:
;;******************************************************
;;
;; +---------------+
;; | PSEUDO-CODE   |
;; +---------------+
;;w_SetCp         Procedure
;;
;;  CALL Check_val_cp
;;  IF  CF = 1 THEN
;;          Set Error_invalid_code_page in AX
;;          Go to EXIT
;;  Set CodePage in codepage_tag of the PTDA area
;;  Set CP_CaseMapTbl to codepage Case Map DCB
;;  IF  Codepage == DBCS_Codepg
;;      clear fCP_DBCS bit in CP_Flgs
;;  ELSE
;;      set fCP_DBCS bit in CP_Flgs
;;  EXIT:
;;  Return
;;
;;w_SetCp         END    Procedure

Procedure w_SetCp,<near,faronly,far16>

        .if  <cx ne 0>                             ;if reserved not 0
                stc                                ;set carry
                mov   ax,ERROR_INVALID_PARAMETER   ;set ax with error
                jmp   short  exit                  ;exit this procedure
        .endif
        CALL    Check_val_cp                       ;check if id is valid
        .if  C                                     ;if carry is set
                mov   ax,ERROR_INVALID_CODE_PAGE   ;set ax with error
                jmp   short  exit                  ;exit this procedure
        .else
                xor   ax,ax                        ;set ax = no error
        .endif
        mov     ss:[codepage_tag],bx               ;set codepg id in PTDA area

; @@    set pointer to casemap table

        mov     di, si                             ;PCR CP20 J200447
        mov     ss:[CP_CaseMapTbl].Segmt,es        ;set pointer to casemap table
        mov     si, es:[si].CDIB_cpd_casemap_ptr
        sub     si, 7Eh                            ;save sub on every character
        mov     ss:[CP_CaseMapTbl].Offst,si

; @@    set the PTDA flag indicating dbcs activity if necessary.

;PCR CP20 J200447        DosContext DS
        or      [CP_Flgs], fCP_DBCS                ;assume no DBCS activity, set flag
;PCR CP20 J200447        cmp     [DBCS_Codepg], bx                  ;new codepage DBCS active?
;PCR CP20 J200447        jnz     exit                               ;no -- done
        mov     di, es:[di].CDIB_cpd_DBCS_ptr      ;PCR CP20 J200447 ;ES:DI => lead byte table
        mov     di, CDIB_DBCS_first_range          ;PCR CP20 J200447
        mov     ax, es:[di]                        ;PCR CP20 J200447 ;get first word of table
        or      ax, ax                             ;PCR CP20 J200447 ;any lead bytes?
        jz      exit                               ;PCR CP20 J200447 ;yes - dbcs codepage
        and     [CP_Flgs],NOT fCP_DBCS             ;yes -- clear the flag
exit:
        RET

EndProc   w_SetCp


;****************************************************************
;SUBROUTINE  Check_val_cp :
;                It checks to see the desired codepage ID is
;                a valid codepage ID. It does this by comparing
;                the codepage ID with the system prepared
;                codepages in the CDIB table.  If the codepage
;                is valid, ES:SI is set to point to the codepage.
;IN:
;        BX  -  the desired CodePage ID
;OUT:
;        Carry Flag  is Set if  the codepage id is NOT
;                               in CDIB
;        Carry Flag is clear -- codepage id is in CDIB
;               ES:SI points to codepage.
;               BX - codepage id
;USES:
;
;************************************************************

;; +---------------+
;; | PSEUDO-CODE   |
;; +---------------+
;;Check_val_cp    Procedure
;;
;;   /* to get the length of the codepage in CDIB */
;; Let CDIB_addr = CDIB table address
;; Let number_codepage = CDIB_cp_number_codepages in
;;                       CDIB_codepage_section
;;IF  CDIB_codepage_section  EXIST
;;   IF  <CBID_codepage_ptr pointer NE 0>       /* no codepage pointer */
;;      IF  number_codepage EQ   0      /* no codepage  in CONFIG.SYS */
;;          number_codepage = 1         /* then use the default       */
;;      ENDIF
;;      WHILE   number_codepage > 0     /* there are codepages in CONFIG.SYS */
;;         BEGIN
;;             number_codepage = number_codepage - 1
;;             IF [ CDIB_addr = (CDIB_addr + 4) ]  EQ  CodePage  THEN
;;                 Clear CF ( CF= 0)           ; if valid code page
;;                 Go to EXIT1
;;             ENDIF
;;         END  WHILE
;;   ENDIF
;;ENDIF
;;
;;Set CF  ( CF = 1 )                      ; if none valid code page
;;EXIT1:
;;RETURN to the calling routine
;;
;;Check_val_cp    END   Procedure


Procedure Check_val_cp,NEAR

DosContext  ds

push    ds:[CDIB_selector]              ;get CDIB selector
pop     es                              ;es -> CDIB selector
.if   <  <ds:[CDIB_selector]> ne  0 >
assume  es:nothing                      ;
mov     si, es:[CDIB_codepage_ptr]      ;es:[si] -> codepage section
.if     < si  ne  0 >                   ;if codepage section exists
    mov     dx, es:[si].CDIB_cp_number_codepages  ;# of code pages in CDIB
;   .if    < dx eq 0 >                @@ if no codepage in CONFIG.SYS
;           mov     dx,1              @@ get the default codepage
;   .endif                            @@
    .while  < dx  A  0 >                ;while # of codepages > 0
            add     si,4                ;si points to the codepage id
            .if  < bx  eq  es:[si].CDIB_cp_id  >   ;desired codepg id in CDIB
                    mov  si, es:[si].CDIB_cp_data_ptr
                    jmp  short  exit1   ;exit
            .endif                      ;
            dec     dx                  ;# of codepg = # of codepg - 1
    .endwhile                           ;
.endif                                  ;
.endif                                  ;
stc                                     ;set carry, if not found
exit1:                                  ;
        RET                             ;
EndProc   Check_val_cp

;;********************************************************/
;;                                                       */
;; SUBROUTINE NAME:     DosGetCp                         */
;;                                                       */
;; DESCRIPTIVE NAME:    Dos Get Code Page                */
;;                                                       */
;; FUNCTION:   Setup dynamic call to DosGetCp worker     */
;;             routine which does the following:         */
;;             This routine will call w_GetCp2 to get    */
;;             the current and prepared code page        */
;;             for a process.                            */
;;                                                       */
;; NOTES:                                                */
;;        An input list size of 2 bytes  returns only    */
;;        the current process code page identifier.      */
;;     NOTES: Assembly Language                          */
;;            INCLUDE files used :                       */
;;               . dossymb.inc                           */
;;               . dosseg.inc                            */
;;               . error.inc                             */
;;               . struc.inc                             */
;;                                                       */
;; ENTRY POINT:         DosGetCp                         */
;;   LINKAGE:           Dynamic Link                     */
;;                                                       */
;; INPUT:                                                */
;;    PUSH  WORD  Length      ;len of codepagelist(bytes)*/
;;    PUSH@ OTHER CodePageList;return area for codepglist*/
;;    PUSH@ WORD  DataLength  ;length of CodePageList    */
;;                            ;returned                  */
;;                                                       */
;; EXIT-NORMAL:   ax will set to 0                       */
;;                code pages are returned                */
;;                to a buffer which is pointed           */
;;                by CodePageList pointer.               */
;;                                                       */
;;            DataLength returned   code pg returned     */
;;          ----------------------  ---------------------*/
;;                    2             current cp returned  */
;;                                                       */
;;                    4 or more     current followed by  */
;;                                  system prepared      */
;;                                  code pages returned  */
;;                                                       */
;; EXIT_ERROR:                                           */
;;               ax = Error_cplist_too_small             */
;;                    Error_invalid_length               */
;;                                                       */
;;                      The error occurs when the        */
;;                      list length is less than the     */
;;                      bytes needed to return all       */
;;                      the prepared system code         */
;;                      pages then the returned list     */
;;                      is truncated.                    */
;;                                                       */
;; EFFECTS:      contents of ax are destroyed            */
;;               all other registers are saved           */
;;                                                       */
;; INTERNAL REFERENCES:                                  */
;;     ROUTINES:                                         */
;;                                                       */
;; EXTERNAL REFERENCES:                                  */
;;     ROUTINES:                                         */
;;                                                       */
;;             w_GetCp2                                  */
;;                                                       */
;;             SCI - system call interpreter             */
;;                                                       */
;;             SysEntry  - macro to indicate the start   */
;;                         of the dynamic link routine   */
;;             EndEntry  - macro to indicate the end of  */
;;                         the dynamic link routine      */
;;             THOPS     - macro to interprete the thread*/
;;                         operator instruction          */
;;********************************************************/

;;************************* START OF SPECIFICATIONS ******************/
;;                                                                   */
;;     SUBROUTINE NAME:   w_GetCp                                    */
;;                                                                   */
;;     DESCRIPTIVE NAME:  Worker routine for Kernel get code page    */
;;                                                                   */
;;                                                                   */
;;     FUNCTION: This routine is called by the Kernel                */
;;               to get the current code page.  The Kernel           */
;;               segment registers are saved and restored.           */
;;                                                                   */
;;                                                                   */
;;     NOTES: An input list size of 2 bytes returns only             */
;;            the current process code page identifier.              */
;;                                                                   */
;;     ENTRY POINT:  w_GetCp                                         */
;;        LINKAGE:  Farcall                                          */
;;                                                                   */
;;     INPUT:                                                        */
;;           BX        = Length   ; len of codepage list (bytes)     */
;;           DS:[DI]   = CODEPGLIST; return area for codepglist      */
;;           CX        = RETLENGTH ; length of CodePageList returned */
;;     EXIT-NORMAL: CF = 0 and code pages are returned to a buffer   */
;;                  which is pointed by CodePageList pointer.        */
;;                                                                   */
;;            DataLength returned   code pg returned                 */
;;          ----------------------  ---------------------            */
;;                    2             current cp returned              */
;;                                                                   */
;;                    4 or more     current followed by              */
;;                                  the primary system               */
;;                                  prepared code pages returned     */
;;                                                                   */
;;                    6 or more     current followed by              */
;;                                  the system prepared              */
;;                                  code pages returned              */
;;                                                                   */
;;     EXIT-ERROR: CF = 1                                            */
;;                 ax = Error_cplist_too_small                       */
;;                                                                   */
;;                 The error occurs when the                         */
;;                 list length is less than the                      */
;;                 bytes needed to return all                        */
;;                 the prepared system code                          */
;;                 pages then the returned list                      */
;;                 is truncated.                                     */
;;                                                                   */
;;                 ax = Error_cp_not_moved                           */
;;                                                                   */
;;                 The error occurs when the user declared an        */
;;                 invalid CODEPGLIST or the Codepage Data           */
;;                 Information Block is not exist in the memory.     */
;;                                                                   */
;;     EFFECTS:    No registers are saved (Segment regs are saved)   */
;;                                                                   */
;;     INTERNAL REFERENCES: w_getcp_all                              */
;;                                                                   */
;;        ROUTINES:                                                  */
;;                                                                   */
;;     EXTERNAL REFERENCES:                                          */
;;                                                                   */
;;        ROUTINES:              DosContext macros                   */
;;                                                                   */
;;************************** END OF SPECIFICATIONS *******************/


Procedure w_GetCp,<near,faronly,far16>

Assume  ds:nothing

push ds                                 ; Kernel is trusted on SuWord
push es                                 ; Kernel is trusted on SuWord
push dx

xor  dx,dx

mov  ax,ds                              ; ax contains user selector
mov  ds,dx
mov  es,dx


call w_GetCp_All                        ; Get the code page

pop dx
pop es
pop ds

ret


EndProc   w_GetCp


;;************************* START OF SPECIFICATIONS ******************/
;;                                                                   */
;;     SUBROUTINE NAME:   w_GetCp2                                   */
;;                                                                   */
;;     DESCRIPTIVE NAME:  Worker routine for DosGetCp                */
;;                                                                   */
;;                                                                   */
;;     FUNCTION: This routine will validate the input                */
;;               parameters and get the current process code         */
;;               page and the system prepared code pages.            */
;;                                                                   */
;;                                                                   */
;;     NOTES: An input list size of 2 bytes returns only             */
;;            the current process code page identifier.              */
;;                                                                   */
;;     ENTRY POINT:  w_GetCp2                                        */
;;        LINKAGE:  Farcall                                          */
;;                                                                   */
;;     INPUT:                                                        */
;;           BX        = Length   ; len of codepage list (bytes)     */
;;           DS:[DI]   = CODEPGLIST; return area for codepglist      */
;;           CX        = RETLENGTH ; length of CodePageList returned */
;;     EXIT-NORMAL: CF = 0 and code pages are returned to a buffer   */
;;                  which is pointed by CodePageList pointer.        */
;;                                                                   */
;;            DataLength returned   code pg returned                 */
;;          ----------------------  ---------------------            */
;;                    2             current cp returned              */
;;                                                                   */
;;                    4 or more     current followed by              */
;;                                  the primary system               */
;;                                  prepared code pages returned     */
;;                                                                   */
;;                    6 or more     current followed by              */
;;                                  the system prepared              */
;;                                  code pages returned              */
;;                                                                   */
;;     EXIT-ERROR: CF = 1                                            */
;;                 ax = Error_cplist_too_small                       */
;;                                                                   */
;;                 The error occurs when the                         */
;;                 list length is less than the                      */
;;                 bytes needed to return all                        */
;;                 the prepared system code                          */
;;                 pages then the returned list                      */
;;                 is truncated.                                     */
;;                                                                   */
;;                 ax = Error_cp_not_moved                           */
;;                                                                   */
;;                 The error occurs when the user declared an        */
;;                 invalid CODEPGLIST or the Codepage Data           */
;;                 Information Block is not exist in the memory.     */
;;                                                                   */
;;     EFFECTS:    No registers are saved                            */
;;                                                                   */
;;     INTERNAL REFERENCES: w_GetCp_All                              */
;;                                                                   */
;;        ROUTINES:                                                  */
;;                                                                   */
;;     EXTERNAL REFERENCES:                                          */
;;                                                                   */
;;        ROUTINES:              DosContext macros                   */
;;                                                                   */
;;************************** END OF SPECIFICATIONS *******************/

Procedure w_GetCp2,HYBRID

if RAS
;***DT  DosGetCp - Pre-Invocation Dynamic Trace
;
;       TRACE   MINOR=0x0030,
;               TP=.DosGetCp_PreTrace,
;               TYPE=(PRE,API),
;               GROUP=NLS,
;               DESC="(OS) DosGetCp Pre-Invocation"

        public  DosGetCp_PreTrace
DosGetCp_PreTrace:
endif ;RAS

Assume  ds:nothing

mov  ax,ds                              ; ax contains user selector
xor  dx,dx
mov  ds,dx                              ; invalidate DS
mov  es,dx                              ; invalidate ES

call w_GetCp_All                        ; Get the code page

if RAS
;***DT  DosGetCp - Post-Invocation Dynamic Trace
;
;       TRACE   MINOR=0x8030,
;               TP=.DosGetCp_PostTrace,
;               TYPE=(POST,API),
;               GROUP=NLS,
;               DESC="(OS) DosGetCp Post-Invocation"

        public  DosGetCp_PostTrace
DosGetCp_PostTrace:
endif ;RAS

ret


EndProc   w_GetCp2


;;************************* START OF SPECIFICATIONS ******************/
;;                                                                   */
;;     SUBROUTINE NAME:   w_GetCp_all                                */
;;                                                                   */
;;     DESCRIPTIVE NAME:  Worker routine Get Code Page               */
;;                                                                   */
;;                                                                   */
;;     FUNCTION: This routine will validate the input                */
;;               parameters and get the current process code         */
;;               page and the system prepared code pages.            */
;;                                                                   */
;;                                                                   */
;;     NOTES: An input list size of 2 bytes returns only             */
;;            the current process code page identifier.              */
;;                                                                   */
;;     ENTRY POINT:  w_GetCp_All                                     */
;;        LINKAGE:  Farcall                                          */
;;                                                                   */
;;     INPUT:                                                        */
;;           BX        = Length   ; len of codepage list (bytes)     */
;;           AX:[DI]   = CODEPGLIST; return area for codepglist      */
;;           CX        = RETLENGTH ; length of CodePageList returned */
;;     EXIT-NORMAL: CF = 0 and code pages are returned to a buffer   */
;;                  which is pointed by CodePageList pointer.        */
;;                                                                   */
;;            DataLength returned   code pg returned                 */
;;          ----------------------  ---------------------            */
;;                    2             current cp returned              */
;;                                                                   */
;;                    4 or more     current followed by              */
;;                                  the primary system               */
;;                                  prepared code pages returned     */
;;                                                                   */
;;                    6 or more     current followed by              */
;;                                  the system prepared              */
;;                                  code pages returned              */
;;                                                                   */
;;     EXIT-ERROR: CF = 1                                            */
;;                 ax = Error_cplist_too_small                       */
;;                                                                   */
;;                 The error occurs when the                         */
;;                 list length is less than the                      */
;;                 bytes needed to return all                        */
;;                 the prepared system code                          */
;;                 pages then the returned list                      */
;;                 is truncated.                                     */
;;                                                                   */
;;                 ax = Error_cp_not_moved                           */
;;                                                                   */
;;                 The error occurs when the user declared an        */
;;                 invalid CODEPGLIST or the Codepage Data           */
;;                 Information Block is not exist in the memory.     */
;;                                                                   */
;;     EFFECTS:    No registers are saved                            */
;;                                                                   */
;;     INTERNAL REFERENCES: Get_val_cp                               */
;;                                                                   */
;;        ROUTINES:                                                  */
;;                                                                   */
;;     EXTERNAL REFERENCES:                                          */
;;                                                                   */
;;        ROUTINES:              DosContext macros                   */
;;                                                                   */
;;************************** END OF SPECIFICATIONS *******************/
;;
;; +---------------+
;; | PSEUDO-CODE   |
;; +---------------+
;;w_GetCp         Procedure
;;
;;IF   Length(in BX)  > 1 THEN
;;     BEGIN
;;          Get current_code_page from PTDA area
;;              by referring the global variable
;;          IF  current_code_page = 0
;;            Get current_code_page from the CDIB
;;          END
;;          put current_code_page in 1st word of code page list
;;          Length = Length - 2 ;length after subtract current cp len
;;          ReturnLength = 2    ;the current cp is always returned
;;          CALL Get_val_cp     ;get prepared codepage and
;;                              ;also returns number_codepage
;;          IF  CF = 1  THEN    ;CDIB not exist or SUBUF failed
;;              goto EXIT
;;          ENDIF
;;
;;          IF (  Length  <  ( number_codepage * 2 )  )
;;             BEGIN
;;              Set the Carry Flag to 1
;;              Set Error_cplist_too_small in AX
;;             END
;;          END
;;
;;     END
;;ELSE
;;     BEGIN
;;          Return the ReturnLength = 0 in CX
;;          Set Carry flag to 1
;;          Set Error_cplist_too_small in AX
;;     END
;;EXIT:
;;RETURN to the calling routine
;;
;;w_GetCp    END    Procedure

Procedure w_GetCp_All,near

Assume  ds:nothing


.if     <bx  A  1>                      ;user table large enough

        push    ax                      ;codepage list selector and
        push    di                      ;  offset
        push    bx                      ;codepage list length

        mov     bx, ax                  ;bx:[di] points to user buffer

        mov     ax, ss:[codepage_tag]   ;get the current cp from PTDA

        .if     <ax eq 0>               ;if no code page
            DosContext  es                       ;
            mov     es, es:CDIB_selector         ; address CDIB
            Assume  es:nothing                   ;
            mov     si, es:[0].CDIB_codepage_ptr ; codepage section
            mov     ax, es:[si].CDIB_cp_first_id ; first codepage id
        .endif

        CALLFAR SuWord                  ;
        pop     bx                      ;restore Codepagelist offset
        pop     di                      ;
        pop     ax                      ;

        sub     bx,2                    ;remaining cp table length
        mov     cx,2                    ;returned data length

        call    Get_val_cp              ;get code pages
        jc      LeaveGetCPAll           ;if carry, error set in Subroutine

        add     dx,dx                   ;multiple by 2, 1 codepage = 2 bytes
        xor     ax,ax                   ; Clear AX, no error (also resets
                                        ; carry)

        .if     <bx  B  dx>             ;not enough room in the table
                mov     ax,ERROR_CPLIST_TOO_SMALL; set ax with error
                stc                     ;set carry flag
        .endif
.else                                   ;requested length is too small
        xor     cx,cx                   ;returned data length = 0
        stc                             ;set carry
        mov     ax,ERROR_CPLIST_TOO_SMALL ;set ax with error
.endif

LeaveGetCPAll:

        RET

EndProc   w_GetCp_All


Procedure Get_val_cp,NEAR
;
;SUBROUTINE  Get_val_cp :
;                It gets the codepage id's from CDIB area then
;                puts them into the CodePageList.
;
;
; IN:
;       bx       =  length of the desired code pages - 2
;       ax:[di] ->  return area for CodePageList
;       cx       =  length of CodePageList returned
;
; OUT:
;       ax:[di] -> the CodepageList which has the returned codepages
;       cx       = length of CodePageList returned
;       dx       = # of codepages in CDIB codepage section
;
;*****************************************************************
;
;  +---------------+
;  | PSEUDO-CODE   |
;  +---------------+
;Get_val_cp       Procedure
;
; Let CDIB_addr = CDIB table address
; Let number_codepage = CDIB_cp_number_codepages in
;                       CDIB_codepage_section
; Let BUF_addr  = DS&gml.[DI]
;
;IF  CDIB_codepage_section  EXIST
;
;     WHILE ( (Length > 1) AND (number_codepage > 0) )
;                                        ;checks "1" instead of "0"
;                                        ;because the length which
;                                        ;is given by the user
;       BEGIN                            ;could be an odd number
;            [ BUF_addr = BUF_addr + 2 ] = [ CDIB_addr = CDIB_addr + 4]
;            ReturnLength = ReturnLength + 2
;            Length = Length - 2
;            number_codepage = number_codepage - 1
;       END WHILE
;ELSE   /* CDIB is not exist then return error */
;       RETURN  ERROR
;ENDIF
;
; RETURN to the calling routine
;
; Get_val_cp    END    Procedure
;
;*****************************************************************
Assume  es:nothing, ds:nothing

push    bx                              ;save length
push    di                              ;save codepagelist offset
DosContext  es                          ;get global segment address
.if  < <es:[CDIB_selector]>  ne  0  >
push    es:[CDIB_selector]              ;get CDIB selector
pop     es                              ;put in segment register
Assume  es:nothing                      ;
mov     si,es:[CDIB_codepage_ptr]       ;es:[si] -> codepage section
.if  < si  ne  0  >                     ;if CDIB exists
  mov     dx,es:[si].CDIB_cp_number_codepages ;get # of codepages
    push    dx                        ;save # of copage of CDIB
    add     di, 2                     ;increment Codepagelist offset
    .while  < bx  A  1 >    and         ;when still a room in CodePageList
    .while  < dx  A  0 >                ;more code pages in CDIB
            add   si,4                  ;CDIB_addr = CDIB_addr + 4
;***************************************************************************
; set up to call SuWord
; Input - AX    -> word to write into user space
;         BX:DI -> pointer to destination buffer
;                    (may be in user space)
; Output - carry flag clear : word in AX moved to BX:DI
;                             DI advanced by 2
;                     set   : general protection fault
;                             AX = Error_protection_violation
;                             Flags set in PTDA to kill process
; Uses   - AX, BX, DI, ES, Flags
;****************************************************************************
            push    ax
            push    bx                  ; save the input length
            push    es                  ; save the input length
            mov     bx, ax              ; bx now has the segment addr
            mov     ax, es:[si]         ; ax has the codepage ID now
            CALLFAR SuWord              ;
            pop     es
            pop     bx                  ; get the length back
            pop     ax                  ;
            .if  c                      ; SuWord fails
               mov  ax,ERROR_CP_NOT_MOVED
               pop  dx                  ; restore # of codepage id
               jmp  short Exit2
            .endif                      ; End SuWord fails
            add     cx, 2               ; returned length of returned len + 2
            sub     bx, 2               ; get available length
            dec     dx                  ; # of codepages - 1
    .endwhile                           ;
        pop     dx                      ; restore # of codepage ID
        clc                             ; clear carry when o.k.
.else                                   ; if CDIB not exist
        stc                             ; then set carry
        mov  ax,ERROR_CP_NOT_MOVED
.endif
.else
        stc                             ; then set carry
        mov  ax,ERROR_CP_NOT_MOVED
.endif
Exit2:                                  ;
        pop     di                      ;restore codepagelist offset
        pop     bx                      ;restore length
        RET

EndProc   Get_val_cp


HIGH3CODE    ENDS

        END
