;       SCCSID = @(#)nlswrk.asm	6.1 90/11/17
;      SCCSID = @(#)nlswrk.asm 13.5 90/09/17
	PAGE	,132
TITLE  nlswrk - NLS routines
NAME   nlswrk
;
;
;   NLS routines
;
;	Protected Mode Functions
;
;		Check_valid_cc
;		Check_valid_cp
;		w_CopyCty
;		w_CopyName
;		w_Copy_nls_info
;		w_International
;
;   Revisions:
;
;Local	DCR/
;Tag	PTM(R)	Who	When
;		danno	28-Nov-1988
;		    created from 3xbox/dos3nls.asm

.xlist
include basemaca.inc
include osmaca.inc
include dosseg.inc
.xcref
include dossymc.inc
include cdib.inc
include country.inc
include error.inc
;include intnat.inc ; BUGBUG danno 28-Nov-1988
include struc.inc
.cref
.list

	ReferGlobal	CDIB_selector,WORD


DATA	 SEGMENT

	PUBLIC	CodePgBuff			; @T1
if 0 ; BUGBUG danno 28-Nov-1988
	PUBLIC	Adapter				; @T1
	PUBLIC	NumCP				; @T1
	PUBLIC	sys_casemap			; @L
	PUBLIC	usr_casemap			; @L


NumCP		dw	0			; Codpage list count
Adapter		db	0			; Adapter type
endif ; BUGBUG danno 28-Nov-1988
CodePgBuff	dw	8   dup (0)		; Codepage list buffer

if 0 ; BUGBUG danno 28-Nov-1988
     ; temporarily disable for MVDM

						; Buffer for returning from  @@
						; Get Extended Country Info call
						; PC DOS 3.30 NLSFUNC uses a
						; a 640 byte buffer, this code
						; uses 640 to be consistent @@
sys_casemap	db	130 dup (0)	;@L	; system casemap table
ctry_info	db	122 dup (0)	;@L	; country info internal buffer
usr_casemap	db	130 dup (0)	;@L	; user casemap table
usr_collate	db	258 dup (0)	;@L	; collate table

endif ; BUGBUG danno 28-Nov-1988

DATA	 ENDS


;	FARCODE HIGH2
;HIGH2CODE SEGMENT
	FARCODE HIGH3
HIGH3CODE SEGMENT


if 0 ; BUGBUG danno 28-Nov-1988
     ; temporarily disable for MVDM

;***	w_International	 -- sets up country table at initialization time
;
;	w_International allows the system to adapt to the country
;	being run in.
;
;	INVOKE	MOV	BX,country
;		CALL	w_International
;
;
;	ENTRY
;	    BX
;
;	EXIT
;
;	  Good return:
;	    No Carry
;	    Current country SET
;	  Bad Return:
;	    carry Set
;
;	PSEUDOCODE
;	  call check_valid_cc  to insure match with CDIB
;	  if (no error)
;	    call w_Copy_NLS_Info to obtain info from CDIB
;	    set country code in table
;	  endif
;	  return
;
;	  DOS 5 change:	 The country code is now defined
;		in the config.sys file.  After system initialization
;		it is not possible to change the value.
;

Procedure   w_International,HYBRID
	ASSUME	DS:NOTHING,ES:NOTHING,SS:TASKAREA
	PMONLY

	push	ds			;save
	push	di			;  affected registers
	push	ax
	push	bx
	push	dx
	mov	dx,bx			;load country code for call
	call	check_valid_cc		;check if country code in CDIB
	.if	<nc>			;check for error
	  mov	al,2			;@L want casemap table for map_syscase
	  DosContext ds			;@L address of
	  lea	di,sys_casemap		;@L system casemap table
	  mov	bx,0ffffh		;@L codepage = default
	  call	w_Copy_NLS_info		;@L load casemap from CDIB
	  mov	al,setcountryinfo	;want country info
	  mov	ah,CDIB_fmt_date_format ;but only for 38h part
	  DosContext ds		;address of
	  mov	di,[Current_Country]	;  country table
	  mov	bx,0ffffh		;codepage = default
	  call	w_Copy_NLS_info		;load ctyinfo to block from CDIB
	  .if	<nc>
	    mov [cntry_id_code],dx	;set country code
	    mov di,[Current_Country]	;country table offset
	    mov WORD PTR ds:[di].Map_call+2,DOSCODE ;set casemap routine addr
	    mov WORD PTR ds:[di].Map_call,OFFSET MAP_SYSCASE
	  .endif

	.endif
	pop	dx
	pop	bx
	pop	ax
	pop	di
	pop	ds
	ret

EndProc w_International

;***	w_Copy_NLS_info - copy NLS info from CDIB to a buffer in real mode
;
;	ENTRY	DS:DI address of buffer to contain NLS info
;
;		BX = codepage id (0ffffh if default desired)
;
;		AL = selection
;
;		AH = number of bytes into country info to begin copying.
;		     This is done so INT 21H Function 38h can use
;		     this routine.
;
;	EXIT	Carry flag set if type of request not found
;
;		Carry clear if all o.k.
;
;	USES	All
;
;	PSEUDOCODE
;
;	 Get address of CDIB
;
;	 Set ES:SI pointing to address of first code page in CDIB
;
;	 If code page pointed at by ES:SI <> BX
;	     Then increment ES:SI to point to next code page
;	     Else  (ES:SI points to correct code page)
;		 Begin
;		 Set ES:SI to point to proper information for code page
;		 CX = first word of desired information
;		 Move CX number of bytes from ES:SI to DS:DI
;		 End
;

Procedure   w_Copy_NLS_info,hybrid

	ASSUME	DS:NOTHING,ES:NOTHING,SS:TASKAREA
		PMONLY

		DosContext  es			;get global segment address
;
		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
		add	si,4			;es:[si] -> first codepage
		cmp	bx,0ffffh		;If BX = -1 then use default
		je	Found_code_pg		;code page
;
Next_code_pg:
		cmp	word ptr es:[si],bx	;See if code page found
		je	found_code_pg
		add	si,4			;if not, go to next
		jmp	Next_code_pg
Found_code_pg:
		mov	cx,word ptr es:[si].CDIB_cp_data_ptr
						;Get offset of cp data
		mov	si,cx			;es:[si] -> code page data
		cmp	al,1			;Request for country info?
		je	ctry_info_table
		cmp	al,2			;Request for case table?
		je	case_table
		cmp	al,6			;Request for collate table?
		je	collate_table
		cmp	al,7			;Request for DBCS table?
		je	dbcs_table
		stc				;Set carry and exit if request
		jmp	Copy_info_exit		;type not available

ctry_info_table:
		mov	cx,word ptr es:[si].CDIB_cpd_format_ptr
		mov	si,cx			;es:[si] -> country info
		mov	cx,es:[si].CDIB_fmt_length  ;cx=length of country info
		.if	<ah ne 0>		;if not copying entire ctyinfo
		  push	ax			;save
		  sar	ax,8			;Move value in AH to AL
		  add	si,ax			;Increment pointer
		  mov	cx,CDIB_fmt_reserved-CDIB_fmt_date_format ;set counter
		  pop	ax			;Restore AX
		.endif
		jmp	Copy_info
;
case_table:
		mov	cx,word ptr es:[si].CDIB_cpd_casemap_ptr
		mov	si,cx			;es:[si] -> case_table
		mov	cx,es:[si].CDIB_cm_length  ;cx=length of casemap table
		jmp	Copy_info
;
collate_table:
		mov	cx,word ptr es:[si].CDIB_cpd_collate_ptr
		mov	si,cx			;es:[si] -> collate table
		mov	cx,es:[si].CDIB_col_length  ;cx=length of collate table
		jmp	Copy_info
;
dbcs_table:
		mov	cx,word ptr es:[si].CDIB_cpd_dbcs_ptr
		mov	si,cx			;es:[si] -> dbcs table
		mov	cx,es:[si].CDIB_dbcs_length  ;cx=length of country info
		jmp	Copy_info
;
; Copy information from protect mode memory to real mode memory.
;
; DS:DI -> caller's buffer if al = 1, otherwise DS:DI points to
; ctry_info buffer.
; ES:SI -> NLS info in CDIB
; CX = number of words to transfer
;
Copy_info:
;
		 sar	cx,1			; Divide CX by 2 since moving
						; words
;repnz		 movsb
;
Next_word_ctry_info:
;
;***************************************************************************
; 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 code page
	    push    es			; save the NLS segment address
	    mov	    ax, es:[si]		; ax has word of NLS info
	    mov	    bx, ds		; bx now has the segment addr
	    CALLFAR SuWord		;
	    pop	    es
	    pop	    bx			; get the length back
	    pop	    ax			;
	    jc	    Copy_info_exit
	    add	    si,2		; Move ptr to next word of NLS info
;
	    loop    Next_word_ctry_info ; If CX > 0 copy next word
	    clc				; Clear carry
;
Copy_info_exit:
		return

EndProc		w_copy_nls_info


endif ; BUGBUG danno 28-Nov-1988

;****************************************************************
;SUBROUTINE  Check_valid_cp :
;		 It checks to see the desired code page ID is
;		 a valid code page ID. It does this by comparing
;		 the code page ID with the system prepared
;		 code pages in the CDIB table.
;IN:
;	 BX  -	the desired CodePage ID
;OUT:
;	 Carry Flag  is Set if	the codepage id is NOT
;				in CDIB
;
;************************************************************

;; +---------------+
;; | PSEUDO-CODE   |
;; +---------------+
;;Check_valid_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	 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
;;
;;Set CF  ( CF = 1 )			  ; if none valid code page
;;EXIT1:
;;RETURN to the calling routine
;;
;;Check_valid_cp    END	  Procedure


Procedure Check_valid_cp,hybrid

;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 <bx eq 0ffffh>				 ;@@
	     mov     bx,word ptr ds:CodePgBuff	 ;@@ use active codepage
	     .if <bx eq 0>			 ;@L if no codepage declared
		mov    bx,es:[si+4]		 ;@L then use the default
	     .endif				 ;@L
    .endif					 ;@@

.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]  >	;desired codepg id in CDIB
		    clc			;clear carry
		    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_valid_cp


;****************************************************************
;SUBROUTINE  Check_valid_CC :
;		 It checks to see the desired country code is
;		 a valid country code. It does this by comparing
;		 the country code with the system country code
;		 in the CDIB table.
;IN:
;	 DX  -	the desired country code
;OUT:
;	 Carry Flag  is Set if	the codepage id is NOT
;				in CDIB
;
;************************************************************

;; +---------------+
;; | PSEUDO-CODE   |
;; +---------------+
;;Check_valid_CC    Procedure
;;
;;  Get addressability to CDIB
;;
;;  Get address of country code in CDIB
;;
;;  If DX = -1
;;  Then
;;	Begin
;;	DX = country code in CDIB
;;	Clear carry
;;	Goto Check_valid_CC_exit
;;	End
;;
;;  If DX <> country code in CDIB
;;  Then goto Check_valid_CC_error
;;
;;  Else
;;	Begin
;;	Set carry flag
;;	Goto Check_valid_CC_exit
;;	End
;;
;;Check_valid_CC_error:
;;
;;	Set carry
;;
;;Check_valid_CC_exit
;;
;;Check_valid_CC    END	  Procedure


Procedure Check_valid_CC,hybrid

;DosContext  ds

	     push   ds:[CDIB_selector] ;get CDIB selector
	     pop    es		       ;es -> CDIB selector

	     cmp    ds:word ptr [CDIB_selector],0 ;Make sure there is something
						  ;in CDIB
	     je	    Check_valid_CC_error	  ;if not then exit with error
;
	     mov    si,es:[CDIB_country_ptr]  ;es:[si] -> country section
	     cmp    dx,0ffffh		      ;If DX = -1 then set DX to
	     jne    Not_default_CC	      ;default country code
;
	     mov    dx,es:word ptr [si+2]
	     clc
	     jmp    Check_valid_CC_exit
;
Not_default_CC:
	     cmp    es:word ptr [si+2],DX     ;DX = country code?
	     jne    Check_valid_CC_error      ;if not set carry and exit
;
	     clc			      ;else clear carry and exit
	     jmp    Check_valid_CC_exit
;
Check_valid_CC_error:
	     stc			      ;set carry
Check_valid_CC_exit:
	     RET
EndProc	  Check_valid_CC



;***	w_CopyName -  Copy font file name to buffer from CDIB
;
;	ENTRY	DS:DI =	 Address of buffer (must be at least 129 bytes long)
;
;
;	EXIT:	DS:DI -> ASCIIZ font filename
;
;		CY = 0	No error
;
;		CY = 1	Error
;
;
;	UESE:	AX,CX,SI,ES
;
Procedure w_CopyName,HYBRID
Assume	es:nothing, ds:nothing

	push	di
	push	ds
	pop	es			; ES = DOSGROUP
	DosContext  ds
	cmp	ds:[CDIB_selector],0	; Just in case CDIB not initialized
	jz	Bad_Ret
	push	ds:[CDIB_selector]	; Establish addressibility to CDIB
	pop	ds			; data segment
	mov	si,ds:[CDIB_screen_ptr] ; Get offset to screen device data
	or	si,si			; DEVINFO specified in CONFIG.SYS?
	jz	Bad_Ret
	mov	ax,si			; Save the offset of structure
	mov	cx,[si]			; Get length of structure
	mov	si,[si].CDIB_dev_filename_ptr	; Get offset to filename
	add	cx,ax			; Calculate offset to the end of
					; structure
	sub	cx,si			; We now can determine the actual
	dec	cx			; length
	jz	Bad_Ret			; NULL filename
	cld
GetNextChar:				; Copy file name ASCIIZ from CDIB
					; into caller's buffer
	lodsb				; Get a byte from CDIB
	stosb
	loop	GetNextChar		; Copy next byte
	mov	al,0
	stosb				; Force ASCIIZ terminator
	jmp	SHORT Good_Ret		; CY should be clear
Bad_Ret:
	stc
Good_Ret:
	push	es
	pop	ds
	pop	di
	ret
EndProc w_CopyName

BREAK	<w_CopyCty - obtain country file name from CDIB>

;************** START OF SPECIFICATIONS *****************************
;
; SUBROUTINE NAME: w_CopyCty
;
; DESCRIPTIVE NAME: copy country filename
;
; FUNCTION:  obtains the countyr filename from CDIB and places it in
;	     caller's buffer
;
; NOTES:  @@ NEW ROUTINE
;
; ENTRY POINT:	w_CopyCty
;	  LINKAGE:	Protect, far, ring 0
;
; INPUT:	DS:DX	caller's buffer (128 bytes long)
;
; EXIT-NORMAL:	Carry Flag Clear
;
; EXIT-ERROR:	Carry Flag Set
;
; EFFECTS:	Fills Buffer with ASCIIZ country filespec
;
; PSUEDO CODE:
;
;	save affected registers
;	obtain buffer selector
;	obtain CDIB selector
;	obtain offset of country filename within CDIB
;	obtain buffer offset
;	repeat
;	  transfer byte from CDIB to input buffer
;	until (transferred byte = 0) or		* end of ASCIIZ string
;	until (128 bytes transferred)		* maximum size of ASCIIZ string
;	if (128 bytes transferred) and		* if maximum size
;	if (the last byte was non zero)		*   and not end of ASCIIZ
;	  set carry flag			* error
;	else
;	  if (odd number of bytes transferred)
;	    load a zero byte in input buffer to word round the string
;	  endif
;	  clear carry flag			* successful
;	endif
;	restore affected registers
;	return
;
; INTERNAL REFERENCES:
;    ROUTINES:
;
; EXTERNAL REFERENCES:
;    ROUTINES:
;
;************** END OF SPECIFICATIONS *******************************

Procedure w_CopyCty,HYBRID
assume ds:nothing, es:nothing

	push	ds			;save
	push	es			;
	push	di			;  affected
	push	si			;
	push	ax			;    registers
	push	cx			;

	push	ds			;set up
	pop	es			;   the destination selector

	DosContext ds			;obtain
	push	ds:[CDIB_selector]	;  the
	pop	ds			;    CDIB selector

	mov	si,ds:[CDIB_country_ptr]    ;obtain the
	lea	si,ds:[si].CDIB_ct_filename ;  country filename offset

	mov	di,dx			;load the destination offset

	xor	cx,cx			;set count = 0

	cld				;insure auto increment

	.repeat				;
	  lodsb				;move byte from es:[di]
	  stosb				;  to ds:[si] via al
	  inc	cx			;keep count
	.until <zero al> or		;end of string?
	.until <cx eq 128>		;buffer full?

	.if <cx eq 128> and		;buffer full
	.if <al ne 0>			;  and not finished?
	  stc				;error
	.else				;
	  .if <bit cx and 1>		;odd number of bytes?
	     mov byte ptr es:[di],0	;load byte to word round
	  .endif			;
	  clc				;no error
	.endif				;

	pop	cx			;restore
	pop	ax			;
	pop	si			;  affected
	pop	di			;
	pop	es			;    registers
	pop	ds			;

	ret				;

EndProc w_CopyCty

;HIGH2CODE  ENDS
HIGH3CODE  ENDS
	END
