Obsah / Utility / TEXT / TextAddFormat
Zdrojový kód:
INCLUDE\UTIL\TEXT.INC, UTIL\TEXT.ASM
TextAddFormat
- Přidání formátovaného textu na konec textu
Funkce TextAddFormat přidá
formátovaný text na konec textu.
; -----------------------------------------------------------------------------
; Add formated text to end of text
; -----------------------------------------------------------------------------
; INPUT: EAX = pointer to source TEXT variable
; EBX = pointer to destination TEXT variable
; ECX = number of DWORDs in array of arguments (max. 256)
; EDX = pointer to array of arguments
; ESI = pointer to nationality descriptor NATIONAL (NULL=default)
; OUTPUT: CY = memory error or invalid argument index (text not changed)
; -----------------------------------------------------------------------------
; Local variables (ebp+N are read-only variables):
;
; ECX = local variables in stack
%define TFRMSrc ecx+24 ; (4) source TEXT
%define TFRMDst ecx+20 ; (4) destination TEXT
%define TFRMArgN ecx+16 ; (4) number of arguments
%define TFRMArg ecx+12 ; (4) pointer to arguments
%define TFRMNat ecx+8 ; (4) pointer to nationality
|
Na vstupu funkce obsahuje registr EAX
ukazatel na textovou proměnnou obsahující formátovací
řetězec. Registr EBX obsahuje
ukazatel na cílovou proměnnou, do které se zformátovaný text
uloží. Registr ECX obsahuje velikost pole argumentů v
násobcích dvojslov DWORD, registr EDX je ukazatel na pole
argumentů. Registr ESI obsahuje ukazatel na popisovač
národnostních informací NATIONAL. Je-li
ukazatel nulový (tj. obsahuje NULL), použije se implicitní
popisovač národnostních informací. V případě chyby
paměti, nebo pokud je ve formátovacím řetězci použit
neplatný index argumentu, je navrácen chybový příznak CY a
obsah cílové textové proměnné se nezmění.
Funkce používá tyto lokální
proměnné: TFRMSrc ukazatel na textovou proměnnou s
formátovacím řetězcem, TFRMDst ukazatel na cílovou textovou
proměnnou, TFRMArgN velikost pole argumentů, TFRMArg ukazatel
na pole argumentl a TFRMNat ukazatel na popisovač
národnostních informací. Stejné lokální proměnné
využívá i funkce zpětného volání TextAddFormCB (viz dále).
; ------------- Push registers
TextAddFormat: push eax ; push EAX (source TEXT)
push ebx ; push EBX (destination TEXT)
push ecx ; push ECX (number of arguments)
push edx ; push EDX (pointer to arguments)
push esi ; push ESI (pointer to nationality)
push edi ; push EDI
push ebp ; push EBP
mov ecx,esp ; ECX <- local variables
; ------------- Get text length (-> ESI)
mov edx,[eax] ; EDX <- source text data
mov ebx,[edx+TEXT_Length] ; EBX <- size of source text
add edx,TEXT_Text ; EDX <- start of source text
mov ebp,TextAddFormCB ; EBP <- callback function
xchg eax,ecx ; EAX <- callback value,local variables
call FormToTextBufN ; get text length
xchg eax,ecx ; ECX <- local variables
jc TextAddFormat9 ; invalid argument index
|
Po úschově registrů do zásobníku se
zjistí potřebná velikost cílového bufferu voláním funkce
FormToTextBufN, registr EBP přitom obsahuje adresu funkce
zpětného volání TextAddFormCB (viz
dále) a registr EAX hodnotu pro zpětnou funkci, což je
ukazatel na zásobník s lokálními proměnnými. V případě
chybného indexu argumentu se funkce ihned ukončí s chybou.
; ------------- Copy text on write
mov ebx,[TFRMDst] ; EBX <- destination text
call TextCopyWrite ; copy text on write
jc TextAddFormat9 ; memory error
|
Cílová textová proměnná se připraví
pro zápis kopií textu před zápisem pomocí funkce
TextCopyWrite. V případě chyby paměti se funkce ihned
ukončí s příznakem chyby.
; ------------- Resize buffer
mov eax,[ebx] ; EAX <- destination data buffer
mov eax,[eax+TEXT_Length] ; EAX <- length of data buffer
add eax,esi ; EAX <- new text length
call TextResize ; resize data buffer
jc TextAddFormat9 ; memory error
|
Velikost cílového bufferu se změní
podle zjištěné požadované délky pomocí funkce TextResize.
V případě chyby paměti se funkce ihned ukončí s příznakem
chyby.
; ------------- Format text
sub eax,esi ; EAX <- old length of text
add eax,[ebx] ; EAX <- data buffer
add eax,TEXT_Text ; EAX <- start of new text
xchg eax,edi ; EDI <- start of new text
mov edx,[TFRMSrc] ; EDX <- pointer to source variable
mov edx,[edx] ; EDX <- source text data
mov ebx,[edx+TEXT_Length] ; EBX <- size of source text
add edx,TEXT_Text ; EDX <- start of source text
mov ebp,TextAddFormCB ; EBP <- callback function
mov eax,[TFRMNat] ; EAX <- pointer to nationality
or eax,eax ; default nationality?
jnz TextAddFormat6 ; nationality is valid
DEFAULT_NAT eax ; EAX <- get default nationality
TextAddFormat6: xchg eax,ecx ; EAX <- callback value,local variables
call FormToTextBuf ; format text into buffer
; ------------- Pop registers
TextAddFormat9: pop ebp ; pop EBP
pop edi ; pop EDI
pop esi ; pop ESI
pop edx ; pop EDX
pop ecx ; pop ECX
pop ebx ; pop EBX
pop eax ; pop EAX
ret
|
Text se zformátuje pomocí funkce
FormToTextBuf, registr EBP přitom obsahuje adresu funkce
zpětného volání TextAddFormCB (viz
dále), registr EAX hodnotu pro zpětnou funkci, což je ukazatel
na zásobník s lokálními proměnnými a registr ECX ukazatel
na popisovač národnostních informací. Pokud nebyl popisovač
národnostních informací zadán, použije se implicitní
popisovač (makro DEFAULT_NAT).
TextAddFormCB - Funkce
zpětného volání pro formátování textu
Funkce TextAddFormCB je funkce
zpětného volání. Tato funkce je volána zpětně z funkce TextAddFormat a slouží k načtení argumentu ze seznamu
argumentů.
; -----------------------------------------------------------------------------
; Local function - Add formated text to end of text, callback
; -----------------------------------------------------------------------------
; INPUT: EAX = callback value
; EBX = formatting parameters with argument type
; EDX = DWORD index in argument stack (0 to 255)
; OUTPUT: CY=error, invalid argument index (no valid value returned)
; EAX = width or precision parameter
; EDX:EAX integer
; EAX character UNICODE
; ST0 floating point (only if NC)
; EAX pointer to text UTF-8, EDX length of text
; DESTROYS: EBX, ECX, EDX:EAX (if not returning a value)
; NOTES: 64-bit integer or double float takes 2 DWORDs, extended double
; takes 3 DWORDs and other numbers take 1 DWORD. Argument index
; refers to index of DWORD argument, not to real argument number.
; -----------------------------------------------------------------------------
|
Na vstupu funkce obsahuje registr EAX
ukazatel na lokální proměnné v zásobníku funkce
TextAddFormat, registr EBX obsahuje formátovací
parametry a registr EDX index
argumentu v seznamu argumentů. Index argumentu je offset v
násobcích DWORD s rozsahem údaje 0 až 255 (tedy není to
skutečný index argumentu, protože argumenty mohou mít různou
velikost). Pokud byl zadán index argumentu mimo povolený
rozsah, vrací funkce nastavený příznak CY a žádné platné
údaje nejsou vráceny (tj. registry jsou neplatné a v
zásobníku koprocesoru není vrácena žádná hodnota).
Není-li příznak chyby nastaven (tj. je
navrácen příznak NC), obsahují registry EAX, EDX, ST0
návratové hodnoty, v závislosti podle typu argumentu. Parametr
šířky nebo přesnosti je navrácen v registru EAX, celé
číslo v registrovém páru EDX:EAX, znak UNICODE v registru
EAX, desetinné číslo v registru ST0, ukazatel na UTF-8 text v
registru EAX a v registru EDX je délka textu.
Registry EAX, EBX, ECX a EDX jsou funkcí
zničeny, pokud neslouží k navrácení hodnoty z funkce.
V seznamu argumentů zabírají 64.-bitové
celočíselné argumenty a desetinná čísla 2 dvojslova,
rozšířená desetinná čísla 3 dvojslova a ostatní argumenty
1 dvojslovo.
; ------------- Prepare pointer to local variables
TextAddFormCB: xchg eax,ecx ; ECX <- local variables
; ------------- Check argument index and size
call FormGetArgLen ; get argument length -> EAX
add eax,edx ; EAX <- end of arguments
cmp [TFRMArgN],eax ; check index and size of argument
jb TextAddFormCB9 ; invalid argument index or size
|
Do registru ECX se uloží ukazatel na
lokální proměnné v zásobníku z funkce TextAddFormat. Používá se stejný registr (ECX), takže je
možné používat stejné názvy proměnných. Pomocí funkce FormGetArgLen se z formátovacích parametrů v registru EBX
zjistí délka argumentu (ve dvojslovech). Přičtením indexu
požadovaného argumentu v registru EDX se zjistí index konce
argumentu a porovnáním s počtem argumentů se ověří
platnost indexu požadovaného argumentu. V případě
neplatného indexu se funkce ukončí s chybou.
; ------------- Prepare pointer to argument (-> EDX)
shl edx,2 ; EDX <- argument index * 4
add edx,[TFRMArg] ; EDX <- argument address
|
Do registru EDX se připraví ukazatel na
požadovaný argument (proměnná TFRMArg obsahuje ukazatel na
pole argumentů).
; ------------- Prepare argument type (-> AL) and flags (-> AH)
xchg eax,ebx ; EAX <- formatting parameters
shr eax,FORMPAR_TypeF_b ; EAX <- type and flags
and al,FORMTYPE_Mask0 ; AL <- argument type
; ------------- Read width/precision parameter
jnz TextAddFormCB2 ; not parameter
TextAddFormCB1: mov eax,[edx] ; EAX <- get parameter
ret ; return with NC
; ------------- Read single character
TextAddFormCB2: cmp al,FORMTYPE_Char ; single character "c","C"?
je TextAddFormCB1 ; single character
|
Do registru AL se připraví typ argumentu
z registru EBX, který obsahuje formátovací parametry. Pokud
měl typ argumentu hodnotu 0, jedná se o čtení parametru
šířky nebo přesnosti, argument je přímo načten z ukazatele
EDX a funkce je úspěšně ukončena (s vynulovaným příznakem
CF). Stejně tak je argument načten jako 32-bitové číslo v
případě, že argumentem je jeden znak v kódu UNICODE.
; ------------- Read string
cmp al,FORMTYPE_String ; string "s", "S"?
jne TextAddFormCB3
mov eax,[edx] ; EAX <- pointer to text variable
mov eax,[eax] ; EAX <- pointer to text data
mov edx,[eax+TEXT_Length] ; EDX <- length of text
add eax,TEXT_Text ; EAX <- start of text
ret ; return with NC
|
Je-li argumentem textový řetězec, bude
do registru EAX načten ukazatel na proměnnou textového
řetězce TEXT a z ní je načten ukazatel na data textového
řetězce TEXTDATA. Do proměnné EDX je uložena délka textu (v
bajtech) a ukazatel dat v registru EAX je posunu na začátek dat
textu. Funkce navrátí vynulovaný příznak chyby CF.
; ------------- Read integer
TextAddFormCB3: cmp al,FORMTYPE_ArgInt ; integer?
ja TextAddFormCB5 ; not integer
; ------------- Integer 16-bit
test ah,FORMFLAG2_Shrt ; short argument?
jz TextAddFormCB43 ; not short argument
cmp al,FORMTYPE_Int ; signed integer?
jne TextAddFormCB42 ; not signed integer
movsx eax,word [edx] ; EAX <- signed short
TextAddFormCB41:cdq ; EDX:EAX <- signed integer
ret ; return with NC
TextAddFormCB42:movzx eax,word [edx] ; EAX <- unsigned short
cdq ; EDX:EAX <- unsigned integer
clc ; clear error flag
ret ; return with NC
; ------------- Integer 32-bit
TextAddFormCB43:test ah,FORMFLAG2_Long ; long argument?
jnz TextAddFormCB44 ; long argument
cmp al,FORMTYPE_Int ; signed integer?
mov eax,[edx] ; EAX <- load integer
je TextAddFormCB41 ; signed integer
xor edx,edx ; EDX:EAX <- unsigned integer
ret ; return with NC
; ------------- Integer 64-bit
TextAddFormCB44:mov eax,[edx] ; EAX <- integer LOW
mov edx,[edx+4] ; EDX <- integer HIGH
ret ; return with NC
|
Následuje načtení celočíselného
argumentu. Pro neceločíselné argumenty se obsluha přeskočí.
Testem příznaků v registru AH se
rozliší velikost argumentu. Jedná-li se o krátký argument,
bude číslo načítáno jako 16-bitové celé číslo - a to
buď se znaménkem nebo bez znaménka. V obou případech bude
číslo rozšířeno na 64-bitovou hodnotu (v registrovém páru
EDX:EAX) a funkce navrácí vynulovaný příznak chyby CF.
Jedná-li se o dlouhý argument, bude
číslo načteno jako 64-bitové do registrového páru EDX:EAX.
Jinak bude načteno jako 32-bitové a výsledek bude opět
rozšířen na 64-bitovou hodnotu (do registrového páru
EDX:EAX) s rozlišením znaménkového a neznaménkového
čísla.
; ------------- Single float
TextAddFormCB5: test ah,FORMFLAG2_Shrt ; short argument?
jz TextAddFormCB52 ; not short argument
fld dword [edx] ; ST0 <- load single float
ret ; return with NC
; ------------- Double float
TextAddFormCB52:test ah,FORMFLAG2_Long ; long argument?
jnz TextAddFormCB54 ; long argument
fld qword [edx] ; ST0 <- load double float
ret ; return with NC
; ------------- Extended double float
TextAddFormCB54:fld tword [edx] ; ST0 <- load extended double float
TextAddFormCB9: ret ; return with NC
|
Nejedná-li se o celé číslo, bude
argumentem desetinné číslo. Podle příznaků v registru AH se
rozliší velikost argumentu - buď číslo s jednoduchou
přesností (velikost 1 dvojslovo), nebo číslo s dvojnásobnou
přesností (velikost 2 dvojslova) nebo číslo s rozšířenou
přesností (velikost 10 bajtů, zarovnáno na 3 dvojslova).
Funkce opět navrátí vynulovaný příznak chyby CF.
Obsah / Utility / TEXT / TextAddFormat