Obsah / Utility / TEXTFORM / FormDateTime
Zdrojový kód: INCLUDE\UTIL\TEXTFORM.INC, UTIL\TEXTFORM.ASM
Související:
Formátovací řetězec funkce FormDateTime | ||
FormDateTimeN | Délka formátovaného textu data a času | |
FormAbsDateTime | Zformátování absolutního času do bufferu |
FormDateTime - Zformátování data a času do bufferu
Funkce FormDateTime zformátuje do bufferu text data a času podle formátovacího řetězce.
|
Na vstupu funkce obsahuje registr EAX ukazatel na strukturu DATETIME s připravenými položkami údaje data a času. Nepoužité položky nemusí být platné. Registr EBX obsahuje délku zdrojového textu v bajtech. Registr ECX obsahuje ukazatel na popisovač národnostních informací NATIONAL. Ke zjištění implicitního popisovače národnostních informací lze použít makro DEFAULT_NAT. Registr EDX obsahuje ukazatel na zdrojový text ke zformátování. Zdrojový text je v kódu UTF-8. Registr ESI obsahuje čítač zbylého místa v cílovém bufferu a registr EDI ukazatel do cílového bufferu. Na výstupu ukazují registry ESI a EDI na novou ukládací pozici.
|
Na začátku funkce jsou uschovány registry do zásobníku a ukazatel na strukturu DATETIME se připraví do registru EBP. Původní obsah registru ECX (tj. ukazatel na národnostní informace NATIONAL) zůstává přístupný přes zásobník jako lokální proměnná FDTNat.
|
Testem registru ESI je ověřeno, zda je v cílovém bufferu volné místo pro další znak. Pokud je cílový buffer plný, funkce se ihned ukončí.
|
Dekrementací registru EBX se ověří, zda je ve zdrojovém bufferu připraven další znak. Pokud ne, funkce se ukončí. Jinak se z ukazatele EDX načte další zdrojový znak a ukazatel se inkrementuje.
|
Interpretace formátovacích znaků data a času závisí na tom, kolik znaků je za sebou uvedeno, proto je nutno spočítat za sebou následující stejné znaky. Čítač ECX se připraví na hodnotu 1 (první znak který byl načten). V cyklu se opakovaně testuje, zda je následující znak stejný jako dříve načtený znak a pokud ano, posunou se ukazatele a zvýší se čítač shodných znaků ECX. Cyklus se ukončí nalezením rozdílného znaku nebo nalezením konce zdrojového textu.
|
Po zjištění počtu znaků se provede skok na obsluhu znaku pomocí skokové tabulky FormDateTimeJmp. Neplatné znaky se uloží opakovaně do bufferu v původním nezměněném tvaru. Během ukládání se dekrementací registru ESI zjišťuje volné místo v cílovém bufferu a pokud dojde k zaplnění cílového bufferu, funkce se ukončí. Registr ECX je čítač znaků k uložení.
|
Znak ":" se nahradí znakem oddělovače času z tabulky národnostních informací a uloží se opakovaně do cílového bufferu.
|
Znak "/" se nahradí znakem oddělovače data z tabulky národnostních informací a uloží se opakovaně do cílového bufferu.
|
Znak "." se nahradí znakem oddělovače desetinných míst z tabulky národnostních informací a uloží se opakovaně do cílového bufferu.
|
Znak "," se nahradí znakem oddělovače řádů tisíců z tabulky národnostních informací a uloží se opakovaně do cílového bufferu.
|
Znak ";" se nahradí znakem oddělovače datových položek z tabulky národnostních informací a uloží se opakovaně do cílového bufferu.
|
Znaky jednoduchých a dvojitých uvozovek ' a " uvozují text, který se do cílového bufferu uloží v nezměněném tvaru. Jsou-li tyto znaky uvedeny opakovaně za sebou, znamenají platný znak. Proto je počet znaků v registru ECX snížen na polovinu. Pokud nezůstal žádný lichý znak uvozovek, šlo pouze o platné znaky a ty se uloží do výstupního bufferu. Pokud zůstal lichý znak, ale přitom byly zadány i platné párové znaky, lichý znak se navrátí (dekódování textu se nechá na později) a uloží se nejdříve pouze párové znaky uvozovek.
V cyklu pro dekódování textu uvnitř uvozovek se testem registru EBX ověří, zda je připraven další znak ve zdrojovém bufferu. Pokud není, funkce se ukončí. Je-li připraven znak, načte se do registru AL a ukazatel EDX a čítač EBX se posunou.
Není-li nový znak shodný se znakem uvozovek (který je uchován v registru AH), uloží se znak do výstupního bufferu. Současně je dekrementací registru ESI ověřeno volné místo v cílovém bufferu. Pokud dojde k zaplnění cílového bufferu, funkce se ukončí.
Pokud byl nalezen znak uvozovek, otestuje se zda je připraven další zdrojový znak. Pokud ne, byl konec textu platný a funkce se ukončí. Je-li připraven další znak, zkontroluje se zda je to opět znak uvozovek. Pokud ano, je to platný znak uvnitř textu a tento znak uvozovek se uloží do cílového bufferu a pokračuje se ve zpracování textu v uvozovkách. Je-li to jiný znak, obsluha textu v uvozovkách je ukončena.
|
Znak "h" označuje hodiny ve 12-hodinovém cyklu. Do registru AL se připraví údaj hodin. Přičtením 11 se údaj dekrementuje (aby mohl být výsledek v rozsahu 1 až 12), instrukcí AAM se převede do intervalu 0 až 11 a inkrementací se převede do intervalu 1 až 12 a přejde se na obsluhu dekódování čísla do bufferu.
|
Znak "H" označuje hodiny ve 24-hodinovém cyklu. Do registru EAX se připraví údaj hodin a přejde se na obsluhu dekódování čísla do bufferu.
|
Znak "d" označuje den v měsíci nebo den v týdnu. Je-li počet znaků "d" 1 nebo 2, jedná se o označení dne v měsíci. Do registru EAX se načte číslo dne v měsíci a přejde se na dekódování čísla do bufferu.
Je-li počet znaků 3, jedná se o označení dne v týdnu v krátkém formátu jmen (3 znaky). Pro větší počet znaků se použije dlouhý formát jmen. Do registru EAX se připraví offset textu ve struktuře národnostních informací a s jeho pomocí se do registru ECX načte ukazatel na textová data s příslušným textem.
Do registru AH se připraví délka textu a registr ECX se posune na začátek textu. Postupně se načítají znaky textu jména dne a ukládají se do výstupního bufferu. Přitom je dekrementací registru ESI kontrolováno volné místo v cílovém bufferu. Pokud dojde k zaplnění cílového bufferu, funkce se ihned ukončí.
|
Znak "a" označuje absolutní den v roce. Do registru EAX se připraví číslo dne v roce a inkrementací se posune na bázi 1. Voláním funkce UDWToTextBuf se číslo zkonvertuje do výstupního bufferu, registr ECX přitom udává minimální počet číslic.
|
Znak "m" označuje minuty. Do registru EAX se připraví údaj minut a přejde se na obsluhu dekódování čísla do bufferu.
|
Znak "M" označuje měsíc. Do registru EAX se připraví údaj měsíce. Je-li počet znaků "M" 1 nebo 2, přejde se na obsluhu dekódování čísla do bufferu.
Do registru AL se připraví offset tabulky jmen měsíců - pro 3 znaky tabulka krátkých jmen (3 znaky), pro 4 znaky tabulka dlouhých jmen ve skloňovaném tvaru pro použití v datu a pro více znaků tabulka jmen v 1. pádu. Poté se přejde na dekódování textu do bufferu, registr ECX obsahuje index textu.
|
Znak "g" představuje označení letopočtu. Pro 1 znak "g" se do registru AL připraví offset krátkého označení letopočtu a pro více znaků offset dlouhého označení letopočtu. Testem absolutního čísla roku se rozliší, zda se jedná o rok našeho letopočtu nebo před naším letopočtem a podle toho je nastaven obsah registru na hodnotu 0 nebo 1. Poté se přejde na dekódování textu do bufferu.
|
Znak "t" představuje označení dopoledne nebo odpoledne. Pro 1 znak "t" se do registru AL připraví offset krátkého označení a pro více znaků offset dlouhého označení. Testem hodiny se rozliší, zda se jedná o dopoledne nebo odpoledne a podle toho je nastaven obsah registru na hodnotu 0 nebo 1. Poté se přejde na dekódování textu do bufferu.
|
Znak "s" označuje sekundy. Do registru EAX se připraví údaj sekund a přejde se na obsluhu dekódování čísla do bufferu.
|
Znak "w" označuje číslo týdne v roce. Do registru EAX se připraví údaj čísla týdne v roce a přejde se na obsluhu dekódování čísla do bufferu.
|
Znak "y" označuje číslo roku v absolutním tvaru (bez rozlišení letopočtu). Do registru EAX se připraví rok a upraví se rok před naším letopočtem na kladný údaj s bází 1.
Jsou-li zadány více než 3 znaky, není číslo nijak upravováno a přejde se přímo na dekódování čísla s tím, že počet znaků udává minimální počet číslic. Pro menší počet znaků je číslo nejdříve upraveno tak, že se použijí jen poslední 3, 2 nebo 1 číslice (souhlasně s počtem znaků).
|
Znak "Y" označuje číslo roku ve znaménkovém tvaru (rok před naším letopočtem má číslo 0, -1, -2, ...). Do registru EAX se připraví rok a údaj se dekóduje pomocí funkce SDWToTextBuf do výstupního bufferu.
|
Znak "f" označuje zlomkovou část sekund bez odstranění koncových nul. Dekódování se provede pomocí funkce FormDateSFrac.
|
Znak "F" označuje zlomkovou část sekund s odstraněním koncových nul. Dekódování se provede pomocí funkce FormDateZFrac.
|
Znak "j" označuje Juliánské datum a čas bez ořezání koncových nul. Počet znaků "j" představuje počet desetinných míst.
Datum a čas ve struktuře DATETIME se pomocí funkce DateTimeToAbs zkonvertuje na absolutní čas v registrovém páru EDX:EAX. Pomocí funkce AbsToJulian se zkonvertuje na Juliánský čas do registru ST0.
Do registru BL se načte požadovaná přesnost, do registru ECX ukazatel na národnostní popisovač (offset "+8" zajistí přeskočení dalších 2 registrů v zásobníku) a údaj se pomocí funkce FltToTextBuf zkonvertuje na text. V registru EBX je přitom nastaven příznak velkého písmene, který zajistí, že číslo se zaokrouhluje vždy dolů. Nakonec se číslo uvolní instrukcí ffreep ze zásobníku koprocesoru.
|
Znak "J" označuje Juliánské datum a čas s ořezáním koncových nul. Počet znaků "J" představuje počet desetinných míst.
Datum a čas ve struktuře DATETIME se pomocí funkce DateTimeToAbs zkonvertuje na absolutní čas v registrovém páru EDX:EAX. Dále se pokračuje společnou částí s obsluhou znaku "j" s tím rozdílem, že parametry v registru EBX zajistí ořezání koncových nul.
|
Funkce FormDateSFrac uloží do výstupního bufferu zlomkovou část sekund bez ořezání koncových nul. Funkce je volána během obsluhy znaku "f". Na vstupu funkce obsahuje registr ECX požadovaný počet číslic, registr EDI cílový buffer a ESI velikost volného místa v cílovém bufferu. Funkce zničí obsah registrů EAX a ECX.
|
Údaj zlomku sekund bude do bufferu ukládán od vyšších číslic, číslic bude maximálně 9. Proto se údaj převede na desetinné číslo a to tak, že se počet nanosekund vydělí číslem 1 000 000 000 (tedy maximálním možným údajem počtu nanosekund, tím se údaj dostane do rozsahu 0 až 0,999999999). Převod se provede vynásobením číslem 1 0000 0000 0000 0000h / 1 000 000 000 (ve 2 oddělených krocích), tím se v registrech EBX:EAX obdrží požadované desetinné číslo.
|
Požadovaný počet číslic se omezí na maximální povolenou hodnotu 9.
|
Číslice se postupně dekódují do výstupního bufferu a to tak, že vynásobením desetinného čísla číslem 10 přeteče přes rozsah QWORD nová číslice, která se uloží do výstupního bufferu. Přitom je dekrementací registru ESI čítáno volné místo v cílovém bufferu. Pokud dojde k zaplnění cílového bufferu, funkce se ukončí.
|
Pokud bylo požadováno více číslic než 9, je nutno ještě doplnit zbývající nevýznamné nuly,. Během ukládání je dekrementací registru ESI čítáno volné místo v cílovém bufferu. Pokud dojde k zaplnění cílového bufferu, funkce se ukončí.
|
Funkce FormDateZFrac uloží do výstupního bufferu zlomkovou část sekund s ořezáním koncových nul. Funkce je volána během obsluhy znaku "F". Na vstupu funkce obsahuje registr ECX požadovaný počet číslic, registr EDI cílový buffer a ESI velikost volného místa v cílovém bufferu. Funkce zničí obsah registrů EAX a ECX.
|
Údaj zlomku sekund bude do bufferu ukládán od vyšších číslic, číslic bude maximálně 9. Proto se údaj převede na desetinné číslo a to tak, že se počet nanosekund vydělí číslem 1 000 000 000 (tedy maximálním možným údajem počtu nanosekund, tím se údaj dostane do rozsahu 0 až 0,999999999). Převod se provede vynásobením číslem 1 0000 0000 0000 0000h / 1 000 000 000 (ve 2 oddělených krocích), tím se v registrech EBX:EAX obdrží požadované desetinné číslo.
|
Požadovaný počet číslic se omezí na maximální povolenou hodnotu 9 a uschová se do registru EBP.
|
Číslice se postupně dekódují do výstupního bufferu a to tak, že vynásobením desetinného čísla číslem 10 přeteče přes rozsah QWORD nová číslice, která se uloží do výstupního bufferu. Přitom je dekrementací registru ESI čítáno volné místo v cílovém bufferu. Pokud dojde k zaplnění cílového bufferu, funkce se ukončí.
Ořezání koncových nul je zajištěno tak, že vyskytne-li se v čísle nula, ukládání číslice se přeskočí a pouze dochází k dekrementaci čítače číslic ECX.
Vyskytne-li se v čísle nenulová číslice, je porovnáním registru EBP a ECX zjištěno, zda byly nějaké nulové číslice přeskočeny. Pokud ne, číslice se uloží běžným způsobem. Kromě čítače ECX je současně posouván i čítač v EBP a testováno volné místo v cílovém bufferu dekrementací registru ESI. Dojde-li k přetečení cílového bufferu, funkce se ukončí.
Pokud nejsou registry EBP a ECX shodné, byly přeskočeny nějaké nuly a proto budou nejdříve uloženy. Ukládání probíhá tak dlouho, dokud se čítače v registrech ECX a EBP opět nevyrovnají. Současně je dekrementací registru ESI kontrolování volné místo v cílovém bufferu a v případě přetečení je funkce ukončena.
Obsah / Utility / TEXTFORM / FormDateTime