Tvůrce webu je i pro tebe! Postav třeba web. Bez grafika. Bez kodéra. Hned.
wz

Obsah / Utility / TEXT / TextFindLast, TextFindRev

Zdrojový kód: INCLUDE\UTIL\TEXT.INC, UTIL\TEXT.ASM


TextFindLast, TextFindRev - Vyhledání posledního/předešlého řetězce v textu

Funkce TextFindLast vyhledá v textu poslední výskyt daného textového řetězce. Funkce TextFindRev vyhledá předešlý výskyt textového řetězce od dané pozice v textu (včetně).


; -----------------------------------------------------------------------------
;                      Find text in reverse direction
; -----------------------------------------------------------------------------
; INPUT:	EAX = pointer to TEXT to find
;		EBX = pointer to TEXT where to search
;		EDX = start offset (it can be out of range)
; OUTPUT:	EDX = offset of found text (or EDX = -1 if text not found)
;		CY = text not found (EDX = -1)
; NOTES:	Set EDX to 0 to find first occurrence of the text.
; -----------------------------------------------------------------------------

; ------------- Find last occurrence of the text

TextFindLast:	mov	edx,TEXTBIGPOS	; EDX <- find last occurrence

Na vstupu funkce obsahuje registr EAX ukazatel na textovou proměnnou s hledaným textovým řetězcem. Registr EBX obsahuje ukazatel na textovou proměnnou s textem k prohledání. Registr EDX obsahuje počáteční offset v textu, od kterého bude textový řetězec vyhledáván. V případě funkce TextFindLast je obsah registru EDX nejdříve nastaven na dostatečně vysoké číslo TEXTBIGPOS (hodnota 80000000h) představující ukazatel nastavený za konec textu.

Je-li textový řetězec v textu nalezen, je navrácena v registru EDX pozice (offset) řetězce v textu a příznak CF je vynulován. Není-li textový řetězec nalezen, je v registru EDX navrácena hodnota -1 a je navrácen příznak chyby CY.


; ------------- Push registers 1

TextFindRev:	push	eax		; push EAX
		push	esi		; push ESI
		push	ebp		; push EBP

; ------------- Use faster method

		mov	esi,[eax]	; ESI <- source data buffer
		mov	ebp,[esi+TEXT_Length] ; EBP <- text length
		or	ebp,ebp		; zero length?
		jz	short TextFindRev9 ; zero length, always return NC
		mov	al,[esi+TEXT_Text] ; AL <- first byte
		dec	ebp		; length 1?
		jz	TextFindRev1	; text is one byte long
		mov	ah,[esi+TEXT_Text+1] ; AH <- second byte
		dec	ebp		; length 2?
		jnz	TextFindRev2	; text is too long
		call	TextFindWordRev	; find two bytes
		jmp	short TextFindRev9
TextFindRev1:	call	TextFindByteRev	; find one byte
		jmp	short TextFindRev9

Po úschově první části registrů se funkce pokusí provést hledání zrychleně. Do registru EBP si připraví délku hledaného textu. Pokud má hledaný řetězec nulovou délku, funkce se ihned ukončí s vynulovaným příznakem chyby NC znamenajícím, že nulový řetězec je nalezen vždy. Pro délku řetězce 1 se do registru AL připraví první bajt řetězce a hledání se provede funkcí TextFindByteRev. Pro délku řetězce 2 se do registru AH navíc připraví druhý bajt řetězce a hledání se provede funkcí TextFindWordRev. Jinak se použije pomalé hledání.


; ------------- Push registers 2

TextFindRev2:	push	ebx		; push EBX
		push	ecx		; push ECX
		push	edi		; push EDI

; ------------- Get number of comparisons (-> ECX)

		mov	edi,[ebx]	; EDI <- data buffer
		mov	ecx,[edi+TEXT_Length] ; ECX <- length of text
		sub	ecx,ebp		; ECX <- without text length - 2
		dec	ecx		; ECX <- without first byte

; ------------- Limit maximal offset (-> EDX)

		cmp	edx,ecx		; check maximal offset
		jl	TextFindRev3	; offset is OK
		mov	edx,ecx		; EDX <- text length
		dec	edx		; EDX <- offset of last byte

; ------------- Get text address (-> EDI, ESI)

TextFindRev3:	or	edx,edx		; is offset valid?
		js	short TextFindRev7 ; invalid offset
		lea	edi,[edi+TEXT_Text+edx] ; EDI <- start pointer
		add	esi,TEXT_Text+2	; ESI <- start of text to find

Po úschově druhé části registrů bude omezen maximální počáteční offset v textu (aby neukazoval za konec textu). Do registru ECX se připraví délka textu (v bajtech) snížená o délku hledaného textu a snížená o 1 (což je rezerva pro hledaný text bez prvního znaku). Přesahuje-li pozice v textu konec textu, omezí se pozice na poslední pozici v textu.

Je-li pozice v textu záporná, nebyl řetězec v textu nalezen (nebo text je kratší než řetězec) a funkce se ukončí s navrácením příznaku chyby CY a s hodnotou -1 v registru EDX. Při platném offsetu se do registru EDI připraví ukazatel na první prohledávaný bajt textu a ukazatel ESI se posune na 3. bajt hledaného řetězce.


; ------------- Find begin of data

		mov	ecx,edx		; ECX <- offset
		inc	ecx		; ECX <- number of bytes
TextFindRev32:	std			; set direction down
TextFindRev4:	repne	scasb		; find data
		jne	short TextFindRev6 ; data not found
		cmp	ah,[edi+2]	; check second byte
		jne	TextFindRev4	; text not equal
		cld			; set direction up

Do registru ECX se připraví počet pozic k prohledání - hledá se směrem zpět, proto počet bajtů odpovídá offsetu bajtu zvýšenému o 1. První bajt se vyhledá instrukcí scasb s nastaveným směrem hledání dolů. Pokud nebyl bajt nalezen, funkce se opět ukončí s navrácením příznaku chyby CY a s hodnotou -1 v registru EDX (a současně se nastaví implicitní směr nahoru). Pokud byl první bajt nalezen, otestuje se druhý bajt. Jestliže druhý bajt nesouhlasí, pokračuje se vyhledáváním prvního bajtu od další pozice v textu.


; ------------- Compare rest of text

		push	esi		; push ESI
		push	edi		; push EDI
		mov	ebx,ecx		; EBX <- push ECX

		add	edi,byte 3	; EDI <- start of text
		mov	ecx,ebp		; ECX <- text length - 2
		shr	ecx,2		; ECX <- text length in DWORDs
		repe	cmpsd		; compare texts in DWORDs
		jne	TextFindRev5	; texts not equal
		mov	ecx,ebp		; ECX <- text length
		and	ecx,byte 3	; ECX <- rest of text in last DWORD
		repe	cmpsb		; compare bytes in last DWORD

TextFindRev5:	mov	ecx,ebx		; pop ECX
		pop	edi		; pop EDI
		pop	esi		; pop ESI
		jne	TextFindRev32	; text not equal

V případě nalezení prvních 2 bajtů hledaného řetězce se provede porovnání zbytku řetězce (směr je nyní už nastaven nahoru). Uchovají se ukazatele pozice v textu a porovná se zbytek řezězce - pro zrychlení se porovnání provádí nejdříve po dvojslovech (instrukce cmpsd) a nakonec se porovnají zbylé bajty v posledním dvojslově řetězce. Navrátí se registry a pokud řetězec nesouhlasí, pokračuje se v hledání další pozicí v textu.


; ------------- Get offset of data (here is NC)

		mov	edx,ecx		; EDX <- remaining bytes
		jmp	short TextFindRev8

; ------------- Text not found

TextFindRev6:	cld			; set direction up
TextFindRev7:	xor	edx,edx		; EDX <- 0
		dec	edx		; EDX <- -1, data not found
		stc			; set error flag

; ------------- Pop registers 2

TextFindRev8:	pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	ebx		; pop EBX

; ------------- Pop registers 1

TextFindRev9:	pop	ebp		; pop EBP
		pop	esi		; pop ESI
		pop	eax		; pop EAX
		ret

Je-li řetězec úspěšně nalezen, získá se z čítače ECX pozice nalezeného textu a funkce se ukončí s vynulovaným příznakem chyby NC.


Obsah / Utility / TEXT / TextFindLast, TextFindRev