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

Obsah / Utility / TEXTFORM / HexToTextBufN

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

Související:

HexSToTextBuf   Zformátování čísla HEX do bufferu, malá písmena
HexCToTextBuf   Zformátování čísla HEX do bufferu, velká písmena
FormToTextBufN   Délka formátovaného textu

HexToTextBufN - Délka textu formátovaného čísla HEX

Funkce HexToTextBufN zjistí délku formátovaného čísla HEX v bufferu.


; -----------------------------------------------------------------------------
;              Convert HEX number into text buffer - get text length
; -----------------------------------------------------------------------------
; INPUT:	EDX:EAX = number
;		EBX = formatting parameters FORMPAR
; OUTPUT:	EAX = text length
; -----------------------------------------------------------------------------

Na vstupu funkce obsahuje registrový pár EDX:EAX číslo bez znaménka ke konverzi a registr EBX formátovací parametry FORMPAR (ne ukazatel). Na výstupu je navrácena v registru EAX délka textu.


HexToTextBufN:	call	Hex0ToTextBufN	; get text length without spaces
		push	ebx		; push EBX
		movzx	ebx,bh		; EBX <- minimal width of field
		cmp	ebx,eax		; check text length
		jb	HexToTextBufN8	; text length is OK
		xchg	eax,ebx		; EAX <- new text length
HexToTextBufN8:	pop	ebx		; pop EBX
HexToTextBufN9:	ret

Funkce HexToTextBufN volá interní funkci Hex0ToTextBufN, která nezapočítává požadovanou šířku pole. Porovnáním s požadovanou minimální šířkou se ověří, zda je délka textu čísla větší než požadovaná minimální šířka. Pokud je menší, navrátí funkce požadovanou minimální šířku namísto délky textu bez mezer.


; -----------------------------------------------------------------------------
;     Convert HEX number into text buffer - get text length without spaces
; -----------------------------------------------------------------------------
; INPUT:	EDX:EAX = number
;		EBX = formatting parameters FORMPAR
; OUTPUT:	EAX = text length
; -----------------------------------------------------------------------------

Funkce Hex0ToTextBufN zjistí délku textu bez uvažování minimální šířky textu. Na vstupu funkce obsahuje registrový pár EDX:EAX číslo bez znaménka ke konverzi a registr EBX formátovací parametry FORMPAR (ne ukazatel). Na výstupu je navrácena v registru EAX délka textu.


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

Hex0ToTextBufN:	push	edx		; push EDX
		push	esi		; push ESI
		push	edi		; push EDI

; ------------- Push number (for testing HEX sufix) (-> EDI:ESI)

		xchg	eax,esi		; ESI <- number LOW
		mov	edi,edx		; EDI <- number HIGH

Po úschově obsahu registrů EDX, ESI a EDI se navíc uschová dekódované číslo do registrového páru EDI:ESI. Údaj bude potřeba během testu HEX sufixu, který může vyžadovat přidání doplňující nuly na začátek čísla (pokud by číslo nezačínalo znakem číslice).


; ------------- Get number of bits in number LOW (-> AL)

		bsr	eax,esi		; AL <- highest bit in number LOW
		setz	ah		; AH <- 1 if EAX == 0, 0 if EAX != 0
		add	al,1		; AL <- number of bits in number LOW
		dec	ah		; AH <- 0 if EAX == 0, 0ffh if EAX != 0
		and	al,ah		; clear AL if number LOW is zero

; ------------- Get number of bits in number HIGH + 32 (-> DL)

		bsr	edx,edi		; DL <- highest bit in number HIGH
		setz	dh		; DH <- 1 if EDX == 0, 0 if EDX != 0
		add	dl,32+1		; DL <- add HIGH correction
		dec	dh		; DH <- 0 if EDX == 0, 0ffh if EDX != 0
		and	dl,dh		; clear DL if number HIGH is zero

; ------------- Put together HIGH and LOW bits (-> DL)

		not	dh		; DH <- 0ffh if EDX == 0, 0 if EDX != 0
		and	al,dh		; clear AL if number HIGH is not zero
		or	dl,al		; DL <- number of bits in the number

; ------------- Get number of digits in the number (-> EDX)

		movzx	edx,dl		; EDX <- number of bits in the number
		add	dl,3		; round up
		shr	edx,2		; EDX <- number of digits in the number

Pro výpočet počtu číslic HEX čísla je nutné nejdříve zjistit pozici nejvyššího bitu v čísle. Číslo má velikost 2 dvojregistry, proto musí být informace sloučena z obou dvojregistrů.

Nejdříve bude vyhledána pozice nejvyššího bitu v registru ESI, který obsahuje nižší část čísla (LOW). Instrukce BSR uloží do registru EAX bitový offset nejvyššího nalezeného bitu 1. Pokud byl obsah registru ESI nulový, nastaví se příznak ZF. To využije následující instrukce SETZ, která uloží do registru AH hodnotu 1 v případě nulového obsahu čísla, jinak do AH uloží 0. Přičtením 1 k AL se obdrží v registru AL počet bitů původního čísla LOW. Avšak pokud byl obsah čísla LOW nulový, je obsah registru AL nedefinovaný. Proto je AL zamaskován maskou vygenerovanou z příznaku ZF v registru AH. Výsledkem je, že registr AL obsahuje buď počet bitů v původní nižší části čísla nebo nulu pokud byla nižší část čísla nulová.

Podobným způsobem je zjištěn počet bitů ve vyšší části čísla (HIGH) s tím rozdílem, že počet bitů je uložen do registru DL a je o 32 vyšší.

Další operací se údaje z nižší a vyšší části čísla sloučí do jednoho údaje. Pokud bylo číslo větší než DWORD, má maska v registru DH hodnotu 0FFh. Pokud se číslo vešlo do nižšího DWORD, má maska v DH hdnotu 0. Proto inverzí masky v DH a zamaskováním počtu bitů v AL z nižší části čísla se počet bitů vynuluje v případě, že číslo bylo větší než DWORD. Následnou instrukcí OR se údaje sloučí do registru DL, který ve výsledku obsahuje počet bitů v registrovém páru EDX:EAX.

Z počtu bitů se odvodí počet hexadecimálních číslic tak, že se počet bitů zaokrouhlí na nejbližší vyšší násobek 4 a výsledek se vydělí 4 (protože jedna HEX číslice zabere 4 bity) .


; ------------- Leading zero for HEX suffix

		bt	ebx,FORMFLAG_Alt2_b ; use suffix?
		jnc	Hex0ToTextBufN1	; not using suffix
		push	ecx		; push ECX
		mov	cl,dl		; CL <- number of digits
		sub	cl,1		; CL <- index of last digit
		jc	Hex0ToTextBfN03	; no digit, there must be a digit
		shl	cl,2		; CL <- bit offset of last digit
		cmp	cl,32		; QWORD?
		jb	Hex0ToTextBfN02	; only DWORD
		mov	esi,edi		; ESI <- number HIGH
		sub	cl,32		; CL <- offset in number HIGH
Hex0ToTextBfN02:shr	esi,cl		; ESI <- last digit
		cmp	esi,0ah		; is it HEX number or character?
		cmc			; CY <- it is HEX character, add zero
Hex0ToTextBfN03:adc	dl,dh		; add leading zero
Hex0ToTextBfN04:pop	ecx		; pop ECX

Pokud má číslo obsahovat sufix "h", tj. pokud je nastaven příznakový bit FORMFLAG_Alt2_b, je nutno zajistit, aby číslo nezačínalo písmenem "A" až "F". Do registru CL se připraví zjištění počet číslic v čísle a snížením o 1 se zjistí index poslední číslice. V případě podtečení (tj. je 0 číslic) se zajistí, aby číslo obsahovalo alespoň jednu číslici (tedy nulu). Vynásobením počtu číslic 4x se index poslední číslice převede na bitový offset.

Je-li bitový offset 32 a více, jedná se o číslici ve vyšším slově čísla. Do registru ESI (který obsahoval nižší dvojslovo čísla) se uloží vyšší dvojslovo čísla a bitový offset v registru CL se sníží o 32. Nyní se rotací dvojslova čísla (může to být vyšší nebo nižší část čísla) o CL bitů doprava obdrží nejvyšší číslice čísla. Pokud je nejvyšší číslice 10 nebo více, jedná se o písmeno a v tím případě se délka čísla prodlouží o 1 aby se zajistilo doplnění nuly na začátek čísla.


; ------------- Limit minimal number of digits (-> EDX)

Hex0ToTextBufN1:cmp	dl,bl		; check minimal number of digits
		ja	Hex0ToTextBufN2	; number of digits is OK
		mov	dl,bl		; EDX <- minimal numer of digits

Vypočtená délka čísla se zvýší podle požadovaného minimálního počtu číslic (zadaného položkou FORMPAR_Prec formátovacích parametrů).


; ------------- Check if use zeros instead of spaces

Hex0ToTextBufN2:bt	ebx,FORMFLAG_Zero_b ; add zeros instead of spaces?
		jnc	Hex0ToTextBufN6	; no zeros

; ------------- Prepare width of field (-> EAX)

		movzx	eax,bh		; EAX <- minimal width of field
		bt	ebx,FORMFLAG_Alt_b ; use prefix?
		jnc	Hex0ToTextBufN3	; not using prefix
		sub	al,2		; without prefix
		jbe	Hex0ToTextBufN6	; width is low
Hex0ToTextBufN3:bt	ebx,FORMFLAG_Alt2_b ; use suffix?
		jnc	Hex0ToTextBufN4	; not using suffix
		sub	al,1		; without suffix
		jbe	Hex0ToTextBufN6	; width is low

; ------------- Check if use thousand separator

Hex0ToTextBufN4:bt	ebx,FORMFLAG_Thsn_b ; use thousand separator?
		jnc	Hex0ToTextBufN5	; not using thousand separator

; ------------- Number of digits without thousand separators (-> EAX)

		inc	eax		; EAX <- width + 1
		imul	eax,eax,52429	; multiply with 10000h*4/5, round up
		shr	eax,16		; EAX <- max. number of digits

; ------------- New minimal number of digits

Hex0ToTextBufN5:cmp	eax,edx		; check number of digits
		jb	Hex0ToTextBufN6	; number of digits is not greater
		xchg	eax,edx		; EDX <- new text length

Další výpočet musí zajistit doplnění nul k číslu, je-li aktivní příznakový bit FORMFLAG_Zero_b.

Do registru EAX se připraví požadovaná minimální šířka pole (z registru BH, tj. parametr FORMPAR_Width formátovacích parametrů) snížená o případný prefix a sufix. Při malé šířce pole se nuly přidávat nebudou.

Je-li požadován oddělovač řádů (přepínač FORMFLAG_Thsn_b), musí se od počtu znaků odečíst počet oddělovačů. Na 4 číslice připadá 1 znak oddělovače, přičemž před oddělovačem musí být vždy minimálně 1 číslice, proto počet číslic pro danou šířku pole EAX se vypočte inkrementací šířky pole o 1 a vynásobením číslem 4/5.

Po výpočtu počtu číslic potřebných k doplnění čísla nulami se výsledek porovná se skutečnou šířkou čísla a případně se počet číslic zvýší.


; ------------- Add thousand separator

Hex0ToTextBufN6:bt	ebx,FORMFLAG_Thsn_b ; use thousand separator?
		jnc	Hex0ToTextBufN7	; not using thousand separator
		mov	eax,edx		; EAX <- number of digits
		dec	eax		; without 1 digit
		jle	Hex0ToTextBufN7	; no digit
		shr	eax,2		; EAX <- number of separators
		add	edx,eax		; EDX <- add thousand separators

Je-li požadován oddělovač řádů (je nastaven přepínač FORMFLAG_Thsn_b), je potřeba k délce čísla přičíst oddělovače řádů. Na 4 číslice čísla připadá 1 oddělovač řádů, přičemž před oddělovačem musí být minimálně jedna číslice. Proto se počet oddělovačů získá snížením počtu číslic o 1 a vydělením údaje čtyřmi. Vypočtený počet oddělovačů se přičte ke střadači délky textu v registru EDX.


; ------------- Add prefix "0x"

Hex0ToTextBufN7:bt	ebx,FORMFLAG_Alt_b ; use prefix?
		jnc	Hex0ToTextBufN8	; not using prefix
		cmp	edx,byte 1	; check minimal number of digits
		adc	edx,byte 2	; EDX <- add 2 or 3 characters

Je-li požadován prefix "0x" před číslem (je nastaven přepínač FORMFLAG_Alt_b), zvýší se délka textu o 2. Současně je zde zajištěno kontrolou minimálního počtu číslic, aby v případě prefixu mělo číslo alespoň 1 číslici (tj. aby při nule byl text "0x0").


; ------------- Add suffix "h"

Hex0ToTextBufN8:bt	ebx,FORMFLAG_Alt2_b ; use suffix?
		adc	edx,byte 0	; EDX <- add suffix "h"

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

Hex0ToTextBufN9:xchg	eax,edx		; EAX <- text length
		pop	edi		; pop EDI
		pop	esi		; pop ESI
		pop	edx		; pop EDX
		ret

Je-li požadován sufix "h" za číslem (je nastaven přepínač FORMFLAG_Alt2_b), zvýší se délka textu o 1. Aby mělo číslo v tomto případě alespoň jednu číslici bylo zajištěno již na začátku funkce v obsluze úvodní nuly při sufixu.


Obsah / Utility / TEXTFORM / HexToTextBufN