mariadb/strings/strings.asm
2013-03-19 13:29:12 +01:00

1060 lines
19 KiB
NASM

; Copyright (c) 2000, 2003, 2006 MySQL AB
;
; This library is free software; you can redistribute it and/or
; modify it under the terms of the GNU Library General Public
; License as published by the Free Software Foundation; version 2
; of the License.
;
; This library is distributed in the hope that it will be useful,
; but WITHOUT ANY WARRANTY; without even the implied warranty of
; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
; Library General Public License for more details.
;
; You should have received a copy of the GNU Library General Public
; License along with this library; if not, write to the Free
; Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
; MA 02110-1301, USA
; Note that if you don't have a macro assembler (like MASM) to compile
; this file, you can instead compile all *.c files in the string
; directory.
TITLE Stringfunctions that we use often at MSDOS / Intel 8086
ifndef M_I386
.8087
DOSSEG
.MODEL LARGE
.CODE
;
; Some macros
;
q_movs MACRO ; as rep movsb but quicker
shr cx,1
rep movsw ; Move 2 bytes at a time
adc cx,cx
rep movsb ; Move last byte if any
ENDM
q_stos MACRO ; as rep stosb but quicker
mov ah,al ; For word store
shr cx,1
rep stosw ; Move 2 bytes at a time
adc cx,cx
rep stosb ; Move last byte if any
ENDM
ifndef ZTC ; If not using ZORTECH compiler
;
; Compare memory
; Args: s1,s2,length
;
PUBLIC _bcmp
_bcmp PROC
mov bx,bp ; Save bp
mov dx,di ; Save di
mov bp,sp
push ds
push si
les di,DWORD PTR [bp+8] ; s2
lds si,DWORD PTR [bp+4] ; s1
mov cx,WORD PTR [bp+12] ; Length of memory-area
jcxz @F ; Length = 0, return same
; cld ; Work uppward
repe cmpsb ; Compare strings
jz @F ; Match found
inc cx ; return matchpoint +1
@@: mov ax,cx ; Return 0 if match, else pos from end
pop si
pop ds
mov di,dx
mov bp,bx
ret
_bcmp ENDP
;
; Find a char in a string
; Arg: str,char
; Ret: pointer to found char or NullS
;
ifdef better_stringfunctions ; Breaks window linkage (broken linking)
PUBLIC _strchr
_strchr PROC
mov bx,bp ; Save bp and di
mov dx,di
mov bp,sp
les di,DWORD PTR [bp+4] ; str
mov ah,BYTE PTR [bp+8] ; search
xor al,al ; for scasb to find end
@@: cmp ah,es:[di]
jz @F ; Found char
scasb
jnz @B ; Not end
xor di,di ; Not found
mov es,di
@@: mov ax,di
mov di,dx ; Restore
mov dx,es ; Seg adr
mov bp,bx ; Restore
ret
_strchr ENDP
;
; Find length of string
; arg: str
; ret: length
;
PUBLIC _strlen
_strlen PROC
mov bx,sp
mov dx,di
les di,DWORD PTR ss:[bx+4] ; Str
xor al,al ; Find end of string
mov cx,-1
; cld
repne scasb ; Find strend or length
inc cx ; Calc strlength
not cx
mov ax,cx
mov di,dx ; Restore register
ret
_strlen ENDP
endif
;
; Move a string
; arg: dst,src
; ret: end-null of to
;
PUBLIC _strmov
_strmov PROC
mov bx,bp
mov cx,si
mov bp,sp
push ds
push di
les di,DWORD PTR [bp+4] ; dst
lds si,DWORD PTR [bp+8] ; src
; cld
@@: mov al,ds:[si]
movsb ; move arg
and al,al
jnz @B ; Not last
lea ax,WORD PTR [di-1] ; Set DX:AX to point at last null
mov dx,es
pop di
pop ds
mov si,cx
mov bp,bx
ret
_strmov ENDP
;
; Fill a area of memory with a walue
; Args: to,length,fillchar
;
PUBLIC _bfill
_bfill PROC
mov bx,sp ; Get args through BX
mov al,BYTE PTR ss:[bx+10] ; Fill
bfill_10:
mov dx,di ; Save di
les di,DWORD PTR ss:[bx+4] ; Memory pointer
mov cx,WORD PTR ss:[bx+8] ; Length
; cld
q_stos
mov di,dx
ret
_bfill ENDP
;
; Fill a area with null
; Args: to,length
PUBLIC _bzero
_bzero PROC
mov bx,sp ; Get args through BX
mov al,0 ; Fill with null
jmp short bfill_10
_bzero ENDP
endif ; ZTC
;
; Move a memory area
; Args: to,from,length
;
PUBLIC _bmove
_bmove PROC
mov bx,bp
mov dx,di
mov ax,si
mov bp,sp
push ds
lds si,DWORD PTR [bp+8] ; from
les di,DWORD PTR [bp+4] ; to
mov cx,WORD PTR [bp+12] ; Length of memory-area
; cld ; Work uppward
rep movsb ; Not q_movs because overlap ?
pop ds
mov si,ax
mov di,dx
mov bp,bx
ret
_bmove ENDP
;
; Move a alligned, not overlapped, by (long) divided memory area
; Args: to,from,length
;
PUBLIC _bmove_align
_bmove_align PROC
mov bx,bp
mov dx,di
mov ax,si
mov bp,sp
push ds
lds si,DWORD PTR [bp+8] ; from
les di,DWORD PTR [bp+4] ; to
mov cx,WORD PTR [bp+12] ; Length of memory-area
; cld ; Work uppward
inc cx ; fix if not divisible with word
shr cx,1
rep movsw ; Move 2 bytes at a time
pop ds
mov si,ax
mov di,dx
mov bp,bx
ret
_bmove_align ENDP
;
; Move a string from higher to lower
; Arg from+1,to+1,length
;
PUBLIC _bmove_upp
_bmove_upp PROC
mov bx,bp
mov dx,di
mov ax,si
mov bp,sp
push ds
lds si,DWORD PTR [bp+8] ; from
les di,DWORD PTR [bp+4] ; to
mov cx,WORD PTR [bp+12] ; Length of memory-area
dec di ; Don't move last arg
dec si
std ; Work downward
rep movsb ; Not q_movs because overlap ?
cld ; C compilator want cld
pop ds
mov si,ax
mov di,dx
mov bp,bx
ret
_bmove_upp ENDP
;
; Append fillchars to string
; Args: dest,len,fill
;
PUBLIC _strappend
_strappend PROC
mov bx,bp
mov dx,di
mov bp,sp
les di,DWORD PTR [bp+4] ; Memory pointer
mov cx,WORD PTR [bp+8] ; Length
sub al,al ; Find end of string
; cld
repne scasb
jnz sa_99 ; String to long, shorten it
mov al,BYTE PTR [bp+10] ; Fillchar
dec di ; Point at end null
inc cx ; rep made one dec for null-char
q_stos ; Store al in string
sa_99: mov BYTE PTR es:[di],0 ; End of string
mov di,dx
mov bp,bx
ret
_strappend ENDP
;
; Find if string contains any char in another string
; Arg: str,set
; Ret: Pointer to first found char in str
;
PUBLIC _strcont
_strcont PROC
mov bx,bp ; Save bp and di in regs
mov dx,di
mov bp,sp
push ds
push si
lds si,DWORD PTR [bp+4] ; str
les di,DWORD PTR [bp+8] ; Set
mov cx,di ; Save for loop
xor ah,ah ; For endtest
jmp sc_60
sc_10: scasb
jz sc_fo ; Found char
sc_20: cmp ah,es:[di] ; Test if null
jnz sc_10 ; Not end of set yet
inc si ; Next char in str
mov di,cx ; es:di = Set
sc_60: mov al,ds:[si] ; Test if this char exist
and al,al
jnz sc_20 ; Not end of string
sub si,si ; Return Null
mov ds,si
sc_fo: mov ax,si ; Char found here
mov di,dx ; Restore
mov dx,ds ; Seg of found char
pop si
pop ds
mov bp,bx
ret
_strcont ENDP
;
; Found end of string
; Arg: str
; ret: Pointer to end null
;
PUBLIC _strend
_strend PROC
mov bx,sp
mov dx,di ; Save
les di,DWORD PTR ss:[bx+4] ; str
mov cx,-1
sub al,al ; Find end of string
; cld
repne scasb
lea ax,WORD PTR [di-1] ; Endpos i DX:AX
mov di,dx ; Restore
mov dx,es
ret
_strend ENDP
;
; Make a string with len fill-chars and endnull
; Args: dest,len,fill
; Ret: dest+len
;
PUBLIC _strfill
_strfill PROC
mov bx,bp ; Save sp
mov bp,sp
push di
les di,DWORD PTR [bp+4] ; Memory pointer
mov cx,WORD PTR [bp+8] ; Length
mov al,BYTE PTR [bp+10] ; Fill
; cld
q_stos
mov BYTE PTR es:[di],0 ; End NULL
mov ax,di ; End i DX:AX
mov dx,es
pop di
mov bp,bx
ret
_strfill ENDP
;
; Find a char in or end of a string
; Arg: str,char
; Ret: pointer to found char or NullS
;
PUBLIC _strcend
_strcend PROC
mov bx,bp ; Save bp and di
mov dx,di
mov bp,sp
les di,DWORD PTR [bp+4] ; str
mov ah,BYTE PTR [bp+8] ; search
xor al,al ; for scasb to find end
@@: cmp ah,es:[di]
jz @F ; Found char
scasb
jnz @B ; Not end
dec di ; Not found, point at end of string
@@: mov ax,di
mov di,dx ; Restore
mov dx,es ; Seg adr
mov bp,bx ; Restore
ret
_strcend ENDP
;
; Test if string has a given suffix
;
PUBLIC _is_prefix
_is_prefix PROC
mov dx,di ; Save di
mov bx,sp ; Arguments through bx
push ds
push si
les di,DWORD PTR ss:[bx+8] ; s2
lds si,DWORD PTR ss:[bx+4] ; s1
mov ax,1 ; Ok and zero-test
; cld ; Work uppward
@@: cmp ah,es:[di]
jz suf_ok ; End of string; found suffix
cmpsb ; Compare strings
jz @B ; Same, possible prefix
xor ax,ax ; Not suffix
suf_ok: pop si
pop ds
mov di,dx
ret
_is_prefix ENDP
;
; Find a substring in string
; Arg: str,search
;
PUBLIC _strstr
_strstr PROC
mov bx,bp
mov bp,sp
push ds
push di
push si
lds si,DWORD PTR [bp+4] ; str
les di,DWORD PTR [bp+8] ; search
mov cx,di
inc cx ; CX = search+1
mov ah,es:[di] ; AH = First char in search
jmp sf_10
sf_00: mov si,dx ; si = Current str-pos
sf_10: mov al,ds:[si] ; Test if this char exist
and al,al
jz sf_90 ; End of string, didn't find search
inc si
cmp al,ah
jnz sf_10 ; Didn't find first char, continue
mov dx,si ; Save str-pos in DX
mov di,cx
sf_20: cmp BYTE PTR es:[di],0
jz sf_fo ; Found substring
cmpsb
jz sf_20 ; Char ok
jmp sf_00 ; Next str-pos
sf_90: sub dx,dx ; Return Null
mov ds,dx
inc dx ; Because of following dec
sf_fo: mov ax,dx ; Char found here
dec ax ; Pointed one after
mov dx,ds
pop si
pop di ; End
pop ds
mov bp,bx
ret
_strstr ENDP
;
; Find a substring in string, return index
; Arg: str,search
;
PUBLIC _strinstr
_strinstr PROC
push bp
mov bp,sp
push di
les di,DWORD PTR [bp+10] ; search
push es
push di
les di,DWORD PTR [bp+6] ; str
push es
push di
call _strstr
mov cx,ax
or cx,dx
jz si_99
sub ax,di ; Pos from start
inc ax ; And first pos = 1
si_99: add sp,8
pop di
pop bp
ret
_strinstr ENDP
;
; Make a string of len length from another string
; Arg: dst,src,length
; ret: end of dst
;
PUBLIC _strmake
_strmake PROC
mov bx,bp
mov bp,sp
push ds
push di
push si
les di,DWORD PTR [bp+4] ; dst
lds si,DWORD PTR [bp+8] ; src
mov cx,WORD PTR [bp+12] ; Length of memory-area
xor al,al ; For test of end-null
jcxz sm_90 ; Nothing to move, put zero at end.
; cld ; Work uppward
@@: cmp al,ds:[si] ; Next char to move
movsb ; move arg
jz sm_99 ; last char, we are ready
loop @B ; Continue moving
sm_90: mov BYTE PTR es:[di],al ; Set end pos
inc di ; Fix that di points at end null
sm_99: dec di ; di points now at end null
mov ax,di ; Ret value in DX:AX
mov dx,es
pop si
pop di
pop ds
mov bp,bx
ret
_strmake ENDP
;
; Find length of string with maxlength
; arg: str,maxlength
; ret: length
;
PUBLIC _strnlen
_strnlen PROC
mov bx,bp
mov bp,sp
push di
les di,DWORD PTR [bp+4] ; Str
mov cx,WORD PTR [bp+8] ; length
mov dx,di ; Save str to calc length
jcxz sn_10 ; Length = 0
xor al,al ; Find end of string
; cld
repne scasb ; Find strend or length
jnz sn_10
dec di ; DI points at last null
sn_10: mov ax,di
sub ax,dx ; Ax = length
pop di
mov bp,bx
ret
_strnlen ENDP
;
; Move a string with max len chars
; arg: dst,src,len
; ret: pos to first null or dst+len
PUBLIC _strnmov
_strnmov PROC
mov bx,bp
mov bp,sp
push ds
push di
push si
les di,DWORD PTR [bp+4] ; dst
lds si,DWORD PTR [bp+8] ; src
mov cx,WORD PTR [bp+12] ; length
jcxz snm_99 ; Nothing to do
xor al,al ; For test of end-null
; cld
@@: cmp al,ds:[si] ; Next char to move
movsb ; move arg
jz snm_20 ; last char, fill with null
loop @B ; Continue moving
inc di ; Point two after last
snm_20: dec di ; Point at first null (or last+1)
snm_99: mov ax,di ; Pointer at last char
mov dx,es ; To-segment
pop si
pop di
pop ds
mov bp,bx ; Restore
ret
_strnmov ENDP
else ; M_I386
include macros.asm
q_stos MACRO ; as rep stosb but quicker, Uses edx
mov ah,al ;(2) Set up a 32 bit pattern.
mov edx,eax ;(2)
shl edx,16 ;(3)
or eax,edx ;(2) EAX has the 32 bit pattern.
mov edx,ecx ;(2) Save the count of bytes.
shr ecx,2 ;(2) Number of dwords.
rep stosd ;(5 + 5n)
mov cl,3 ;(2)
and ecx,edx ;(2) Fill in the remaining odd bytes.
rep stosb ; Move last bytes if any
ENDM
fix_es MACRO fix_cld ; Load ES if neaded
ife ESeqDS
mov ax,ds
mov es,ax
endif
ifnb <fix_cld>
cld
endif
ENDM
;
; Move a memory area
; Args: to,from,length
; Acts as one byte was moved a-time from dst to source.
;
begcode bmove
public _bmove
_bmove proc near
fix_es 1
mov edx,edi
mov eax,esi
mov edi,P-SIZEPTR[esp] ;p1
mov esi,P[esp] ;p2
mov ecx,P+SIZEPTR[esp]
rep movsb ; Not q_movs because overlap ?
mov esi,eax
mov edi,edx
ret
_bmove ENDP
endcode bmove
;
; Move a alligned, not overlapped, by (long) divided memory area
; Args: to,from,length
;
begcode bmove_align
public _bmove_align
_bmove_align proc near
fix_es 1
mov edx,edi
mov eax,esi
mov edi,P-SIZEPTR[esp] ;to
mov esi,P[esp] ;from
mov ecx,P+SIZEPTR[esp] ;length
add cx,3 ;fix if not divisible with long
shr cx,2
rep movsd
mov esi,eax
mov edi,edx
ret
_bmove_align ENDP
endcode bmove_align
;
; Move a string from higher to lower
; Arg from+1,to+1,length
;
begcode bmove_upp
public _bmove_upp
_bmove_upp proc near
fix_es
std ; Work downward
mov edx,edi
mov eax,esi
mov edi,P-SIZEPTR[esp] ;p1
mov esi,P[esp] ;p2
mov ecx,P+SIZEPTR[esp]
dec edi ; Don't move last arg
dec esi
rep movsb ; One byte a time because overlap !
cld ; C compilator wants cld
mov esi,eax
mov edi,edx
ret
_bmove_upp ENDP
endcode bmove_upp
;
; Append fillchars to string
; Args: dest,len,fill
;
begcode strappend
public _strappend
_strappend proc near
push ebp
mov ebp,esp
fix_es 1
push edi
mov edi,P[ebp] ; Memory pointer
mov ecx,P+SIZEPTR[ebp] ; Length
clr eax ; Find end of string
repne scasb
jnz sa_99 ; String to long, shorten it
movzx eax,byte ptr P+(2*SIZEPTR)[ebp] ; Fillchar
dec edi ; Point at end null
inc ecx ; rep made one dec for null-char
q_stos ; Store al in string
sa_99: mov BYTE PTR [edi],0 ; End of string
pop edi
pop ebp
ret
_strappend ENDP
endcode strappend
;
; Find if string contains any char in another string
; Arg: str,set
; Ret: Pointer to first found char in str
;
begcode strcont
PUBLIC _strcont
_strcont proc near
push ebp
mov ebp,esp
fix_es 1
mov edx,edi
push esi
mov esi,P[ebp] ; str
mov ecx,P+SIZEPTR[ebp] ; Set
clr ah ; For endtest
jmps sc_60
sc_10: scasb
jz sc_fo ; Found char
sc_20: cmp ah,[edi] ; Test if null
jnz sc_10 ; Not end of set yet
inc esi ; Next char in str
sc_60: mov edi,ecx ; edi = Set
mov al,[esi] ; Test if this char exist
and al,al
jnz sc_20 ; Not end of string
clr esi ; Return Null
sc_fo: mov eax,esi ; Char found here
mov edi,edx ; Restore
pop esi
pop ebp
ret
_strcont ENDP
endcode strcont
;
; Found end of string
; Arg: str
; ret: Pointer to end null
;
begcode strend
public _strend
_strend proc near
fix_es 1
mov edx,edi ; Save
mov edi,P-SIZEPTR[esp] ; str
clr eax ; Find end of string
mov ecx,eax
dec ecx ; ECX = -1
repne scasb
mov eax,edi
dec eax
mov edi,edx ; Restore
ret
_strend endp
endcode strend
;
; Make a string with len fill-chars and endnull
; Args: dest,len,fill
; Ret: dest+len
;
begcode strfill
public _strfill
_strfill proc near
push ebp
mov ebp,esp
fix_es 1
push edi
mov edi,P[ebp] ; Memory pointer
mov ecx,P+SIZEPTR[ebp] ; Length
movzx eax,byte ptr P+(2*SIZEPTR)[ebp] ; Fill
q_stos
mov BYTE PTR [edi],0 ; End NULL
mov eax,edi ; End i DX:AX
pop edi
pop ebp
ret
_strfill endp
endcode strfill
;
; Find a char in or end of a string
; Arg: str,char
; Ret: pointer to found char or NullS
;
begcode strcend
public _strcend
_strcend proc near
push ebp
mov ebp,esp
fix_es 1
mov edx,edi
mov edi,P[ebp] ; str
mov ah,P+SIZEPTR[ebp] ; search
clr al ; for scasb to find end
@@: cmp ah,[edi]
jz @F ; Found char
scasb
jnz @B ; Not end
dec edi ; Not found, point at end of string
@@: mov eax,edi
mov edi,edx ; Restore
pop ebp
ret
_strcend ENDP
endcode strcend
;
; Test if string has a given suffix
;
begcode is_prefix
public _is_prefix
_is_prefix proc near
fix_es 1
mov edx,edi ; Save edi
mov eax,esi ; Save esi
mov esi,P[esp] ; get suffix
mov edi,P-SIZEPTR[esp] ; s1
push eax ; push esi
mov eax,1 ; Ok and zero-test
@@: cmp ah,[esi]
jz suf_ok ; End of string; found suffix
cmpsb ; Compare strings
jz @B ; Same, possible prefix
xor eax,eax ; Not suffix
suf_ok: pop esi
mov edi,edx
ret
_is_prefix endp
endcode _is_prefix
;
; Find a substring in string
; Arg: str,search
;
begcode strstr
public _strstr
_strstr proc near
push ebp
mov ebp,esp
fix_es 1
push EDI
push ESI
mov esi,P[ebp] ; str
mov edi,P+SIZEPTR[ebp] ; search
mov ecx,edi
inc ecx ; ECX = search+1
mov ah,[edi] ; AH = First char in search
jmps sf_10
sf_00: mov esi,edx ; si = Current str-pos
sf_10: mov al,[esi] ; Test if this char exist
and al,al
jz sf_90 ; End of string, didn't find search
inc esi
cmp al,ah
jnz sf_10 ; Didn't find first char, continue
mov edx,esi ; Save str-pos in EDX
mov edi,ecx
sf_20: cmp BYTE PTR [edi],0
jz sf_fo ; Found substring
cmpsb
jz sf_20 ; Char ok
jmps sf_00 ; Next str-pos
sf_90: mov edx,1 ; Return Null
sf_fo: mov eax,edx ; Char found here
dec eax ; Pointed one after
pop ESI
pop EDI
pop ebp
ret
_strstr endp
endcode strstr
;
; Find a substring in string, return index
; Arg: str,search
;
begcode strinstr
public _strinstr
_strinstr proc near
push ebp
mov ebp,esp
push P+SIZEPTR[ebp] ; search
push P[ebp] ; str
call _strstr
add esp,SIZEPTR*2
or eax,eax
jz si_99 ; Not found, return NULL
sub eax,P[ebp] ; Pos from start
inc eax ; And first pos = 1
si_99: pop ebp
ret
_strinstr endp
endcode strinstr
;
; Make a string of len length from another string
; Arg: dst,src,length
; ret: end of dst
;
begcode strmake
public _strmake
_strmake proc near
push ebp
mov ebp,esp
fix_es 1
push EDI
push ESI
mov edi,P[ebp] ; dst
mov esi,P+SIZEPTR[ebp] ; src
mov ecx,P+SIZEPTR*2[ebp] ; Length of memory-area
clr al ; For test of end-null
jcxz sm_90 ; Nothing to move, put zero at end.
@@: cmp al,[esi] ; Next char to move
movsb ; move arg
jz sm_99 ; last char, we are ready
loop @B ; Continue moving
sm_90: mov BYTE PTR [edi],al ; Set end pos
inc edi ; Fix that di points at end null
sm_99: dec edi ; di points now at end null
mov eax,edi ; Ret value in DX:AX
pop ESI
pop EDI
pop ebp
ret
_strmake ENDP
endcode strmake
;
; Find length of string with maxlength
; arg: str,maxlength
; ret: length
;
begcode strnlen
public _strnlen
_strnlen proc near
push ebp
mov ebp,esp
fix_es 1
push edi
mov edi,P[ebp] ; Str
mov ecx,P+SIZEPTR[ebp] ; length
mov edx,edi ; Save str to calc length
jcxz sn_10 ; Length = 0
clr al ; Find end of string
repne scasb ; Find strend or length
jnz sn_10
dec edi ; DI points at last null
sn_10: mov eax,edi
sub eax,edx ; Ax = length
pop edi
pop ebp
ret
_strnlen ENDP
endcode strnlen
;
; Move a string with max len chars
; arg: dst,src,len
; ret: pos to first null or dst+len
begcode strnmov
public _strnmov
_strnmov PROC near
push ebp
mov ebp,esp
fix_es 1
push EDI
push ESI
mov edi,P[ebp] ; dst
mov esi,P+SIZEPTR[ebp] ; src
mov ecx,P+(SIZEPTR*2)[ebp] ; length
jcxz snm_99 ; Nothing to do
clr al ; For test of end-null
@@: cmp al,[esi] ; Next char to move
movsb ; move arg
jz snm_20 ; last char, fill with null
loop @B ; Continue moving
inc edi ; Point two after last
snm_20: dec edi ; Point at first null (or last+1)
snm_99: mov eax,edi ; Pointer at last char
pop ESI
pop EDI
pop ebp
ret
_strnmov ENDP
endcode strnmov
;
; Zortech has this one in standard library
;
begcode strmov
public _strmov
_strmov proc near
mov ecx,esi ; Save old esi and edi
mov edx,edi
mov esi,P[esp] ; get source pointer (s2)
mov edi,P-SIZEPTR[esp] ; EDI -> s1
fix_es 1
@@: mov al,[esi]
movsb ; move arg
and al,al
jnz @B ; Not last
mov eax,edi
dec eax
mov esi,ecx ; Restore args
mov edi,edx
ret
_strmov endp
endcode strmov
endif ; M_I386
END