; Copyright (C) 2000 MySQL AB & MySQL Finland AB & TCX DataKonsult 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; either ; version 2 of the License, or (at your option) any later version. ; ; 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., 59 Temple Place - Suite 330, Boston, ; MA 02111-1307, 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_allign _bmove_allign 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_allign 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 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_allign public _bmove_allign _bmove_allign 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_allign ENDP endcode bmove_allign ; ; 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