Hlavní navigace

Makro procesor GNU m4 (10)

Michal Burda

Dnešní díl věnujeme dočasnému ukládání výstupu zpracování textu do paměti pro pozdější použití.

Dočasné přesměrování výstupu do paměti

Podobně, jako si můžete uschovat vstup pro pozdější čtení, si můžete uložit do paměti i výsledky zpracování části souboru s tím, že si sami určíte, kdy je chcete poslat na výstup. Uschovávané texty se ukládají do očíslovaných bufferů v paměti. Pokud nebude mít m4 dostatek místa pro uchování v paměti, začne výstupy ukládat do pomocných souborů. Z toho vyplývá, že počet bufferů je teoreticky limitován jen počtem volných souborových deskriptorů – a takové množství nevyčerpá asi nikdo.

Přesměrování výstupu do bufferu se nastartuje takto:

divert[číslo])

kde číslo je označení bufferu, do kterého chcete výstup odklonit. Pokud číslo vynecháte, implicitně se použije 0, což je vlastně označení standardního výstupu.

Po zpracování celého zdrojového souboru odešle m4 na výstup obsahy všech použitých bufferů v pořadí daném jejich čísly.

   Tohle jde přímo na výstup.
=> Tohle jde přímo na výstup.
   divert(1)
   Tento text je uložen do bufferu číslo 1.
   divert(0)
=>
   A tohle jde už zase přímo na výstup
=> A tohle jde už zase přímo na výstup
   divert(2)
   Naplníme i buffer 2
   divert(3)
   ...a buffer 3.
   divert(0)
=>
   ^D
=>
=> Tento text je uložen do bufferu číslo 1.
=>
=> Naplníme i buffer 2
=>
=> ...a buffer 3.

V ukázce jsme nejprve volali makro divert(1), čímž jsme makro procesoru m4 řekli, že všechno od tohoto místa nemá posílat na výstup, ale uchovávat do paměti do „chlívku“ s označením 1. Použitím makra divert(0) pak dáváme najevo své přání, že vše následující se má psát zase na standardní výstup. Následuje zápis do bufferů 2 a 3. Text uložený v bufferech se na výstup dostane automaticky po přečtení celého vstupního souboru. Aby se ale zapsal na standardní výstup, musíme se na něj před koncem souboru přepnout (divert(0)).

Vícenásobné použití divert na stejný buffer existující text nepřepisuje, nýbrž k němu nové řetězce přidává.

   divert(1)
   text1
   divert
=>
   text2
=> text2
   divert(1)
   text3
   divert
=>
   text4
=> text4
   ^D
=>
=> text1
=>
=> text3

V ukázce už zkušeně píšeme místo divert(0) pouze divert, což je to samé.

K označení bufferů slouží pouze kladná čísla. Jak už víme, číslo 0 je vyhrazeno k označení standardního výstupu a všechna záporná čísla jsou neexistující buffery. Můžete si představit, že jakýkoliv buffer se záporným číslem je napojen přímo na /dev/null – vše, co do něj zapíšete, se ihned zapomene. Taková vlastnost se dá použít k odfiltrování nežádoucích výstupů při zpracování souborů s definicemi maker:

   divert(-1)
   Velice užitečné makro:
   define(`pozdrav', `Ahoj `$1'!')

   Další skvělá věc:
   define(`nesmysl', `sakdljkask')

   ...atd.
   divert
=>
   pozdrav(Jozko)
=> Ahoj Jozko!

A je to. Máme definována všechna makra a přitom nás na výstupu ne neotravují žádná nechtěná odřádkování a podobně. Dokonce si ke každému makru můžeme připsat nějakou poznámku…

Abyste uložený text dostali na výstup, nemusíte čekat na konec vstupního souboru. Buffer může být kdykoliv „ručně“ požádán o zaslání svého obsahu na výstup použitím vestavěného makra undivert:

undivert([číslo], ...)

Jako argumenty makra se uvádějí čísla bufferů, které chcete dostat na výstup. Věc se má tak, že undivertovaný text není znovu makroprocesorem čten (ani není výsledkem expanze), ale je jaksi ihned poslán na aktuální výstup.

Vypsáním textu z bufferu se tento buffer automaticky maže, takže není možné uložený text odeslat na výstup vícekrát než jednou.

   divert(1)
   Tento text ukládáme do prvního bufferu.
   divert
=>
   undivert(1)
=>
=> Tento text ukládáme do prvního bufferu.
=>
   Dvakrát na výstup jej dostat nelze:
=> Dvakrát na výstup jej dostat nelze:
   undivert(1)
=>
   divert(1)
   Tento text putuje do vyprázdněného bufferu 1.
   divert
=>
   undivert(1)
=>
=> Tento text putuje do vyprázdněného bufferu 1.

Pokus přiřadit nějakému makru text uložený v bufferu selže:

   divert(1)
   Nějaký text.
   divert
=>
   define(`makro', undivert(1))
=>
=> Nějaký text.
=>
   makro
=>

Zavoláním undivert se uložený text okamžitě poslal přímo na výstup a makro makro se definovalo na prázdný řetězec.

Pokusy undivertovat aktuálně používaný buffer jsou ignorovány.

Zavoláte-li undivert bez parametrů, odešlou se na výstup uchované texty všech bufferů:

   divert(1)
   Jedna
   divert(3)
   Tři
   divert(2)
   Dvě
   divert
=>
   undivert
=>
=> Jedna
=>
=> Dvě
=>
=> Tři
=>

Makro undivert má ještě jednu vlastnost. Předáte-li mu jako argument jméno souboru, vloží ho nezpracovaný na výstup. Rozdíl mezi undivert s názvem souboru jako parametrem a makrem include je nejlépe vidět na následujícím příkladu. Pro jeho účely předpokládejme, že soubor soubor.txt obsahuje řetězec „makro“:

   define(`makro', `ahoj')
=>
   undivert(`soubor.txt')
=> makro
=>
   include(`soubor.txt')
=> ahoj
=>

Vymazání obsahu bufferu, aniž by se cokoliv vypsalo na výstup, se dělá takto:

   divert(1)
   Nějaký text...
   divert
=>
   Nyní se rozhodneme, že text uložený v bufferu 1 nepotřebujeme.
=> Nyní se rozhodneme, že text uložený v bufferu 1 nepotřebujeme.
   divert(-1)
   undivert(1)
   divert
=>
   A je to...
=> A je to...
   undivert(1)
=>

Zjištění čísla aktuálního bufferu

…provedete pomocí makra

divnum

Příklad:

   divnum
=> 0
   divert(1)
   Jedna: divnum
   divert(2)
   Dvě: divnum
   divert
=>
   undivert
=>
=> jedna: 1
=>
=> dvě: 2
=>

Pokračování příště…

Našli jste v článku chybu?