summaryrefslogtreecommitdiff
path: root/Master/texmf-dist/doc/cstex/opmac-d.tex
diff options
context:
space:
mode:
authorKarl Berry <karl@freefriends.org>2012-12-21 17:17:30 +0000
committerKarl Berry <karl@freefriends.org>2012-12-21 17:17:30 +0000
commit2257828845c52e3a8b6becfa850d1eafdf6f20e5 (patch)
treee2b67b1c091e49fe54a1a551823339974ca31410 /Master/texmf-dist/doc/cstex/opmac-d.tex
parent99eb8d14f7469f1d9a1c7edc39c573ccaa36dc44 (diff)
new doc package cstex (20dec12)
git-svn-id: svn://tug.org/texlive/trunk@28595 c570f23f-e606-0410-a88d-b1316a301751
Diffstat (limited to 'Master/texmf-dist/doc/cstex/opmac-d.tex')
-rw-r--r--Master/texmf-dist/doc/cstex/opmac-d.tex2170
1 files changed, 2170 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/cstex/opmac-d.tex b/Master/texmf-dist/doc/cstex/opmac-d.tex
new file mode 100644
index 00000000000..95d241e0f0a
--- /dev/null
+++ b/Master/texmf-dist/doc/cstex/opmac-d.tex
@@ -0,0 +1,2170 @@
+%% OPmac -- Olsak's PlainTeX macros
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+% Tech-documentation, Petr Olsak, 2012
+
+\input utf8off \clearmubyte
+
+% This file is encoded in ISO-8859-2 because
+% UTF-8 encTeX has a conflict with DocByTeX
+
+\def\projectversion{Dec. 2012}
+\def\headtitle{OPmac}
+
+\widowpenalty=10000
+\clubpenalty=10000
+
+\emergencystretch=2em
+\hbadness=2200
+
+\showboxbreadth=1500 \showboxdepth=2
+
+\def\csplain{\CS plain}
+\def\CS{CS}
+
+\input docby.tex
+
+\setlinecomment{\percent} \noactive{\nb\percent} \noactive{\percent\cbrace}
+\noactive{\nb fontdimen}
+
+\title OPmac -- rozšiřující makra plain\TeX{}u
+
+\author Petr Olšák
+
+\centerline{\ulink[http://www.olsak.net/opmac.html]%
+ {www.olsak.net/opmac.html}}
+
+\def\db{\dg\nb}
+\def\du#1{\api{\nb#1}}
+\let\quotehook=\langleactive
+\def\insdef#1 {\ifirst{docby.tex}{def\nb#1 }{^^B\cbrace}{++}}
+\def\inssdef#1 {\ifirst{docby.tex}{def\nb#1}{\empty}{+-}}
+\bgroup
+ \catcode`\[=1 \catcode`]=2 \catcode`\{=12 \catcode`\}=12
+ \gdef\obrace[{] \gdef\cbrace[}]
+\egroup
+\def\indexhook{%
+% Kontrolní sekvence označené šipkou ($\succ$) jsou
+% uživatelskými příkazy. Ostatní kontrolní sekvence jsou
+% v~OPmac interní.
+ Tučně je označena strana, kde je slovo
+ dokumentováno, pak následuje seznam všech stran, na kterých se slovo
+ vyskytuje.
+% Uživatelské příkazy mají v seznamu stránek podtržené číslo,
+% což je stránka, kde je příkaz vyložen na uživatelské úrovni.
+ \medskip}
+\def\nn#1 {\noactive{\nb#1}} \nn insert \nn undefined
+
+\def\cnvbookmark#1{\lowercase{\lowercase{#1}}}
+\def\bookmarkshook{\lo ěe \lo šs \lo čc \lo řr \lo žz \lo ýy
+ \lo áa \lo íi \lo ée \lo úu \lo ůu \lo óo \lo ňn }
+\def\lo #1#2{\lccode`#1=`#2}
+
+
+\dotoc \bookmarks
+
+\sec Úvod
+%%%%%%%%%
+
+OPmac je balík jednoduchých doplňujících maker k plain\TeX{}u umožňující
+uživatelům základní La\TeX{}ovou funkcionalitu: změny velikosti písma,
+automatickou tvorbu obsahu a rejstříku, práci s {\tt bib} databázemi,
+referencemi, možnost proložení referencí hyperlinkovými odkazy atd.
+
+
+\sec Uživatelská dokumentace
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Uživatelská dokumentace je zatím v souboru "opmac-u.tex" a "opmac-u.pdf".
+Do tohoto místa ji zahrnu později a prolinkuji ji s technickou dokumentací.
+
+
+\sec Technická dokumentace
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Tato část dokumentace je určena pro tvůrce maker, kteří se chtějí zde
+uvedenými makry inspirovat a případně je přizpůsobit svému požadavku.
+Předpokládá se znalost \TeX{}u, tj. například aspoň zběžná orientace
+v~\TeX{}booku naruby. Na tuto knihu je na mnoha místech odkazováno pod
+zkratkou TBN.
+
+
+\subsec Základní makra
+%%%%%%%%%%%%%%%%%%%%%%
+
+Na začátku souboru "opmac.tex" zjistíme, zda není soubor čtený podruhé. V
+takovém případě čtení odmítneme. Ptáme se na to, zda je definováno makro \db
+OPmacversion, které vzápětí definujeme. Je-li někdo překvapen, proč jsem
+nepoužil "\expandafter\endpinput\fi", může si prostudovat TBN, stranu~358,
+heslo "\endinput".
+
+\ifirst {opmac.tex}{OPmacversion}{\empty}{+-}
+
+Dva pracovní registry:
+\dgn \nb tmpnum
+\dgn \nb tmpdim
+
+\inext {newcount}{\empty}{+-}
+
+OPmac nebude nikdy hlásit chyby. Často ale bude psát pomocí \db opwarning
+na terminál varování.
+
+\inext {warning}{\empty}{+-}
+
+Makro \db addto "<makro>{<tokeny>}" přidá na konec "<makra>" dané "<tokeny>".
+
+\inext {addto}{\empty}{+-}
+
+V OPmac budeme pracovat se seznamem \db protectlist, který bude obsahovat
+makra, jež chceme mít tzv. robustní, tj. chceme, aby se při "\write" v output
+rutině neexpandovala. Každému makru v~seznamu předchází "\doprotect", takže
+seznam "\protectlist" vypadá takto:
+
+\def\begtthook{\langleactive}
+\begtt
+\doprotect<makro1> \doprotect<makro2> ...
+\endtt
+
+\def\begtthook{}
+Seznam budeme spouštět v output rutině s tím, že "\doprotect" tam bude mít
+význam makra, které zařídí, aby jeho parametr získal význam "\relax".
+Tím bude zabráněno jeho expanzi.
+Naprogramujeme \db addprotect "<makro>", které zařídí vložení "<makra>" do seznamu.
+
+\inext {protectlist}{\empty}{+-}
+
+Některá makra budou fungovat jen v pdf\TeX{}u při nastaveném "\pdfoutput=1".
+Připravíme si tedy test \db ifpdftex, který pak použijeme při čtení souboru
+"opmac.tex". Test nikdy nebudeme vkládat do maker, takže při čtení souboru
+"opmac.tex" už musí být jasné, zda bude výstup směrován do DVI nebo PDF.
+Pozdější změna "\pdfoutput" může způsobit potíže.
+
+\inext {ifpdftex}{\empty}{+-}
+
+Makra \db sdef a \db sxdef umožňují pohodlně definovat kontrolní sekvence
+ohraničené pomocí "\csname...\endcsname".
+
+\inext {sdef}{\empty}{+-}
+
+Makro \db adef umožní nastavit znak na aktivní a rovnou ho definovat, což
+normálně uvnitř maker není jednoduché (TBN str. 25 a 26).
+Využijeme toho, že "~" je aktivní znak a pomocí
+"\lccode" a "\lowercase" jej přepíšeme na požadovaný znak. Dostaneme tím
+aktivní token s požadovanou ASCII hodnotou a tento token definujeme.
+Pomocí \db lccodetiezero vrátíme po přiřazení (tj. po provedení definice)
+"\lccode" vlnky na původní hodnotu.
+
+\inext {adef}{\empty}{+-}
+
+Makrem \db isdefined "{<jméno>}\iftrue" se ptáme, zda je definovaná
+"\csname<jméno>\endcsname". To závěrečné připojené "\iftrue" makro sežere,
+ale uživatel ho píše zejména z toho důvodu, aby mu tato konstrukce fungovala
+uvnitř vnořených "\if..\fi"
+
+\inext {isdefined}{^^B\cbrace}{++}
+
+Makro \db isinlist "<list>{<tokeny>}\iftrue" zjistí, zda "<tokeny>" jsou
+(jako string) obsaženy v~makru "<list>". Přitom sežere "\iftrue" ze stejných
+důvodů, jak je uvedeno před chvílí.
+
+\inext {isinlist}{^^B\cbrace}{++}
+
+Makro \db isnextchar "<znak>{<co dělat při ano>}{<co dělat při ne>}"
+pracuje poněkud odlišně od předchozích maker. Zjistí, zda následující znak
+je "<znak>" a pokud ano, vykoná vnitřek první závorky, jinak vykoná vnitřek
+druhé závorky. Pomocí "\futurelet" uloží zkoumaný znak do "\next" a spustí
+\db isnextcharA.
+
+\inext {isnextchar}{\empty}{+-}
+
+Předefinujeme makro \db uv z \csplain{}u. Tam je toto makro navrženo tak, aby
+mohlo mít za svůj parametr verbatim text. Důsledkem toho nefunguje správně
+kerning. Považuji za lepší mít správně kerning a případné uvozování verbatim
+textů řešit třeba pomocí "\clqq...\crqq".
+
+\inext {def\nb uv}{}{+-}
+
+Knuth v souboru "plain.tex" zanechal řídicí sekvenci "\\" v provizorním stavu
+(cvičení: podívejte se v jakém). Domnívám se, že je lepší ji dát jednoznačný
+význam "\undefined". Některým uživatelům totiž může OPmac připomínat
+La\TeX{} a není tedy vyloučeno, že je napadne psát "\\". Měli by na to
+dostat jednoznačnou odpověď: {\tt undefined control sequence}.
+
+\inext {undefined}{}{+-}
+
+Do pracovního souboru určeného k novému načtení budeme chtít vložit
+komentáře za znakem procento. K tomu potřebujeme mít procento jako obyčejný
+znak kategorie 12. Na tento znak se v našem kódu překlopí otazník, Takže
+\db percent expanduje na znak procento s kategorií 12.
+
+\inext {percent}{}{+-}
+
+Makro plain\TeX{}u "\,"
+funguje jen v matematické sazbě. Uživatel bude chtít makro často
+použít například mezi číslem a jednotkou v textovém módu: "5\,mm", takže
+makro předefinujeme.
+
+\inext {kern}{}{+-}
+
+
+\subsec Globální parametry
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Zakážeme vdovy a sirotky a dále nastavíme registry pro listingy tiskového
+materiálu na smysluplnější hodnoty, než jsou implicitní.
+
+\inext {widowpenalty}{\empty}{+-}
+
+Následující makra a registry ovlivní chování klíčových maker OPmac způsobem,
+jak je popsáno v~komentářích. Mnohé z těchto maker a registrů byly zmíněny v
+uživatelské dokumentaci.
+\dgn \nb iindent
+\dgn \nb ttindent
+\dgn \nb ttskip
+\dgn \nb ttpenalty
+\dgn \nb tthook
+\dgn \nb intthook
+\dgn \nb iiskip
+\dgn \nb bibskip
+\dgn \nb tabstrut
+\dgn \nb tabiteml
+\dgn \nb tabitemr
+\dgn \nb vvkern
+\dgn \nb hhkern
+\dgn \nb multiskip
+\dgn \nb colsep
+\dgn \nb mnoteindent
+\dgn \nb mnotesize
+\dgn \nb picdir
+\dgn \nb bibtexhook
+\dgn \nb chaphook
+\dgn \nb sechook
+\dgn \nb secchook
+\dgn \nb cnvhook
+\dgn \nb pghook
+
+\inext {newdimen}{\count=7 \empty}{+-}
+
+
+
+\subsec Loga
+%%%%%%%%%%%%
+
+V logu \db OPmac je pomocí "\thefontscale" zvětšeno písmeno O. Logo \db CS je
+přepsáno beze změny z CS\TeX{}u. Tím snadno vytvoříme i logo \db csplain.
+
+\inext {def\nb OPmac}{\empty}{+-}
+
+Troufám si tvrdit, že logo \db LaTeX (ačkoli je plain\TeX{}isté asi moc
+nebudou potřebovat) je v~následujícím kódu daleko lépe řešeno, než v
+samotném La\TeX{}u. Počítá totiž ve spolupráci s makrem \db slantcorr
+i se sklonem písma při usazování zmenšeného A.
+
+\inext {LaTeX}{\empty}{+-}
+
+Loga se občas mohou vyskytnout v nadpisech. Zabezpečíme je tedy proti
+rozboření při zápisu do REF souboru.
+
+\inext {addprotect}{\empty}{+-}
+
+
+\subsec Velikosti fontů, řádkování
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+\csplain{} od verze "<Nov. 2012>" definuje makro
+\db resizefont "<fontselector>", které změní
+velikost fontu daného svým přepínačem a tento změněný font si ponechá
+stejný přepínač. Změna velikosti je dána obsahem makra \db sizespec.
+Tam může být například napsáno "at13pt" nebo "scaled800".
+Dále CSplain definuje makro
+\db resizeall, které změní velikost
+fontů s registrovanými přepínači. Registrování se provádí makrem
+\db regfont. Implicitně jsou registrovány přepínače
+ "\tenrm", "\tenit", "\tenbf", "\tenbi", a "\tentt".
+Do nových velikostí tedy půjdeme se starými názvy přepínačů
+"\ten<něco>" a to slovo "ten" budeme chápat jen jako historický relikt,
+který nám ovšem napoví, že kontrolní sekvence je fontovým přepínačem.
+
+OPmac si zjistí, zda je definovaný "\regfont". Pokud ne, upozorní na starou
+verzi \csplain{}u na terminálu a potřebná makra si definuje. Je to kopie
+kódu ze souboru "csfontsm.tex" z balíčku \csplain{}.
+
+\inext {regfont}{\empty}{+-}
+
+Implicitně jsou zavedeny \CS{}fonty, takže k nim přidáme AMS fonty z
+"ams-math.tex", které vizuálně odpovídají. Později si může uživatel zavést
+jiné makro (např. "tx-math.tex") a zavede si třeba i jiné textové fonty. To nezmění
+vlastnosti maker v OPmac, pokud nové soubory maker správně předefinují
+makra "\setmathsizes[<text>/<script>/<scriptscript>]", "\normalmath" a
+"\boldmath".
+
+\inext {ams-math}{\empty}{+-}
+
+Po načtení souboru ams-math disponujeme makry \db regtfm na registraci
+různých metrik pro různé designované velikosti fontů a \db whichtfm, které
+expanduje na svůj parametr nebo na metriku, která je registrována pro
+velikost \db dgsize. Registrace metrik \CS{}fontů je rovněž provedena
+v souboru {\tt ams-math.tex}. Jak bylo řečeno,
+makro "\resizefont<fontselector>" \csplain{}u změní
+velikost fontu "<fontselector>" podle obsahu makra "\sizespec" (viz soubor
+{\tt csfontsm.tex}). Toto makro "\resizefont" volá pomocné makro \db
+resizefontskipat na odstranění \uv{sizespec} z názvu metriky. Toto pomocné
+makro je v OPmac předefinováno s využitím "\whichtfm", takže když před
+voláním makra "\resizefont" připravíme správnou "\dgsize", \TeX{} použije
+metriku designovanou na požadovanou velikost:
+
+\inext {resizefontskip}{\empty}{+-}
+
+Makra "\typosize", "\fontsizex", "\textfontsize",
+"\setbaselineskip" požadují zápis parametru bez jednotky.
+Jednotkou je \db ptunit, která je nastavena na 1pt. Uživatel může
+jednotku změnit (např. "\ptunit=1mm" při návrhu plakátu). Dále \db fontdim
+je registr, který udává aktuální velikost písma.
+
+\inext {ptunit}{\empty}{+-}
+
+Často budeme potřebovat odstranit jednotku "pt" ve výpisu "\the<dimen>".
+Provedeme to pomocí "\expandafter\ignorept\the<dimen>". Protože "\the"
+vyrábí znaky pt s kategorií 12, je makro \db ignorept definováno trikem přes
+"\lowercase". Z otazníku vznikne p kategorie 12 a z vykřičníku vznikne t.
+
+\inext {lccode}{\empty}{+-}
+
+Makra \db typosize a \db typoscale změní velikosti a nastavují
+výchozí font "\tenrm" a výchozí
+matematiku "\normalmath". Nehrajeme si na OFS nebo NFSS, které se snaží ctít
+naposledy nastavený duktus a variantu. Uživatel si variantu písma a tučný
+duktus pro matematiku musí nastavit až po zavolání makra na změnu velikosti fontu.
+
+\inext {typosize}{\empty}{+-}
+
+Makro \db fontsizex "[<velikost>]" předpokládá svůj parametr bez jednotky.
+Písmeno x v názvu značí, že makro není v uživatelské dokumentaci. Uživatel
+totiž může použít "\typosize[<velikost>/]" a třeba ho napadne si nějaké
+vlastní makro "\fontsize" definovat.
+Je-li parametr "<velikost>" prázdný, makro "\fontsizex" neudělá nic.
+Jinak pomocí "\textfontsize" nastaví
+velikost textových fontů. Dále zavolá
+"\setmathsizes[\fontsize/.7\fontsize/.5\fontsize]", ovšem v parametru musí
+odstranit jednotky a parametr přichystá pro makro "\setmathsizes"
+expandovaný. Příkazem "\normalmath" nakonec nastaví matematické fonty do
+nové velikosti.
+
+\inext {fontsizex}{^^B\cbrace}{++}
+
+Makro \db textfontsize "[<velikost>]" předpokládá svůj parametr bez
+jednotky. Připojí jednotku "\ptunit", nastaví "\dgsize" a "\sizespec" a
+zavolá "\resizeall", což je makro definované v \csplain{}u, které postupně
+volá "\resizefont" na všechny registrované fonty.
+
+\inext {textfontsize}{^^B\cbrace}{++}
+
+Makro \db setbaselineskip "[<velikost>]" předpokládá parametr bez jednotky.
+Připojí jednotku "\ptunit" a nastaví "\baselineskip" bez dodatečné
+pružnosti. Nastaví další registry, které s "\baselineskip" souvisejí.
+Záměrně není nastavena "\topskip", "\splittopskip",
+"\above/belowdisplayskip". Tyto parametry (globální pro celý dokument) by si
+měl uživatel nastavit sám.
+
+\inext {setbaselineskip}{^^B\cbrace}{++}
+
+Makro \db withoutunit "\makro<dimen>" odstraní jednotku z "<dimen>" a takto
+upravené číslo vloží do parametru "\makro", které očekává údaj bez jednotky
+v~hranaté závorce.
+
+\inext {withoutunit}{\empty}{+-}
+
+Makra \db fontscalex "<factor>", \db textfontscale "<factor>" a
+\db scalebaselineskip "<factor>"
+přepočítají "<factor>" podle aktuálního "\fontdim" resp. "\baselineskip"
+na absolutní jednotku a zavolají odpovídající makro definované před chvílí.
+
+\inext {fontscalex}{\count=3 ^^B\cbrace}{++}
+
+Makro \db thefontsize si alokuje aktuální font do sekvence \db thefont a
+tento nový fontový přepínač podrobí změně velikosti "\resizefont".
+Makro \db thefontscale přepočítá parametr na absolutní velikost a zavolá
+"\thefontsize".
+
+\inext {thefontsize}{\count=2 ^^B\cbrace}{++}
+
+Plain\TeX{}ový \db magstep má na konci "\relax", takže nefunguje jako pouze
+expandující makro. My ale "\magstep" očekáváme v parametrech příkazů
+"\typoscale" a podobných, proto v "\magstep" je nahrazeno "\relax" méně
+drsným "\space". To separuje číselný parametr dostatečně.
+
+\inext {magstep}{\empty}{+-}
+
+Makro \db em přepíná kontextově do odpovídající varianty a ve spolupráci s
+makrem "\additcorr" přidává italickou korekci. Makro \db additcorr
+si pomocí "\lastskip" zapamatuje poslední mezeru, pak ji odstraní, vloží
+italickou korekci a nakonec vrátí tu odstraněnou mezeru.
+
+\inext {def\nb em}{\empty}{+-}
+
+Fontová makra zabezpečíme proti rozkladu v parametru "\write".
+
+\inext {addprotect}{\empty}{+-}
+
+
+\subsec Texty ve více jazycích
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Makro \db mtext "<značka>" je zkratkou za \uv{multilingual text}.
+Toto makro si podle značky a aktuálního jazyka (dle registru "\language")
+vyhledá, jaký text má vypsat.
+
+\inext {mtext}{\empty}{+-}
+
+Jednotlivé texty definujeme pomocí "\sdef{mt:<značka>:<jazyk>}" takto:
+
+\inext {chap:en}{\empty}{+-}
+
+Některé texty jsou zapsány pomocí "\v" notace. Je lepší udělat to takto
+než vytvořit soubor "opmac.tex" závislý na kódování. Aby byla tato notace
+správně interpretována, spustíme "\csaccents", což je makro \csplain{}u.
+Pokud někdo používá OPmac s jiným formátem, než \csplain, neprovede se nic,
+protože konstrukce "\csname csaccents\endcsname" se v takovém případě přerodí v
+"\relax". Makro "\csaccents" spustíme jen tehdy, pokud je už uživatel
+nespustil před "\input opmac". To poznáme podle toho, zda je definovaná
+sekvence "\r".
+
+\inext {}{}{+-}
+
+CSplain od verze "Nov. 2012" připravuje následující
+makra, která konvertují číslo "\language" na značku jazyka pro všechny
+jazyky, které mají nataženy vzory dělení slov.
+Pro jistotu (pokud je použita starší verze CSplainu) tuto koverzi
+\uv{naučíme} i makro OPmac:
+
+\inext {sdef}{\empty}{+-}
+
+
+
+\subsec REF soubor
+%%%%%%%%%%%%%%%%%%
+
+OPmac používá pro všechny potřeby (obsah, reference, citace, rejstřík,
+poznámky na okraji)
+jediný soubor "\jobname.ref" (tzv. REF soubor).
+Navíc, pokud není potřeba, vůbec tento soubor
+nezakládá. Často totiž budeme chtít dělat s OPmac jen jednoduché věci a je
+únavné pořád na disku kvůli tomu uklízet smetí.
+
+Je potřeba deklarovat souborové deskriptory \db reffile a \db testin:
+
+\inext {newwrite}{\empty}{+-}
+
+Do souboru zapisujeme makrem \db wref "\<sekvence>{<data>}", které vloží do
+"\reffile" řádek obsahující "\<sekvence><data>".
+Implicitně ale není "\reffile" založeno, takže implicitní hodnota tohoto
+makra je \db wrefrelax, tedy nedělej nic.
+
+\inext {wrefrelax}{\empty}{+-}
+
+Makro \db inputref spustíme na konci čtení souboru "opmac.tex", tedy v
+situaci, kdy už budeme mít definovány všechny kontrolní sekvence, které se v
+REF souboru mohou vyskytnout. Nyní si toto makro jen připravíme.
+Makro ověří existenci souboru "\jobname.ref" a pokud existuje, provede
+"\input \jobname.ref". V takovém případě po načtení REF souboru jej otevře
+k~zápisu a připraví "\wref" do stavu, kdy toto
+makro bude ukládat data do souboru.
+
+\inext {inputref}{^^B\cbrace}{+-}
+
+Makro \db openref kdekoli v dokumentu si vynutí založení souboru
+"\jobname.ref". Toto makro neprovede nic, je-li REF soubor už založen. To
+pozná podle toho, že makro "\wref" nemá význam "\wrefrelax". Jestliže soubor
+ještě není založen, makro jej založí, předefinuje "\wref" a vloží první
+řádek do souboru. Tím je zaručeno, že při příštím \TeX{}ování dokumentu
+je soubor neprázdný, takže jej OPmac rovnou přečte a znovu založí na začátku
+své činnosti. Nakonec se "\openref" zasebevraždí, aby se nemuselo při
+opakovaném volání obtěžovat vykonávat nějakou práci. Práce už je totiž
+hotova.
+
+\inext {openref}{^^B\cbrace}{++}
+
+Pro zápisy do REF souboru používáme tuto konvenci: první kontrolní sekvence
+na řádku je vždy tvaru "\X<název>", takže máme přehled, která kontrolní sekvence
+pochází z REF souboru.
+
+
+
+\subsec Lejblíky a odkazy
+%%%%%%%%%%%%%%%%%%%%%%%%%
+
+K vytvoření zpětného odkazu provedeme tři kroky (v tomto pořadí):
+
+\begitems
+\item* V místě "\label[<lejblík>]" si zapamatujeme "<lejblík>".
+\item* V době vygenerování čísla (sekce, kapitoly, caption, atd.)
+ propojíme "<lejblík>" s tímto číslem. Provedeme to
+ pomocí "\sxdef{lab:<lejblík>}{<číslo>}".
+\item* V místě "\ref[<lejblík>]" vytiskneme "\csname lab:<lejblík>\endcsname",
+ tedy "<číslo>".
+\enditems
+
+To je základní idea pro zpětné odkazy. V takovém případě nepotřebujeme REF
+soubor. Pokud ale chceme dopředné odkazy, je potřeba použít REF soubor
+zhruba takto:
+
+\begitems
+\item* V době vygenerování čísla (sekce atd.) navíc uložíme informaci
+ "\Xlabel{<lejblík>}{<číslo>}" do REF souboru.
+\item* V době čtení REF souboru (tedy na začátku dokumentu) provede "\Xlabel"
+ přiřazení pomocí "\sdef{lab:<lejblík>}{<číslo>}".
+\item* Nyní může přijít "\ref[<lejblík>]"
+ se svým "\csname lab:<lejblík>\endcsname" kdekoli v dokumentu.
+\enditems
+
+Přejdeme od idejí k implementaci.
+Makro \db label "[<lejblík>]" si pouze zapamatuje "<lejblík>" do makra \db
+lastlabel, aby s touto hodnotou mohlo později pracovat makro, které automaticky
+generuje nějaké číslo.
+
+\inext {def\nb label}{\empty}{+-}
+
+Makro, které automaticky generuje nějaké číslo, má za úkol zavolat
+\db wlabel "<číslo>". Toto makro propojí "\lastlabel" a "<číslo>" tak, že
+definuje sekvenci "\lab:\lastlabel" jako makro s hodnotou "<číslo>".
+Kromě toho zapíše expandované "\lastlabel" i "<číslo>" do
+REF souboru (jen, je-li otevřen, zpětné reference totiž fungují i bez
+souboru). Nakonec vrátí makru "\lastlabel" jeho původní nedefinovanou
+hodnotu, tj.~lejblík
+už byl použit. Další makro automaticky generující číslo zavolá "\wlabel",
+který nyní neprovede nic (pokud tedy uživatel nenapsal další
+"\label[<lejblík>]").
+
+\inext {wlabel}{^^B\cbrace}{++}
+
+\goodbreak
+Makro \db ref "[<lejblík>]" zkontroluje definovanost "\lab:<lejblík>".
+Je-li to pravda, vytiskne "\lab:<lejblík>" (krz reflink, aby to bylo
+případně klikací). Jinak vytiskne dva otazníky a předpokládá, že v tomto
+případě jde o dopřednou referenci. Vynutí si tedy otevření REF souboru
+zavoláním "\openref".
+
+\inext {ref}{^^B\cbrace}{++}
+
+Makro \db pgref "[<lejblík>]" dělá podobnou práci, jako "\ref", jen s makrem
+"\""pgref:<lejblík>". Toto makro je definováno až při znovunačtení REF
+souboru makrem \db Xlabel, protože ke správnému určení čísla stránky
+potřebujeme asynchronní "\write".
+
+\inext {pgref}{\empty}{+-}
+
+
+
+\subsec Kapitoly, sekce, podsekce
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Fonty pro titul, kapitoly a sekce \db titfont,
+\db chapfont, \db secfont a \db seccfont
+jsou definovány jako odpovídající zvětšení a nastavení tučného duktu.
+Ten je nastaven pomocí \db bfshape jako "\bf" a navíc je ztotožněn
+"\tenit" s "\tenbi", takže když nyní uživatel napíše "\it", dostane tučnou
+kurzívu.
+
+\inext{titfont}{\empty}{+-}
+
+Pro číslování kapitol, sekcí a podsekcí potřebujeme čítače:
+
+\dgn \nb chapnum \dgn \nb secnum \dgn \nb seccnum
+
+\inext{newcount}{\empty}{+-}
+
+Makro pro titul \db tit počítá s tím, že bude titul na více řádcích. Sází ho
+tedy jako odstavec s~pružnými "\leftskip" a "\rightskip". Příkaz "\unskip"
+těsně za parametrem "#1" odstraní mezeru z konce řádku, která tam obvykle
+je. Teprve poté je nadpis řádně centrován.
+
+\inext{tit}{^^B\cbrace}{++}
+
+Makra \db chap, \db sec a \db secc nastaví odpovídající čítače, dále vytvoří
+číslování pro tisk (sestávající z více čísel) v makrech \db thechapnum,
+\db thesecnum a \db theseccnum a zavolají odpovídající makro "\printchap",
+"\printsec" a "\printsecc".
+Poté zavolá "\wlabel" na
+propojení případného labelu s číslem kapitoly/sekce/podsekce a
+pomocí \db wcontents uloží do "\reffile" potřebná data pro obsah.\par\vskip-1pt
+
+\inext{chap}{\empty}{+-}
+
+Text titulu sekce a její číslo jsou vloženy do "\mark", takže tyto údaje
+můžete použít v plovoucím záhlaví. Tato vlastnost není dokumentována v
+uživatelské části, protože je poněkud techničtějšího charakteru. Makro \db
+insertmark "\thesecnum{<text>}" vloží do "\mark" data ve formátu
+"{<secnum>} {<text>}", takže je možno je použít přímo expanzí např.
+"\firstmark", nebo je oddělit a zpracovat zvlášť. Parametru "<text>" je
+zabráněna expanze pomocí protažení tohoto parametru přes "\toks", viz TBN
+str. 54 dole a strany 55--57. Příkaz "\mark" se totiž snaží o expanzi.
+
+\inext{insertmark}{\empty}{+-}
+
+Příklad použití plovoucího záhlaví v "\headline":
+
+\begtt
+\headline{\expandafter\domark\firstmark\hss}
+\def\domark#1#2{\llap{\it\headsize #1. }\rm\headsize #2}
+\def\headsize{\thefontsize[10]}
+\endtt
+
+Makro "\headsize" v této ukázce zaručí, že bude mít záhlaví vždy
+požadovanou velikost. Bez toho ta záruka není, pokud tedy uživatel v sazbě
+dokumentu střídá velikosti písma. Output rutina totiž může přijít náhle,
+třeba v okamžiku, kdy je zapnutá jiná velikost písma.
+
+Pokud chcete kombinovat na levých a pravých stránkách plovoucí záhlaví z
+kapitol a sekcí, inspirujte se v TBN na stranách 259 a 260.
+
+Makra \db printchap, \db printsec a \db printsecc vytisknou číslo a titul
+kapitoly, sekce resp. podsekce. Příkazem "\firstnoindent" dávají najevo,
+že následující odstavec nebude mít odstavcovou zarážku.
+
+\inext {printchap}{\count=3 ^^B\cbrace}{++}
+
+Makro \db afternoindent potlačí odstavcovou zarážku pomocí přechodného
+naplnění "\everypar" kódem, který odstraní box vzniklý z "\indent" a
+vyprázdní pomocí \db wipeepar registr "\everypar".
+Makro \db firstnoindent je ztotožněno s
+"\afternoindent", ale uživatel může psát "\let\firstnoindent=\relax".
+Pak bude "\afternoindent" pracovat jen za verbatim výpisy.
+
+\inext{afternoindent}{firstnoindent}{++}
+
+Nechceme, aby se nám odstavce tvořené z titulů kapitol a sekcí rozdělily do
+více stran. Proto místo příkazu "\par" je použito \db nbpar.
+Konečně uživatel může odřádkovat například v titulu pomocí \db nl.
+Tomuto makru později v "\output" rutině změníme význam na mezeru.
+
+\inext{nbpar}{\empty}{+-}
+
+
+\subsec Popisky, rovnice
+%%%%%%%%%%%%%%%%%%%%%%%%
+
+Nejprve deklarujeme potřebné čítače:
+\dgn \nb tnum \dgn \nb fnum \dgn \nb dnum
+
+\inext{newcount}{\empty}{+-}
+
+Výchozí hodnoty maker, které se vypisují v místě generovaného čísla jsou:
+
+\inext{thetnum}{\empty}{+-}
+
+Makro \db caption "/<typ> " zvedne čítač "\<typ>num" o jedničku,
+dále nastaví pružné mezery s odsazením "\iindent" a s centrováním posledního
+řádku (viz TBN str.~234), propojí pomocí "\wlabel" číslo s případným
+lejblíkem, vytiskne slovo Tabulka/Obrázek v závislosti na jazyku makrem
+"\mtext", vytiskne číslo "\the<typ>num" a zpracuje odstavec s nastavenými
+"\leftskip", "\rightskip". Předefinuje "\par" tak, že první výskyt prázdného
+řádku ukončí skupinu a tím se všechna nastavení vrátí do původního stavu.
+
+\inext{caption}{^^B\cbrace}{++}
+
+Makro \db eqmark zvedne "\dnum" o jedničku.
+V display módu pak použije primitiv "\eqno", za kterým
+následuje "\thednum". V interním módu (v boxu) vytiskne jen "\thetnum".
+V obou případech propojí případný lejblík s číslem pomocí makra "\wlabel".
+
+\inext{eqmark}{\empty}{+-}
+
+\subsec Odrážky
+%%%%%%%%%%%%%%%
+
+Odsazení každé další vnořené úrovně odrážek bude o "\iindent" větší.
+Jeho hodnota je nastavena na "\parindent" v době čtení {\tt opmac.tex}.
+Jestliže uživatel později změní "\parindent", měl by odpovídajícím způsobem
+změnit "\iindent". Kromě toho deklarujeme čítač pro odrážky \db itemnum.
+
+\inext{newcount}{\empty}{+-}
+
+Makro \db begitems vloží "\iiskip", zahájí novou skupinu, pronuluje "\itemnum",
+zvětší odsazení o~"\iindent" a pomocí "\adef" definuje hvězdičku jako
+aktivní makro, které provede "\startitem". Makro \db enditems ukončí
+skupinu a vloží "\iiskip".
+
+\inext{begitems}{\empty}{+-}
+
+Makro \db startitem ukončí případný předchozí odstavec, posune čítač, zahájí
+první odstavec jako "\noindent" a vyšoupne doleva text definovaný v
+\db printitem, který je implicitně nastaven makrem "\begitems" na
+\db normalitem.
+
+\inext{startitem}{\empty}{+-}
+
+Makro \db style "<znak>" přečte "<znak>" a rozvine jen na makro
+"\item:<znak>". Tato jednotlivá makra jsou definována pomocí "\sdef".
+Není-li makro "\item:<znak>" definováno, použije se "\normalitem".
+
+\inext{style}{\empty}{+-}
+
+Čtvereček kreslíme jako "\vrule" odpovídajících rozměrů makrem
+\db fullrectangle "{<dimen>}".
+
+\inext{fullrectangle}{\empty}{+-}
+
+Pro převod mezi numerickou hodnotou čítače a příslušným písmenem a, b, c
+atd. je vytvořeno makro \db athe "<number>".
+
+\inext{athe}{\empty}{+-}
+
+
+\subsec Tvorba obsahu
+%%%%%%%%%%%%%%%%%%%%%
+
+Do \db toclist budeme ukládat data pro obsah.
+Pomocí \db ifischap se budeme ptát, zda v dokumentu jsou kapitoly.
+
+\inext{toclist}{\empty}{+-}
+
+V době čtení REF souboru vložíme veškerá data obsahu do makra "\toclist"
+tak, že v tomto bufferu budeme mít za sebou sekvence "\tocline" následované pěti
+parametry. Makra \db Xchap, \db Xsec a \db Xsecc
+mají parametry "{<číslo>}{<text>}{<strana>}" a jsou definovány následovně:
+
+\inext{Xchap}{\empty}{+-}
+
+Makro \db tocline "{<odsazení>}{<font>}{<číslo>}{<text>}{<strana>}" vytvoří
+řádek obsahu. Řádek tiskneme jako odstavec, protože "<text>" může být třeba
+delší. Registr "\leftskip" nastavíme jako součin "<odsazení>" krát "\iindent".
+Pokud se v dokumentu vyskytují kapitoly, odsadíme ještě o další "\iindent".
+Registr "\rightskip" nastavíme na 2"\iindent", aby delší "<text>" se zalomil
+dřív než v místě, kde jsou stránkové číslice. Konec odstavce se stránkovou
+číslicí pak vytáhneme mimo tento rozsah pomocí "\hskip-2\iindent". Odstavec
+pruží v "\tocdotfill", protože tento výplněk má větší pružnost než
+"\parfillskip". Registr "\parfillskip" má "1fil", zatímco "\tocdotfill" má
+pružnost "1fill". Makro \db tocdotfill je implementováno pomocí "\leaders"
+jako opakované tečky, které budou lícovat pod sebou.
+
+\inext{tocline}{\empty}{+-}
+
+Makro \db maketoc jednoduše spustí "\toclist", Pokud je "\toclist" prázdný,
+upozorní o tom adekvátním způsobem na terminál.
+
+\inext{maketoc}{\empty}{+-}
+
+
+\subsec Sestavení rejstříku
+%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Slovo do rejstříku vložíme pomocí \db iindex "{<heslo>}". Protože výskyt
+slova na stránce není v době zpracování znám, je nutné použít REF soubor s
+asynchronním "\write".
+
+\inext{iindex}{\empty}{+-}
+
+Nyní naprogramujeme čtení parametru makra
+\db ii "<slovo>,<slovo>,...<slovo> ". Vzhledem k tomu, že za
+přítomnosti zkratky "@" budeme potřebovat projít seznam slov oddělených čárkou
+v~parametru ještě jednou, zapamatujeme si tento seznam do "\tmp".
+
+\inext{leavevmode}{\empty}{+-}
+
+Makro \db iiA sejme vždy jedno slovo ze seznamu. Podle prázdného parametru
+poznáme, že jsme u konce a neděláme nic. Při výskytu "<slovo>=@" (poznáme to
+podle shodnosti parametru s \db iiatsign \unskip),
+spustíme "\iiB", jinak vložíme údaj o slově do rejstříku pomocí "\iindex".
+Nakonec makro "\iiA" volá rekurzivně samo sebe.
+
+\inext{iiA}{\empty}{+-}
+
+Makro \db iiB rovněž sejme vždy jedno slovo ze seznamu a na konci volá
+rekurzivně samo sebe. Toto makro ovšem za použití makra \db iiC prohodí pořadí
+prvního podslova před prvním lomítkem se zbytkem. Není-li ve slově lomítko,
+pozná to makro "\iiC" podle toho, že parametr "#2" je prázdný. V takovém případě
+neprovede nic, neboť slovo je už zaneseno do rejstříku v makru "\iiA".
+
+\inext{iiB}{\empty}{+-}
+
+Makro \db iid "<slovo> " pošle slovo do rejstříku a současně je zopakuje do
+sazby. Pomocí "\futurelet" a \db iiD zjistí, zda následuje tečka nebo čárka. Pokud
+ne, vloží mezeru.
+
+\inext{iid}{\empty}{+-}
+
+Při čtení REF souboru se vykonávají makra \db Xindex "{<heslo>}{<strana>}",
+která postupně vytvářejí makra tvaru "\,<heslo>", ve kterých je shromažďován
+seznam stránek pro dané "<heslo>".
+Kromě toho každé makro "\,<heslo>" je vloženo do seznamu \db iilist.
+Na konci čtení
+REF souboru tedy máme v~"\iilist" seznam všech hesel jako řídicí sekvence (to
+zabere nejmíň místa v \TeX{}u). Každé
+"\,<heslo>" na konci čtení REF souboru obsahuje dva údaje ve svorkách, první údaj
+obsahuje pomocná data a druhý obsahuje seznam stránek. Tedy "\,<heslo>" je makro
+s obsahem "{<pomocná-data>}{<seznam-stránek>}".
+
+Seznam stránek není jen tupý seznam všech stránek, na kterých se objevil
+záznam "\ii" pro dané slovo. Některé stránky se totiž mohou opakovat a my je
+chceme mít jen jednou. Pokud stránky jsou souvisle za sebou: 13, 14, 15, 16,
+chceme navíc takový seznam nahradit zápisem 13--16. Makro
+"\Xindex{<heslo>}{<strana>}" je z tohoto důvodu poněkud sofistikovanější.
+
+\ilabel [Xindex:first] {firstdata}
+\ilabel [Xindex:second] {seconddata}
+
+\inext{Xindex}{\empty}{+-}
+
+Činnost makra "\Xindex" si vysvětlíme za chvíli podrobněji. Nejprve ovšem
+definujeme pomocné makro \db firstdata "\,<heslo>"~"\<cs>", které expanduje na
+"\<cs>"~"<první-datový-údaj-hesla>&". Je-li třeba "\,aa" definováno jako
+"{prvni}{druhy}", pak "\firstdata"~"\,aa"~"\cosi" expanduje na "\cosi"~"prvni&".
+Tím máme možnost vyzískat data z makra. Podobně makro
+\db seconddata "\,<heslo>"~"\<cs>" expanduje na
+"\<cs>"~"<druhý-datový-údaj-hesla>&".
+
+\inext{firstdata}{\empty}{+-}
+
+Než se pustíme do výkladu makra "\Xindex", vysvětlím, proč pro hesla rejstříku
+tvořím jednu řídicí sekvenci, která je makrem se dvěma datovými údaji.
+Mohl bych jednodušeji pracovat se dvěma různými řídicími sekvencemi,
+např. "\,<heslo>" a "\:<heslo>". Důvod je prostý: šetřím paměť \TeX u. Dá se totiž
+očekávat, že počet hesel v rejstříku můžeme počítat na tisíce a je rozdíl
+alokovat kvůli tomu tisíce kontrolních sekvencí nebo dvojnásobné množství
+takových sekvencí.
+
+V makru "\Xindex" čteme "\firstdata" na řádku \cite[Xindex:first]
+a "\seconddata" na řádku \cite[Xindex:second].
+Čtení je provedeno makry \db XindexA a \db XindexB. První úsek dat je tvaru
+"<poslední-strana>/<stav>" a druhý úsek dat obsahuje rozpracovaný seznam stránek.
+Podíváme-li se na definice "\XindexA" a "\XindexB", shledáme, že seznam stránek
+bude uložen v "\tmp", dále "<poslední-strana>" bude v "\tmpa" a "<stav>" je v
+"\tmpb".
+
+\inext{XindexA}{\empty}{+-}
+
+Rozlišujeme dva stavy: "<stav>=+", pokud je seznam stránek zakončen konkrétní
+stránkou. Tato konkrétní stránka je uložena v "<poslední-strana>". Druhým
+stavem je "<stav>=-", když je seznam stránek ukončen "--" (přesněji obsahem
+makra \db iiendash, které můžete snadno předefinovat) a v tomto případě
+"<poslední-strana>" obsahuje poslední stránku, na které byl zjištěn výskyt
+hesla. Tato strana nemusí být v~seznamu stránek explicitně uvedena.
+
+Makro "\Xindex{<heslo>}{<strana>}" tedy postupně vytváří seznam stran
+zhruba takto:
+
+\def\begtthook{\langleactive}
+\begtt
+if (první výskyt \,<heslo>) {
+ založ \,<heslo> do iilist;
+ <seznam-stran> = "<strana>"; <stav> = +; <posledni-strana> = <strana>;
+ return;
+}
+if (<strana> == <posledni-strana>) return;
+if (<stav> == +) {
+ if (<strana> == <posledni-strana>+1) {
+ <seznam-stran> += "--";
+ <stav> = - ;
+ }
+else {
+ <seznam-stran> += ", <strana>";
+ <stav> = + ;
+ }
+ else {
+ if (<strana> > <posledni-strana>+1) {
+ <seznam-stran> += "<posledni-strana>, <strana>";
+ <stav> = + ;
+ }
+ }
+}
+<poslední-strana> = <strana>;
+\endtt
+
+\def\begtthook{}
+Makro \db makeindex nejprve definuje přechodný význam rekurzivního
+"\act" tak, aby byly uzavřeny seznamy stránek (tj. aby seznam nekončil
+znakem "--") a do první
+datové oblasti každého makra typu "\,<heslo>" vloží konverzi textu "<heslo>" do
+tvaru vhodném pro abecední řazení českých slov.
+Pomocí "\expandafter \act \iilist \relax" se
+požadovaná činnost vykoná pro každý prvek v "\iilist".
+Dále makro "\makeindex" provede seřazení "\iilist" podle abecedy
+makrem "\dosorting" a nakonec provede tisk jednotlivých hesel. K tomu účelu
+znovu přechodně předefinuje "\act" a předloží mu "\iilist".
+
+\ilabel [mkindex:od] {firstdata}
+\ilabel [mkindex:do] {after\nb act}
+\ilabel [mkindex:orippx] {orippx}
+
+\inext{makeindex}{^^B\cbrace}{++}
+
+Makro \db printiipages sebere z "<druhého-datového-údaje>" seznam stránek a
+jednoduše je vytiskne.
+
+\inext{printiipages}{\empty}{+-}
+
+Makro \uv{prepare index item} \db prepii "\,<heslo>" odstraní prostřednictvím
+\db prepiiA z názvu kontrolní sekvence backslash a čárku a zbytek tiskne pomocí
+"\printii". Pokud ale je "\,<heslo>" uloženo v~seznamu "\iispeclist", pak se
+expanduje sekvenci s názvem "\\,<heslo>", ve které je uloženo, co se
+má místo hesla vytisknout. Data těchto výjimek jsou připravena makrem "\iis"
+
+\inext{prepii}{\empty}{+-}
+
+Kontrolní otázka: proč se nedotazujeme jednoduše na to, zda je
+"\\,<heslo>" definovaná řídicí sekvence? Odpověď: museli bychom ji
+sestavit pomocí "\csname...\endcsname", ale to založí do \TeX{}ové paměti
+novou řídicí sekvenci pro každé heslo v rejstříku. My se snažíme počet
+těchto řídicích sekvencí redukovat na minimum. Počítáme s tím, že obyčejných
+hesel bude tisíce a výjimek jen pár desítek.
+
+Makro \db iis "<heslo> {<text>}" vloží další údaj do slovníku výjimek pro
+hesla v rejstříku. Přesněji: vloží "\,<heslo>" do \db iispeclist a definuje
+sekvenci "\\,<heslo>" jako "<text>".
+
+\inext{iis}{\empty}{+-}
+
+Makro \uv{print index item} \db printii "<heslo>&" vytiskne jeden údaj do
+rejstříku. Makro projde prostřednictvím \db printiiA jednotlivá podslova
+oddělená lomítkem a přepíše je do rejstříku odděleny mezerou. Přitom
+kontroluje, zda se podslova rovnají odpovídajícím podslovům z předchozího
+hesla, které je uloženo v \db previi. Pokud ano, místo podslova vloží \db
+iiemdash, což je pomlka. Na konci činnosti se spustí makro \db printiiB,
+které nastaví "\previi" na \db currii (nové slovo se pro další zpracování stává
+předchozím) a vytiskne seznam stránek. Makrem \db everyii
+(implicitně je prázdné) dovolíme uživateli vstoupit do procesu tisku hesla.
+Může například psát "\def\everyii{\indent}", pokud chce.
+
+\ilabel [printii:iindent] {iindent}
+\inext{printii}{\empty}{+-}
+
+Makro \db iiparparams nastavuje parametry sazby odstavce v rejstříku. Vlevo
+budeme mít "\leftsip" rovný "\iindent", ale první řádek posuneme o
+"-\iindent" (viz řádek kódu~\cite[printii:iindent]) takže první řádek je
+vystrčen doleva. Vpravo máme pružnou mezeru, aby se seznam čísel stran mohl
+rozumně lámat, když je moc dlouhý. Makro "\iiparparams" si musí poznačit do
+makra \db orippx původní údaje měněných hodnot. Není možné se totiž schovat
+do skupiny, protože rejstřík je obvykle tištěn pomocí
+"\begmulti...\endmulti" a toto makro občas ukončuje plnění boxu a spouští
+"\flushcolumns". Kdybychom měli "\makeindex" ve skupině, pak by při
+"\flushcolumns" došlo ke křížení skupin. Na konci práce "\makeindex" na
+řádku \cite[mkindex:orippx] je makro "\orippx" zavoláno a tím jsou parametry
+odstavce vráceny do původní podoby.
+
+\inext{iiparparams}{\empty}{+-}
+
+Pomocné makro \db scanprevii "<expanded-previi>&" se podívá do "\previi",
+odloupne z něj úsek před prvním lomítkem a tento úsek definuje jako
+"\tmpa".
+
+\inext{scanprevii}{}{+-}
+
+Výchozí hodnota "\previi" před zpracováním prvního slova v rejstříku je
+prázdná.
+
+\inext{previi}{\empty}{+-}
+
+
+\subsec Abecední řazení rejstříku
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Nejprve se zaměříme na vytvoření makra
+"\isAleB"~"\,<heslo1>"~"\,<heslo2>", které rozhodne, zda je "<heslo1>" řazeno za
+"<heslem2>" nebo ne. Výsledek zkoumání můžeme prověřit pomocí "\ifAleB".
+
+Pro porovnání dvou údajů vyžaduje norma dva průchody. V prvním (primární
+řazení) se rozlišuje jen mezi písmeny A B C Č D E F G H Ch I J K L M N O P Q
+R Ř S Š T U V W X Y Z Ž. Pokud jsou hesla z tohoto pohledu stejná, pak se
+provede druhý průchod (sekundární řazení), ve kterém jsou řazena
+neakcentovaná písmena před přehlasovaná před čárkovaná před háčkovaná před
+stříškovaná před kroužkovaná a dále s nejnižší prioritou malá písmena před
+velká. Připravíme si tedy dvě sady "\lccode" dvojic: pro první průchod a pro
+druhý. Porovnávaná hesla zkonvertujeme pomocí "\lowercase" při nastavení
+"\lccode" odpovídajícího průchodu. Pak takto zkonvertovaná hesla teprve
+začneme porovnávat.
+
+Makro \db setprimarysorting připraví "\lccode" znaků české a slovenské
+abecedy pro první průchod a \db setsecondarysorting pro druhý průchod.
+Makro "\setprimarysorting" expanduje \db sortingdata
+a předhodí před takto expandovaná data "\act".
+Povšimneme si, že pro první průchod dostanou stejný "\lccode" všechny znaky
+na společném řádku makra "\sortingdata", zatímco v druhém průchodu budou mít
+všechny znaky z tohoto makra rozdílný "\lccode", ve vzestupném pořadí.
+Je to tím, že v makru "\setprimarysorting" se zvedá "\tmpnum" jen v místě
+čárky, zatímco v "\setsecondarysorting" se "\tmpnum" zvedá pro každý znak.
+Nejnižší hodnotu má mezera vyznačená v "\sortingdata" pomocí "{ }".
+Tím je zaručeno, že kratší slovo je řazeno dřív než delší slovo se stejným
+začátkem, obsahující celé kratší slovo (ten~tučňák$\prec$tento).
+Je sice pravda, že ASCII hodnota mezery je ještě menší, ale my musíme
+mezeru někam šoupnout na jiný kód než 32, jinak by nám ji nepřečetlo
+makro s~neseparovaným parametrem. Ovšem my budeme chtít mezeru přečíst.
+
+\ilabel [sorten] {sort:en}
+\ilabel [lan] {lan:}
+\ilabel [chsorting] {chsorting}
+
+\inext{sortingdata}{\count=3 ^^B\cbrace}{++}
+
+Jedním z problémů českého řazení je dvojhláska ch. Tu potřebujeme
+proměnit v jediný znak. Pro potřeby řazení proměníme ch v "^^T", Ch v "^^U"
+a CH v "^^V". Uděláme to následujícím okultním kódem, který definuje makro
+\db preparesorting "\,<heslo>". Toto makro připraví pomocí do "\tmpb"
+"<heslo>" zkonvertované krz "\lowercase",
+ovšem nejprve je dvojhláska ch nahrazena jedním znakem.
+Makro \db chsorting je implicitně nedefinované, což znamená, že pracujeme s
+dvojhláskou ch. Na řádku \cite[sorten], \cite[lan] a \cite[chsorting] je ovšem nastaveno
+"\chsorting" jako "n", což je vzkaz, že dvojhlásku ch nechceme
+interpretovat.
+
+\inext{bgroup}{\empty}{+-}
+
+Tento kód je bohužel obtížněji čitelný, protože makra "\iiscanch" a další
+potřebují mít separátor "ch" ve stavu, kdy jednotlivá písmena mají "\catcode" 12.
+Pracujeme totiž s výstupem primitivu "\string", který bohužel vše (až na
+mezeru) balí do tokenů s kategorií 12. Proto je celý kód obalen do
+"\bgroup", "\egroup" a "\lowercase". Tam jsou znaky 4, 5, 6, 7,
+které mají kategorii 12, šoupnuty na c, h, C, H. Po tomto dešifrování tedy
+vidíme, že makro \db iiscanch je definováno takto:
+
+\begtt
+\gdef\iiscanch #1ch#2\relax{#1\if$#2$\else^^T\iiscanch #2\relax\fi}
+\iiscanch Schází hrách, který bych házel na stěnu.ch\relax
+\endtt
+
+Uvedený příklad expanduje postupně na
+
+\begtt
+#1<-S
+#2<-ází hrách, který bych házel na stěnu.ch
+=> s^^T\iiscanch #2\relax
+
+#1<-ází hrá
+#2<-, který bych házel na stěnu.ch
+=> s^^Tází hrá^^T\iiscanch #2\relax
+
+#1<-, který by
+#2<- házel na stěnu.ch
+=> s^^Tází hrá^^T, který by^^T\iiscan #2\relax
+
+#1<- házel na stěnu.
+#2<-
+=> s^^Tází hrá^^T, který by^^T házel na stěnu.
+\endtt
+a to nahradí všechny výskyty dvojhlásky ch znakem "^^T". Analogicky pracují
+makra \db iiscanCh a \db iiscanCH. Makro \db preparesortingA nakonec zavolá
+všechna tři makra, takže máme nahrazeny všechny dvojhlásky ch, Ch i CH.
+
+V rámci optimalizace rychlosti jsou před algoritmem na setřídění seznamu
+všechna hesla jednorázově zkonvertovaná podle pravidel prvního průchodu
+řazení a tato data jsou uložena v prvním datovém údaji hesla (ve druhém máme
+seznam stránek). Není tedy nutné dělat konverzi při každém porovnávání dvou
+hesel. Ovšem, pokud porovnání hesel vyjde bez rozdílu, je potřeba provést
+druhý průchod řazení (sekundární řazení). Ten nastavujeme jednotlivě jen pro
+takové dvojice hesel, kde to je potřeba. Pravděpodobnost, že to je vůbec
+někdy potřeba, je mizivá. Data pro primární řazení jsou tedy už připravena na
+řádcích \cite[mkindex:od] až \cite[mkindex:do] v makru "\makeindex".
+
+V českém řazení se nemá přihlížet na interpunkční znaky (tečka, středník,
+otazník, atd.). Hesla máme řadit tak, jako kdyby tam tyto znaky nebyly.
+Kdyby se dvě hesla podle tohoto pravidla nelišila, norma předepisuje nasadit
+cca čtvrtý průchod, ve kterém se tyto znaky rozliší. Čtvrtý průchod
+implementován není: hesla lišící se jen interpunkčními znaky, jsou v OPmac
+při řazení nerozlišitelná, tj. jsou řazena v pořadí, v jakém vstupují do
+rejstříku. Ignorování interpunkčních znaků je provedeno tak, že všem
+těmto znakům je přidělen makrem \db setignoredchars "\lccode" tečky a
+tečka je při zpracování v~"\setprimarysorting" a "\setsecondarysorting" odstraněna
+makrem \db removedot.
+
+\inext{removedot}{\empty}{+-}
+
+Připravíme si "\newif", kterým ohlásíme výsledek porovnání dvou hesel:
+
+\inext{newif}{\empty}{+-}
+
+Makro \db isAleB "\,<heslo1>"~"\,<heslo2>" spustí\hfil\break
+"\testAleB"~"<zkonvertované heslo1>&\relax"~"<zkonvertované heslo2>&\relax"~%
+"\,<heslo1>"~"\,<heslo2>".
+
+\inext{isAleB}{^^B\cbrace}{++}
+
+Idea makra \db testAleB lexikograficky porovnávající dvě slova je v tom, že ze
+dvou stringů v~parametru oddělených "\relax" postupně odlupuje vždy
+první znak "#1" a "#3" z každého stringu a ten porovnává a samozřejmě při rovnosti
+rekurzivně zavolá samo sebe. Pokud jsme se dostali na konec bez rozhodnutí, co
+je menší, narazíme na znak "&". V takovém případě přestoupíme do
+sekundárního průchodu.
+
+\inext{testAleB}{^^B\cbrace}{++}
+
+Makro \db testAleBsecondary "\,<heslo1>"~"\,<heslo2>" založí skupinu, v ní
+nastaví "\lccode" dle sekundárního řazení a pomocí "\preparesorting"
+připraví zkonvertovaná data do "\tmpa" a "\tmpb". Na chvosty těchto dat
+přidám nulu a jedničku, aby porovnání vždy nějak dopadlo, a spustím
+\db testAleBsecondaryX, což pracuje obdobně, jako "\testAleB".
+
+\inext{testAleBsecond}{\count=2 ^^B\cbrace}{++}
+
+Nyní můžeme pomocí "\isAleB\,<heslo1>\,<heslo2>\ifAleB" rozhodnout, který
+ze dvou daných parametrů má být řazen dříve. Stačí tedy už jen naprogramovat
+celkové řazení seznamu. Toto makro vycházející z algoritmu mergesort
+vytvořil můj syn Miroslav. Makro bylo poprvé použito v DocBy\TeX{}u, což je
+nástroj, kterým je například pořízena i tato dokumentace.
+
+Makro \db dosorting pomocí pomocného makra "\act" doplní za každý údaj v
+"\iilist" čárku a dále předloží makru "\mergesort" jako parametr obsah
+"\iilist" ukončený "\end,\end", vyprázdní "\iilist" a spustí "\mergesort".
+
+\inext{dosorting}{\empty}{+-}
+
+Makro \db mergesort pracuje tak, že bere ze vstupní fronty vždy dvojici
+skupin
+položek, každá skupina je zatříděná. Skupiny jsou od sebe odděleny
+čárkami. Tyto dvě skupiny spojí do jedné a zatřídí. Pak přejde na
+následující dvojici skupin položek. Jedno zatřídění tedy vypadá
+například takto: dvě skupiny: "eimn,bdkz," promění v~jedinou
+skupinu "bdeikmnz,". V tomto příkladě jsou položky jednotlivá písmena,
+ve skutečnosti jsou to kontrolní sekvence, které obsahují celá slova.
+
+Na počátku jsou skupiny jednoprvkové ("\iilist" odděluje každou
+položku čárkou). Makro "\mergesort" v tomto případě projde seznam a vytvoří
+seznam zatříděných dvoupoložkových skupin, uložený zpětně v
+"\iilist". V dalším průchodu znovu vyvrhne "\iilist" do vstupní
+fronty,
+vyprázdní ho a startuje znovu. Nyní vznikají čtyřpoložkové zatříděné
+skupiny. Pak osmipoložkové~atd. V~závěru (na řádku~\cite[konecsortu])
+je první skupina celá setříděná a druhá obsahuje "\end", tj.
+všechny položky jsou už setříděné v první skupině, takže stačí
+ji uložit do "\iilist" a ukončit činnost. Pomocí \db gobbletoend
+odstraníme druhé "\end" ze vstupního proudu.
+
+\noactive{dvojice}
+\ilabel [merge:porovnani] {isAleB}
+\ilabel [merge:trojka] {mergesort p1+}
+\ilabel [merge:p1] {ifx,}
+\ilabel [merge:p2] {fif\nb mergesort\cbrace}
+\ilabel [konecsortu] {empty\nb iilist}
+\inext {def\nb mergesort }{^^B\cbrace}{++}
+
+{\def\quotehook{\catcode`\<12}
+Jádro "\mergesort" vidíme na řádcích~\cite[merge:porovnani]
+až~\cite[merge:trojka]. Makro "\mergesort" sejme ze vstupního proudu
+do "#1" první položku první skupiny, do "#2" zbytek první skupiny a do
+"#3" první položku druhé skupiny. Je-li "#1<#3", je do výstupního
+zatříděného seznamu "\indexbuffer" vložen "#1", ze vstupního proudu je
+"#1" odebrán a "\mergesort" je zavolán znovu. V případě "#3<#1"
+je do "\indexbuffer" vložen "#3", ze vstupního proudu je "#3" odebrán a
+"\mergesort" je zavolán znovu. Řádky~\cite[merge:p1]
+až~\cite[merge:p2] řeší případy, kdy je jedna ze skupin prázdná:
+je potřeba vložit do "\indexbuffer" zbytek neprázdné skupiny a přejít
+na další dvojici skupin. Ostatní řádky makra se vyrovnávají se
+skutečností, že zpracování narazilo na zarážku "\end,\end" a je tedy
+potřeba vystartovat další průchod.
+\par}
+
+
+\subsec Více sloupců
+%%%%%%%%%%%%%%%%%%%%
+
+Makro pro sazbu do více sloupců je převzato z TBN, kde je podrobně
+vysvětleno na stranách 224 až~245. Základní myšlenka makra spočívá v tom, že
+se naplní jeden velký "\vbox" (box6) jedním sloupcem a "\endmulti" jej
+rozlomí do sloupců požadované výšky a strčí do sazby. Není k tomu nutno
+měnit výstupní rutinu. Makro z TBN je zde v OPmac ve dvou věcech přepracováno:
+\begitems
+\item * Důslednější balancování sloupců vylučující možnost ztráty sazby
+ a umožňující mít sazbu s nezlomitelnými mezerami mezi řádky.
+\item * Makro měří kumulovanou sazbu a umožňuje při rozsáhlém množství
+ tiskového materiálu přechodně přejít do režimu \uv{vyprazdňování}.
+\enditems
+
+Makra \db begmulti, \db endmulti, \db corrsize, \db makecolumns a \db
+splitpart pracují zhruba tak, jak je popsáno v TBN.
+
+\ilabel [mul:endgraf] {endgraf}
+\ilabel [mul:balance] {last balancing}
+\ilabel [mul:relax] {relax\cbrace}
+\ilabel [mul:prevgraf] {prevdepth}
+
+\inext{corrsize}{\count=2 \empty}{+-}
+
+Výstup rozlomené sazby do sloupců probíhá ve dvou režimech: když je třeba
+sloupci zaplnit celou stránku, použijeme "\makecolumns". Toto makro neřeší
+otázku, že může v kumulovaném boxu~6 zbýt nějaká sazba, protože se
+předpokládá, že lámání bude pokračovat na další straně. Pokud ale
+je na aktuální straně vícesloupcová sazba ukončena, použijeme
+propracovanější \db balancecolumns. Toto makro si zazálohuje materiál
+z~boxu~6 do boxu~7 a jme se zkoušeti rozlomit box~6 na sloupce s
+výškou "\dimen0". Pokud ale po rozlomení není výchozí box~6 zcela prázdný, makro
+zvětší krapánek (o 0,2"\baselineskip") požadovanou výšku, vrátí se k~zálohované
+sazbě v boxu~7 a zkusí rozlomit znovu. To opakuje tak dlouho, dokud je box~6
+prázdný.
+
+\inext{balancecolumns}{^^B\cbrace}{++}
+
+Když je sazba plněna do boxu~6, může ji být tak moc, že tento box
+překročí maximální výšku boxu, která je v \TeX{}u bohužel
+omezena na cca pět metrů
+(16383~pt). Proto na řádku~\cite[mul:endgraf] je předefinován "\par", který
+přičítá do "\dimen0" celkovou výšku postupně kumulované sazby. Jakmile tato
+výška dosáhne "0.9\maxdimen", předefinujeme makro
+"\balancecolumns" na "\flushcolumns" a spustíme předčasně "\endmulti". Toto makro
+vyprázdní box pomocí opakovaného "\splitpart", ovšem nevyprázdní ho celý.
+Jen tu část, která zaplní celé stránky. Jakmile bude chtít
+"\splitpart" přejít k~vybalancování sazby pomocí
+"\balancecolumns" na řádku \cite[mul:balance], spustí se místo běžného
+"\balancecolumns" makro \db flushcolumns. Toto makro ignoruje zbytek činnosti
+"\endmulti" až po "\relax" na řádku \cite[mul:relax], takže vyskočí z
+trojitě zanořeného "\if". Musí tedy vrátit příslušné množství "\fi" a dále
+vystartuje nový "\setbox6=\vbox". Uvnitř tohoto boxu nejprve vysype zbytek
+boxu~6, pomocí "\unskip\unskip" odstraní "\vfil" a "\vskip-\prevdepth",
+který tam vložil "\endmulti" na řádku~\cite[mul:prevgraf],
+vrátí se k zálohovanému významu makra \db ibalancecolumns
+a znovu definuje "\par" obdobným způsobem jako v~"\begmulti".
+Pak pokračuje ve čtení sazby.
+
+\inext{flushcolumns}{\empty}{+-}
+
+
+\subsec Barvy
+%%%%%%%%%%%%%
+
+Deklarujeme \db ifpgcolor, což budeme potřebovat v makru "\locpgcolor".
+Dále deklarujeme \db lastpage. Tento registr budeme průběžně zvětšovat při
+čtení REF souboru v makru "\Xpage" a na konci čtení REF souboru tedy bude
+obsahovat číslo poslední strany.
+
+\inext{ifpgcolor}{\empty}{+-}
+
+Od verze pdf\TeX{}u 1.40 nabízí tento program primitivy
+"\pdfcolorstackinit" a "\pdfcolorstack". Makra v OPmac tyto
+primitivy nepoužívají, protože:
+
+\begitems
+\item * Řešení v OPmac jsem vytvořil a použil podstatně dřív, než si programátoři
+ pdf\TeX{}u vůbec všimli, že existuje problém s přecházením barev na nové
+ stránky.
+\item * Primitivy "\pdfcolorstackinit" a "\pdfcolorstack" stále nejsou dokumentované.
+\item * Barevné řešení v "pdftex.def" pro La\TeX{} nepovažuji za koncepčně
+ správné, protože se snaží pomocí "\aftergroup" vytvořit zdání, že
+ barvy fungují lokálně uvnitř skupiny. To je zbytečná komplikace
+ navíc, která jde proti přirozenosti nastavování barev v PDF souboru.
+\enditems
+
+Barvy se v PDF přepínají pomocí PDF speciálů "<num> <num> <num> <num> k"
+(pro text a plochy) a "<num> <num> <num> <num> K" pro linky. Pro oba typy
+barev připravíme barevná makra \db Blue, \db Red, \db Brown, \db Green, \db
+Yellow, \db Cyan, \db Magenta, \db White, \db Grey, \db LightGrey, \db Black.
+Uživatel si může definovat další.
+
+\inext{Blue}{\empty}{+-}
+
+Problém barev v PDF je, že od výskytu speciálu pro barvu jsou změněné barvy
+až po jiný výskyt takového speciálu nebo po konec strany. Na každé nové
+straně začíná sazba v barvě černé. Nám ovšem někdy může obarvený text přetéci
+na další stranu. Pak ale musíme v "\output" rutině (v makru "\prepage")
+nastavit barvu, která přetekla. Ovšem jak poznáme, že něco přeteklo do další
+strany? Jedině pomocí REF souboru a asynchronního "\write". Proto makro \db
+setcmykcolor nevkládá do PDF jen požadovaný speciál, ale taky ukládá o sobě
+informaci do REF souboru. Jakmile se při čtení REF souboru objeví "\Xpage",
+zkontrolujeme, zda naposledy nastavená barva byla černá. Pokud ne, dáme
+pokyn makru "\prepage" prostřednictvím makra "\pg:<číslo strany>", aby
+aktivovalo hned po "\headline" barvu naposledy nastavenou. To je tedy
+základní idea, nyní implementace:
+
+\inext{ifpdftex}{\count=2 \empty}{+-}
+
+Makro \db pdfK má implicitně hodnotu "k" (barva pro texty a plochy) a
+přechodně při použití \db linecolor má hodnotu "K". Právě nastavenou barvu
+pak makro "\setcmykcolor" uloží do REF souboru.
+Jen tehdy, když je explicitně
+známo, že barva nepřeteče do další strany, je možné použít před použitím
+přepínače barvy prefix \db locpgcolor, který potlačí v takovém případě tisk
+informací do REF souboru. Následně budou potlačeny zápisy informací do REF souboru
+všech barevných přepínačů až po "\Black" včetně. Další barevné přepínače (po
+"\Black") se chovají už normálně.
+Toto opatření je zde jen proto, aby byl REF soubor
+poněkud menší a přehlednější i v případě, kdy navrhujeme bohatě barevný dokument.
+
+Makra \db Xpdfcolork a \db XpdfcolorK udržují při čtení REF souboru
+informaci o naposledy vložené barvě v makrech \db pdflastcolork a
+\db pdflastcolorK (název koresponduje typu barvy).
+
+\inext{Xpdfcolork}{\empty}{+-}
+
+Output rutina vkládá na každé stránce do REF souboru
+\db Xpage "{<číslo strany>}".
+Toto makro při čtení REF souboru kontroluje, zda byla naposledy použita
+na předcházející straně barva černá. Pokud ne, přidá do makra
+"\pg:<číslo strany>" pokyn pro nastavení barvy ve tvaru
+\db setpgcolor "<k nebo K>{<čísla barvy>}".
+Toto makro se spustí v output rutině na straně "<číslo strany>"
+za "\headline", ale před sestavením boxu s textem.
+
+\inext{Xpage}{\empty}{+-}
+
+Makro \db draft vloží do "\headline" box nulové výšky a šířky "\draftbox",
+který vystrčí svou šedou sazbu ven ze svého rozměru a je tištěn dřív, než
+jakýkoli jiný materiál na stránce.
+
+\inext{draft}{\empty}{+-}
+
+V makru \db draftbox "{<text>}" je "<text>" otočen o 55 stupňů, zvětšen
+desetkrát a vytištěn v barvě "\LightGrey". K tomu jsou
+využity PDF transformace souřadnic.
+
+\inext{draftbox}{\empty}{+-}
+
+
+\subsec Klikací odkazy
+%%%%%%%%%%%%%%%%%%%%%%
+
+Makro \db destactive "[<typ>:<lejblík>]{<výška>}" založí cíl odkazu jen tehdy, když
+je "<lejblík>" neprázdný. Ve vertikálním módu se nalepí na předchozí box
+díky "\prevdepth=-1000pt" a po vložení boxu s cílem vrátí hodnotu
+"\prevdepth" do původního stavu, aby následující box byl správně řádkován.
+V horizontálním módu postě vloží "\destbox". Makro
+\db destbox "[<typ>:<lejblík>]{<výška>}" vytvoří box nulové výšky a z~něj
+vystrčí nahoru cíl klikacího odkazu vzdálený od účaří o "<výška>". Interně
+použije pdf\TeX{}ový primitiv "\pdfdest" s parametrem "xyz", což
+charakterizuje obvyklou možnost chování PDF prohlížeče při odskoku na cíl.
+Podrobněji viz manuál k~pdf\TeX{}u.
+
+\inext{dest}{\empty}{+-}
+
+V uživatelské dokumentaci je zmíněno místo "\destactive" makro \db dest
+se stejnými parametry. Toto makro je implicitně prázdné a tedy nečiné.
+Teprve "\hyperlinks" je přinutí k činnosti.
+
+Klikací text vytvoří makro \db link "[<typ>:<lejblík>]{<barva>}{<text>}".
+Makro používá
+pdf\TeX{}ový primitiv "\pdfstartlink", ve kterém je vymezena výška a hloubka
+aktivní plochy. Nakonec přepne na požadovanou "<barvu>" (pokud není černá),
+vytiskne aktivní "<text>" a přepne zpět na černou barvu. Pdf\TeX{}ový primitiv
+"\pdfendlink" ukončí sazbu aktivního textu.
+
+\inext{link}{^^B\cbrace}{++}
+
+Makro \db urllink "[<typ>:<lejblík>]{<text>}" pracuje
+analogicky jako "\link". Jen navíc přidává některé
+atributy do PDF výstupu a pracuje s barvou "\urlcolor".
+
+\inext{urllink}{^^B\cbrace}{++}
+
+Makro \db url "{<odkaz>}" vysází "<odkaz>" strojopisem, přičemž znak "/" je
+na přechodnou dobu aktivní a definován jako "\\". Toto makro při sestavování
+externího odkazu zpětně expanduje na normální "/", ale při sazbě expanduje
+na "\discretionary", aby bylo možné v něm rozdělit sazbu do více řádků.
+
+\inext{url}{\empty}{+-}
+
+Makra \db toclink, \db pglink, \db citelink, \db reflink, \db ulink, která se
+specializují na určitý typ linku, implicitně nedělají nic:
+
+\inext{toclink}{\empty}{+-}
+
+Ovšem po použití makra \db hyperlinks "{<barva-lok>}{<barva-url>}" se
+uvedená makra "\toclink", "\pglink", "\citelink" a "\reflink" probouzejí k
+životu:
+
+\inext{hyperlinks}{\empty}{+-}
+
+Pdf\TeX{}ové primitivy pro klikací odkazy dovolují dopravit do PDF další
+atributy odkazu za slovem "attr". Tam je možné dát najevo, že chceme vidět
+aktivní plochy ve formě rámečků. To zařídí makro \db pdfborder "{<typ>}", které
+expanduje na nic, pokud není kontrolní sekvence "\<typ>border" definována.
+Jinak expandují na "arrt" "/C" s obsahem podle "\<typ>border".
+
+\inext{pdfborder}{\empty}{+-}
+
+Pokud je dokument zpracován do DVI výstupu, je vhodné výše zmíněná makra
+deaktivovat:
+
+\inext{ifpdftex}{\empty}{+-}
+
+
+\subsec Outlines -- obsah v záložce PDF dokumentu
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Hlavní problém implementace strukturovaného obsahu do záložky PDF dokumentu
+spočívá v~tom, že při vkládání jednotlivých položek obsahu je nutno znát
+počet přímých potomků každé položky (v~rámci stromové struktury položek),
+ovšem tito přímí potomci budou zařazeni později. OPmac tento problém řeší
+dvěma průchody nad daty, které jsou vytvořeny pro tisk obsahu, tj. v makru
+"\toclist". V prvním průchodu spočítá potřebné potomky a ve druhém
+průchodu zařadí všechny položky postupně jako \uv{outlines} do záložky.
+Připomeneme si, že v "\toclist" se nachází seznam maker tvaru
+"\tocline{<odsazení>}{<font>}{<číslo>}{<text>}{<strana>}".
+Makro \db outlines "{<úroveň>}" nejprve nastaví "\tocline" na hodnotu
+"\outlinesA" a projde "\toclist". Pak je nastaví na hodnotu "\outlinesB" a
+znovu projde "\toclist".
+
+\inext{def\nb outlines}{^^B\cbrace}{++}
+
+V makru \db outlinesA "{<odsazení>}{<font>}{<číslo>}{<text>}{<strana>}"
+počítáme potomky. Makro je navrženo tak, aby bylo
+snadno rozšířitelné na libovolnou úroveň hloubky stromu, nicméně pro potřeby
+OPmac stačí hloubka tři (kapitoly, sekce, podsekce). Úroveň uzlu přečteme v
+parametru "<odsazení>". Pro kapitolu je "<odsazení>"=0, pro sekci je
+"<odsazení>"=1 a pro podsekci je "<odsazení>"=2.
+Představme si vedle sebe řadu counterů
+"\count0:\count1:\count2". Při sekvenčním čtení jednotlivých uzlů stromu
+si každý uzel zvětší v této pomyslné řadě hodnotu svého
+counteru o~jedničku. Kapitoly zvětšují "\count0", sekce "\count1", podsekce
+"\count2". Stačí tedy zvětšit "\count<odsazení>". Řada counterů pak
+jednoznačně určuje zpracovávaný uzel.
+Uzly pro kapitoly mají přidělenu kontrolní sekvenci "ol:\the\count0"
+a uzly pro sekce mají přidělenu kontrolní sekvenci
+"ol:\the\count0:\the\count1". Jsou to makra, jejichž obsahem je počet
+potomků daného uzlu. Makrem \db addoneol "<csname>" zvětšíme obsah dané
+kontrolní sekvence o~jedničku. Příkazem "\ifcase<odsazení>" řešíme, kterému
+rodiči je třeba zvednout tuto hodnotu. Při nule (kapitola) nikomu,
+neboť daný uzel nemá rodiče. Při "<odsazeni>"=1 zvětšíme o
+jedničku počet potomků nadřazené kapitole a při "<odsazeni>"=2 nadřazené
+sekci. Asi by bylo přehlednější na začátku definovat všechny potřebné
+sekvence "ol:<něco>" a nastavit jim hodnotu~0. Ovšem šetříme pamětí i časem,
+takže zakládáme sekvenci "ol:<něco>" teprve v makru "\addoneol" a to tehdy,
+když je ji poprvé potřeba zvětšit o~jedničku.
+
+\inext{outlinesA}{\count=2 ^^B\cbrace}{++}
+
+V makru \db outlinesB "{<odsazení>}{<font>}{<číslo>}{<text>}{<strana>}"
+vkládáme jednotlivou položku obsahu do záložek pomocí pdf\TeX{}ového
+primitivu\hfil\break
+"\pdfoutline goto name{<lejblík>} count<potomci> {<text>}".
+Číslo "<potomci>" je opatřeno znaménkem mínus právě tehdy, když chceme, aby
+položka ve výchozím stavu nezobrazovala své potomky, ale jen trojúhelníček.
+Potomci se zobrazí až po kliknutí na trojúhelníček. V makru \db outlinelevel
+máme makrem "\outlines" připravenu úroveň rozevření, kterou si uživatel
+přeje. Nejprve přičtením "\count<odsazení>" dostaneme řadu
+"\count0:\count1:\count2" do stejného stavu, jako v předchozím prvním průchodu
+a máme tím jednoznačně přidělen uzel stromu.
+Do "\tmpnum" vložíme údaj o počtu potomků daného uzlu. K tomu je potřeba
+rozvětvit výpočet příkazem "\ifcase", protože pro různou úroveň uzlu máme
+údaj v~různě definovaném makru. Příkazem "\protectlist" zastavíme expanze
+případných maker registrovaných pomocí "\addprotect" a definujeme vlnku jako
+mezeru (v záložce vypadá líp než vlnka). Dále pomocí "\setcnvcodesA"
+expandujeme "\toasciidata". Pomocí "\setlccodes\toasciidata" připravíme
+"\lccode" znaků tak, aby "\lowercase" odstranil háčky a čárky. To
+vzápětí provedeme, ale nejprve ještě do toho může promluvit uživatel v makru
+"\cnvhook", které je implicitně nastaveno na makro prázdné.
+
+\ilabel [outlines:setlccodes] {setlccodes}
+
+\inext{outlinesB}{^^B\cbrace}{++}
+
+Makro \db setcnvcodesA zkontroluje podle definovanosti "\r", zda je zapnutý
+"\csaccents" a pokud je, expanduje "\toasciidata".
+Makro \db toasciidata potřebujeme expandovat, protože
+neobsahuje přímý zápis znaků. Důvod je zřejmý, nechceme, aby se
+soubor {\tt opmac.tex} stal závislý na použitém kódování.
+
+\inext{setcnvcodesA}{\count=2 ^^B\cbrace}{++}
+
+Na řádku \cite[outlines:setlccodes]
+se makro \db setlccodes spustí jako "\setlccodes AAÁAÄAáa...{}{}".
+Toto makro si odloupne dva parametry "xy", provede "\lccode`x=`y" a
+v~rekurzivním cyklu pokračuje v~činnosti, dokud nenarazí na "{}{}".
+
+\inext{setlccodes}{\empty}{+-}
+
+Makro \db insertoutline "{<text>}" vloží jedinou položku do záložky. Pro
+tuto položku se předpokládá nulový počet potomků. Využití: uživatel může
+takto odkázat na začátek nebo konec dokumentu.
+
+\inext{insertoutline}{\empty}{+-}
+
+Pokud je dokument zpracován do DVI výstupu, je vhodné výše zmíněná makra
+deaktivovat:
+
+\inext{ifpdftex}{\empty}{+-}
+
+
+
+\subsec Verbatim
+%%%%%%%%%%%%%%%%
+
+Verbatim výpisy budou odsazeny o "\ttindent". Je nastaven na hodnotu
+"\parindent" v době čtení souboru a společně s "\parindent" by měl
+uživatel změnit i "\ttindent". Čítač \db ttline čísluje řádky běžného verbatim výstupu,
+čítač \db viline čísluje řádky souboru čteného pomoci "\verbinput". Souborový
+deskriptor \db vifile bude přiřazen souboru v makru "\verbinput".
+
+\inext{newcount}{\empty}{+-}
+
+Makra \db setverb, \db begtt "...\endtt" jsou dokumentována v TBN, str. 29.
+
+\inext{setverb}{testparA}{++}
+
+Makro "\begtt" očichá na konci své činnosti, zda se nachází pod "\endtt"
+prázdný řádek (alias "\par"). K tomu slouží makra \db testparA (přeskočí
+mezeru, která za "\endtt" vždy je), \db testparB (přečte následující znak
+pomocí "\futurelet") a \db testparC (ošetří, zda tento následující znak je
+"\par").
+
+\inext{testparA}{\empty}{+-}
+
+Makro \db activettchar pracuje podobně, jako makro "\adef". Navíc
+potřebuje použít nově načtený znak ve své aktivní kategorii jako separátor
+vymezující konec parametru.
+
+\inext{activettchar}{\empty}{+-}
+
+Makro \db verbinput si pomocí "\tmpa" ověří, zda minule byl čten stejný
+soubor. Pokud ne, otevře soubor "#2" ke čtení pomocí "\openin" a uloží do
+\db vifilename jméno naposledy otevřeného souboru. Dále zkontroluje pomocí
+"\ifeof", zda je možné ze souboru číst. Pokud ne, vypíše se varování a
+pomocí \db skiptorelax se přeskočí zbytek obsahu makra až po "\relax",
+takže se neprovede nic dalšího. Je-li soubor úspěšně otevřen nebo byl-li
+otevřen již minule, pustí se makro "\verbinput" do prozkoumání parametru
+"#1" zapsaného v závorce před jménem souboru.
+
+\inext{verbinput}{\empty}{+-}
+
+Cílem vyhodnocení parametru v závorce makra "\verbinput" jsou dva údaje: \db
+vinolines bude obsahovat počet řádků, které je od začátku souboru nutno
+přeskočit, než se má zahájit přepisování řádků a \db vidolines bude
+obsahovat počet řádků, které se mají přepsat ze souboru do dokumentu.
+Písmena "vi" na začátku těchto názvů představují zkratku pro "verbinput".
+Vyšetření parametru ukončeného textem "+\relax" se v makru \db
+viscanparameter větví na případ, kdy parametr obsahuje symbol "+" a použije
+se pak \db viscanplus. Druhý případ, kdy uživatel nenapsal symbol plus
+(takže parametr "#2" makra "\viscanparameter" je prázdný) je dále
+vyšetřen v makru \db viscanminus. Obě makra si oddělí do svých parametrů
+první a druhou číslici (každá z nich může být prázdná) a nastaví podle
+zdokumentovaných pravidel pro zápis parametru odpovídající interní údaje
+"\vinolines" a "\vidolines". Vychází přitom z předpokladu, že registr
+"\viline" obsahuje číslo naposledy přečteného řádku (nebo nulu, jsme-li na
+začátku souboru).
+
+\inext{viscanparameter}{\count=3 ^^B\cbrace}{++}
+
+Makro \db doverbinput provede samotnou práci: přeskočí "\vinolines" řádků a
+přepíše "\vidolines" řádků. To provede v prvním a druhém cyklu "\loop". Než
+se k těmto cyklům dostane, musí udělat jisté přípravné práce. Nejprve odečte
+od "\vinolines" počet už přečtených řádků, protože při opakovaném čtení
+stejného souboru jej neotevíráme znova, jen přeskočíme příslušný menší počet
+řádků. Pokud ale se ukáže, že rozdíl je záporný (je potřeba se v souboru
+vracet dozadu), makro znovuotevře soubor ke čtení pomocí "\openin" a upraví
+podle toho příslušné údaje o řádcích. Pak zahájí skupinu, dále pomocí
+"\setverb" nastaví speciálním znakům kategorii 12 a pomocí "\adef{ }{ }"
+nastaví mezeře aktivní kategorii (bude expandovat na neaktivní mezeru jako
+"\space") a také nastaví kategorii 12 znaku, který byl deklarován pomocí
+"\activettchar". Připraví odsazení podle "\ttindent" a spustí uživatelský
+"\tthook". Je-li potřeba tisknout čísla řádků, připraví si na to font
+"\sevenrm", který má velikost rovnu 0,7 násobku základní velikosti. A pustí se do
+zmíněných dvou cyklů "\loop". V obou cyklech se může stát, že narazíme
+nečekaně na konec souboru. To je ošetřeno testem "\ifeof\vifile" a následnou
+úpravou čítače "\tmpnum" tak, abychom okamžitě vyskočili z cyklu. Druhý
+cyklus obsahuje ještě jeden speciální rys: přeje-li si uživatel číst až do
+konce souboru, je nastaveno "\vidolines" na nulu a před zahájením cyklu je
+čítač "\tmpnum" nastaven na "-1". Uvnitř cyklu je pak zajištěno, že v tomto
+případě není čítač zvětšován o jedničku. Po ukončení práce v těchto dvou
+cyklech je ukončena skupina, vložena mezera "\ttskip" a makrem "\testparB"
+se ověří, zda následuje prázdný řádek.
+
+\inext{doverbinput}{^^B\cbrace}{++}
+
+V prvním cyklu "\loop" v těle makra "\doverbinput" se opakovaně volá
+\db vireadline, což je makro, které přečte další řádek ze souboru. V druhém
+cyklu se opakovaně volá "\vireadline" následované \db viprintline. Toto
+makro vytiskne přečtený řádek do dokumentu. Před řádkem může být v "\llap"
+vytištěno číslo řádku. Záleží na hodnotě "\ttline". Je to naprogramováno v
+souladu s uživatelskou dokumentací.
+
+\inext{vireadline}{\empty}{++}
+
+
+\subsec Jednoduchá tabulka
+%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Tabulku makrem "\table" vytvoříme jako "\vbox", ve kterém je "\halign". Je
+tedy potřeba načíst deklaraci typu "{llc|rr}" a převést ji na deklaraci pro
+"\halign". Tato deklarace obsahuje znak "#" a tento znak se obtížně přidává
+do těla maker. Nashromáždíme tedy postupně deklaraci pro "\halign" do
+registru typu "\toks", který je nazvaný \db tabdata. Dále definujeme interní
+\db tabstrutA, který bude obsahovat uživatelův "\tabstrut", ovšem přechodně
+budeme toto makro měnit. Také deklarujeme čítač \db colnum, ve kterém budeme
+mít po přečtení deklarace uložen počet sloupců tabulky.
+Dále během skenování "<deklarace>" vytvoříme makro \db
+ddlinedata, které bude obsahovat "&\dditem &\dditem ..." (počet těchto dvojic
+bude roven $n-1$, kde $n$ je počet sloupců). Pokud je v deklaraci dvojitá
+svislá čára, bude v makru "\ddlinedata" na příslušném místě ještě "\vvitem".
+Makro "\ddlinedata" pak použijeme v "\crli" a v "\tskip",
+Strýček Příhoda to může použít jinde a jinak. Konečně makro \db vvleft je
+neprázdné, pokud úplně vlevo tabulky je dvojitá čára.
+
+\inext{newtoks}{\empty}{+-}
+
+Makro \db table "{<deklarace>}{<data>}" vypadá takto:
+
+\inext{table}{\empty}{+-}
+
+Makro \db scantabdata postupně čte znak po znaku z deklarace "\table" a podle
+přečteného znaku ukládá do "\tabdata" odpovídající úsek skutečné deklarace pro
+"\halign". Volá přitom "\addtabvrule" nebo "\addtabitem{\tabdeclare<znak>}".
+
+\inext{scantabdata}{^^B\cbrace}{++}
+
+OPmac předdefinuje tři "<znaky>" pro "<deklaraci>", sice "<znaky>" "c", "l", "r"
+v makrech \db tabdeclarec, \db tabdeclarel, \db tabdeclarer.
+
+\inext{tabdeclarec}{\empty}{+-}
+
+Makro \db unsskip vkládané na konec každé datové položky odebere mezeru,
+pokud má nenulovou základní velikost. Uživatelé totiž někdy dávají kolem
+datových položek mezery a někdy ne, přitom chtějí, aby se jim to chovalo
+stejně. Je náročné si pamatovat, že mezery před položkou jsou
+ignorovány primitivem "\halign", ale mezery za položkou jsou podstatné. Tak
+raději i mezery za položkou uděláme nepodstatné.
+
+\inext{unsskip}{}{++}
+
+Příklad: po deklaraci: "{|cr||cl|}" makro "\scantabdata" vytvoří:
+
+\begtt
+tabdata: \vrule\tabiteml\hfil#\unsskip\hfil\tabitemr
+ &\tabiteml\hfil#\unsskip\tabitemr \vrule\kern\vvkern\vrule
+ &\tabiteml\hfil#\unsskip\hfil\tabitemr
+ &\tabiteml#\unsskip\hfil\tabitemr\vrule
+ddlinedata: &\dditem &\dditem\vvitem &\dditem &\dditem
+\endtt
+
+Makra \db addtabitem, \db addtabdata a \db addtabvrule vloží do "\tabdata" a
+"\ddlinedata" požadovaný údaj. Makro "\addtabitem" pozná podle "\colnum=0",
+zda vkládá data pro první sloupec (nepřidává~"&") nebo pro další sloupce
+(přidává~"&"). Makro "\addtabvrule" pozná podle "\tmpa", zda před
+ním předchází další "\vrule". Pokud ano, vloží dodatečnou mezeru
+"\kern\vvkern" a přidá "\vvitem" do "\ddlinedata".
+
+\inext{addtabitem}{\empty}{+-}
+
+Než se pustíme do výkladu dalších maker, předvedeme příklad, ve kterém je
+definováno další písmeno "P" pro "<deklaraci>". Písmeno "P" vymezí
+tabulkovou položku, jež má stanovenou šířku a delší text se láme
+do více řádků. Je možné si vyzkoušet třeba tento kód:
+
+\begtt
+\newdimen\Pwidth
+\def\tabdeclareP {\enskip\vtop{\hsize=\Pwidth \rightskip=0pt plus1fil
+ \baselineskip=1.2em \lineskiplimit=0pt \noindent ##\tabstrut}\enskip}
+
+\Pwidth=3cm \table{|c|P|}{\crl
+ aaa & Tady je delší textík, který se nevejde na jeden řádek. \crl
+ bb & A tady je taky je něco delšího. \crl}
+\endtt
+
+Pusťme se nyní do rozboru maker na ukončení řádků.
+Makro \db crl přidá čáru pomocí "\noalign". Makro \db crll přidá dvojitou
+čáru pomocí "\noalign".
+
+\inext{crl}{\empty}{+-}
+
+Makro \db crli provede "\cr" a dále se vnoří do řádku tabulky, ve kterém
+klade postupně následující
+"\omit\tablinefil &\omit\tablinefil &..."
+Přitom v místě dvojité vertikální čáry naklade navíc "\tabvvline".
+Makro \db tablinefil vloží natahovací čáru na šířku celé položky a makro
+\db tabvvline vloží dvě "\vrule" vzdáleny od sebe o "\vvkern". Tím vzniká
+přetrzené místo v postupně tvořené lince. Ke správnému nakladení uvedených
+povelů použije makro "\crli" obsah makra "\ddlinedata" a vlevo přidává
+"\vvleft". Před spuštěním makra "\ddlinedata" definuje odpovídajícím
+způsobem \db dditem a \db vvitem.
+
+\inext{crli}{\empty}{+-}
+
+Makro \db tskip prostřednictvím \db tskipA přechodně vyprázdní "\tabstrut"
+předefinováním "\tabstrutA" a také vyprázdní "\dditem" a "\vvitem", aby
+po použití "\ddlinedata" vznikl řádek tabulky s prázdnými položkami.
+Řádek je vypodložený strutem stanovené výšky "\tmpdim".
+Nakonec je potřeba vrátit "\tabstrutA" do původního stavu.
+
+\inext{tskip}{\empty}{+-}
+
+Globální změna šířek všech linek tvořených pomocí "\vrule" a "\hrule" je
+provedena makry \db rulewidth a \db rulewidthA. Myšlenka je dokumentována v
+TBN na str.~328.
+\dgn \nb orivrule
+\dgn \nb orihrule
+
+\inext{orihrule}{\empty}{+-}
+
+Makro \db frame "{<text>}" vloží vnější "\vbox{\hrule..\hrule}".
+V něm se nachází další box "\hbox{\vrule\kern\vvkern..\kern\vvkern\vrule}"
+a v něm "\vbox{\kern\hhkern..\kern\hhkern}".
+Nejvíce uvnitř je pak "\hbox{<text>}". To by pro sazbu rámovaného textu
+stačilo, nicméně my ještě řešíme úpravu výsledného boxu tak, aby měl účaří
+ve stejném místě jako je účaří textu. Proto uložíme "\hbox{<text>}" do boxu0
+a změříme mu hloubku. V proměnné "\tmpdim" spočítáme celkovou hloubku
+výsledného boxu. Ve výpočtu přičítáme výšku "\hrule", která nemusí být
+0.4pt. Proto si její výšku změříme v boxu1. Ve vnějším "\vbox"u po
+nakreslení spodní "\hrule" se pak vracíme pomocí "\kern-\tmpdim" na úroveň
+účaří a zde umístíme strut hloubky "\tmpdim", aby sazba směrem dolů
+nepřečnívala, ale byla obsažena v~hloubce výsledného boxu.
+
+\inext{frame}{\empty}{+-}
+
+
+\subsec Vložení obrázku
+%%%%%%%%%%%%%%%%%%%%%%%
+
+Nejprve deklarujeme \db picw.
+
+\inext{picw}{\empty}{+-}
+
+Makro \db inspic je zkratka za použití primitivů "\pdfximage",
+"\pdfrefximage" a "\pdflastximage". Kdo si to má pořád pamatovat.
+Není-li aktivován PDF výstup, napíšeme jen varování a neprovedeme nic.
+Pokud budeme pracovat se stejnými obrázky v jednom dokumentu, bude
+vhodné možnosti primitivů využít naplno.
+
+\inext{ifpdftex}{\empty}{+-}
+
+
+\subsec PDF transformace
+%%%%%%%%%%%%%%%%%%%%%%%%
+
+Makro \db pdfscale "{<vodorovně>}{<svisle>}" pracuje jednoduše:
+
+\inext{pdfscale}{\empty}{+-}
+
+Na druhé straně makro \db pdfrotate "<úhel>" vytvoří
+"\pdfsetmatrix{"$\cos\varphi\enspace\sin\varphi\enspace
+ {-}\sin\varphi\enspace\cos\varphi$"}",
+což není jednoduché, protože funkce $\cos$, $\sin$ nejsou v \TeX{}u
+implementovány. Balíček "trig.sty" nabízí vyhodnocování těchto funkcí pomocí
+Taylorových polynomů, nicméně OPmac nechce být závislý na balíčcích a také
+chce ukázat alternativní způsob implementace. Makro "\pdfrotate" pracuje
+zhruba takto: je-li argument 0, neprovede nic, je-li argument 90, provede
+otočení o~90 stupňů. V ostatních případech zavolá makro \db pdfrotateA,
+které rozloží argument na celou "#1" a zlomkovou "#2" část. V další části
+na řádcích~\cite[rot:360] až \cite[rot:smallsin] se
+zabývá jen celými stupni. Nejprve pomocí prvního a druhého "\loop" posune
+argument o celé násobky 360 stupňů tak, že poté je argument mezi
+0 až 360 stupni, a přitom se hodnoty funkcí $\sin$ a $\cos$ nezměnily.
+Ve třetím "\loop" postupně snižuje argument o 90 stupňů a přitom dělá rotaci
+o 90 stupňů tak dlouho, až máme argument mezi nulou a devadesáti.
+Je-li dále argument větší než 44 stupňů, otočíme se o 45 a snížíme argument
+o 45. Je-li dále argument větší než 22, otočíme se o 22 a snížíme argument o
+22. Nyní máme argument v množině $\{0, 1, 2, 3, \ldots, 22\}$. Pro každý
+prvek z této množiny argumentů máme předpřipraveny hodnoty funkcí
+$\cos$ a $\sin$ v makrech \db smallcos a \db smallsin. Použijeme je pro
+závěrečnou rotaci. Tím máme sazbu otočenou o celé stupně.
+Další část makra na řádcích \cite[rot:174532] až \cite[rot:else]
+řeší jemné dotočení podle zlomkové části argumentu. V intervalu nula až
+jeden stupeň aproximujeme funkci $\cos$ konstantní jedničkou a funkci $\sin$
+lineární funkcí $x\cdot \pi/180$. V daném rozmezí je to velmi dobrá
+aproximace.
+
+\ilabel [rot:360] {360}
+\ilabel [rot:smallsin] {smallsin}
+\ilabel [rot:174532] {174532}
+\ilabel [rot:else] {else\space\space\space\space}
+
+\inext{pdfrotate}{\empty}{+-}
+
+Pro případ, že nepracujeme s PDF výstupem, definujeme klíčové primitivy
+pdf\TeX{}u jako makra, která nedělají nic.
+
+\inext{ifpdftex}{\empty}{+-}
+
+
+
+\subsec Poznámky pod čarou a na okraji stránek
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Makro \db fnote předpokládá, že správné číslo poznámky na dané stránce je
+připraveno v makru "\fn:<číslo>", kde "<číslo>" je celkové číslo poznámky napříč
+celým dokumentem sledované globálním čítačem \db fnotenum.
+Makro ohlásí svou existenci do REF souboru záznamem "\Xfnote" (bez
+parametru). Dále vytiskne značku pomocí "\fnmarkx" a ve skupině přejde na
+menší sazbu a zavolá plain\TeX{}ové makro "\vfootnote", které vloží sazbu
+pomocí tzv. insertu (TBN, kapitola~6.7). Plain\TeX{}ové nastavení této
+třídy insertu není makrem OPmac nijak měněno.
+
+\inext{fnotenum}{^^B\cbrace}{++}
+
+Makro \db fnotemark přičte lokálně k "\fnotenum" svůj parametr a vytiskne
+odpovídající značku. Celá práce makra probíhá ve skupině, takže po ukončení
+makra se "\fnotenum" vrátí do své původní hodnoty.
+
+\inext{fnotemark}{^^B\cbrace}{++}
+
+Makro \db fnotetext teprve zvedne čítač "\fnotenum" globálně a vytiskne
+poznámku pomocí plain\TeX{}ového "\vfootnote".
+
+\inext{fnotetext}{^^B\cbrace}{++}
+
+Makro \db fnmarkx vytiskne otazník nebo \db thefnote. Předpokládá se, že si
+uživatel předefinuje "\thefnote" k obrazu svému. Lokální číslo poznámky na
+stránce má připraveno v makru \db locfnum.
+
+\inext{fnmarkx}{\empty}{+-}
+
+Při čtení REF souboru se pro každou stranu přečte nejprve "\Xpage", což
+je makro, které pronuluje \db fnotenumlocal.
+Makru \db Xfnote tedy stačí pozvednout
+"\fnotenumlocal" o jedničku a pomocí
+"\sxdef" si tuto hodnotu zapamatovat v makru "\fn:<číslo>".
+
+\inext{Xfnote}{\empty}{+-}
+
+Registr \db mnotenum.
+globálně čísluje okrajové poznámky a plní podobnou funkci, jako registr
+"\fnotenum" pro podčárové poznámky.
+
+\inext{mnotenum}{\empty}{+-}
+
+Makro \db mnote ve vertikálním módu založí box nulové výšky pomocí
+"\mnoteA" a vycouvá na původní místo sazby pomocí "\vskip-\baselineskip". V
+odstavcovém módu toto makro nalepí box nulové výšky pod právě vytvořený
+řádek v odstavci. Víme, že "\vadjust" nalepí svůj materiál bez mezery pod
+tento řádek. My ovšem potřebujeme vycouvat nahoru na účaří řádku. To nejde
+snadno provést, protože hloubka řádku je proměnlivá. Proto do je řádku
+vložen "\strut" a předpokládá se, že nyní má řádek hloubku "\dp\strutbox" a
+o tento rozměr makro vycouvá nahoru. Vloží požadovaný box výšky nula na
+úrovni účaří a pak se vrátí na původní místo.
+
+\inext{mnote}{^^B\cbrace}{++}
+
+Makro \db mnoteA si zjistí, zda je v makru "\mn:<číslo>" uložen primitivní
+příkaz "\left" nebo "\right". Podle toho pozná, zda má umístit poznámku
+doleva nebo doprava. Rovněž dá o sobě vědět do REF souboru vložením
+sekvence "\Xmnote" (bez parametru). Sazba musí v obou případech vyprodukovat
+box nulové výšky i hloubky. Proto je "\vtop", uvnitř kterého je text poznámky
+zpracován, vložen přechodně do boxu0 a je mu pronulována hloubka. Nulová
+výška je zařízena pomocí "\vbox to0pt{\vss\box0}". Vlastní sazbu poznámky
+zahajujeme pomocí "\noindent" s tím, že je připraven pružný "\leftskip" nebo
+"\rightskip" podle toho, zda poznámku klademe vlevo nebo vpravo.
+Při kladení vlevo musíme použít "fill", abychom přeprali natahovací mezeru z
+"\parfillskip".
+
+\inext{mnoteA}{^^B\cbrace}{++}
+
+Makro \db Xmnote pracuje během čtení REF souboru a využívá toho, že makro
+"\Xpage" nastavuje číslo právě procesované strany do registru "\lastpge".
+Takže stačí použít "\sxdef" následujícím způsobem:
+
+\inext{Xmnote}{\empty}{+-}
+
+Makro \db fixmnotes "<token>" předefinuje v cyklu všechny definované
+kontrolní sekvence "\mn:<číslo>" tak, že budou obsahovat "<token>".
+Tím toto makro zlikviduje práci makra "\Xmnote", ale o to nám právě jde v
+případě, když chceme mít poznámky na jednoznačně dané straně.
+
+\inext{fixmnotes}{\empty}{+-}
+
+
+\subsec Bibliografické reference
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Nejprve uvedeme deklarace deskriptoru \db auxfile a čítačů
+\db bibnum a \db lastcitenum.
+
+\inext{auxfile}{\empty}{+-}
+
+Makro \db cite "[<lejblík1>,<lejblík2>,...]" si prostřednictvím \db citeA
+zavolá "\rcite{<lejblík>}" pro každou jednotlivou položku oddělenou čárkou ve
+svém parametru. Makro "\citeA" v sobě skrývá fintu: parametr nemá jediný,
+ale dva "#1#2". Protože první z nich je neseparovaný, ignorují se případné
+mezery za čárkou a "#1" obsahuje první písmeno "<lejblíku>". Uvnitř makra
+měníme \db citesep, což je čárka a mezera, která se má mezi údaji
+vytisknout. Makro \db nocite "[<lejblík1>,<lejblík2>,...]" je definováno
+stejně, jen připraví jiný význam makra "\docite", krz které budeme tisknout
+v "\rcite" potřebný údaj. Veškerá
+činnost maker "\cite" a "\nocite" probíhá uvnitř skupiny.
+
+\inext{cite}{\empty}{+-}
+
+Makro \db rcite "{<lejblík>}" řeší zhruba řečeno následující věci:
+
+
+\begitems
+\item * Zjistí, zda je definován "\csname bib:<lejblík>\endcsname". Pokud ano,
+ vytiskne jeho hodnotu, pokud ne, vytiskne do textu otazníky a na terminál
+ varování. Tato kontrolní sekvence začne být známá po použití
+ "\bib[<lejblík>]" nebo "\bibitem{<lejblík>}". Tato makra uloží
+ odpovídající informaci do REF souboru, odkud ji při opakovaném \TeX{}ování
+ vyzvedneme. Je to klasická činnost, kterou provozujeme i u ostatních
+ křížových referencí.
+\item * Uloží o sobě zprávu do bufferu "\citelist". To použijeme
+ v makrech "\usebibtex" nebo "\usebbl".
+\enditems
+
+Makro "\rcite" je naprogramováno zhruba takto
+
+\def\begtthook{\langleactive}
+\begtt
+function rcite(<lejblík>) {
+ if (<lejblík> == '*') { <zapiš do> \citelist '*'; return; }
+ if (\bib:<lejblík> == nedef) {
+ <zapiš do> \citelist <lejblík>;
+ <na terminál:> "Warning, cite [label] unknown";
+ <do tiskového výstupu:> "??";
+ \bib:<lejblík> = empty;
+ return;
+ if (\bib:<lejblík> == empty) {
+ <do tiskového výstupu:> "??";
+ return;
+ }
+ if (\bib:<lejblík> končí znakem '&') {
+ <zapiš do> \citelist <lejblík>;
+ <odstraň znak & z obsahu makra> \bib:<lejblík>;
+ }
+ <tiskni obsah makra> \bib:<lejblík>;
+}
+\endtt
+
+\def\begtthook{\langleactive}
+Výklad kódu: Protože chceme šetřit pamětí bufferu "\citelist", zapisujeme
+tam každý "<lejblík>" jen jednou. Zda se nedeklarovaný "<lejblík>" vyskytl
+poprvé poznáme podle nedefinované hodnoty "\bib:<lejblík>". Zda se vyskytl
+později znovu poznáme podle toho, že má hodnotu "empty". Zda se deklarovaný
+"<lejblík>" vyskytl poprvé poznáme podle znaku "&" v jeho obsahu.
+
+Návrh kódu v C-like notaci nyní převedeme do maker v \TeX{}u:
+
+\inext{rcite}{^^B\cbrace}{++}
+
+Asi nejzajímavější vychytávka v tomto makru se týká testu na znak "&".
+Implicitně při čtení REF souboru se do makra "bib:<lejblík>" uloží
+"\bibnn{<hodnota>}&". Příkaz "\if" za sebou totálně expanduje vše
+následující, takže nejprve narazí na "&", pak se obsah "bib:<lejblík>"
+expanduje prostřednictvím \db bibnn "{<hodnota>}" na nic a za tímto
+\uv{nic} se zjeví druhý znak "&", který se tedy přilepí na ten první.
+Ano, je pravda, že tyto dva znaky jsou stejné.
+Odstranění tohoto znaku probíhá znovu totální expanzí,
+tentokrát "\bibnn" první parametr "<hodnota>" zopakuje a druhý parametr
+se znakem "&" zahodí.
+
+Než se pustíme do výkladu makra "\docite", připravíme si makra \db printcite
+"<položka>" a \db printdashcite "<položka>". První z nich tiskne jednu
+položku oddělenou od případné
+další čárkou, druhé tiskne položku, před kterou předchází pomlčka
+vyznačující interval položek. Pointa makra "\printcite" je v tom, že si samo
+po prvním zavolání připraví separátor "\citesep" (který je na začátku
+činnosti "\cite" prázdný), takže při opakovaném volání "\printcite" se
+vytiskne i požadovaný separátor. Pomlčka v "\printdashcite" je schována do
+"\hbox", aby nedocházelo těsně za ní ke zlomu řádku.
+
+\inext{printcite}{\empty}{+-}
+
+Makro \db docite "<položka>" vytiskne otazníky při prázdném parametru a jinak
+vytiskne prostřednictvím "\printcite" jednu "<položku>". Kromě toho řeší při
+nenulovém "\lastcitenum" slučování po sobě následujících čísel položek do
+intervalů. Naposledy vytištěnou položku uchovává v registru "\lastcitenum".
+Při příštím zavolání zvětší "\lastcitenum" o jedničku a srovná ji s
+"<položkou>". Jsou-li si rovny, jde o následující položku v řadě a takovou
+položku netiskneme, nicméně si její hodnotu uchováme v "\tmpb". Pokud je
+mezi souvislou řadou položek díra, tj. "\lastcitenum" se nerovná
+"<položce>", pak dovytiskneme předchozí interval pomocí
+"\printdashcite{\the\tmpb}" a následně vytiskneme i "<položku>".
+Makro \db shortcitations jednoduše nastavuje "\lastcitenum" na nenulovou
+hodnotu a tím probudí k životu hlavní část makra "\docite".
+
+\inext{docite}{\empty}{+-}
+
+Následuje kód makra \db bib "[<lejblík>]", které prostřednictvím
+\db wbib "{<lejblík>}{<hodnota>}" vloží do REF souboru propojené údaje o
+tom, jaké má "<lejblík>" přiřazeno číslo v seznamu literatury.
+Makro "\wbib" připojí před "\wref" příkaz "\immediate" právě tehdy, když
+"\wref" je ve stavu, kdy skutečně zapisuje do souboru REF.
+Makro \db Xbib pracuje při čtení souboru REF a dělá to, co jsme si řekli už
+dříve: nastaví hodnotu makra "\bib:<lejblík>" na "\bibnn{<hodnota>}&".
+
+\inext{bib}{\empty}{+-}
+
+Makro \db addcitelist "{<lejblík>}" přidá do \db citelist údaj ve tvaru
+"\lcite[<lejblík>]". Hranaté závorky jsou použity proto, aby fungoval test
+"\isinlist\citelist{[<lejblík>]}". Jak uvidíme za chvíli, makro
+"\addcitelist" změní během činnosti makra "\usebibtex" svůj význam na
+\db writeaux, aby případné použití "\cite" až za "\usebitex" rovnou
+zapisovalo do AUX souboru. Podobně makro "\addcitelist" změní v makru
+"\usebbl" svůj význam \db writeXcite "{<lejblík>}",
+aby v příštím průchodu \TeX{}em
+mělo makro "\usebbl" přehled i o výskytech "\cite", které jsou napsány
+později, než "\usebbl".
+
+\inext{addcitelist}{\empty}{+-}
+
+Než se pustíme do výkladu maker "\usebibtex", "\genbbl" a "\usebbl", uvedeme
+stručně popis činnosti Bib\TeX{}u. Příkaz "bibtex <dokument>" způsobí,
+že program {\tt bibtex} se podívá do souboru "<dokument>.aux" a tam si všímá
+sekvencí \db bibdata "{<bib-báze>}", \db bibstyle "{<bib-style>}" a \db
+citation "{<lejblík>}". Na základě toho následně přečte soubor
+"<bib-báze>.bib" se zdrojovými zápisy bibliografických údajů.
+Pro konverzi těchto zdrojových zápisů do výstupního souboru "<dokument>.bbl"
+použije stylový soubor "<bib-style>.bst". Není-li mezi sekvencemi
+"\citation" uvedeno "\citation{*}", program {\tt bibtex} zahrne do výstupu
+jen ty bibliografické údaje, které mají "<lejblík>" shodný s některým z
+"<lejblíků>" uvedených v parametrech sekvencí "\citation". Každá sekvence
+"\citation{<lejblík>}" v souboru "<dokument>.aux" typicky odpovídá jednomu
+použití příkazu "\cite[<lejblík>]".
+
+Makro \db usebibtex "{<bib-báze>}{<bst-styl>}" otevře soubor AUX
+prostřednictvím \db openauxfile "{<bib-báze>}{<bst-styl>}". Napíše tam tedy
+požadovaná data pro Bib\TeX{}. Dále z "\citelist" přepíše do AUX souboru
+lejbílky ve formátu "\citation{<lejblík>}". Nakonec se uvnitř skupiny pustí do
+čtení souboru BBL prostřednictvím makra "\readbblfile".
+
+\inext{usebibtex}{\count=2 ^^B\cbrace}{++}
+
+Makro \db readbblfile "{<soubor>}" vyzkouší, zda je "<soubor>.bbl" připraven
+ke čtení. Pokud ne, podá o tom odpovídající zprávu na terminál. Jinak
+nastaví čítač "\bibnum" na nulu a (vědomo si toho, že je spuštěno ve
+skupině) pustí se do lokálních re-definic La\TeX{}ových konstrukcí, které se
+typicky v BBL souborech používají. Nastaví "\leftskip" na "\iindent" a
+spustí "\bibtexhook". Konečně načte soubor BBL.
+
+\inext{readbblfile}{^^B\cbrace}{++}
+
+V BBL souboru se vyskytují povely \db bibitem. Za každým z nich se možná
+objeví parametr v~hranaté závorce "[<značka>]" a následně je uveden
+"{<lejblík>}". Pak na dalších řádcích jsou bibliografická data jednoho
+záznamu ukončená prázdným řádkem. Objeví-li se "[<značka>]", dává tím
+Bib\TeX{} najevo, že se má tato "<značka>" použít místo běžného číslování
+záznamů. Následuje kód, který takové údaje přečte, vytiskne a vloží do REF
+souboru o tom zprávu prostřednictvím "\wref{<lejblík>}{<hodnota>}".
+Rozlišují se dva režimy tisku: není-li přítomna "[<značka>]" (makro "\tmpa"
+je prázdné), pak pomocí "\llap" vytiskneme "[<číslo>]". Jinak se posuneme o
+"-\iindent" a tiskneme "[<značku>]" následovanou mezerou. Pak se vytisknou
+další údaje bibliografického záznamu.
+\dgn\nb bibitemB \dgn\nb bibitemC \dgn\nb bibitemD
+
+\inext{bibitem}{^^B\cbrace}{++}
+
+Makro \db genbbl "{<bib-báze>}{<bst-style>}" otevře AUX soubor a zapíše do
+něj údaje potřebné pro Bib\TeX{} včetně "\citation{*}". Poté se makro pokusí
+přečíst výstup z Bib\TeX{}u pomocí "\readbblfile". V tomto případě pracuje
+"\bibitem" ve zvláštním režimu, kdy netiskne "<hodnoty>", ale "<lejblíky>".
+Z toho důvodu je předefinováno makro "\bibitemC".
+
+\inext{genbbl}{^^B\cbrace}{++}
+
+Makro \db usebbl "/<typ> <bbl-file>" spustí jiné makro s názvem "\bbl:<typ>".
+Tři taková makra jsou definována pomocí "\sdef". První "\bbl:a" je
+jednoduché: prostě projde BBL soubor a vytiskne údaje z~něj.
+Druhé makro "\bbl:b" projde BBL
+soubor v režimu, při kterém jsou bibliografická data každého záznamu (až po
+prázdný řádek alias "\par") přečtena do parametru "#2" makra "\bibitemC".
+Celý údaj je pak vytištěn jen za předpokladu, že "[<lejblík>]" je přítomen
+v seznamu "\citelist". Třetí makro "\bbl:c" pracuje jako druhé až na to, že
+údaj netiskne, ale zapamatuje si ho do makra "\bb:<lejblík>". Po takovém
+projití BBL souboru ještě projde "\citelist", kde se "\lcite[<lejblík>]"
+promění v "\bb:<lejblík>", takže se záznam vytiskne. Nyní ale v pořadí, v
+jakém jsou "<lejblíky>" zařazeny do "\citelist".
+
+\inext{usebbl}{\count=3 ^^B\cbrace}{++}
+
+Za zmínku stojí ještě práce uvedených maker s "\citelist". Před výskytem makra
+"\usebbl" se lejblíky z "\cite" a "\nocite" hromadí v "\citelist". Ovšem
+další "\cite" a "\nocite" se mohou vyskytovat za příkazem "\usebbl". Pokud
+se tak stane, pracuje "\addcitelist" nyní ve významu "\writeXcite" a uloží
+potřebnou informaci do REF souboru. Při dalším \TeX{}ování se tato informace
+přečte makrem \db Xcite "{<lejblík>}" z REF souboru takto:
+
+\inext{Xcite}{}{++}
+
+\noindent To tedy znamená, že se uloží do seznamu "\citelistB". Konečně
+makra "\bbl:b" a "\bbl:c" si dva seznamy "\citelist" a "\citelistB" před svou
+činností spojí do seznamu jediného nazvaného "\citelist".
+
+
+\subsec Úprava output rutiny
+%%%%%%%%%%%%%%%%%%%%%%%%%%%%
+
+Místo původního makra "\plainoutput" používá OPmac makro \db opmacoutput.
+
+\inext{opmacoutput}{}{++}
+
+OPmac mění output rutinu proti originální "\plainoutput" jen v nejnutnějších věcech.
+Řeší tyto dva problémy:
+
+\begitems
+\item * Místo přímého "\shipout" nechá nejprve box sestavit jako "\box0",
+ pak provede "\protectlist" a pak provede "\shipout\box0".
+\item * Mezi "\makeheadline" a "\pagebody" vkládá "\prepage".
+\enditems
+
+První úprava zabrání expanzi maker přidaných pomocí "\addprotect" v době
+práce příkazu "\shipout", tedy v době, kdy expandují parametry "\write".
+Těmto makrům je přidělen prostřednictvím \db doprotect "<makro>"
+pro tento okamžik význam "\relax". Je potřeba ještě
+vysvětlit, proč bylo nutné sestavit nejprve "\box0" a teprve poté jej poslat
+ven pomocí "\shipout". Je to z toho důvodu, že v době sestavování "\box0"
+jsou expandována "\headline" a "\footline" a pro ten případ ještě chceme,
+aby všechna makra správně expandovala.
+
+\inext{opmacoutput}{\empty}{+-}
+
+Druhá úprava vkládá makro \db prepage, které zajistí tisk stránkové číslice
+do "\reffile" (to je docela užitečné) a kromě toho nastaví správnou barvu
+textu strany pomocí PDF speciálu.
+
+\inext{prepage}{\empty}{+-}
+
+Když budou barvy přecházet na další stranu, jistě nechceme mít obarvenu
+stránkovou číslici. Je tedy potřeba do \db footline vložit "\Black". Když
+bude uživatel měnit velikost fontů v dokumentu, jistě nechce mít
+stránkovou číslici pokaždé jinak velkou. Proto je do "\footline" vloženo
+"\thefontsize". Je nastaveno pevně na 10pt. Předpokládáme, že pokud bude
+někdo chtít jinak velkou stránkovou číslici, jednoduže si "\footline"
+nastaví podle svého. Jinak je "\footline" shodná s původním nastavením
+v~plain\TeX{}u.
+
+\inext{footline}{\empty}{+-}
+
+
+\subsec Okraje
+%%%%%%%%%%%%%%
+
+V registrech \db pgwidth a \db pgheight budeme mít po zavolání "\setpagedimens"
+šířku a výšku strany. V~registru \db shiftoffset budeme mít případný rozdíl
+okrajů mezi levou a pravou stránkou.
+
+\inext{pgwidth}{\empty}{+-}
+
+Makro \db margins "/<typ> <formát> (<levý>,<pravý>,<horní>,<dolní>)<jednotka> "
+si nastaví registry "\pgwidth" a "\pgheight" prostřednictvím "\setpagedimens" a dále v
+souladu s uživatelskou dokumentací nastaví potřebné okraje. V makru "\tmp"
+je schována jednotka, kterou uživatel taky může zapomenout napsat. V~takovém
+případě vypíšeme varování a doplníme jednotku "mm". Jakmile měníme
+"\hoffset" nebo "\voffset", nastavíme je nejprve na "-1in" (tím se dostaneme
+na okraj papíru) a pak budeme požadovanou velikost okraje k těmto registrům
+přidávat. Nemohu za to, že Knutha napadla taková ne příliš podařená myšlenka
+dát výchozí bod sazby kamsi doprostřed papíru umístěný pomocí ujetých
+jednotek. Za zmínku stojí ještě dvě myšlenky. Makro \db rbmargin
+"\h(v)offset\h(v)size{<okraj>}" provede výpočet hodnoty "\hoffset" nebo
+"\voffset" v případě, že je dána protější hodnota okraje než je okraj přímo
+nastavitelný pomocí "\h(v)offset".
+A konečně posun okraje při přechodu z pravé na levou stránku "\shiftoffset"
+počítáme jako "\pgwidth"~"-"~"\hsize"~"-"~"2*<levý>" což dá stejnou hodnotu jako
+"<pravý>-<levý>". Změna "\hoffset" o tuto hodnotu je provedena v makru
+"\pghook", tedy v "\output" rutině, schována do skupiny, takže po ukončení
+"\output" rutiny se vrátí "\hoffset" na původní hodnotu.
+
+\inext{margins}{\empty}{+-}
+
+Makro \db setpagedimens "<formát> " spustí
+\db setpagedimensA "<šířka> <výška>/" a k tomu musí
+dopředu vyexpandovat obsah makra "\pgs:<formát>". To provedeme pomocí tří
+"\expandafter".
+
+\inext{setpagedimens}{\empty}{+-}
+
+Jednotlivé "<formáty>" papíru je potřeba deklarovat.
+
+\inext{sdef}{\empty}{+-}
+
+Makro \db magscale "[<factor>]" zvětší/zmenší sazbu nastavením
+registru "\mag" a definuje dosud prázdné makro \db trueunit hodnotou
+"true", aby později při činnosti makra "\setpagedimensA" zůstaly zachovány
+rozměry stránek. Pokud ale je makro "\magscale" spuštěno až po nastavení
+velikosti stránek, jsou tyto velikosti dodatečně korigovány na \uv{true}
+jednotky pomocí makra \db truedimen.
+
+\inext{trueunit}{\empty}{+-}
+
+
+\subsec Závěr
+%%%%%%%%%%%%%
+
+Nakonec pomocí "\inputref" přečteme REF soubor (pokud existuje) a vrhneme se
+na zpracování dokumentu, který nám připravil uživatel. Přeji dobré pořízení.
+
+\inext{inputref}{\empty}{+-}
+
+\doindex
+
+
+\bye
+
+