;++
;
;   WOW v1.0
;
;   Copyright (c) 1991, Microsoft Corporation
;
;   WINSTR.ASM
;   Win16 string services
;
;   History:
;
;   Created 18-Jun-1991 by Jeff Parsons (jeffpar)
;   Copied from WIN31 and edited (as little as possible) for WOW16
;--


;****************************************************************************
;*									    *
;*  WinStr.ASM -							    *
;*									    *
;*	String related API calls to support different lanuages	 	    *
;*									    *
;****************************************************************************

        TITLE   WinStr.ASM

ifdef WOW
NOEXTERNS equ 1
endif
NOTEXT = 1
include user.inc

sBegin	DATA

ExternW	hLangDrv
ExternD	fpLangProc

sEnd

createSeg _TEXT, CODE, WORD, PUBLIC, CODE

sBegin	CODE

assumes CS,CODE
assumes DS,DATA

ExternNP	Loc_IsConvertibleToUpperCase
ExternNP	Loc_Upper
ExternFP	IAnsiUpper
ExternFP	IAnsiLower
ExternFP	Ilstrcmpi
ifdef DBCS
ExternFP	IsDBCSLeadByte
endif

; Function codes for all the string functions in USER
;
ANSINEXT_ID	equ	1
ANSIPREV_ID	equ	2
ANSIUPPER_ID	equ	3
ANSILOWER_ID	equ	4

;--------------------------------------------------------------------------
;    The order of entries in the following table can not be changed 
;    unless the *_ID codes are also changed in KERNEL also.
;    ((FunctionCode - 1) << 1) is used as the index into this table
;
;	Function Codes:
;
;    NOTE: If you change the entries in this table, kindly update the
;    *_ID statements above and also lString.asm of KERNEL.
;
;--------------------------------------------------------------------------
LabelW	StringFuncTable
	dw	codeOFFSET	IAnsiNext
	dw	codeOFFSET	IAnsiPrev
	dw	codeOFFSET	IAnsiUpper
	dw	codeOFFSET	IAnsiLower

;*----------------------------------------------------------------------*
;*    StringFunc()							*
;*	The string manipulation functions in kernel have been moved 	*
;*	into USER.							*
;*	This is the common entry point in USER for all the string 	*
;*	manipulation functions Kernel wants to call. Kernel jumps to 	*
;*      this function with the function code in CX                      *
;*									*
;*    Input Parameters:							*
;*      [CX] contains the Function code.                                *
;*      [sp] contains the FAR return address of the original caller of  *
;*		the string manipulation functions in Kernel		*
;*----------------------------------------------------------------------*

cProc	StringFunc, <FAR, PUBLIC>
cBegin	nogen
        xchg    bx,cx   ; move function code to BX
	dec	bx
	shl	bx, 1
	jmp	StringFuncTable[bx]
			; Control does not comeback here. It returns directly
			; to the caller
cEnd	nogen

;*----------------------------------------------------------------------*
;*									*
;*  AnsiPrev()								*
;*									*
;*----------------------------------------------------------------------*

ifdef	DBCS

cProc	IAnsiPrev,<PUBLIC,FAR>
;       parmD   pFirst                  ; [bx+10] es:di
;       parmD   pStr                    ; [bx+6] ds:si

cBegin  nogen
	push	bp
	mov	bp,sp

	push    ds
        push    si
        push    di

        lds     si,[bp+6]
        les     di,[bp+10]
        regptr  dssi,ds,si
        regptr  esdi,es,di
        cld

        cmp     si,di           ; pointer to first char?
        jz      ap5             ; yes, just quit

	dec	si		; backup once
	cmp	si,di		; pointer to first char?
	jz	ap5		; yse, just quit

ap1:
	dec	si		; backup once
	mov	al, [si]	; fetch a character
        cCall   IsDBCSLeadByte,<ax>  ; DBCS lead byte candidate?
	test	ax,ax		;
	jz	ap2		; jump if not.
	cmp	si,di		; backword exhausted?
	jz	ap3		; jump if so
	jmp	ap1		; repeat if not
ap2:
	inc	si		; adjust pointer correctly
ap3:
	mov	bx, [bp+6]	;
	mov	di, bx		; result in DI
	dec	di		;
	sub	bx, si		; how many characters backworded
	test	bx, 1		; see even or odd...
	jnz	ap4		; odd - previous char is SBCS
	dec	di		; make DI for DBCS
ap4:
	mov	si, di		; final result in SI
ap5:
	mov	ax,si
	mov	dx,ds

	pop     di
        pop     si
        pop     ds

	pop	bp
        ret     8
cEnd    nogen

else

cProc	IAnsiPrev,<PUBLIC,FAR>
;       parmD   pFirst                  ; [bx+8] es:di
;       parmD   pStr                    ; [bx+4] ds:si

cBegin  nogen
        mov     bx,sp

	push    ds
        push    si
        push    di

        lds     si,ss:[bx+4]
        les     di,ss:[bx+8]
        regptr  dssi,ds,si
        regptr  esdi,es,di
        cld

        cmp     si,di           ; pointer to first char?
        jz      ap3             ; yes, just quit
;;ifdef DBCS
;;	xchg	si,di
;;ap1:    mov     dx,si
;;        lodsb                   ; get a char
;;        cCall   IsDBCSLeadByte,<ax>  ; is it kanji?
;;	cmp	al,0
;;        je      ap2             ; no, get next char
;;        inc     si              ; yes, inc past second part
;;ap2:    cmp     si,di           ; have we at or past end?
;;        jb      ap1             ; no, keep going
;;        mov     si,dx           ; return previous pointer
;;else
        dec     si              ; assume easy case...
;;endif ; DBCS
ap3:    mov     ax,si
        mov     dx,ds

	pop     di
        pop     si
        pop     ds
        ret     8
cEnd    nogen

endif

;*----------------------------------------------------------------------*
;*									*
;*   AnsiNext()								*
;*									*
;*----------------------------------------------------------------------*

cProc	IAnsiNext,<PUBLIC,FAR>
;       parmD   pStr
cBegin  nogen
        mov     bx,sp
        push    di
        les     di,ss:[bx+4]
        mov     al,es:[di]
        or      al,al
        jz      an1
        inc     di
ifdef DBCS
        cCall	IsDBCSLeadByte,<ax>
        cmp	al,0
        je      an1
        inc     di
endif ; DBCS
an1:    mov     ax,di
        mov     dx,es
        pop     di
        ret     4
cEnd    nogen

;-----------------------------------------------------------------------
;   MyAnsiUpper()
; 	convert string at es:di to upper case
;-----------------------------------------------------------------------
        public  MyAnsiUpper
MyAnsiUpper:
        cld
        mov     si,di
mau1:   lods    byte ptr es:[si]

ifdef DBCS
	push	ax
        cCall   IsDBCSLeadByte,<ax>
	cmp	ax,0
	pop	ax
	je	mau2
        inc     si
        inc     di
        inc     di
        jmp     short mau1
endif

mau2:   call    MyUpper
        stosb
        or      al,al
        jnz     mau1
        ret

;-----------------------------------------------------------------------
;    MyAnsiLower()
; 	convert string at es:di to lower case
;-----------------------------------------------------------------------
        public  MyAnsiLower
MyAnsiLower:
        cld
        mov     si,di
mal1:   lods    byte ptr es:[si]

ifdef DBCS
	push	ax
        cCall   IsDBCSLeadByte,<ax>     ; first byte of double byte?
	cmp	ax,0
	pop	ax
        je      mal2                    ; no just do normal stuff
        inc     si                      ; skip the two bytes
        inc     di
        inc     di
        jmp     short mal1
endif

mal2:   call    MyLower
        stosb
        or      al,al
        jnz     mal1
        ret

;-------------------------------------------------------------------------
;   MyUpper()
; 	convert lower case to upper, must preserve es,di,cx
;-------------------------------------------------------------------------
        public  MyUpper
MyUpper:
	call	Loc_IsConvertibleToUpperCase ; Check if it is a lower case char
				           ; that has an uppercase equivalent
	jnc	myu1		; 
	sub     al,'a'-'A'
myu1:   ret

ifdef KANJI
####################  KANJI  ###############################################
        ; convert upper case to lower, must preserve es,di,cx
        public  MyLower
MyLower:
        cmp     al,'A'
        jb      myl2
        cmp     al,'Z'
        jbe     myl1

	push	ds
	SetKernelDS
	cmp	[fFarEast],1	; this is a far east kbd 1/12/87 linsh
	pop	ds
	UnSetKernelDS
	jge	myl2		; yes do nothing to the 0C0H - 0DEH range

        cmp     al,0C0H         ; this is lower case a with a back slash
        jb      myl2
        cmp     al,0DEH
        ja      myl2
myl1:   add     al,'a'-'A'
myl2:   ret
####################  KANJI  ###############################################
endif

;--------------------------------------------------------------------------
;   MyLower()
; 	convert upper case to lower, must preserve es,di,cx
;--------------------------------------------------------------------------
        public  MyLower
MyLower:
	call	Loc_Upper
	jnc	myl1
	add	al, 'a'-'A'
myl1:	
	ret

sEnd	CODE
end
