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

Obsah / Utility / TEXT / TextCopyWrite

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


TextCopyWrite - Kopie dat textového řetězce před zápisem (interní funkce)

Funkce TextCopyWrite duplikuje data textového řetězce před změnou textového řetězce v případě, že data textového řetězce vlastní více vlastníků (tj. referenční čítač je větší než 1).


; -----------------------------------------------------------------------------
;                     Copy text data buffer before write
; -----------------------------------------------------------------------------
; INPUT:	EBX = pointer to TEXT
; OUTPUT:	CY = memory error (content of TEXT not changed)
; NOTES:	It duplicates text data if reference counter is > 1.
; -----------------------------------------------------------------------------

Na vstupu funkce obsahuje registr EBX ukazatel na textovou proměnnou TEXT. V případě chyby nedostatku paměti je navrácen příznak chyby CY, v tom případě není obsah proměnné textového řetězce změněn.


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

TextCopyWrite:	push	esi		; push ESI

; ------------- Check reference counter

		mov	esi,[ebx]	; ESI <- address of data buffer
		cmp	dword [esi+TEXT_Ref],byte 1 ; check reference counter
		jne	TextCopyWrite2	; data buffer need to be duplicated

; ------------- Pop registers (here is NC)

		pop	esi		; pop ESI
		ret

Nejdříve je proveden rychlý test, zda data textového řetězce vlastní více vlastníků. Do registru ESI je připraven ukazatel na data textového řetězce a pokud má referenční čítač textového řetězce hodnotu 1, proměnná textového řetězce je jediným vlastníkem dat a není potřeba je před zápisem duplikovat, funkce se může ihned ukončit. Tento text obsáhne i konstantní texty, konstantní text se duplikuje vždy.


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

TextCopyWrite2:	push	eax		; push EAX
		push	ecx		; push ECX
		push	edi		; push EDI

; ------------- Create new data buffer

		mov	eax,[esi+TEXT_Length] ; EAX <- length of data buffer
		call	TextNew		; create new data buffer
		jc	TextCopyWrite6	; memory error

Po úschově registrů je vytvořen nový datový buffer se stejnou délkou textu jako byla původní. Při chybě paměti se funkce ukončí s chybou, obsah textové proměnné přitom zůstává nezměněn.


; ------------- Copy data

		push	esi		; push ESI (old data buffer)
		mov	edi,[ebx]	; EDI <- address of new data buffer
		add	edi,byte TEXTDATA_size ; EDI <- start of text
		add	esi,byte TEXTDATA_size ; ESI <- start of text
		mov	ecx,eax		; ECX <- size of data
		shr	ecx,2		; ECX <- size of data in DWORDs
		rep	movsd		; copy text in DWORDs
		and	eax,byte 3	; EAX <- size in last DWORD
		xchg	eax,ecx		; ECX <- size in last DWORD
		rep	movsb		; copy rest of text
		pop	eax		; pop EAX (old data buffer)

Původní datový buffer bude zkopírován do nového bufferu. Z textové proměnné [EBX] je do registru EDI načten ukazatel na nový datový buffer. Adresa starého (ESI) i nového (EDI) bufferu se posune na začátek textu v bufferu. Do registru ECX se připraví délka textu. Text se zkopíruje nejdříve po násobcích dvojslov a poté se zkopírují zbylé bajty v posledním dvojslově.


; ------------- Detach old data buffer

		cmp	byte [eax+TEXT_Ref+3],CTEXTREFHIGH ; read-only?
		je	TextCopyWrite6	; text string is read only
		LOCKSMP			; CPU instruction lock
		dec	dword [eax+TEXT_Ref] ; decrease reference counter
		jnz	TextCopyWrite4	; counter does not reached zero
		TEXTBUFFREE		; free TEXTDATA
TextCopyWrite4:	clc			; clear error flag

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

TextCopyWrite6:	pop	edi		; pop EDI
		pop	ecx		; pop ECX
		pop	eax		; pop EAX
		pop	esi		; pop ESI
		ret

Nakonec musí být odpojen starý text. Pokud se jednalo o konstantní text (nejvyšší bajt referenčního čítače má hodnotu 80h), referenční čítač nebude měněn a funkce se ukončí. Nejednalo-li se o konstantní text, dekrementuje se referenční čítač dat textového řetězce. Dekrementace se provede s uzamknutím sběrnice procesoru instrukcí LOCK, čímž je ošetřena možnost souběhu více procesorů.

Pokud referenční čítač dosáhl nuly, žádný další vlastník data textového řetězce již nevlastní a proto jsou zrušena pomocí makra TEXTBUFFREE. Tento případ by zdánlivě nemohl nastati, protože kopie při zápisu byla provedena v případě, že textová data vlastnilo více vlastníků. Ve skutečnosti může nastat případ, kdy se jiný vlastník odpojil od dat v průběhu provádění funkce TextCopyWrite, takže se textová proměnná EBX stala jediným vlastníkem.


Obsah / Utility / TEXT / TextCopyWrite