Makro procesor m4 obsahuje několik vestavěných maker, která umožňují přímo ze zdrojového textu volat příkazy Unixu. Nejjednodušším makrem, které to umožňuje, je syscmd:
syscmd(příkaz shellu)
Makro syscmd vykoná příkaz shellu, který mu předáte jako argument. Výsledkem expanze je prázdný řetězec, ne výsledek příkazu. Výstup a chybová hlášení příkazu nejsou makro procesorem čtena (k tomu slouží jiné makro).
Standardní vstup, výstup a chybový výstup makro procesoru jsou při vykonávání přímo napojeny na spouštěný příkaz.
syscmd(`ls') => Makefile => test.txt => dopis1.m4 => dopis2.m4
Makro syscmd je rozpoznáváno jen s argumenty.
Chcete-li výstup externího programu ještě nějak zpracovávat, použijte místo syscmd makro esyscmd.
esyscmd(příkaz shellu)
esyscmd expanduje na to, co daný příkaz zapíše na svůj standardní výstup. Standardní vstup a standardní chybový vstup příkazu se opět napojí na I/O makro procesoru, což znamená, že zahlásí-li příkaz chybu, nedostanete ji jako výsledek expanze, ale objeví se mezi chybami samotného m4.
define(`dnesni_datum', `esyscmd(`date "+%d. %m. %Y"')') => dnesni_datum => 16. 11. 2001
Rozdíl mezi syscmd a esyscmd je nejlépe vidět na následujícím příkladu:
define(`soubory', sysmd(`ls')) => Makefile => test.txt => dopis1.m4 => dopis2.m4 => soubory => define(`soubory', esysmd(`ls')) => soubory => Makefile => test.txt => dopis1.m4 => dopis2.m4 =>
Upozorňuji, že se snažíme definovat makro makro na seznam souborů v aktuálním adresáři, ne na volání makra sysmd (popř. esysmd).
I esysmd je rozpoznáváno jen s argumenty.
V souvislosti s vykonáváním příkazů Unixu obsahuje m4 ještě jedno vestavěné makro:
sysval
Jeho expanzí je návratový kód posledního externího příkazu vykonaného pomocí syscmd nebo esyscmd.
syscmd(`false') => sysval => 1 syscmd(`true') => sysval => 0
Generování jmen dočasných souborů
Příkazy Unixu mohou požadovat jako své argumenty nějaké dočasné soubory. V makrech procesoru m4 může vyvstat problém, jaká jména pro takové soubory zvolit, aby nedošlo ke kolizi mezi několika uživateli.
m4 obsahuje vestavěné makro maketemp, které generuje jedinečné názvy souborů.
maketemp(template)
Makro maketemp expanduje na název neexistujícího souboru. Název je vytvořen ze zadané šablony, která by měla končit řetězcem XXXXXX. Těchto šest X se nahradí něčím, co název souboru učiní jedinečným.
maketemp(`/tmp/moje_XXXXXX') => /tmp/moje_zc7EU8 maketemp(`/tmp/moje_XXXXXX') => tmp/moje_MEHAkw
Pozor! Znaků X musí být opravdu šest (nebo víc) a musí být na konci! Jinak se nevygeneruje nic.
maketemp(`/tmp/moje_XXX') => maketemp(`/tmp/moje_XXXXXXXXX') => /tmp/moje_XXXFUhUGO maketemp(`/tmp/moje_XXXXXX.txt') =>
Makro maketemp je rozpoznáváno jen s argumenty.
Tisk chybových hlášení
Přímo pomocí volání expanze specializovaných maker můžete makro procesor m4 donutit k tomu, aby na standardní chybový výstup vypsal hlášení o chybě. Asi ani nemusím připomínat, jak je to užitečné při ošetřování nesmyslných vstupů pro vlastní makra. Jednoduše použijte vestavěné makro errprint a chybové hlášení je na světě:
errprint(řetězec, ...)
Makro errprint vypíše hodnoty všech svých parametrů na standardní chybový výstup. Pozor na fakt, že na konec se automaticky NEpřidává znak nového řádku (kromě verze pro BSD) – a tak si musíme pomoci sami:
errprint(`Čtvrtý argument musí být číslo! ') => E> Čtvrtý argument musí být číslo!
Aby chybové hlášení sloužilo ještě lépe, můžete je obohatit informací o jménu souboru a čísle řádku, kde se chyba stala. Vestavěná makra
__file__ __line__
totiž přesně na tyto údaje expandují.
define(`m4nl', ` ') => define(`obycejna_chyba', `errprint(`Chyba:'__file__:__line__:$@`'m4nl)') => Obyčejný text... => Obyčejný text... Pozor, chyba: obycejna_chyba(`Chybička se vloudí') => Pozor, chyba: E> Chyba:stdin:6:Chybička se vloudí Obyčejný text... => Obyčejný text...
Předčasné ukončení m4
Pokud potřebujete ukončit zpracování textu ještě dřív, než bude přečten celý vstup, sáhněte po makru
m4exit([návratový_kód])
Toto makro zapříčiní, že se m4 ihned ukončí a systému předá stanovený návratový kód. Pokud návratový kód neuvedete, použije se 0.
define(`fatalni_chyba', `errprint(`Fatální chyba:'__file__:__line__:$@`'m4nl)m4exit(1)') => Obyčejný text... => Obyčejný text... Pozor, chyba: fatalni_chyba(`Chybička se vloudí') => Pozor, chyba: E> Fatální chyba:stdin:4:Chybička se vloudí
Makro m4exit je určeno jen pro předčasné ukončování zpracování kvůli chybám, protože se neprovádějí akce, které makro procesor vykonává po normálním skončení čtení. Tj. uložený vstup není načítán a uchovaný výstup není odeslán (o co jde, viz později).
Ukládání vstupu pro pozdější zpracování
V makro procesoru m4 je možné nějaký text „odložit“ pro pozdější zpracování, až se vyčerpá veškerý normální vstup.
m4wrap(řetězec, ...)
Text uložený makrem m4wrap si makro procesor m4 uloží a začne ho číst, až narazí na konec svého normálního vstupu. Potom se uchované řetězce začnou zpracovávat (a expandovat), jako by šlo o pokračování vstupu. Tato vlastnost se používá hlavně k zavolání „úklidových“ maker, například pro smazání dočasných souborů a podobně.
define(`uklid', `Nějaká úklidová akce') => m4wrap(`uklid') => Text, text, text, text, text... => Text, text, text, text, text... ^D => Nějaká úklidová akce
(V ukázce řetězec ^D znamená stisk kláves CTRL+D, což, jak jistě víte, má v Unixu význam konce souboru.)
Jak již bylo zmíněno dříve, uložený vstup je na konci čten jen v případě normálního ukončení činnosti makro procesoru. Vynuceným koncem zpracování pomocí m4exit se zpracování uloženého vstupu přeskočí.
Uložené řetězce jsou zpracovávány v opačném pořadí, než v jakém byly registrovány.
m4wrap(`jedna') => m4wrap(`dvě') => m4wrap(`tři') => ^D => třidvějedna
Pokračování příště.