Obsah / Utility / TEXTFORM / FltToTextBuf
Zdrojový kód: INCLUDE\UTIL\TEXTFORM.INC, UTIL\TEXTFORM.ASM
Související:
FltToTextBufN | Délka textu formátovaného desetinného čísla | |
MixSToTextBuf | Zformátování smíšeného desetinného čísla do bufferu, malé "e" | |
MixCToTextBuf | Zformátování smíšeného desetinného čísla do bufferu, velké "E" | |
FormToTextBuf | Zformátování textu do bufferu |
FltToTextBuf - Délka formátovaného textu data a času
Funkce FltToTextBuf zkonvertuje desetinné číslo na text ve formátovaném tvaru bez exponentu.
|
Na vstupu funkce obsahuje registr ST0 desetinné číslo ke konverzi, registr EBX obsahuje formátovací parametry FORMPAR (ne ukazatel), registr ECX ukazatel na popisovač národnostních informací NATIONAL, registr ESI čítač zbylého místa v cílovém bufferu a registr EDI ukazatel do cílového bufferu. Na výstupu z funkce jsou registry ESI a EDI posunuty na novou ukládací pozici. Funkce používá další 2 registry koprocesoru. Vstupní číslo v registru ST0 zůstává zachováno, neuvolňuje se ze zásobníku koprocesoru. K uvolnění čísla z registru ST0 lze použít instrukci "ffreep st0" volanou po ukončení funkce. Funkce předpokládá, že koprocesor je v implicitním nastavení - přesnost 64 bitů, zaokrouhlení k nejbližšímu.
Funkce používá lokální proměnné s bázovým registrem EBP. Proměnné s kladným offsetem (FLTNat) jsou použity jen pro čtení, jejich obsah není modifikován. FLTNat je ukazatel na národnostní informace NATIONAL (vstupní registr ECX). FLTForm jsou formátovací parametry FORMPAR (vstupní registr EBX). FLTLen je délka ukládaného textu. FLTThsnd je čítač k zobrazení oddělovače řádů. FLTDec je čítač k zobrazení oddělovače desetinných míst. FLTIntDig je počet číslic celočíselné části čísla. FLTDigits je celkový počet číslic. FLTDigNum je čítač číslic. FLTSign jsou příznaky - bit 7 označuje záporné znaménko čísla. FLTFloat je desetinné číslo v zásobníku a skládá se z částí FLTMantL - nižší dvojslovo mantisy, FLTMantH - vyšší dvojslovo mantisy a FLTExp - exponent. FLTStack je velikost lokálních proměnných v zásobníku.
|
Makro FLTDECIM uloží oddělovač desetinných míst do výstupního bufferu. Parametrem makra je návěští na které má program přejít, je-li výstupní buffer plný. Makro ničí registr EAX.
Na začátku makro čítá čítač FLTDec. Dosáhne-li nuly, má být oddělovač desetinných míst uložen. Testem příznaku FORMFLAG2_Alt se zjistí, zda má být oddělovač uložen. Pokud ano, načte se znak oddělovače z popisovače národnostních informací a uloží se do výstupního bufferu. Čítáním čítače volného místa ESI se ověří, zda nedošlo k zaplnění výstupního bufferu, pokud ano, funkce se ihned ukončí. Jinak se pokračuje vynulováním čítače k zobrazení oddělovače řádů, čímž se zajistí, že pro následující číslice se již oddělovač řádů nebude používat.
|
Makro FLTTHSND uloží oddělovač řádů do výstupního bufferu. Parametrem makra je návěští na které má program přejít, je-li výstupní buffer plný. Makro ničí registr EAX.
Na začátku makro čítá čítač FLTThsnd. Dosáhne-li nuly, má být oddělovač řádů uložen. Znak oddělovače se načte z popisovače národnostních informací a uloží se do výstupního bufferu. Čítáním čítače volného místa ESI se ověří, zda nedošlo k zaplnění výstupního bufferu, pokud ano, funkce se ihned ukončí. Jinak se pokračuje nastavením čítače na novou hodnotu 3.
|
Na začátku funkce FltToTextBuf je nejdříve proveden test volného místa v cílovém bufferu. Není-li v cílovém bufferu volné místo, funkce se ihned ukončí.
Po úschově registrů se vytvoří v zásobníku místo pro lokální proměnné. Formátovací parametry se uloží z registru EBX do lokální proměnné FLTForm.
|
Nyní se připraví exponent konvertovaného čísla. Číslo se uloží do bufferu v zásobníku FLTFloat (nejdříve se musí zduplikovat, protože není k dispozici instrukce pro uložení čísla v rozšířené přesnosti bez uvolnění čísla ze zásobníku koprocesoru).
Exponent čísla FLTExp se načte do registru EDX. Do proměnné FLTSign se uchová znaménko čísla, současně se vynulují ostatní bity FLTSign.
|
Konvertované číslo se zduplikuje (aby mohlo být modifikováno a přitom zůstalo vstupní číslo uchováno) a převede se na absolutní hodnotu. Vynulováním nejvyššího bitu v registru DX se vynuluje znaménkový bit. Je-li exponent v registru DX nulový, jedná se o speciální případ nuly nebo nenormalizovaného čísla.
|
V případě nulového exponentu se provede test mantisy na nulu. Není-li mantisa nulová, jedná se o nenormalizované číslo (s exponentem menším než přibližně 1e-4931), takové číslo se bude dále zpracovávat běžným způsobem.
Jsou-li exponent i mantisa nulové, jedná se o nulu. Číslo je uvolněno ze zásobníku koprocesoru, do registru EBX je připraven nulový dekadický exponent a přeskočí se část rozdělující číslo na exponent a mantisu. V případě požadavku ořezání koncových nul se omezí přesnost na 0 desetinných číslic.
|
Má-li exponent v registru DX hodnotu 7FFFh, jedná se o další zvláštní případ - nekonečno nebo nedefinované číslo. Číslo se uvolní ze zásobníku koprocesoru, do registru AH (bit 7) se připraví příznak záporného znaménka, do registru ECX se připraví ukazatel na národnostní informace, do registru EDX se připraví ukazatel na buffer čísla v zásobníku a voláním funkce FloatInfNan se dekóduje text speciálního případu do výstupního bufferu. Je-li navrácen příznak ZY, došlo k přetečení výstupního bufferu a funkce se ihned ukončí. Jinak se pokračuje uložením koncových mezer (v registru EAX je navrácena délka textu).
|
Dále bude pokračovat obsluha rozložení čísla na číslice. Pomocí funkce FloatSplit je číslo rozloženo na mantisu a dekadický exponent. Na vstupu funkce je v registru EDX binární exponent čísla, registr ECX ukazuje na buffer čísla v zásobníku a v registru ST0 je absolutní hodnota konvertovaného čísla. Funkce navrací v registru EBX dekadický exponent a v registru ST0 mantisu čísla (normalizovanou do rozsahu 1 včetně až 10 vyjma).
|
Číslo bude pomocí funkce FloatMantBCD zaokrouhleno na poslední číslici a rozloženo na jednotlivé číslice. Před voláním funkce je do registru EAX připravena požadovaná přesnost.
Není-li nastaven příznak FORMFLAG2_Prec, má přesnost význam počtu číslic desetinné části. Přičtením exponentu se obdrží počet zobrazených platných číslic - 1. Podteče-li počet číslic pod 0, číslo leží celé za koncem zobrazené desetinné části, počet číslic se omezí na 0.
Je-li zvolena alternativní přesnost FORMFLAG2_Prec, má přesnost význam počtu významných číslic. Odečtením 1 se provede korekce pro funkci FloatMantBCD (která očekává počet číslic bez první číslice), došlo-li podtečení pod 0, omezí se počet číslic na 0.
Do registru ECX se připraví ukazatel na buffer čísla v zásobníku. Testem příznaku FORMTYPE_Cap_b je funkci předán příznak, zda se má vypnout zaokrouhlování poslední zobrazené číslice. Voláním FloatMantBCD se mantisa převede na BCD číslice.
|
Bude následovat ořezání nevýznamných koncových nul (s využitím funkce FloatTrunc). Do registru EDX se připraví ukazatel na poslední bajt mantisy v BCD tvaru a rozliší se, jakým způsobem má být interpretována požadovaná přesnost.
Je-li nastaven příznakový bit FORMFLAG2_Prec, má přesnost význam počtu významných číslic. Přesnost navrácená funkcí FloatTrunc (tedy počet významných číslic - 1) se použije jako nová požadovaná přesnost k zápisu čísla, tj. počet dekódovaných významných číslic - 1. Odečtením exponentu v registru EBX se obdrží počet číslic desetinné části. Ponechá se v registru ECX a při podtečení pod nulu (tj. číslo je příliš vlevo) se omezí na 0.
Není-li příznakový bit FORMFLAG2_Prec nastaven, má přesnost význam počtu desetinných míst. Není-li požadováno odstranění nevýznamných koncových nul, následující úsek se přeskočí. Jinak se pokračuje přípravou požadované přesnosti do registru EAX. Přičtením exponentu z registru EBX se zjistí vzdálenost první významné číslice od poslední číslice desetinné části. Podteče-li vzdálenost pod nulu, leží číslo za koncem desetinné části a tedy se nezobrazí. V tom případě se nahradí číslem nula bez desetinných míst.
Zavoláním funkce FloatTrunc se zjistí počet významných číslic - 1 (registr ECX). Odečtením exponentu z registru EBX se obdrží skutečný počet číslic desetinné části. V případě podtečení, tj. leží-li číslo příliš vlevo, se omezí na nulu. Do registru EAX se načte požadovaná přesnost a porovná se se skutečnou přesností. Je-li skutečná přesnost nižší, nahradí se jí požadovaná přesnost v proměnné formátovacích parametrů.
|
V další části bude zjištěna délka textu dekódovaného čísla. Do registru ECX se připraví požadovaná přesnost představující počet číslic za desetinnou tečkou. V případě alternativní přesnosti se tato instrukce přeskočí s registrem ECX již připraveným.
Do registru AL se připraví znaménkový bit, do registru AH formátovací příznaky. Je-li znaménkový bit nastaven (bude znaménko "-") nebo je-li nastaven požadavek vynuceného znaménka (bude znaménko "+") nebo je-li nastaven požadavek vynucené mezery, připraví se do registru EAX číslo 1 jako délka textu znaménka, jinak bude obsah registru EAX nulový.
Obsah registru ECX, představující počet číslic za oddělovačem desetinných míst, se uloží do proměnné FLTDigits, kam bude později přičten počet číslic celočíselné části. Není-li počet číslic desetinné části nulový, nastaví se vynuceně příznak požadavku uložení oddělovače desetinných míst. Je-li příznak FORMFLAG_Alt_b nastaven, je požadováno uložení oddělovače desetinných míst, délka textu ve střadači ECX se zvýší o 1. Současně se přičte délka textu znaménka (která může být 0 nebo 1).
|
Délka celočíselné části odpovídá kladné hodnotě exponentu zvýšené o 1. V případě záporného exponentu bude hodnota exponentu omezena na 0. Namísto testu se skokovou instrukcí se použije rychlejší registrová operace. Testem exponentu v registru EBX se zjistí, zda je exponent záporný. Pokud ano, nastavi se obsah registru AL na 1. Pokud ne, bude obsah registru AL nulový.
Dekrementací EAX se připraví do EAX maska, která je nulová v případě záporného exponentu, v případě nezáporného exponentu je 0FFFFFFFFh. Zamaskováním s exponentem v registru EBX se v registru EAX obdrží hodnota exponentu omezená na nulu při záporném exponentu. Po inkrementaci údaje bude registr EAX obsahovat počet číslic celočíselné části.
|
Není-li nastaven příznak FORMFLAG2_Zero, výpočet počtu číslic celočíselné části je hotov a může se přejít k uložení výsledku. Jinak se pokračuje zjištením minimálního počtu číslic vyplývajícího z požadované minimální šířky pole s číslem.
Do registru EDX je načtena požadovaná minimální šířka pole s číslem. Po odečtení délky textu desetinné částí se znaménkem v registru ECX se obdrží zbývající šířka pro celočíselnou část. Dál má smysl pokračovat jen je-li zbývající šířka kladná.
Není-li nastaven příznakový bit FORMFLAG2_Thsnd, nepoužijí se oddělovače řádů a registr EDX již přímo obsahuje počet číslic. Pokud se oddělovače řádů mají použít, je nutno odečíst znaky připadající na oddělovače řádů. Inkrementací šířky pole v registru EDX se provede korekce pro započtení první číslice. Vynásobením číslem 3/4 se v registru EDX obdrží počet číslic bez oddělovačů řádů.
Po výpočtu minimálního počtu číslic celočíselné části, vyžadovaného doplněním nul zleva, se minimální počet číslic porovná se skutečně zjištěným počtem číslic v registru EAX a je-li větší, použije se namísto skutečného počtu číslic.
Zjištěná délka celočíselné části se uloží jednak do proměnné délky celočíselné části FLTIntDig, přičte se k celkovému počtu číslic FLTDigits a nastaví se jí čítač pro zobrazení oddělovače desetinných míst FLTDec.
|
Dále je potřeba připravit čítač k zobrazení oddělovače řádů. Nejsou-li oddělovače řádů požadovány (tj. není nastaven příznak FORMFLAG2_Thsnd), bude čítač k zobrazení oddělovače řádů vynulován a délka textu bude odpovídat součtu délky celočíselné části a desetinné části se znaménkem a oddělovačem destinných míst. Jsou-li oddělovače řádů požadovány, je potřeba zjistit jejich počet z počtu číslic celočíselné části.
Do registru EDX se připraví počet číslic celočíselné části snížený o první číslici, která je vždy vyžadována před prvním oddělovačem. Vydělením počtu číslic třemi se obdrží počet celých skupin číslic po 3 znacích, které budou odpovídat počtu oddělovačů řádů. Namísto operace dělení se použije rychlejší operace násobení převrácenou hodnotou. Výsledek se obdrží v registru EDX a přičtením k registru EAX se opraví údaj délky celočíselné části.
Při přípravě čítače pro první oddělovač řádů se vynásobením počtu oddělovačů čtyřmi obdrží počet znaků v celých skupinách číslic (tj. 1 znak oddělovače a 3 znaky číslic). Odečtením od počtu číslic celočíselné části se obdrží počet číslic před prvním oddělovačem, což je čítač k zobrazení prvního oddělovače.
Zjištěná hodnota čítače k zobrazení prvního oddělovače řádů se uloží do proměnné FLTThsnd. Po sečtení celočíselné a desetinné části se obdrží celková délka textu čísla, která se uloží do proměnné FLTLen a současně do registru EDX.
|
Všechny potřebné informace jsou nyní již k dispozici a proto může být zahájeno dekódování čísla do výstupního bufferu.
Není-li číslo zarovnáno doleva (příznak FORMFLAG1_Left), je nutno před číslo doplnit úvodní mezery. Do registru ECX se připraví z parametru FORMPAR_Width požadovaná šířka pole. Odečtením délky textu z registru EDX se obdrží zbývající šířka pro okraje. Má-li být text centrován, použije se pouze polovina mezer se zaokrouhlením dolů.
V cyklu se ukládají znaky mezer do cílového bufferu. Počet mezer je v registru ECX. Dekrementací registru ESI se ověřuje, zda bude v bufferu místo pro další znak. Pokud čítač ESI dosáhne nuly, dosáhlo se konce cílového bufferu a funkce se ukončí.
|
Před číslo se uloží znaménko. Je-li číslo záporné, uloží se znaménko mínus "-". Je-li znaménko vynucené (příznak FORMFLAG1_Sign), uloží se znaménko plus "+". Má-li být mezera místo kladného znaménka (příznak FORMFLAG1_Space), uloží se znak mezery " ". Jinak se žádný znak neuloží. Pokud čítač ESI volného místa v cílovém bufferu dosáhl nuly, funkce se ihned ukončí.
|
Před první platnou číslici budou uloženy nuly vyžádané buď vyšší šířkou pole (s nastaveným požadavkem uložení nul namísto mezer) nebo nulami před první platnou číslicí (je-li exponent záporný).
Do registru ECX se z proměnné FLTIntDig připraví počet číslic celočíselné části čísla. Odečtením dekadického exponentu z registru EBX a hodnoty 1 pro první číslici zůstane v registru ECX počet nul, které mají být umístěny na začátek čísla. Není-li počet nul kladné číslo, nebude nic uloženo.
Počet nul se odečte od celkového počtu číslic FLDDigits. Pokud došlo k podtečení počtu číslic, celkový počet číslic se vynuluje a opraví se počet nul v registru ECX.
Během ukládání úvodních nul se dekrementací čítače v registru ESI kontroluje volné místo v cílovém bufferu. Pokud nastane zaplnění cílového bufferu, funkce se ihned ukončí.
Po uložení znaku nuly je pomocí makra FLTDECIM uložen znak oddělovače desetinných míst, pomocí makra FLTTHSND uložen znak oddělovače řádů a čítáním registru ECX se pokračuje v ukládání dalšího znaku nuly.
|
Bude následovat dekódování významných číslic mantisy. Do registru EDX se připraví ukazatel na začátek mantisy v zásobníku. Je-li nastaven přepínač FORMFLAG2_Prec, bude počet ukládaných číslic odpovídat údaji přesnosti FORMPAR_Prec zvýšenému o 1.
Není-li příznak nastaven, odpovídá údaj přesnosti počtu číslic za desetinnou tečkou, počet číslic mantisy se tedy obdrží přičtením exponentu. Nebude-li získaný počet číslic kladným číslem, přeskočí se obsluha dekódování mantisy. Počet číslic k dekódování mantisy se omezí na 19 a odečte se od celkového počtu číslic.
|
Při dekódování mantiry se uloží nejdříve číslice z nižší tetrády bajtu mantisy a poté číslice z vyšší tetrády. Během ukládání se sleduje volné místo v cílovém bufferu čítáním registru ESI a pokud dojde k zaplnění cílového bufferu, funkce se ihned ukončí.
Po uložení číslice do bufferu je pomocí makra FLTDECIM uložen oddělovač desetinných míst a pomocí makra FLTTHSND oddělovač řádů. V proměnné FLTDigNum jsou čítány číslice k uložení.
|
Následuje uložení koncových nul. Nuly se uloží v případě, že v proměnné FLTDigits zbývají ještě nějaké neuložené číslice. Pokud během ukládání číslic čítač ESI volného místa v cílovém bufferu dosáhne nuly, funkce se ihned ukončí.
Po uložení nuly do bufferu je pomocí makra FLTDECIM uložen oddělovač desetinných míst a pomocí makra FLTTHSND oddělovač řádů. V registru ECX jsou čítány nuly k uložení.
|
Poslední operací je uložení mezer za koncem čísla. Je-li požadováno použití nul namísto mezer, není potřeba již ukládat žádnou mezeru a funkce se ukončí. Jinak se do registru EAX načte délka textu (bez mezer) a do registru ECX požadovaná šířka pole, odečtením zůstane v registru ECX počet zbývajících mezer. Pokud žádné mezery pro okraje nezbyly, funkce se ukončí.
Je-li nastaven příznakový bit FORMFLAG1_Left, je číslo zarovnáno doleva, ihned se přejde k ukládání mezer za číslo. Není-li tento příznak nastaven a není-li nastaven ani příznakový bit FORMFLAG2_Cent, bylo číslo zarovnáno doprava a mezery tedy již byly uloženy dříve, takže se funkce ukončí. Jinak platí, že číslo je centrováno. Do registru ECX se připraví poloviční počet mezer, ale tentokrát se zaokrouhlí nahoru (aby se zachytila případná lichá mezera).
Následuje ukládání mezer do bufferu. Počet mezer je dán čítačem v registru ECX. Současně se sleduje zbývající volné místo v cílovém bufferu čítáním registru ESI. Pokud dosáhne nuly, bylo dosaženo konce bufferu a smyčka se ukončí.
Obsah / Utility / TEXTFORM / FltToTextBuf