m4 poznámky
V textu zpracovávaném procesorem m4 se mohou vyskytnout posloupnosti znaků, se kterými m4 zachází speciálně. Konkrétně mám na mysli token poznámka, což je jakýkoliv řetězec ohraničený znakem # a novým řádkem. Název poznámka plně nevystihuje to, co se s takovým textem dělá. Nicméně v manuálech jej takto nazývají, proto já sám nebudu vymýšlet nové názvy. Všechno mezi hraničním znakem # a odřádkováním (včetně) je procesorem ignorováno, ale celá poznámka včetně oddělovačů je poslána na výstup.
Poznámky nemohou být vnořovány, tedy první výskyt konce řádku poznámku ukončí. Chcete-li na výstup dostat znak # bez toho, aby jej m4 pochopil jako začátek poznámky, vložte ho do uvozovek:
define(`makro', `ahoj') => toto je poznámka: # makro makro makro => toto je poznámka: # makro makro makro ale tohle ne: `#' makro makro makro => ale tohle ne: # ahoj ahoj ahoj
Příjemné je, že znaky určující počátek a konec poznámek mohou být změněny použitím vestavěného makra changecom:
changecom([počátek][, konec])
Při psaní HTML stránek se mi osvědčilo nastavení hranic poznámek na tagy <pre> a </pre>:
changecom(`<pre>', `</pre>') => Nové makro se definuje takto: => Nové makro se definuje takto: <pre> => <pre> define(`makro', `ahoj světe') => define(`makro', `ahoj světe') </pre> => </pre>
Pokud v makru changecom neuvedete ukončovací sekvenci, použije se standardně konec řádku. Volání changecom bez parametrů zapříčiní úplné potlačení rozpoznávání poznámek.
Vynechávání konce řádku
V m4 existuje ještě jedna konstrukce, která se zpracovává nestandardním způsobem. Je to makro
dnl
Expanze makra dnl způsobí, že všechny následující znaky až do konce řádku (včetně znaku nového řádku) budou vypuštěny. V podobě makra dnl získáváte další způsob, jak psát do zdrojového textu m4 skutečné poznámky. dnl se také často používá právě pro potlačení znaku nového řádku.
ahoj, dnl pozdrav jak se máš? => ahoj, jak se máš?
Volání makra dnl s argumenty popudí m4 natolik, že vydá varovnou hlášku, všechny parametry přečte, ale neudělá s nimi nic a klasicky vynechá vše až do konce řádku:
tohle se nemá: dnl(arg1, arg2) tohle se vynechá ...pokračování prvního řádku => tohle se nemá: ...pokračování prvního řádku E> stdin:1: m4: Warning: Excess arguments to built-in `dnl' ignored
Změna typu uvozovek
Pokud vám z jakéhokoliv důvodu nevyhovují jako uvozovky jednoduché anglické uvozovky „`“ a „'“, můžete si pomocí vestavěného makra changequote jako uvozovací znaky zvolit něco jiného:
changequote([levá uvozovka][, pravá uvozovka])
Vynecháte-li v makru changequote jakýkoliv argument, použijí se na jeho místě standardní uvozovky „`“ a „'“. Volání changequote bez parametrů proto obnoví původní nastavení.
changequote([, ]) => define([makro], [ahoj]) => `makro' [makro] => `ahoj' makro changequote => `makro' [makro] => makro [ahoj]
Uvozovací řetězce mohou být i víceznakové:
changequote(\[, \]) => define(\[makro\], \[ahoj\]) => `makro' \[makro\] => `ahoj' makro
Jediné omezení, které se na uvozovací řetězce klade, je, že nesmí začínat písmenem nebo znakem podtržítka (_), protože by se pletly s názvy maker. Pokud tak přesto učiníte, mechanizmus uvozování si zablokujete.
Trochu divoce působí třeba následující „uvozovky“:
changequote(\lq, \rq) => define(\lqmakro\rq, \lqahoj\rq) => `makro' \lqmakro\rq => `ahoj' makro
S uvozováním jsou v m4 velké problémy. Dovolil bych si tvrdit, že to je nejslabší místo celého systému. Například jediný způsob, jak uvodit řetězec obsahující samotnou levou uvozovku, je použít makro changequote.
Makro changequote přiřadí nějakým znakům význam uvozovek. Problém ale nastane, pokud changequote použijete až po definici nějakých složitějších maker, ve kterých používáte jiný pár uvozovek. Zavoláním těchto maker začnete rázem dostávat zmatené výstupy a chybová hlášení.
Definice makra je v paměti uložena jako text. Makro procesor neví nic o tom, že na některých místech používáte uvozovky. Význam makra se interpretuje až v okamžiku jeho použití, tzn. že když jste při vytváření makra počítali s uvozovkami ve tvaru `' a pak za uvozovky prohlásíte třeba [], se všemi výskyty jednoduchých anglických uvozovek (narozdíl od hranatých závorek) se začne zacházet jako s obyčejnými znaky…
Vkládání souborů
Ve zdrojovém souboru m4 máte možnost procesor požádat, aby v určitém okamžiku zpracoval nějaký další soubor. Dělá se to vestavěnými makry:
include(název souboru) sinclude(název souboru)
Oba makra způsobí, že m4 začne číst soubor, jehož název jste uvedli v parametru. Po skončení se procesor vrátí zpět ke zpracovávání původního vstupu.
Rozdíl mezi uvedenými dvěma makry je v tom, že include při neexistenci souboru zahlásí chybu, kdežto sinclude jednoduše expanduje na prázdný řetězec:
include(`nic.txt') => E> stdin:1: m4: Cannot open nic.txt: No such file or directory sinclude(`nic.txt') =>
Čtení souboru pochopitelně podléhá expanzi maker. Předpokládejme, že máme soubor incl.m4 s tímto obsahem:
Začátek souboru makro Konec souboru
Použijeme include…:
define(`makro', `ahoj') => include(`incl.m4') => Začátek souboru ahoj Konec souboru
Výhodné je umístit do zvláštních souborů definice maker nebo společné části (např. hlavičky) a tento soubor ve všech zdrojích jenom includovat. (Později se dovíme, že „knihovny“ maker lze do m4 nahrávat efektivněji.)
Kde se vkládané soubory hledají
Zavoláte-li jedno z maker pro vložení souboru a název souboru není absolutní (tedy i s cestou), makro procesor m4 se nejprve podívá do aktuálního adresáře. Jestliže tam soubor nenajde, projde adresáře specifikované pomocí volby -I makro procesoru. Pokud ani tam neuspěje, začne prohledávat adresáře určené proměnnou prostředí M4PATH. Tato proměnná by měla obsahovat dvojtečkou oddělovaný seznam adresářů (podobně jako PATH). Selže-li i tato možnost, v případě makra include se zahlásí chyba.
Pokračování příště.