
%% DocBy.\TeX{} -- nástroj na dokumentování zdrojových kódů

\def\projectversion{\dbtversion}
\def\headtitle{DocBy.\TeX}

\showboxbreadth=1500 \showboxdepth=2

\chyph
\input docby.tex

\title DocBy.\TeX{} -- nástroj na dokumentování zdrojových kódů

\author Petr Olšák

\centerline{\ulink[http://www.olsak.net/docbytex.html]%
                         {www.olsak.net/docbytex.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~DocBy.\TeX{}u interní. Tučně je označena strana, kde je slovo
   dokumentováno, pak následuje seznam stran s výskyty slova.
   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
%%%%%%%%%

DocBy.\TeX{} umožňuje jednoduše dokumentovat pomocí \TeX{}u 
zdrojové kódy programu napsaném v~jazyce~C případně v jakémkoli
jiném jazyce.

Na rozdíl od Knuthova literárního programování tento nástroj nepoužívá
žádné preprocesory nebo filtry pro oddělení informace pro člověka a
pro počítač. Vycházím z toho, že programátor je zvyklý psát tyto
informace odděleně a chce mít věci pod vlastní kontrolou. Rovněž mnozí
programátoři uvítají, že mohou psát dokumentaci dodatečně, a přitom
skoro nezasahovat do už napsaného (a možná odladěného) zdrojového
kódu.  Doba, kdy Knuth navrhoval literární programování, pokročila a
tvůrce dokumentace dnes může mít zároveň ve více oknech otevřeno více
textů.  Některé jsou určeny pro člověka a jiné pro počítač. Nevnímám
tedy tak hlasitou potřebu tyto informace slučovat do jednoho
souboru, jako tomu bylo kdysi.

V první části (sekce~\cite[uziv]) dokumentu seznamujeme čtenáře
s použitím \docbytex{}u na uživatelské úrovni. V další sekci jsou
dokumentovaná výchozí makra \docbytex{}u, u nichž se předpokládá, že
je bude chtít náročný uživatel měnit, aby přizpůsobil chování \docbytex{}u
obrazu svému. Dále následuje sekce~\cite[design] s dokumentací
maker, která rovněž budou měněna, pokud uživatel bude chtít jiný
vzhled dokumentu. V~poslední sekci~\cite[implementace] 
je dokumentován kompletní \docbytex{} na implementační úrovni. 
Takže se tam můžete dočíst, jak makra fungují. 

Tento dokument je zpracován \docbytex{}em, takže slouží mimo jiné jako
ukázka, co je možné tímto nástrojem vytvořit.

\sec [uziv] Pro uživatele
%%%%%%%%%%%%%%%%%%%%%%%%%

\subsec [cleneni] Členění souborů
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

\docbytex{} je implicitně navržen pro dokumentování zdrojových kódů 
v~jazyce~C. Proto i následující ukázka dokumentuje hypotetický program
napsaný v tomto jazyce. Chcete-li dokumentovat jiný jazyk, můžete
implicitní chování \docbytex{}u pozměnit. Tomu je věnována 
sekce~\cite[zmeny].

Předpokládá se, že zdrojové kódy programu jsou členěny na moduly. Každý modul
je myšlenkově samostatná záležitost. Alespoň pro programátora. Každý modul
má své jméno (například "cosi") a je napsán v souborech "cosi.h" a "cosi.c",
případně v dalších. Tyto soubory se kompilují, aby vznikl "cosi.o" a 
v~závěru kompilace se linkují všechny kompilované moduly do výsledného
programu.

Chceme-li takové zdrojové kódy dokumentovat, připíšeme ke každému
modulu soubor s příponou ".d", například "cosi.d", který obsahuje
dokumentaci k danému modulu.  Dále založíme třeba soubor
"program.tex", ze kterého postupně načítáme dokumentace jednotlivých
modulů pomocí příkazu "\module"\du{module}. V \uv{hlavním souboru} "program.tex"
můžeme též použít příkazy "\title" pro vyznačení názvu programu,
"\author" se jménem autora programu a třeba "\dotoc" pro vytvoření
obsahu a "\doindex" pro vygenerování rejstříku. Samozřejmě zde můžeme
napsat třeba úvodní poznámky ke zdrojovým kódům programu a použít plno
dalších vymezovacích příkazů (viz dále). Obsah souboru "program.tex"
může vypadat třeba takto:

\begtt
\input docby.tex
\title   Program lup -- dokumentace ke zdrojovým textům

\author  Progr a Mátor

\dotoc  % tady bude obsah

\sec Členění zdrojových textů

Zdrojové texty programu "lup" jsou rozděleny do tří modulů. 
V "base.c" jsou definovány pomocné funkce a v "base.h" jsou jejich
prototypy. Podobně ve "win.c" jsou funkce pro okenní záležitosti a
"win.h" obsahuje jejich prototypy. Konečně "main.c" obsahuje hlavní
funkci programu.
\module base
\module win
\module main
\doindex  % v tomto místě bude sestaven rejstřík
\bye
\endtt

V tomto příkladě jsme se rozhodli čtenáře dokumentace seznamovat s
programem \uv{zdola nahoru}, tedy od elementárních funkcí až k hotovému
programu. Někdo možná preferuje cestu \uv{shora dolů} a může mít v
dokumentaci napsáno:

\begtt
\module main
\module win
\module base
\doindex
\bye
\endtt

Oba přístupy jsou možné, protože dokumentace je automaticky provázána
hyperlinky. Čtenář se kdykoli může podívat na dokumentaci té funkce,
jejíž použití zrovna čte, a obráceně může projít výskyty veškerého
použití funkce, když čte její dokumentaci.

\subsec [priklad] Příklad dokumentace modulu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Soubor s dokumentací jednotlivého modulu budu pro tento 
případ značit "cosi.d". Ten je načten příkazem "\module"~"cosi ".
V souboru "cosi.d" je možno se literárně vyřádit a kdykoli vložit část 
existujícího zdrojového kódu programu se stejným jménem modulu.
To provedeme příkazem "\ins"~"c keyword "\du{ins}, který vloží do dokumentace
část zdrojového kódu ze souboru "cosi.c", která je vymezena pomocí slova 
"keyword". Místo písmene "c" je možno použít "h" nebo jakoukoli jinou
příponu souboru, ze kterého chceme vložit část do dokumentace. K
vymezení částí, které se mají vložit, je nutno mít ve zdrojovém
souboru text "//: keyword". Vše vysvětlí následující příklad.

Předpokládejme, že v souboru "cosi.d" máme napsánu tuto dokumentaci:

\begtt
Struktura \dg dvojice se používá jako návratová hodnota funkce
"uzasna_funkce" a sdružuje dvě hodnoty typu "float".
\ins c dvojice

Funkce \dg [struct dvojice] uzasna_funkce() si vezme jeden parametr "p" 
a vrátí ve struktuře "dvojice" dvojnásobek a trojnásobek tohoto parametru.
\ins c uzasna_funkce
\endtt

V tomto případě je nutné, aby v souboru "cosi.c" existoval vymezující
text "//: "{\tt dvojice} a text "//: "{\tt uzasna\_funkce}. 
Tyto texty vymezují úseky,
které se mají do dokumentace vložit. Soubor "cosi.c" může vypadat
třeba takto:

\begtt
#include <stdio.h>

//: dvojice

struct dvojice {
  float x, y;
};

//: uzasna_funkce

struct dvojice uzasna_funkce (float p)
{
  struct dvojice navrat;
  navrat.x = 2*p; // tady nasobim p dvema
  navrat.y = 3*p; // tady nasobim p tremi
  return navrat;
} 
\endtt

Výsledek po zpracování části dokumentace z "cosi.d" pak vypadá takto:

\bigskip

Struktura \dg [struct] dvojice se používá jako návratová hodnota funkce
"uzasna_funkce" a sdružuje dvě hodnoty typu "float".
\def\modulename{cosi}
\ins c dvojice

Funkce \dg [struct dvojice] uzasna_funkce() si vezme jeden parametr "p" a vrátí
ve struktuře "dvojice" dvojnásobek a trojnásobek tohoto parametru.
\ins c uzasna_funkce

V ukázkovém zdrojovém kódu je první vložený úsek vymezen na
začátku textem "//: "{\tt dvojice} a na konci textem "//:". Druhý úsek je
vymezen textem "//: "{\tt uzasna\_funkce} a končí na konci souboru.

Na pořadí úseků, které zahrnujeme ze zdrojového textu do dokumentace,
nezáleží. Klidně jsme mohli dokumentaci začít od povídání o úžasné
funkci (včetně vložení jejího kódu) a potom ještě dopsat, co to je ta 
struktura "dvojice" a následně vložit deklaraci této struktury.

Kdybychom před řádek "#include "{\tt<stdio.h>} vložili třeba text
"//: start", bylo by možné příkazem "\ins"~"c start " vložit 
do dokumentace začátek souboru "cosi.c", který v ukázce vložen není.

Všimněme si, že \TeX{} zapsal čísla řádků přesně podle toho, jak
jsou ve zdrojovém kódu. Tj. počítal i přeskakovaný řádek 
"#include "{\tt<stdio.h>} i přeskakované prázdné a vymezující řádky.

Vymezení "//: keyword" se může v řádku nacházet kdekoli, není nutné,
aby se vyskytovalo na začátku řádku. Řádek s~tímto vymezením není do
dokumentace zahrnut a pokud následuje za řádkem s~vymezením prázdný
řádek, ani ten není do dokumentace zahrnut. 

Stejně tak koncové vymezení "//:" se může v řádku nacházet kdekoli a
celý řádek s tímto vymezením není do dokumentace zahrnut. 
Pokud před tímto koncovým řádkem je prázdný řádek, ani ten 
není do dokumentace zahrnut.

Konečně za povšimnutí stojí použití příkazu "\dg" v dokumentaci. Za
ním následuje slovo (separované mezerou), které dokumentujeme. Toto
slovo se v dokumentaci výrazně označí (v PDF verzi červenou barvou
navíc v barevném rámečku) a jakýkoli jiný výskyt takového slova ve
zdrojovém textu nebo mezi uvozovkami {\tt\char`\"...\char`\"} bude
automaticky označen modrou barvou a bude klikací. Kliknutí na modrý
výskyt slova kdekoli v dokumentaci vrátí čtenáře na červený výskyt,
kde je slovo dokumentováno.

Dokumentované slovo může mít před sebou v hranatých závorkách text,
který např. označuje typ funkce a za sebou může mít kulaté závorky
"()".  Tím můžeme dát najevo, že dokumentujeme funkci. V místě
dokumentace se neobjeví ani tento nepovinný text ani závorky, ale v
poznámce pod čarou a v~rejstříku se tyto informace vytisknou.

\uv{Palcové uvozovky} {\tt\char`\"...\char`\"} vymezují kusy kódu
uvnitř odstavce. Text takto uvozený je psán strojopisem a pokud se 
v něm vyskutují deklarovaná slova, tato slova automaticky modrají
a stávají se klikatelnými odkazy.
Text mezi těmito uvozovkami je navíc přepisován ve \uv{verbatim}
módu \TeX{}u, tj. žádné znaky nemají speciální vlastnosti (s výjimkou
koncové palcové uvozovky). 

Na stránce, kde je slovo dokumentováno (pomocí "\dg"), je v poznánkách
pod čarou slovo znovu zmíněno a vedle této zmínky je seznam všech
stránek, na kterých se kdekoli v textu vyskytuje použití tohoto slova.
Dále jsou všechna dokumentovaná slova zahrnuta do závěrečného
abecedního rejstříku, který odkazuje jednak na stránku, kde je
slovo dokumentováno, i na stránky se všemi výskyty slova.


\subsec Jaký \TeX{} pro \docbytex{}?
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Aby fungovaly všechny výše uvedené vlastnosti, je potřeba použít
pdf\TeX{} rozšířený o enc\TeX{}. Dále je dle "\language" detekován 
jazyk, který se použije v automaticky generovaných slovech.
\docbytex{} se ohlásí na terminálu například těmito slovy:

\def\begtthook{\catcode`\!=0}
\begtt
This is DocBy.TeX, version !dbtversion, modes: enc+PDF+ENG
\endtt

\def\begtthook{}

\docbytex{} rozlišuje tři módy, každý může nabývat dvou stavů:
mód "enc/NOenc", dále mód "PDF/DVI" a konečně mód jazyka "ENG/CS".

Mód "enc"\api{enc} se zapne, je-li detekována přítomnost enc\TeX{}u.
Pokud enc\TeX{} není dostupný, vypíše o~tom \docbytex{} varování a
přejde do "NOenc"\api{NOenc} módu. V tomto módu nefunguje automatická detekce
slov, která jsou dokumentována, takže tato slova nemodrají a nestávají
se klikacími odkazy. V rejstříku pak také není seznam stránek se všemi
výskyty slova, ale jen místo, kde je slovo dokumentováno.
V~tomto případě tedy je deaktivována nejdůležitější vlastnost
\docbytex{}u, takže je žádoucí vynaložit jisté úsilí a enc\TeX{}
zprovoznit. V současných distribucích \TeX{}u bývá enc\TeX{}
v pdf\TeX{}u zahrnut a je aktivován například ve formátu "pdfcsplain".

Mód "PDF"\api{PDF} je detekován, pokud je použit pdf\TeX{}, jinak \docbytex{}
přejde do módu "DVI"\api{DVI} a napíše o tom varování na terminál. V módu "DVI"
nefungují barvy ani klikací odkazy. Ovšem seznam stránek s~použitím
dokumentovaného slova se generuje, je-li přítomen enc\TeX.

\docbytex{} detekuje mód jazyka "ENG" (angličtina), je-li 
"\language=0". To je implicitní chování.
Pokud například v "csplainu" nastavíte "\chyph" před
"\input docby.tex", \docbytex{}
to vyhodnotí jako dokument v češtině ("CS"). 
Jiné jazyky nejsou zatím podporovány.
V módu "ENG" jsou automaticky generované názvy 
\uv{Contents}, \uv{Index} anglické, 
v módu "CS" jsou tyto názvy \uv{Obsah}, \uv{Rejstřík} české.
V~sekci~\cite[nazvy] je řečeno, jak jsou tato slova generována 
a co tedy udělat, když chcete mít dokument v jiném jazyce.

\subsec Vyhledávání slov enc\TeX{}em
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Slova, která se stávají klikatelnými odkazy vyhledává enc\TeX{}. Ten
má zabudován tzv. \uv{hladový algoritmus}. To znamená, že jsou-li
dokumentována např. slova "abc" a "abcde", pak text "abcdefgh" zmodrá
až po písmeno "e" a odkazuje na "abcde", zatímco "abcdx" zmodrá až po
písmeno "c" a odkazuje na "abc". To bývá obvykle žádoucí. 
%
V enc\TeX{}u není možno programovat vyhledávání podle regulárních
výrazů, takže není možné jednoduše říci, aby enc\TeX{} hledal jen
slova, která jsou ohraničena mezerou, tečkou, závorkou, středníkem,
atd. Místo toho enc\TeX{} tupě vyhledá slovo třeba uvnitř jiného slova.

Může se tedy stát, že máme dokumentováno kratší slovo, které se
objevuje jako část jiných nedokumentovaných slov. Například je
dokumentována struktura "turn", ale ve výpisech programu nechceme, aby
v každém výskytu klíčového slova "return" zmodrala jeho část. V
takovém případě je potřeba explicitně definovat "return" jako 
\uv{normální} nedokumentované slovo. K tomu slouží příkaz
"\noactive{<slovo>}"\du{noactive}, tedy například 
"\noactive{return}". Tento příkaz globálně
deklaruje "<slovo>" jako vyhledávané slovo (pro enc\TeX), ale 
specifikuje jej jako neaktivní.

Může se také stát, že máme dokumentováno slovo, které se objevuje ve
zdrojových textech i v jiném (nedokumentovaném) významu. Přitom dokumentované
slovo poznáme podle toho, jak vypadá text před slovem a za slovem.
Pak lze použít deklaraci "\onlyactive{<před>}{<slovo>}{<za>}"\du{onlyactive}, 
která sama o sobě nedělá nic. Pokud ale vyznačíme "<slovo>" pomocí
"\dg" (nebo podobného makra na dokumentování slov, viz
sekce~\cite[ddsl]), pak bude "<slovo>" automaticky modrat jen tehdy,
předchází-li mu text "<před>" a následuje text "<za>". Texty "<před>"
nebo "<za>" mohou být prázdné (ne oba současně) a k jednomu "<slovu>"
můžeme napsat více různých deklarací "\onlyactive".
 
\docbytex{} aktivuje enc\TeX{} (pomocí "\mubytein=1") jen uvnitř
skupiny, když zpracovává text mezi palcovými uvozovkami
({\tt\char`\"...\char`\"}) nebo při načítání zdrojového textu
programu. Předpokládá se, že nepoužíváte enc\TeX{} k~dekódování UTF-8
kódu. Pokud používáte, zkuste si zapnout "\mubytein=1" pro celý dokument,
ale na {\it vlastní riziko}. V takovém případě vám budou modrat slova
nebo jejich části i v~běžném textu a pokud je dokumentované slovo
podmnožinou nějaké \TeX{}ové sekvence, kterou používáte, pak se
dočkáte nepříjemných chyb.

\subsec Generování rejstříku, obsahu, poznámek pod čarou a záložek
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Generování rejstříku i obsahu probíhá v \docbytex{}u zcela
automaticky. Pro vytvoření rejstříku není nutné používat externí
program (\docbytex{} si slova abecedně zatřídí sám).
Stačí tedy vložit na požadovaná místa příkazy "\dotoc"\du{dotoc} a
"\doindex"\du{doindex}. Upozorňuji, že rejstřík ani obsah nejsou správně
vygenerovány po prvním průchodu \TeX{}u. Je potřeba \TeX{}ovat
dvakrát. Po druhém průchodu dojde zřejmě k přestránkování textu
(protože je například vložen obsah). Je tedy nutné \TeX{}ovat ještě
jednou. Tři průchody \TeX{}em jsou (snad) dostačující.
Slovo \uv{snad} vychází z problému s poznámkami pod čarou podrobně
popsaném v sekci~\cite[specfootnote].
Poznámky pod čarou se totiž průběžně v průchodech mění a ovlivňují
zpětně vertikální sazbu. \docbytex{} proto provádí na konci zpracování
v příkaze "\bye"\du{bye} kontrolu, zda nedošlo ke změnám v referencích.
Je proto užitečné používat "\bye" místo "\end".
V závěru zpracování pak \docbytex{} vypíše zprávu 
"OK, all references are consistent" nebo vypíše
varování, že některé reference jsou nekonzistentní a 
že je tedy potřeba \TeX{}ovat znovu.

Další test konzistence můžeme provést například následujícím skriptem:

\begtt
#!/bin/bash
cp dokument.ref dokument.r0
pdfcsplain dokument.d
diff dokument.r0 dokument.ref
\endtt

\docbytex{} se snaží (z důvodu záruky konvergence dokumentu) fixovat 
zpracování poznámek pod čarou po druhém průchodu. Pokud poté měníte
rozsáhle dokument, takže seznamy stránek vedle poznámek pod čarou jsou
výrazně jiné délky, \docbytex{} to nepozná a může docházet 
k přeplnění nebo nenaplnění stránek. V takovém případě je rozumné
vymazat soubor {\tt.ref} a znovu spustit tři průchody.

Pro vytvoření záložek se strukturovaným obsahem v PDF výstupu slouží
příkaz "\bookmarks"\du{bookmarks}. Je zcela jedno, v které části
dokumentu je tento příkaz napsaný, neboť sestaví stukturovaný seznam
záložek prolinkovaný s dokumentem na základě údajů ze souboru~{\tt.ref}.
Může se stát, že některé texty v záložkách nejsou optimálně čitelné. O
možnostech, jak toto řešit, pojednává sekce~\cite[hooky].

\subsec [vkladani] Vkládání zdrojových textů podrobněji
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Kromě jednoduchého příkazu "\ins" na vkládání zdrojových textů jsou 
k dispozici příkazy "\ifirst"\du{ifirst} a "\inext"\du{inext}, 
které nabízejí uživateli
daleko více možností.

Příkaz "\ifirst{<soubor>}{<odkud>}{<kam>}{<jak>}" vloží do 
dokumentu část souboru "<soubor>" (plný název souboru včetně přípony)
od prvního řádku, na kterém se vyskytuje text "<odkud>" po
řádek, na kterém se vyskytuje text "<kam>", nebo (pokud text "<kam>"
nelze nalézt) po konec souboru. Neexistuje-li ani řádek s textem
"<odkud>", \docbytex{} vypíše pouze varování na terminál.

Příkaz "\ifirst" si své parametry nejprve 
expanduje a pak teprve použije. 
Aktivní vlnka v parametru expanduje na mezeru.

Parametr "<jak>" udává, zda se bude tisknout výchozí řádek (s~textem
"<odkud>") a koncový řádek (s~textem "<kam>"). Tento parametr obsahuje
právě dva znaky (plus nebo mínus) s následujícím významem:

\begtt
jak:  --   netiskne se výchozí ani koncový řádek
jak:  +-   tiskne se výchozí řádek a netiskne se koncový řádek
jak:  -+   netiskne se výchozí řádek, tiskne se koncový řádek
jak:  ++   tisknou se oba řádky
\endtt

Je-li parametr "<odkud>" prázdný (zapíšeme pomocí "{}"), tiskne se od
začátku souboru. Je-li parametr "<kam>" prázdný, tiskne se jediný řádek.
Je-li parametr "<kam>=\end",\du{end} tiskne se až do konce souboru.
Koncový řádek v tomto případě neexistuje. 

Má-li parametr "<odkud>" (nebo "<kam>") hodnotu "\empty"\du{empty} 
(zapíšeme pomocí "{\empty}"), tiskne se od (nebo do) prvního prázdného řádku.
Parametr "<jak>" ovlivní jeho tisk.

Parametry "<odkud>" nebo "<kam>" mohou mít na svém začátku znak "^^B"
(tím dáváme najevo, že text musí na řádku začínat) nebo na svém konci
znak "^^E" (tím dáváme najevo, že text musí na řádku končit). Takže
třeba "^^Btext^^E" znamená, že se vyhledává řádek, ve kterém je pouze
"text" a nic jiného.

V parametrech "<odkud>" a "<kam>" se nesmějí vyskytovat speciální
\TeX{}ové znaky (speciální kategorie). Pro použití znaků
"\", "{", "}", "%" a {\tt\char`\"} v těchto parametrech jsou 
v~\docbytex{}u připraveny zástupné kontrolní
sekvence "\nb"\du{nb}, "\obrace"\du{obrace}, "\cbrace"\du{cbrace},
"\percent"\du{percent} a "\inchquote"\du{inchquote}. 
Sekvence pro další speciální 
znaky "#", "$", atd. si musíte vytvořit např. pomocí:

\begtt
{\catcode`\#=12 \gdef\vezeni{#}}
\endtt

Jsou-li parametry "<odkud>" a "<kam>" stejné, nebo oba texty jsou na
stejném řádku, pak se při "<jak>=++" nebo "<jak>=+-" vytiskne 
tento jeden řádek. Při "<jak>=-+" nebo "<jak>=--" se tiskne až 
do konce souboru nebo do dalšího výskytu textu "<kam>". 

Příkaz "\ifirst" si zapamatuje název čteného souboru a pozici
posledního přečteného řádku v~daném souboru. Pak je možné použít
příkaz "\inext{<odkud>}{<kam>}{<jak>}", který začíná hledat výchozí řádek 
s textem "<odkud>" od místa v souboru, kde naposledy skončilo čtení
příkazem "\ifirst" nebo "\inext". Parametry "<odkud>", "<kam>" a "<jak>"
mají stejný význam, jako u příkazu "\ifirst".

V registru "\lineno"\du{lineno} je po ukončení příkazu "\ifirst" nebo "\inext"
číslo řádku, které bylo naposledy přečteno (třebaže tento řádek nebyl
vytištěn). Pokud bylo dosaženo konce souboru, obsahuje "\lineno"
počet řádků souboru. Pomocí "\ifeof\infile" je možné se zeptat, zda
bylo dosaženo konce souboru.

Příklady

\begtt
\ifirst {soubor.txt}{textik}{textik}{++}    % vytiskne první výskyt řádku
                                            % obsahující slovo textik
\inext {textik}{textik}{++}                 % vytiskne následující výskyt
                                            % řádku obsahující slovo textík
\ifirst {soubor.c}{//: odkud}{//:}{--}      % analogie příkazu \ins
\ifirst {soubor.c}{funkce(}{)}{++}          % tisk prototypu funkce
\ifirst {soubor.c}{funkce(}{^^B\cbrace}{++} % tisk celého kódu funkce
\ifirst {soubor.txt}{}{\end}{++}            % tisk celého souboru
\ifirst {soubor.txt}{}{\empty}{+-}          % tisk po prázdný řádek
\endtt

Je-li první řádek, který se má tisknout, prázdný, netiskne se. Je-li
poslední řádek, který se má tisknout, prázdný, také se netiskne. Toto
je implicitní chování. Pokud napíšete "\skippingfalse",\du{skippingfalse} 
uvedená inteligence je zrušena a přepisují se i prázdné řádky vpředu a vzadu.
Příkazem "\skippingtrue"\du{skippingtrue} se vrátíte k původnímu nastavení.

Parametrům "<odkud>" a "<kam>" může předcházet text 
"\count=<číslo> ".\du{count} Hodnota "<číslo>" označuje,
kolikátý výskyt textu "<odkud>" nebo "<kam>" se má použít.
Například "{\count=3 <odkud>}" znamená, že se má
při vyhledávání "<odkud>" přeskočit dva jeho výskyty a začít
přepisovat soubor až od výskytu třetího. Podobně "{\count=5 <kam>}"
značí, že se při přepisování souboru ignorují čtyři výskyty "<kam>" a
přepisování se zastaví až u výskytu pátého.

Implicitně, není-li "\count=<číslo> " uvedeno, předpokládá se
"\count=1 ". 

Pokud je text "<odkud>" prázdný, pak
"\count" označuje číslo řádku, na kterém se má zahájit výpis. Je-li
prázdný parametr "<kam>", pak "\count" označuje počet přepisovaných
řádků. Toto platí pro "<jak>=++" a pro "\skippingfalse". 
Při jiných hodnotách "<jak>" se
uvedená čísla logicky posunou o jedničku. Při prázdném "<odkud>" nebo
"<kam>" není mezera za "\count=<číslo>" povinná. Příklady:

\begtt
\skippingfalse
\ifirst {soubor.txt}{\count=20}{\count=10}{++} % tisk řádků 20 až 29
\ifirst {soubor.txt}{}{\count=2 \empty}{+-} % tisk po druhý prázdný řádek
\ifirst {soubor.txt}{\count=50}{\end}{++}  % tisk od 50. řádku do konce
\ifirst {soubor.tex}{\count=5 \nb section}{\count=2 \nb section}{+-}
                                    % tisk páté sekce z TeXového souboru 
\endtt


\subsec [lineodkazy] Odkazy na čísla řádků
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Pomocí "\cite[<lejblík>]" je možné odkazovat na číslo řádku ve výpisu
zdrojového kódu. Tento příkaz se promění na skutečné číslo řádku.
Před použitím příkazu "\ifirst" nebo "\inext" je nutné "<lejblík>"
deklarovat příkazem "\ilabel [<lejblík>]{<text>}".\du{ilabel} 
Těchto příkazů může být před použitím "\ifirst" resp. "\inext" více.
Na pořadí příkazů "\ilabel" před jedním "\ifirst" nebo "\inext" nezáleží.

Existují-li deklarované "<lejblík>"y a "<text>"y, pak příkaz 
"\ifirst" nebo "\inext" si všímá výskytu "<text>"u ve vkládaných
řádcích. Pokud takový "<text>" najde, přiřadí číslo řádku
odpovídajícímu "<lejblík>"u, takže příkaz "\cite" bude fungovat, jak má.

Parametr "<lejblík>" musí být jednoznačný v celém dokumentu. Příkaz
"\cite" funguje dopředně i zpětně.

Příkazy "\ilabel" mají lokální působnost a spolupracují jen 
s nejbližším následujícím "\ifirst" a "\inext".
Takže před použitím dalšího "\ifirst" resp. "\inext" 
je potřeba deklarovat další vyhledávané texty 
pomocí "\ilabel" znovu. 

\docbytex{} nevypíše žádné varování, pokud nějaký "<text>"
deklarovaný v "\ilabel" nenajde. Ovšem při použití "\cite" se objeví
varování, že není známý "<lejblík>" a toto varování nezmizí ani při
opakovaném \TeX{}ování. 

Pokud se "<text>" vyskytuje ve více řádcích ukázky, je odkazován
řádek s prvním výskytem.

V následující ukázce je čten již známý soubor "cosi.c" 
(viz kapitolu~\cite[priklad]).

\begtt
Na řádku~\cite[ufunkce] je deklarovaná úžasná funkce.

\ilabel [ufunkce] {funkce (float}
\ilabel [navratx] {navrat.x}
\ifirst {cosi.c}{}{}{++}

Zvláště upozorňuji na geniální myšlenku na řádku~\cite[navratx], 
kde je vstupní parametr vynásoben dvěma. 
\endtt

\subsec Verbatim ukázky pomocí {\tt\nb begtt}/{\tt\nb endtt} a
        palcových uvozovek
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Verbatim ukázky můžete do dokumentace vkládat pomocí "\begtt"\du{begtt} a
"\endtt"\du{endtt}. Ty jsou (na rozdíl od vkládaných souborů) napsány přímo ve
zdrojovém textu \TeX{}u.
Všechny řádky za "\begtt" jsou vloženy beze změn až po
ukončovací "\endtt". Řádky nejsou číslovány a texty v nich nemodrají a
nestávají se klikatelnými odkazy.

Následující sekce~\cite[hooky] a~\cite[begtt] obsahují informace,
jak je možné toto implicitní chování změnit.

Verbatim ukázky uvnitř odstavce lze vymezit palcovými uvozovkami
{\tt\char`\"...\char`\"}. V tomto prostředí probíhá tisk strojopisem a
je aktivní enc\TeX{}, takže dokumentovaná slova se stávají 
automaticky odkazy na místo, kde je "\dg". Doporučuje se toto
prostředí používat na výpisy veškerých částí kódů dokumentovaného
programu, které jsou vloženy uvnitř textu v odstavci (analogie
matematického prostředí "$...$").

\subsec [ddsl] Deklarace dokumentovaného slova
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Na deklaraci slova, které dokumentujeme, lze použít příkaz "\dg",\du{dg}
"\dgn",\du{dgn} "\dgh",\du{dgh} "\dl",\du{dl} "\dln"\du{dln} 
nebo "\dlh"\du{dlh}. Významy jednotlivých
příkazů vysvětlíme později. Nejprve se věnujme syntaxi parametrů.
Všechny příkazy mají stejnou syntaxi, takže nebude vadit, když bude
vyložena jen v souvislosti s příkazem "\dg". Syntaxe je poněkud
zvláštní. Účelem totiž bylo minimalizovat práci písaře, takže jsem se
vyhnul kučeravým závorkám, parametr separuji podle mezery nebo něčeho
jiného, atd.

Existují tyto možnosti syntaxe parametrů:

\def\begtthook{\langleactive \mubytein=1}
\begtt
\dg <slovo>            % <slovo> separované mezerou
\dg [<text>] <slovo>    % navíc nepovinný "přední" <text>
\dg [<text>]<slovo>     % <slovo> může na [<text>] navazovat bez mezery
\dg <slovo>()          % <slovo> s dvojicí "()" separované mezerou
\dg [<text>]<slovo>()   % kombinace předchozího
\dg <slovo>,           % <slovo> separované čárkou
\dg [<text>] <slovo>,   % kombinace předchozího
\dg <slovo>(),         % <slovo> s dvojicí "()" separované čárkou
\dg [<text>]<slovo>(),  % kombinace předchozího
\dg <slovo>.           % slovo separované tečkou
atd...
\endtt
\def\begtthook{}

Obecně: za příkazem "\dg" může následovat nepovinná "[". Pokud
následuje, pak se přečte "<text>" až po ukončovací "]". Parametr
"<text>" může obsahovat mezery. Za ukončovací "]" může a nemusí být
mezera. Pokud tam je, pak ji makro přesune před koncovou závorku "]",
takže "\dg"~"[aha] slovo" je totéž jako "\dg"~"[aha ]slovo".
Dále následuje čtení parametru "<slovo>". 
Tento parametr nesmí obsahovat mezeru, čárku, tečku, středník
a dvojtečku. Čtení parametru je ukončeno, jakmile se objeví mezera
nebo čárka nebo tečka nebo středník nebo dvojtečka. Uvedená
interpunkce není součástí parametru "<slovo>" a po zpracování parametru
se vrátí do vstupní fronty, takže se běžně vytiskne.
Nakonec se zjistí, zda přečtený parametr až po separátor není ve tvaru
"<slovo>()". Pokud je, pak symbol "()" se nepovažuje za součást
parametru "<slovo>", ale mluvíme o "<slovu>" následovaném dvojicí~"()".

Pozor, za separátorem typu čárka, tečka, středník a dvojtečka se musí
vyskytnout mezera. Ne nutně ihned, ale dříve, než se objeví úsek
textu, který má být přečten s jinými kategoriemi 
(např.~{\tt\char`\"...\char`\"}). Není tedy možné psát 
"\dg" {\tt text,\char`\"...\char`\"}.
Pokud za separátorem mezera následuje znak {\tt\char`\`} (obrácený
apostrof), mezera ani tento znak se netiskne. To je možné využít
například pro vložení nezlomitelné mezery nebo pro jiné účely: 
"\dg"~"<slovo> `~<přilepený text>"
nebo "\dg"~"<slovo> `"{\tt\char`\"...\char`\"}.

Příkazy "\dgh", "\dgn", "\dln", "\dlh" separující mezeru 
netisknou nikdy, protože tyto příkazy většinou netisknou nic (viz níže).

Parametr "<slovo>" je dokumentované slovo. Pokud se takové "<slovo>"
vyskytne někde jinde v dokumentu mezi {\tt\char`\"...\char`\"} nebo ve
vloženém zdrojovém kódu, automaticky zmodrá a stává se klikatelným
odkazem na místo, kde je použito "\dg". V místě použití "\dg" je slovo
zvýrazněno červenou barvou. Je vytištěno samotné bez parametru
"<text>" a bez případných závorek "()". V poznámce pod čarou se vypíše
"<slovo>" (červeně). Tam je i případný "<text>" (před slovem) a za ním
je případná dvojice "()". Vedle tohoto výpisu je
seznam stránek s výskyty "<slova>". V rejstříku se objeví něco podobného,
jako v poznámce pod čarou. Rejstřík je řazen abecedně podle "<slovo>",
nikoli podle "<text>".

Příkaz "\dg" deklaruje "<slovo>" globálně. Bude na něj odkazováno v celém
dokumentu. 

Příkaz "\dgh" pracuje jako "\dg", ale slovo nebude v místě "\dgh"
vypsáno ("\dg" hidden). Bude tam jen cíl odkazů a "<slovo>" 
se objeví v poznámce a v rejstříku. 

Příkaz "\dgn" způsobí, že první následující výskyt
"<slova>" ve vypisovaném zdrojovém kódu 
se stane cílem všech ostatních odkazů, zčervená (tedy
nezmodrá) a v místě tohoto výskytu se objeví příslušná poznámka pod
čarou. Příkaz "\dgn" čteme jako "\dg" next, nebo "\dg" následující.

Příkaz "\dl" deklaruje "<slovo>" lokálně. Bude na něj odkazováno svým
krátkým jménem "<slovo>" jen v místě stejného jmenného prostoru,
typicky při dokumentaci jednoho modulu. Každý modul zahájený příkazem
"\module" zavádí jmenný prostor tvaru "<slovo>./<název>", kde
"<název>" je jméno modulu. Slovo deklarované pomocí "\dl" žije ve dvou
variantách. V krátké variantě jako "<slovo>" jen v rozsahu jednoho
jmenného prostoru a v dlouhé variantě "<slovo>./<název>" žije globálně
v celém dokumentu. Případný výskyt dlouhého názvu odkáže na místo
deklarace napříč celým dokumentem.

Podrobněji o jmenných prostorech a možnosti jejich změny najdete 
v~sekci~\cite[jmenneprostory]. 

Každé "<slovo>" musí být v dokumentu deklarováno nejvýše jednou, jinak
\docbytex{} ohlásí chybu. V případě "\dl" musí existovat
jednoznačný dlouhý název.

Příkaz "\dlh" je skrytý "\dl". Příkaz "\dln" znamená "\dl" next.
Analogicky, jako příkazy "\dgh" a "\dgn".

Pokud někoho irituje vysoká inteligence těchto příkazů při čtení
parametrů, může použít interní verzi příkazů s povinnými třemi
parametry obalenými do kučeravých závorek: "\iidg",\du{iidg} 
"\iidgh",\du{iidgh} "\iidgn",\du{iidgn} 
"\iidl",\du{iidl} "\iidlh",\du{iidlh} "\iidln".\du{iidln} 
Parametry vypadají
takto: "\iidg{<před>}{<slovo>}{<za>}". Pravda, tyto příkazy umožňují
více než jejich krátké verze: umožňují do parametru "<slovo>"
propašovat čárku, mezeru, středník atd. a do parametru "<za>" napsat
cokoli, nejen kulaté závorky.
 

\subsec [jmenneprostory] Jmenné prostory
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Jmenný prostor je pravidlo, podle kterého se krátký název
dokumentovaného "<slova>" transformuje při použití "\dl"
na název dlouhý. Je možné jej nastavit nebo změnit pomocí příkazu
"\namespace"\du{namespace}, který se použije takto:
"\namespace" "{<text1>#1<text2>}...\endnamespace".\du{endnamespace} 
Pokud je uvnitř tohoto prostředí použit příkaz 
"\dl<slovo>", je slovu přidělen krátký název "<slovo>" a dlouhý název 
"<text1><slovo><text2>". 
Uvnitř takto deklarovaného prostředí se všechny výskyty
krátkého názvu "<slovo>" transformují na dlouhý název a jsou
prolinkovány s odpovídajícím místem "\dl". Jmenný prostor je lokální
uvnitř svého prostředí, takže vně prostředí se "<slovo>"
chová, jakoby nebyl žádný příkaz "\dl" použit.
Například uvnitř prostředí "\namespace"~"{#1//uff}...\endnamespace" je ke
každému slovu deklarovanému pomocí "\dl<slovo>" přidělen dlouhý název 
"<slovo>//uff" a výskyty "<slovo>" odkazují na místo "\dl<slovo>". 

Vně všech prostředí "\namespace...\endnamespace" není jmenný prostor definován, 
takže tam není možné použít příkaz "\dl". 
Ovšem příkaz "\module"~"<název> " nastaví jmenný
prostor na "{#1./<název>}", takže uvnitř dokumentace modulu
je možné používat příkaz~"\dl".

V rejstříku a v poznámce pod čarou se tisknou dlouhé názvy. Rejstřík
abecedně řadí podle dlouhých~názvů. V obsahu se tisknou názvy krátké.

Příklad práce se jmennými prostory:

\begtt
\namespace {ju::#1}   %% nastavuji namespace ju
Tady deklaruji slovo \dl aha.
Tady slovo "aha" automaticky odkazuje na místo deklarace.
Slovo "ju::aha" také odkazuje na místo deklarace.
\endnamespace
\namespace {hele::#1} %% nastavuji namespace hele
Tady znovu deklaruji slovo \dl aha.
Zde slovo "aha" odkazuje na lokální deklaraci uvnitř "hele"
\endnamespace         %% ruším namespace
Zde slovo "aha" neodkazuje nikam, ale slova "ju::aha"
a "hele::aha"  stále odkazují na místa, kde byla deklarována.
\endtt

Prostředí "\namespace...\endnamespace" je možné vnořovat, ovšem vnořená 
prostředí musejí mít jiný jmenný prostor než prostředí vnější. Prostředí 
jmenných prostorů pracují globálně nezávisle na "\bgroup", "\egroup".
Příkaz "\endnamespace" použitý vně všech prostředí 
"\namespace...\endnamespace" neudělá nic. Prostředí není nutné před 
příkazem "\bye" ukončovat.


\subsec Místo pro dokumentaci aplikačního rozhraní
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Může se stát, že píšeme dokumentaci jednak pro uživatele, které zajímá
způsob použití dokumentovaných funkcí a co zhruba dělají (tzv.~API),
ale nezajímá je, jak je funkce naprogramovaná. Druhak chceme mít
dokumentován i způsob, jak funkce funguje uvnitř. V takovém případě
musí dokumentované "<slovo>" odkazovat na dvě místa v dokumentu. 

Místo, kde je podrobně "<slovo>" popsáno, je vymezeno příkazem "\dg"
nebo podobným. Místo, kde slovo dokumentujeme pro uživatele (je-li
toto místo odlišné od prvního místa), lze vyznačit příkazem
"\api{<slovo>}"\du{api}. V místě použití "\api{<slovo>}" se nestane
nic, jen se tam umístí neviditelný cíl odkazů. V obsahu se pak
"<slovo>" objeví s odkazem na toto místo. V rejstříku se v seznamu
stránek objeví jedna stránka podtržená: to je stránka, kde byl použit
příkaz~"\api{<slovo>}". Ovšem, aby se v rejstříku "<slovo>" vůbec
objevilo, musí se někde v dokumentu vyskytovat i jeho plná deklarace
pomocí "\dg" nebo podobných příkazů. Na stránce, kde je použito "\dg",
je pod čarou vedle slova seznam stránek a rovněž je tam jedna stránka
podtržená. Když čtete implementační popis pro "<slovo>", snadno se
tedy dostanete na stránku, kde je API k tomuto "<slovu>".  V~rejstříku
a obsahu jsou také slova, která byla deklarovaná pomocí "\api", zleva
vyznačena textem "\apitext"\du{apitext}. Ten je implicitně nastaven na
šipku. Můžete se podívat do rejstříku a do obsahu tohoto dokumentu. V
tomto místě bylo použito "\api{\nb api}", zatímco skutečná definice
příkazu "\api" je v sekci~\cite[reference].

Je-li použito "\api{<slovo>}", pak je možné se na místo odkazovat také
pomocí "\cite[+<slovo>]". Tato konstrukce se promění v číslo stránky,
kde je dokumentováno API daného slova. Například v tomto dokumentu
se "\cite[+\nb api]" promění na:~\cite[+\nb api]. 

Pokud toto slovo má také svůj API cíl (vytvořený pomocí
"\api"), pak se červený text (tištěný v místě "\dg") 
stává aktivním odkazem na API cíl. Tam
typicky čtenář najde výskyt slova, který je zase klikatelným odkazem
na "\dg" cíl. Takže tyto dva cíle jsou prolinkovány křížem.

\subsec [kapsec] Sekce, sekcičky, část, titul
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Sekce se uvozují příkazem "\sec"~"<název sekce>\par"\du{sec}. Každá
sekce může mít několik podsekcí (sekciček), které lze vyznačit
příkazem "\subsec"~"<název podsekce>\par"\du{subsec}. 
Symbol "\par" zde znamená,
že název sekce či podsekce je oddělen od dalšího textu prázdným
řádkem (viz ukázku v~\cite[cleneni]).

Několik sekcí může tvořit část. Část je uvozena příkazem
"\part"~"<název části>\par"\du{part}. Části jsou automaticky označeny
písmeny A,B,C,\dots a jsou vyznačeny výrazněji než sekce v~místě
začátku části i v~obsahu. Části ale nenarušují číslování
sekcí. Tj. sekce jsou číslovány od jedné napříč celým dokumentem bez
ohledu na to, zda jsou nebo nejsou rozděleny na části.

Příkaz "\module <soubor> " automaticky založí sekci s názvem
"Modul <soubor>" a deklaruje svůj jmenný prostor.
Toto chování lze změnit, viz~\cite[nazvy], \cite[module].

Příkaz "\title<název>\par"\du{title} vytiskne název dokumentu větším písmem a v
rámečku. Je-li definováno makro "\projectversion"\du{projectversion},
bude jeho obsah vytištěn drobně vpravo nahoře doplněný zepředu textem 
"verze".  Pokud váš projekt nemá verzi, může se hodit třeba: 

\begtt
\def\projectversion{\the\day. \the\month. \the\year}
\endtt

Příkaz "\author<text>\par"\du{author} napíše do 
středu řádku tučně "<text>",
což bývá obvykle jméno autora (jména autorů).

Do záhlaví každé stránky se začne přepisovat zleva název aktuální
sekce a zprava název dokumentu. Uživatel může text pro pravé záhlaví
změnit změnou makra "\headtitle"\du{headtitle}.

Příkazy "\sec" a "\subsec" mohou mít v hranaté závorce nepovinný
parametr "<lejblík>". V takovém případě vypadají parametry takto:
"\sec"~"[<lejblík>] <název sekce>\par". Po takovém použití je možné
se na sekci (podsekci) odkazovat příkazem "\cite[<lejblík>]". Tento příkaz se
promění v číslo odkazované sekce (podsekce) a navíc se stane
aktivním odkazem.

Pomocí příkazu "\savetocfalse"\du{savetocfalse} lze před použitím 
příkazu "\sec" nebo "\subsec" zajistit, že název sekce se 
nedostane do obsahu a nebude mít své číslo. Místo čísla se 
vytiskne obsah makra "\emptynumber"\du{emptynumber}, které je
implicitně prázdné. Příkaz "\savetocfalse" ovlivní jen
první následující "\sec" nebo "\subsec".

\subsec [krizodkaz] Křížové odkazy
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Cíl, kam směřuje odkaz, je potřeba vyznačit pomocí "<lejblíku>".
To je možné udělat v příkaze "\sec", "\subsec" (viz předchozí 
sekci~\cite[kapsec]) nebo kdekoli v textu samostatným příkazem
"\label[<lejblík>]"\du{label}. Také je možné odkazovat na číslo řádku
(viz sekci~\cite[lineodkazy]).
Všechny lejblíky musejí být jednoznačné (bez ohledu na jejich typ)
napříč celým dokumentem.

Příkaz "\pgref[<lejblík>]"\du{pgref} expanduje na číslo strany, na které se
vyskytuje cíl odkazu. Příkaz "\numref[<lejblík>]"\du{numref} expanduje 
v~závislosti na typu cíle na:

\begitems
\item * číslo sekce, je-li cílem sekce,
\item * dvojčíslí "<sekce>.<podsekce>", je-li cílem podsekce,
\item * číslo řádku, je-li cílem řádek zdrojového kódu,
\item * prázdné makro, je-li "<lejblík>" deklarovaný pomocí "\label".
\enditems

Oba příkazy "\pgref" a "\numref" expandují na uvedené texty bez další
inteligence. Tj. výstupní text se nestává klikatelným odkazem. 

K aktivaci odkazu v PDF módu slouží 
makro "\ilink"~"[<lejblík>]{<text>}"\du{ilink}. Toto makro vytiskne modře
"<text>", který se stává klikatelným odkazem na cíl, deklarovaný
pomocí "<lejblíku>". Takže již známý příkaz "\cite[<lejblík>]"\du{cite}
udělá zhruba to samé, jako "\ilink[<lejblík>]{\numref[<lejblík>]}".
Skutečný příkaz "\cite" navíc ověří, zda není "\numref[<lejblík>]"
prázdné makro. Pokud je, obarví namísto výstupu "\numref" 
výstup makra "\pgref".

Pokud "<lejblík>" jako argument příkazu "\pgref", "\numref" nemá svůj
cíl, příkaz "\pgref" expanduje na hodnotu $-1000$ a "\numref"
expanduje na prázdný výstup. Jsou to expanzní makra, takže v nich není
implementován například tisk varování. Podívejte se na definici
příkazu "\cite" (na straně~\cite[@\nb cite]), jak se dá tisk varování
implementovat.

Makro "\module"~"<jméno> " založí sekci s lejblíkem "m:<jméno>", takže
lze na ní pak odkazovat. Například si můžete vytvořit makro

\begtt
\def\refmodul[#1]{\ilink[m:#1]{\tt#1}}
\endtt
%
které aktivizuje svůj parametr, pokud tento je názvem nějakého
modulu. Třeba "\refmodul[base]" vytiskne slovo "base" strojopisem a
modře a stává se klikatelným odkazem na začátek sekce
\uv{Modul base}, pokud je tato sekce založena příkazem "\module".

Makra "\dg", "\dgn", "\dgh" interně provedou příkaz "\label[@<slovo>]"
a makra "\dl", "\dln", "\dlh" provedou příkaz 
"\label[@<dlouhé slovo>]", kde "<dlouhé slovo>" je "<slovo>" 
po transformaci podle aktuálního jmenného prostoru.
Na místa, kde jsou slova dokumentovaná, je tedy možné odkazovat
například pomocí 
"\link[@<slovo>]{<slovo> dokumentované na straně~\pgref[@<slovo>]}". 

Makro "\api{<slovo>}" interně provede "\label[+<slovo>]", takže je
možné na toto místo odkazovat třeba pomocí 
"\ilink[+<slovo>]{API: <slovo>}".

\docbytex{} nenabízí kromě čísel sekcí, podsekcí a čísel řádků žádné další
automatické číslování. Pokud tedy chcete implementovat např. číslování
obrázků, čísla publikací atd., musíte si napsat makra vlastní.
K tomu můžete využít makro
"\labeltext[<lejblík>]{<text>}"\du{labeltext}, které uloží v
horizontálním módu do sazby neviditelný cíl odkazu, a při dalším
průchodu \TeX{}em expanduje makro "\numref" na "<text>".
Použití makra ukážeme na příkladě, ve kterém definujeme makro 
"\bib[<lejblík>]". Toto makro zahájí sazbu další položky v seznamu
literatury. Odkazovat na knihu pak lze pomocí "\cite[b:<lejblík>]".

\begtt
\newcount\bibnum
\def\bib [#1]{\par\advance\bibnum by1 \indent
    \llap{[\the\bibnum] }\labeltext[b:#1]{[\the\bibnum]}\ignorespaces}
\endtt

\subsec Vkládání obrázků
%%%%%%%%%%%%%%%%%%%%%%%%

Příkazem "\ifig" "<šířka> <jméno obrázku> "\du{ifig} je možné vložit obrázek.
Obrázek musí být připraven v souboru "fig/<jméno obrázku>.eps" (v případě
DVI módu) a v souboru "fig/<jméno obrázku>.pdf" (v~případě PDF módu). 
Adresář, kde \docbytex{} vyhledává obrázky ("fig/"), lze změnit 
předefinováním sekvence "\figdir"\du{figdir} . Rozměr "<šířka>" 
je bez jednotky a udává poměr požadované šířky obrázku ku 
šířce sazby. Obrázek je umístěn zarovnán doleva na odstavcovou zarážku.

Máte-li připraven obrázek ve formátu "eps", pak jej do "pdf" převedete
příkazem

{\def\begtthook{\langleactive}
\begtt 
ps2pdf -dEPSCrop <jméno obrázku>.eps
\endtt
\par}

\subsec Výčty
%%%%%%%%%%%%%

Seznam položek obklopíte "\begitems"\du{begitems} a
"\enditems"\du{enditems}. V tomto prostředí je text odsazen zleva 
o~odstavcovou zarážku. Prostředí lze vnořovat. Jednotlivou položku
zahájíte pomocí "\item"~"<značka> <text>",\du{item} 
přitom "<značka>" se
vystrčí vlevo od "<textu>". Je-li "<značka>" hvězdička, promění se v
puntík. Další možnost: "\item"~"\the\itemno) <text>",\du{itemno} 
což vytvoří číslované výčty, v každém prostředí číslovány od jedné.

Makro plainu "\item" není předefinováno globálně, ale jen uvnitř
"\begitems...\enditems". Můžete tedy použít i makro plainu,
pokud se vám koncept položek nabízený \docbytex{}em nelíbí.


\noactive{/*}\noactive{*/}\noactive{//} 
\setlinecomment{\percent} \noactive{\nb\percent} \noactive{\percent\cbrace}


\sec [zmeny] Pro náročné
%%%%%%%%%%%%%%%%%%%%%%%%

V této sekci jsou uvedeny a vysvětleny definice základních 
příkazů \docbytex{}u. Uživatel si může tyto definice změnit, pokud chce
změnit chování \docbytex{}u. Pokud například pracuje s jiným
programovacím jazykem, může si změnit makro "\docsuffix" nebo
kompletně předefinovat makra "\module" a "\ins".

\subsec [nazvy] Interní názvy
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Příkazem "\doindex" vytvoří \docbytex{} automaticky novou
sekci s názvem \uv{Rejstřík}. Podobně při tvorbě obsahu nebo natažení
modulu vzniká název \uv{Obsah} nebo \uv{Modul}. Před názvem verze 
v~titulu při použití "\projectversion" se objeví slůvko \uv{verze}.
Část (vytvořená pomocí "\part") má v záložkách uvozující text 
">> CAST".
Tyto texty jsou definovány v makrech
\db titindex, \db tittoc, \db titmodule, \db titversion a \db opartname.

\ifirst {docby.tex}{Intern}{\empty}{--}

Za povšimnutí stojí, že jsou jinak tato makra definována při použití
klasického "plain"u a jinak při použití "csplain"u. To ovšem
neznamená, že uživatel si tyto názvy nemůže předefinovat ještě jinak,
nezávisle na použitém formátu.

\subsec [hooky] Vložené skupiny příkazů (hooks)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Některá složitější makra ("\begtt", palcové uvozovky, "\ifirst",
"\inext", "\doindex", "\dotoc") dovolují vkládat uživateli na začátku
zpracování různé příkazy (tzv.~hooks). Implicitně
jsou tyto vložky prázdné:

\ifirst {docby.tex}{begtthook}{\empty}{+-}

Makro \db begtthook je vloženo po založení skupiny a nastavení všech
kategorií těsně před začátkem zpracování prostředí "\begtt...\endtt".
Makro \db quotehook je vloženo po založení skupiny a nastavení všech
kategorií těsně před začátkem zpracování prostředí {\tt\char`\"...\char`\"}.
Makro \db indexhook je vloženo makrem "\doindex" po založení sekce
a před přechodem do sazby ve dvou sloupcích. V tomto dokumentu je v
něm úvodní povídání k rejstříku. 
Makro \db tochook je vloženo makrem "\dotoc" po založení sekce
před sazbou prvního řádku obsahu.
Makro \db bookmarkshook je vloženo uvnitř skupiny na začátku
zpracování záložek. Je možné v něm nastavit expanze maker
vyskytujících se v nadpisech na rozumnou hodnotu pro záložky.
Pokud navíc nastavíte "\let\cnvbookmark=\lowercase", budou všechny
znaky pro záložky procházet filtrem "\lowercase". Uvnitř
"\bookmarkshook" je pak možné nastavit "\lccode" vybraným znakům
(například pro odstranění háčků a čárek).
Makro \db outputhook je vloženo na začátek výstupní rutiny. Je vhodné
v něm nastavit vybrané příkazy na hodnotu "\relax", aby se
neexpandovaly do souboru {\tt.ref}.

Příklady použití

\bgroup
\catcode`'13 \def'{\nb} \catcode`?=13 \def?{<} 
\def\begtthook{\langleactive\mubytein=1}
\begtt
\def\quotehook{\obeyspaces}   % ve výpisech "..." budou normální mezery
\def\quotehook{\langleactive} % ?text> se promění na <text>
\def\begtthook{\mubytein=1}   % mezi 'begtt...'endtt bude aktivní encTeX
\def\begtthook{\setsmallprinting} % ukázky 'begtt...'endtt budou malé
\def\begtthook{\catcode`\!=0} % mezi 'begtt...'endtt fungují !prikazy
\def\indexhook{To čubrníte, jaký tu mám rejstřík.}
\def\outputhook{\let\mylogo=\relax} % \mylogo nebude expandovat
\endtt
\par
\egroup

\subsec [module] Příkaz {\tt\nb module} a {\tt\nb ins}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Uživatelská dokumentace k těmto příkazům je v sekci~\cite[cleneni].
Příkaz \db module "<soubor> " načte soubor s názvem 
"<soubor>\docsuffix", kde makro
\db docsuffix obsahuje příponu souboru včetně tečky.

\ilabel [linkincomment] {extension}
\insdef docsuffix  

Příkaz "\module" vloží název čteného souboru (bez přípony) 
do pomocného makra
\db modulename. Toto makro pak využívá příkaz 
\db ins "<pripona> <text> ".

\inssdef ins

\subsec Zelenající komentáře
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Příkazy "\ifirst" a "\inext" si také všímají (implicitně) C komentářů
tvaru "//..<eol>" a "/* .. */". Tyto komentáře barví ve výpisu
programu zeleně. Zrušit tuto vlastnost lze příkazem "\noactive<string>".
Pomocí \db setlinecomment "{<string>}" lze nastavit nový typ komentářů, 
které budou barveny zeleně od "<string>" do konce řádku. Příkazy mají globální
platnost. Například

{\def\begtthook{\mubytein=1}
\begtt
\noactive{/*}\noactive{*/}\noactive{//} 
\setlinecomment{\percent} \noactive{\nb\percent}}
\endtt
\par}
\noindent
nastaví komentáře podle zvyklostí v \TeX{}u a PostScriptu.

Příkazem \db setlrcomment "{<levý>}{<pravý>}"
lze nastavit komentáře typu "/*...*/".

Pro změnu vlastností obarvování komentářů stačí uvedená makra
použít. Kdo chce vědět, jak jsou implementovaná, nechť čte dále.

\inext {mubyte}{\empty}{+-}

Uvedené příkazy jsou prázdné v módu bez enc\TeX{}u a při
detekci enc\TeX{}u zapíší informace do enc\TeX{}ové tabulky
prostřednictvím primitivů "\mubyte...\endmubyte".

Příkazy \db linecomment a \db leftcomment se díky enc\TeX{}u
automaticky vloží před detekovanou sekvenci znaků. Tyto 
příkazy nastaví barvu textu na zelenou:

\inext {linecomment}{\empty}{+-}

Na druhé straně příkaz \db rightcomment potřebuje vypnout zelenou barvu
až po přeskočení detekované sekvence. Proto enc\TeX{} v tomto případě
detekovanou sekvenci zruší a příkaz "\rightcomment" má za úkol ji vrátit
do sazby zpět a teprve poté pomocí \db returntoBlack se vrátit 
k~černé barvě.

\inext {returntoBlack}{\empty}{+-}

Je potřeba vysvětlit, proč přepínače barev jsou tak komplikovaně
zapsány. Přepínač totiž v PDF zapíná barvu nezávisle na skupině a
barva textu se drží tak dlouho, dokud není použit jiný přepínač barvy.
Každý tisk řádku kódu je uveden přepínačem "\Black", takže při
poznámce \uv{do konce řádku} stačí jen přepnout na "\Green". Ovšem
uvnitř komentáře se může objevit link obalený
příkazy "\Blue...\Black" (viz např. řádek~\cite[linkincomment] v
předchozí sekci). Pak ale chceme, aby "\Black" vrátil barvu
"\Green". Proto je provedeno předefinování pomocí "\let". Toto
předefinování je lokální. Protože řádek je tištěn uvnitř skupiny, je
další řádek už černý.

Při tisku komentáře, který má úvodní a koncový znak a může přesáhnout
jeden řádek, musíme globálně předefinovat "\Black" na "\Green", aby i
další řádky (uvozené příkazem "\Black") byly zelené. Koncový znak 
komentáře pak musí uvést barvy do původního stavu. 

\docbytex{} inicializuje poznámky podle pravidel jazyka C:

\inext {setlinecomment}{\empty}{+-}

\sec [design] Pro designéry
%%%%%%%%%%%%%%%%%%%%%%%%%%%

Následuje dokumentace definic maker ovlivňující vzhled dokumentu.
Jejich předefinování může způsobit změnu vzhledu podle požadavku
uživatele. Místo komplikovaných maker s množstvím parametrů pro řízení
vzhledu jsou zde jednoduchá dobře dokumentovaná makra pro jedno
použití.  Předpokládá se, že při potřebě jiného vzhledu dokumentu je
uživatel předefinuje.

Makra zabývající se vzhledem dokumentu jsou
pokud možno oddělena od složitosti ostatních maker, ve kterých probíhá
hlavní zpracování \docbytex{}u. To umožňuje designérovi zaměřit se
jen na programování vzhledu a neutopit se v různých cyklech a
rekurzích interních maker \docbytex{}u.

Typicky jsou makra pro vzhled ve dvou verzích: pro pdf\TeX{} a bez
pdf\TeX{}u. To je důvod, proč ve výpisech se často vyskytuje test
"\ifx\pdfoutput\undefined".

\subsec Parametry a pomocná makra pro nastavení vzhledu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Velikost \db hsize ani \db vsize neměníme. Buď si ji nastaví uživatel,
nebo se převezme velikost z~plainu (vhodné pro papír letter) či
csplainu (vhodné pro papír A4). Nastavujeme ale větší \db parindent,
neboť chceme do proužku vymezeného "\parindent" dát podbarvené
čtverečky u názvů sekcí. 

\ifirst {docby.tex}{parindent=}{\empty}{+-}

Připravíme si \uv{zúženou šířku} \db nwidth využitou např. jako šířka záhlaví:

\inext {nwidth}{\empty}{+-}

Příkazem plainu "\raggedbottom"
nastavíme pružnost stránky dole, a ne mezi jednotlivými řádky.
Nastavením "\exhyphenpenalty=10000" zakážeme zlom za pomlčkou
(v~tisku rozsahu stránek, např. 11--13, takový zlom působí rušivě).

\inext {raggedbottom}{\empty}{+-}

Zavedeme potřebné fonty 
\db bbf, \db bbbf, \db btt,
\db ttsmall, \db rmsmall, \db itsmall a \db partfont.

\inext {bbf=}{\empty}{+-}

Makro \db setsmallprinting přepne do malého strojopisu, připraví
\db ttstrut vhodné velikosti a pomocí "\offinterlineskip" připraví tisk
řádků v režimu, kdy se o sebe opírají. Hodnota "\parskip" je nastavena
na "-1pt", aby docházelo k mírnému překrývání a nevznikaly v tisku
nebo na obrazovce pruhy. Analogicky pracuje makro \db setnormalprinting.

\inext {setsmallprinting}{\empty}{+-}

V návrhu vzhledu pracuji jen s barvami
\db Blue, \db Red, \db Brown, \db Green, \db Yellow a \db Black.
Pokud budete chtít další barvy, definujte si je.\par\penalty1234

\inext {pdfoutput}{\empty}{+-}

Barvy jsou definovány pomocí makra \db setcmykcolor, které je v
případě DVI výstupu nastaveno na prázdné makro a v případě PDF výstupu
je použit PDF~"\special". Takže příkazy "\Brown" atd. je možné použít i
ve verzi maker pro DVI, ovšem v této verzi neudělají nic.
Barva \db oriBlack je konstantně černá barva. Některá makra totiž
normální "\Black" předefinovávají a pak se potřebují vrátit pomocí
"\oriBlack" ke skutečné černé barvě.

Makro \db rectangle "{<výška>}{<hloubka>}{<šířka>}{<obsah>}"
vytvoří rámeček o stanovených rozměrech se stanoveným obsahem.
V PDF verzi je rámeček ve tvaru plného žlutého obdélníku na kterém
se nachází "<obsah>" zatímco v~DVI verzi se vytvoří obrysový rámeček.
Pozor: parametr "<obsah>" musí obsahovat přepínač barvy, jinak nebude v
PDF verzi viditelný. Na druhé straně makro "\rectangle" se postará 
o návrat do \uv{normální} černé barvy.

\inext {pdfoutput}{\empty}{+-}

Nakonec připravíme makro \db docbytex jako zkratku pro logo \docbytex{}u.

\inext {def\nb docbytex}{\empty}{+-}

\subsec Vzhled sekcí a podsekcí
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Makra \db printsec "{<nadpis>}" a \db printsecbelow,
jsou volána z makra pro vytvoření sekce "\sec" a mají za úkol
vytisknout nadpis. Ostatní problematika, kterou musí řešit makro
"\sec" (reference do obsahu, cílové reference, čísla sekcí, plovoucí
záhlaví atd.) je zde odstíněna a nemusíme se jí v tuto chvíli zabývat.

Musíme ale dodržet následující úmluvu: Na začátku makra "\printsec"
přejdeme pro jistotu do vertikálního módu, pak vložíme potřebné
mezery, pak vložíme text nadpisu. V okamžiku, kdy přejdeme do
horizontálního módu, vložíme makro "\makelinks", které zajistí
umístění cílů odkazů. Nakonec přejdeme do vertikálního módu příkazem
"\par" a {\it nevkládáme žádné další vertikální mezery}. Makro "\sec" vloží pod
vytištěný nadpis do horizontálního seznamu další prvky a posléze 
zavolá "\printsecbelow". Tam teprve vložíme mezery obvykle blokované
proti zlomu pomocí "\nobreak". Základní řazení vertikálního seznamu 
v \TeX{}u totiž vypadá takto: box, (whatsit, mark, atd.), penalty, glue. 
O objekty uvedené v~závorce se postará "\sec", my zde řešíme jen box
(v makru "\printsec"), a dále penaltu a glue (v makru "\printsecbelow").

K dispozici máme hodnotu "\secnum" a "\subsecnum" a dále můžeme použít
test "\ifsavetoc", kterým se ptáme, zda daný nadpis bude v
obsahu. Nebude-li, měli bychom místo "\the\secnum" tisknout
"\emptynumber". V makru "\seclabel" je obsah lejblíku sekce, nebo
je makro prázdné. To můžeme využít při tisku v režimu \uv{nahrubo},
například tisknout tyto lejblíky do okrajů. \docbytex{} tuto
vlastnost implicitně neimplementuje.

\ifirst {docby.tex}{def\nb printsec }{\empty}{+-}

Makra \db printsubsec a \db printsubsecbelow fungují analogicky jako právě
zmíněná, ale spolupracují s makrem "\subsec".

\inext {def\nb printsubsec }{\empty}{+-}

Makro \db printpart vytiskne nadpis části a dopředu dá veliké 
písmeno. Makro \db printpartbelow tiskne mezeru pod nadpisem části.

\inext {def\nb printpart }{\empty}{+-}

Makro \db emptynumber, které se použije při "\savetocfalse", je
implicitně nastaveno na prázdnou hodnotu.

\inext {emptynumber}{\empty}{+-}

\subsec Titul, autor
%%%%%%%%%%%%%%%%%%%%

Makro \db title "<titul>\par" čte parametr "<titul>"
pomocí makra "\secparam", které se postará o~případné 
ignorování mezery na konci parametru (viz~sekci~\cite[secsec]). 
Makro "\secparam" uloží parametr
"<titul>" do tokenlistu "\sectitle" a spustí interní
\db iititle. Toto makro pracuje ve dvou módech
(DVI a PDF). V~obou módech "\iititle" uloží "<titul>" do makra 
"\headtitle" (pokud je toto makro prázdné, tedy neinicializované
uživatelem) a pomocí příkazu "\noheadline" potlačí na aktuální stránce
tisk záhlaví.

\inext {def\nb title}{\empty}{+-}

Makro "\title" v DVI verzi je prosté "\centerline", zatímco v PDF
verzi tiskne podkladový obdélník šířky "\nwidth".

Pokud není makro \db projectversion definováno, nastavíme mu výchozí
hodnotu jako prázdné makro:

\inext {ifx\nb project}{\empty}{+-}

Makro \db author "<autor>\par" je společné v obou módech. 
Umístí jméno autora tučně a na střed.

\inssdef author

\subsec Hlavičky a patičky
%%%%%%%%%%%%%%%%%%%%%%%%%%

\docbytex{} nemění výstupní rutinu plainu. Využívá tedy klasické
nástroje na modifikaci vzhledu, tj. text "\footline" a "\headline".

Návrh vzhledu stránky nepočítá s pravou a levou
stranou, protože dokumentaci většinou čteme na monitoru a když ji
tiskneme, tak kdo ví, na čem...

Text \db footline je nastaven tak, aby byla stránková číslice uprostřed
podbarvena případně orámována pomocí "\rectangle".

\inext {footline}{\empty}{+-}

Text \db headline se mění. Implicitně obsahuje jen makro \db normalhead,
ale při použití příkazu "\noheadline" na chvíli změní svůj obsah.

\ilabel[headlinebox] {headlinebox}
\inext {headline}{\empty}{+-}

Makro "\normalhead" uloží stránkový link pomocí "\savepglink"
a "\vbox/\hbox" gymnastikou vytvoří potřebné záhlaví. Zleva je tištěn
název sekce ("\firstmark") a zprava konstantní text "\headtitle".

Makro \db noheadline nastaví "\headline" přechodně na text, podle
kterého se vloží jen stránkový odkaz a provede změna obsahu
"\headline" na standardní hodnotu. Operace musíme provádět globálně,
protože jsme uvnitř výstupní rutiny.

\inssdef noheadline

Makro \db headtitle obsahuje text shodný v celém dokumentu tištěný
vpravo v záhlaví. Implicitně je makro prázdné, po použití příkazu
"\title" obsahuje název dokumentu, pokud si uživatel makro nedefinoval sám.

\inext {headtitle}{\empty}{+-}

Pomocné makro \db headlinebox udělá v DVI módu prázdný čtvereček a
v PDF módu plný (žlutý) čtvereček. Je použito na řádku~\cite[headlinebox]
pro vytvoření čtverečkované čáry v záhlaví,

\inext {ifx\nb pdfoutput}{\empty}{+-}

\subsec Tisk cíle odkazu a odkazů pod čarou
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Cíl odkazu vytvořený makry "\dg" nebo "\dl" je potřeba vytisknout
výrazně, aby jej čtenář pokud možno rychle našel. Tisk
probíhá v makru \db printdg "{<před>}{<slovo>}{<za>}", kde "<před>" je
text před slovem a "<za>" je prázdný parametr nebo obsahuje "()",
pokud tyto závorky uživatel v příkaze "\dg", "\dl" použil.

Současný návrh \docbytex{}u tiskne z těchto tří parametrů jen jeden,
sice "<slovo>". V DVI módu tiskne "<slovo>" v rámečku a v PDF módu
tiskne "<slovo>" červeně a na pozadí je žlutý obdélník.

\inext {ifx\nb pdfoutput}{\empty}{+-}

Červený text se tiskne pomocným makrem \db printdginside, které tiskne
jednoduše červeně, pokud ke slovu neexistuje "\api" cíl a tiskne
červeně pomocí "\ilink", jestliže existuje "\api" cíl.

\inext {def\nb printdginside}{\empty}{+-}

Údaj pod čáru tiskneme makrem 
\db printfnote "{<před>}{<d-slovo>}{<za>}{<k-slovo>}", 
kde parametry "<před>" a "<za>" mají stejný význam, jako u makra "\printdg".
Parametr "<k-slovo>" (krátká verze slova) tiskneme červeně, 
ostatní parametry černě. Parametr "<d-slovo>" (dlouhá verze slova) není
použit.

K naprogramování tohoto makra využiji makro
"\specfootnote"~"{<text>}", které pošle text do speciální poznámky pod
čarou. Dále je potřeba vědět, že "\pgref[+<slovo>]" vrátí číslo
strany, kde je "\api" deklarace "<slova>" nebo vrátí $-1000$. 
Toto číslo vložíme do "\apinum" a je-li nezáporné, tak jej uvedeme
jako první v seznamu stránek a podtržené. 
Seznam stránek vytiskneme pomocí
"\listofpages{<slovo>}". V seznamu bude chybět stránka "\apinum", protože
makro "\listofpages" ji vynechává. Prázdný seznam stránek (při kterém
netiskneme dvojtečku ani čárku) poznáme podle toho, že "\box0" má
nulovou šířku.

\inext {def\nb printfnote}{\empty}{+-}

\subsec Tisk údaje v obsahu a v rejstříku
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Příkaz \db ptocline "{<číslo>}{<text>}{<strana>}" se postará o tisk
údaje o sekci nebo části do obsahu. Dále příkaz \db ptocsubline
"{<číslo>}{<text>}{<strana>}" vytiskne údaj o subsekci. Jak je patrné,
tyto dva příkazy se liší jen o jeden "\indent":

\inext {def\nb ptocline}{\empty}{+-}

Příkaz \db mydotfill vytiskne tečky do obsahu tak, aby byly pod sebou
zarovnány.

Příkaz \db ptocentry "<typ>{<slovo>}{<k-slovo>}" vytiskne jednu položku
o dokumentovaném slově do obsahu. Parametr "<typ>=+", pokud je v daném
místě "\api" dokumentace, a "<typ>=@", je-li v daném místě "\dg"
dokumentace. "<k-slovo>" je prázdné, ale při použití "\dl" je v něm
krátká verze slova, zatímco ve "<slovo>" je dlouhá verze slova.
Dlouhou verzí odkazujeme, krátkou verzi tiskneme. 

\inext {def\nb ptocentry}{\empty}{+-}

Kdyby bylo potřeba tisknout text před slovem nebo závorky za slovem,
je možné využít kontrolní sekvenci "\csname-<slovo>\endcsname" jako
v následujícím makru "\printindexentry".

Makro \db myldots vytvoří tři tečky, které jsou zarovnány s ostatními
tečkami v obsahu.

Makro \db printindexentry "{<slovo>}" tiskne údaj o slově do
rejstříku. Začíná ve vertikálním módu uvnitř sloupce, vytiskne údaj a
pomocí "\par" se musí vrátit do vertikálního módu.

\inext {def\nb printindexentry}{\empty}{+-}

Pomocí \db separeright uložím do "\tmpa" text vlevo od slova a do
"\tmpb" text vpravo od slova. Makro "\refdg" tyto údaje uložilo do
makra "\csname-<slovo>\endcsname" oddělené od sebe značkou "\right".
Pomocí makra "\pgref[@<slovo>]" získám stránku s "\dg" deklarací
slova. Pomocí "\pgref[+<slovo>]" získám stránku s "\api" deklarací
slova. Tuto stránku (pokud existuje) tisknu podtrženě.

\subsec Tisk zdrojového textu
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Makra "\ifirst" a "\inext" přetisknou požadovanou část zdrojového
textu. Při řešení návrhu vzhledu tisku nás nyní pouze zajímá, že tato
makra založí skupinu, pak zavolají příkaz \db printiabove, pak pro tisk
každého řádku zavolají \db printiline "{<číslo>}{<text řádku>}" a nakonec před
ukončením skupiny se spustí \db printibelow. Právě tato tři makra si
nyní naprogramujeme. Budeme rozlišovat mezi DVI a PDF
módem.

\ilabel [isnameprinted]  {raise8}
\ilabel [isnameprinted2] {pt \nb inputfilename}
\inext {ifx\nb pdfoutput}{\empty}{+-}

V DVI módu tiskneme nahoře čáru se jménem souboru pomocí "\leaders"
a makra \db specrule. Dole pak tiskneme jen jednoduchou čáru.
V~PDF módu nahoře pouze nastavíme "\setsmallprinting" 
a vložíme malou mezeru. Dole vložíme střední mezeru.

Makro "\printiline" přejde nejprve do horizontálního módu, tam vloží v
DVI módu podpěru a dále box s číslem a box s řádkem. Mezi řádky
vkládám penaltu~11. V PDF módu se místo podpěry tiskne celý žlutý
proužek v~"\rlap". Protože přes první řádek je potřeba vpravo nahoru
vytisknout jméno souboru (později než žlutý proužek), je potřeba
zjistit, zda tisknu první řádek nebo další řádky. K tomu slouží
kontrolní sekvence \db isnameprinted, která je typicky "\undefined".
Po vytištění jména souboru (řádky~\cite[isnameprinted] a~\cite[isnameprinted2]) 
nastavím "\isnameprinted" na "\relax" a tím poznám, že už je práce
provedena. Až makro "\ifirst" nebo "\inext" ukončí skupinu, bude zase
mít "\isnameprinted" hodnotu "\undefined".

\subsec [begtt] Tisk z prostředí {\tt\nb begtt}/{\tt\nb endtt}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Makro "\begtt" založí skupinu a zavolá \db printvabove.
Dále pro každý tištěný řádek volá makro \db printvline "{<číslo>}{<text řádku>}"
a nakonec zavolá \db printvbelow. Číslo řádku jsme se rozhodli
nevyužít. V DVI verzi kreslíme jen čáry nahoře a dole. V~PDF verzi 
kreslíme žluté čáry nahoře a dole a v~každém řádku pomocí "\rlap" kreslíme 
žluté obdélníky vpravo a vlevo.

\inext {ifx\nb pdfoutput}{\empty}{+-} 

\subsec Vkládání obrázků
%%%%%%%%%%%%%%%%%%%%%%%%

Obrázky jsou vkládány nalevo podle odstavcové zarážky. Tato
zarážka je dostatečně velká, takže to působí docela dobře.
Celkovou šířku prostoru pro obrázek \db figwidth spočítám jako
"\hsize" mínus "\parindent"

\inext {newdimen\nb figwidth}{\empty}{+-}

Makro \db ifig "<poměr šířky> <název> " v DVI módu vloží "<název>.eps" a
využije k tomu makrobalík {\tt epsf.tex}. V PDF módu vloží
"<název>.pdf" a využije k tomu pdf\TeX{}ové primitivy "\pdfximage",
"\pdfrefximage", "\pdflastximage".

\inext {ifx\nb pdfoutput}{\empty}{+-}

Makro \db figdir obsahuje adresář, ze kterého se obrázky loví.

\subsec Výčty
%%%%%%%%%%%%%

Makra pro výčty jsou natolik jednoduchá, že asi nepotřebují dalšího
konimentáře. \db begitems zahájí prostředí s výčty, \db enditems ukončí
toto prostředí, \db itemno čísluje a \db dbtitem "<značka> " zahajuje položku,
přičemž se uvnitř prostředí převtělí na \db item.

\inext {newcount\nb itemno}{def\nb enditems}{++}


\sec [implementace] Pro otrlé
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Zde je dokumentována implementace \docbytex{}u. Je zde výpis 
všech jeho interních maker včetně podrobného
komentáře, jak fungují. Asi není rozumné tato makra měnit, ledaže by
si chtěl čtenář naprogramovat \docbytex{} vlastní.

\subsec Pomocná makra
%%%%%%%%%%%%%%%%%%%%%

Makro \db dbtwarning zprostředkuje tisk varovných hlášek:

\inext {def\nb dbtwarning}{\empty}{+-}

Makra \db defsec "{<text>}", \db edefsec "{<text>}" a \db undef "{<text>}"
jsou zkratky za časté operace s~"\csname<text>\endcsname".

\inext {def\nb defsec}{\empty}{+-}

Makro "\undef" je potřeba použít takto:

{\def\begtthook{\langleactive\mubytein=1}
\begtt
\undef{<text>}\iftrue <sekvence nedefinovaná> \else <sekvence definovaná> \fi
\endtt
\par}

Nutnost použití "\iftrue" se bohatě vyplatí, až budeme "\undef" přeskakovat
vnějšími podmínkami typu~"\if".

Definuji makro \db nb (normální backslash). Toto makro je pak možné
používat při vyhledávání textu s tímto znakem. Rovněž definuji aktivní
tabelátor a zástupné sekvence \db obrace, \db cbrace, \db percent
a \db inchquote.

{\catcode`\%=12 \noactive{\nb %} \noactive{[%} }

\inext {catcode}{\empty}{+-}

Makro \db softinput je vysvětleno v \TeX{}booku naruby na straně 288,
takže bez komentáře.

\inext {def\nb softinput}{\empty}{+-}

Makro \db setverb nastaví kategorie všech speciálních znaků na
normální. Viz \TeX{}book naruby, stranu~28. 

\inext {def\nb setverb}{\empty}{+-}

\subsec Inicializace
%%%%%%%%%%%%%%%%%%%%

Ohlásíme se na terminál:

\inext {This is DocBy}{\empty}{+-}

Makro \db dbtversion obsahuje verzi \docbytex{}u a je definováno 
na začátku souboru {\tt docby.tex}. Tam je autor \docbytex{}u pozmění, 
pokud přejde na novou verzi.

\inssdef dbtversion

Je-li použit "csplain", je aktivován UTF-8 vstup pomocí enc\TeX{}u. To 
ale bohužel není kompatibilní s použitím enc\TeX{}u \docbytex{}em.
Je tedy potřeba deaktivovat UTF-8 vstup a české texty napsat například
v ISO-8859-2.

\inext {utf8off}{\empty}{+-}

%Inicializujeme csplain mód:
%
%\inext {ifx\nb chyph\nb undefined \nb else}{\empty}{+-}

Inicializujeme enc\TeX{}ový mód:

\inext {encTeX ??}{\empty}{+-}

Makro \db enctextable "{<slovo>}{<tělo makra>}" vloží do enc\TeX{}ové
tabulky vzor "<slovo>". Jakmile takový vzor enc\TeX{}
objeví, zruší jej ze vstupního proudu a promění jej v kontrolní
sekvenci "\.<slovo>", která expanduje na "<tělo makra>". 
Například makro "\dg"~"<slovo>" aktivuje pro enc\TeX{} "<slovo>", takže
provede (mimo jiné) 
"\enctextable{<slovo>}{\sword{<slovo>}}", což způsobí,
že se "<slovo>" v načítaném zdrojovém kódu promění na "\sword{<slovo>}".

Makro "\enctextable" odmítá uložit do enc\TeX{}ové tabulky slova,
která jsou v seznamu \uv{zakázaných} slov \db owordbuffer. Tam jsou
slova (oddělená z obou stran čárkou), která se nesmějí aktivovat kvůli 
"\onlyactive". Pro taková slova provede "\enctextable" jen definici
sekvence "\.<slovo>".

Makro \db noactive "{<text>}" vloží do enc\TeX{}ové tabulky vyhledávaný 
text, který ve vstupu zůstane a před něj bude vložena sekvence \db emptysec.
Protože enc\TeX{} neumí ze své tabulky zrušit údaj (umí jen přepsat
informaci, na co se má vyhledávaný text proměnit), je potřeba texty,
které už v encTeXové tabulce nepotřebujeme, deaktivovat alespoň pomocí 
"\noactive".

Na \db sword "{<text>}" se díky enc\TeX{}u proměňují texty, které se mají
automaticky stát klikatelnými linky. 

\inext {def\nb sword}{\empty}{+-}

Makro \db onlyactive "{<před>}{<slovo>}{<za>}" zakáže vkládat
"<slovo>" do enc\TeX{}ové tabulky (vloží je do "\owordbuffer", 
ovšem jen za předpokladu, že už tam není),
a nechá celý text "<před><slovo><za>" proměnit v~"\oword{#1}{#2}{#3}".
Dále pomocí "\noactive" dekativuje "<slovo>" (při čtení "\reffile" 
totiž pravděpodobně bylo aktivováno).
Makro \db oword "{<před>}{<slovo>}{<za>}"
tiskne normálně "<před>", dále, pokud je definováno "\.<slovo>", tak
je spustí, jinak tiskne normálně "<slovo>". Konečně tiskne vždy
normálně text "<za>".

\inext {def\nb onlyactive}{\empty}{+-}

Nakonec inicializujeme DVI/PDF mód:

\inext {ifx\nb pdfoutput}{\empty}{+-}

\subsec Makra {\tt\nb ifirst}, {\tt\nb inext}, {\tt\nb ilabel}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Deklarujeme \db lineno jako číslo řádku, \db ttlineno jako číslo řádku
pro "\begtt...\endtt" výpisy, \db ifcontinue pro řízení cyklu a 
\db infile je deskriptor souboru otevřeného ke čtení.
\db ifskipping implementuje uživatelské \db skippingfalse a 
\db skippingtrue.

\inext {newcount\nb lineno}{\empty}{+-}

%Makra "\ifirst", "\inext" jsou pro uživatele popsána
%v~sekci~\cite[vkladani] a makro "\ilabel" má své povídání 
%v~sekci~\cite[lineodkazy].

Příkaz \db ifirst "{<soubor>}{<odkud>}{<kam>}{<jak>}" nejprve
pomocí "\readiparamwhy" analyzuje parametr "<jak>", pak otevře soubor
ke čtení primitivem "\openin". Je-li otevření neúspěšné, vypíše
varování, jinak si uloží název souboru do makra \db inputfilename 
a analyzuje parametry pomocí "\scaniparam": "<odkud>" je uloženo do
"\tmpa" a "<kam>" do "\tmpb". Do "\tmpA" a "\tmbB" se uloží počet
opakování (z konstruktoru "\count=<num>"). Nakonec se spustí makro 
"\insinternal" s expandovanými parametry "<odkud>", "<kam>".
K tomu je použit známý trik s makrem "\act".

\insdef ifirst 

Příkaz \db inext "{<odkud>}{<kam>}{<jak>}" pracuje analogicky, jako
"\ifirst", pouze neotevírá soubor, ale pomocí testu na definovanost
makra "\inputfilename" kontroluje, zda náhodou nebyl  spuštěn příkaz
"\inext" bez předchozího "\ifirst".

\insdef inext

V rámci expanze parametrů chceme, aby zmizely všechny kontrolní sekvence, které
nám do textu vložil automaticky enc\TeX{}. To provede makro
\db noswords.

\inssdef noswords

Makro \db readiparamwhy načte znaky "+" nebo "-" z parametru "<jak>" a
uloží je do sekvencí \db startline a \db stopline.

\inssdef readiparamwhy

Makro \db scaniparam "<param>^^X<out><outnum>" čte "<param>" 
ve tvaru "\count=<num> <text>". Do sekvence "<out>" uloží "<text>"
a do sekvence "<outnum>" uloží "<num>". Protože konstruktor
"\count=<num>" je nepovinný, dá trochu více práce parametr analyzovat.
K tomu slouží i pomocná makra \db scaniparamA, \db scaniparamB, \db scaniparamC.
V případě nepřítomnosti "\count=<num>" je v~"<outnum>" jednička.

\inssdef scaniparam

Hlavní práci při vkládání zdrojového textu do dokumentace dělá makro
\db insinternal s parametry "{<odkud>}{<kam>}".

\ilabel [prvniloop]       {preskakovani}
\ilabel [konec:prvniloop] {ifcontinue \nb repeat}
\ilabel [druhyloop]       {pretisk}
\ilabel [konec:druhyloop] {readnewline \nb repeat}
\ilabel [insinternal:end] {printibelow}
\insdef insinternal

Makro "\insinternal" se skládá ze dvou hlavních cyklů. První (na
řádcích~\cite[prvniloop] až~\cite[konec:prvniloop]) čte postupně 
řádky ze vstupního souboru (makrem
"\readnewline") a uloží je do makra "\etext". V tomto cyklu hledá
výskyt textu "<odkud>" a nic netiskne.

Druhý cyklus na řádku~\cite[druhyloop] až~\cite[konec:druhyloop] 
čte postupně řádky ze vstupního
souboru a hledá výskyt textu "<kam>". V této chvíli tiskne pomocí
makra "\printilineA".

Před prvním cyklem jsou provedeny přípravné práce: nastavení
kategorií, fontů, "\mubytein".
Dále je v přípravné fázi definováno makro \db testline se separátorem
"<odkud>", pomocí něhož budeme testovat přítomnost textu "<odkud>".
Variantní definice makra "\testline" následují pro speciální případ
parametru "<odkud>" (viz uživatelská dokumentace v~sekci~\cite[vkladani]).
Ukončení cyklu je řízeno podmínkou "\ifcontinue". Příkaz \db nocontinue
provede "\continuefalse", ovšem ne vždy. Pokud je zadáno "\count>1", tj. 
"\tempnum>1", pak příkaz pouze zaznamená výskyt hledaného textu a sníží 
"\tempnum" o jedničku.

\inssdef nocontinue

Před druhým cyklem v makru "\insinternal" jsou provedeny podobné přípravné 
práce jako před
prvním, znovu je definováno makro "\testline", tentokrát se separátorem 
"<kam>". Vyhledávání probíhá podobně, jako když jsme hledali "<odkud>".

Pomocí "\ifx+\startline" testujeme, zda tisknout výchozí řádek.
Pomocí "\ifx+\stopline" testujeme, zda tisknout ukončovací řádek.

Makro "\ilabellist" obsahuje testování přítomnosti lejblíků
deklarovaných příkazem "\ilabel".

Trikoidní je makro \db returninsinternal "{<text>}{<možná fi>}{<ignoruj>}",
které se spustí při dosažení konce čteného souboru. Marko opustí svůj
cyklus pomocí parametru "<ignoruj>", který je separován textem
"\printibelow", takže to přeskočí větší část obsahu makra "\insinternal" až
po řádek~\cite[insinternal:end]. Abychom správně opustili vnořené
podmínky, jsou přečtena v druhém parametru případná "\fi" a v makru použita.
První parametr obsahuje varovací hlášku, chceme-li vypsat varování.
Chceme-li být zticha, je parametr prázdný.

\insdef returninsinternal

Makro \db readnewline je naproti tomu jednoduché:

\inssdef readnewline

Pracujeme s řádkem čteného souboru ve dvou verzích: neexpandovaným
\db text a expandovaným \db etext při "\noswords". Tím máme zaručeno,
že v "\etext" nejsou kontrolní sekvence vytvořené enc\TeX{}em (pro
test přítomnosti "<odkud>" nebo "<kam>" by tam ty sekvence překážely). 
Verze s enc\TeX{}ovými sekvencemi "\text" se použije při tisku.

Makro \db printilineA musí mít svou inteligenci: nesmí bezhlavě tisknout
prázdné řádky, ale ty tiskne až se zpožděním, následuje-li tisk
neprázdného řádku. Tím je zaručeno, že se při "\skippingtrue" nevytiskne poslední
prázdný řádek. Makro \db lastline má tři stavy: "\empty" (na začátku), 
"\relax" (po vytištění řádku), "<číslo řádku>" (je-li předchozí řádek 
prázdný).

\insdef printilineA

Pro uložení deklarací pomocí \db ilabel "[<lejblík>]{<text>}"
slouží makro \db ilabellist, které musíme nastavit nejprve na prázdnou
hodnotu. 

\insdef ilabellist

Makro "\ilabel" nejprve expanduje své parametry (pomocí
"\act") a zavolá interní \db ilabelee. Toto makro přidá do
"\ilabellist" toto: 

\def\begtthook{\langleactive\mubytein=1}
\begtt
\expandafter\testilabel\etext\end{<lejblík>}{<text>}
\endtt

Makro \db testilabel "<řádek>\end{<lejblík>}{<text>}"
si definuje pomocné makro "\tmp" se separátorem "<text>", aby
zjistilo, zda je "<text>" uvnitř "<řádek>". Pokud se to povede, 
registruje cíl odkazu pomocí "\labeltext".

\inext {testilabel}{\empty}{+-}
 
\def\begtthook{}

\subsec Příkazy {\tt\nb begtt}, {\tt\nb endtt}
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Makro \db begtt a "\endtt" 
je podrobně popsáno v \TeX{}booku naruby
na stranách~27 až~30.  Makru \db startverb dodáme kompletní
verbatim text separovaný "\endtt". 
Tento text je dělený znakem "^^M" (kategorie 12) na řádky a koncový řádek
obsahuje token "\end". Makro spustí ve spolupráci s makrem \db runttloop
cyklus a řádky rozebere, každý řádek zvlášť předá makru "\printvline".
Na konci cyklu se provede makro \db endttloop. To udělá závěrečné
činnosti (zavolá "\printvbelow", ukončí skupinu) a pomocí makra
\db scannexttoken otestuje první následující
token. Pokud to není "\par", není pod "\endtt" prázdný řádek, 
takže se provede "\noindent".

\ifirst {docby.tex}{def\nb begtt }{\empty}{+-}

V numerickém registru "\ttlineno" je číslo řádku průběžně zvětšované
v celém dokumentu. Pokud by někdo chtěl toto číslo využít, může jej
nulovat například na začátku každé sekce.

\subsec [ns] Jmenné prostory
%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Každý jmenný prostor si udržuje své \db namespacemacro, což je makro 
s jedním parametrem, které příkazem "\namespace{<tělo makra>}" mimoděk
definuje uživatel. Na počátku je "\namespacemacro" prázdné:

\ifirst {docby.tex}{def\nb namespacemacro}{\empty}{+-}

Ke každému jmennému prostoru budeme chtít přiřadit lejblík. Rozhodl
jsem se za lejblík považovat výsledek expanze "\namespacemacro{@!}".
Budu jej nadále značit "<nslejblík>".
Existuje sice určité riziko nejednoznačnosti "<nslejblíku>", ale 
předpokládám, že v praxi nenastane.

Každý jmenný prostor už na počátku musí vědět, jaká všechna lokální
slova obsahuje, aby jejich výskyt mohl směřovat na místo, kde je
deklarace "\dl", která může být třeba později než výskyt.  Jmenný
prostor na svém startu musí tedy do enc\TeX{}ových tabulek uložit
všechna lokální slova a na svém konci vrátit vše pokud možno do
původního stavu.  Je tedy zřejmé, že není vhodné čekat až na příkaz
"\dl", ale že je třeba využít soubor "\reffile". V prvním průchodu
tedy jmenné prostory nemohou být aktivní.

Po přečtení "\reffile" má každý jmenný prostor k dispozici makro
"\ns:<nslejblík>", které obsahuje seznam všech svých 
lokálně deklarovaných slov ve formátu 

{\def\begtthook{\mubytein=1\langleactive}
\begtt
\locword{<slovo1>}\locword{<slovo2>}\locword{<slovo3>}...
\endtt
\par}

Protože ukládání do enc\TeX{}ové tabulky je globální, definujeme 
v rámci duševní hygieny všechna makra s tím spojená globálně. Proto je
prostředí "\namespace...\endnamespace" nezávislé na skupinách \TeX{}u.

Při startu \db namespace je třeba definovat "\namespacemacro". 
Původní hodnotu "\namespacemacro" uložíme do "\no:<nslejblík>",
abychom se k němu mohli na konci prostředí
"\namespace...\endnamespace" vrátit. Dále definujeme makro \db locword
tak, aby uložilo potřebné údaje do enc\TeX{}ové tabulky a před tím
ještě si uložilo stávající významy předefinovávaných kontrolních
sekvencí. Pak se prostě spustí "\ns:<nslejblík>". 

\inext {def\nb namespace }{^^B\cbrace}{++}

Na konci \db endnamespace znovu definujeme makro "\locword" tentokrát tak, aby
vrátilo pozměněným sekvencím původní význam. Pokud původní význam byl
\uv{nedefinovaná sekvence}, je potřeba do enc\TeX{}ové tabulky vložit
aspoň "\nword", protože zcela odstranit údaj z tabulky nelze. 
Dále se vrátíme k~původní hodnotě "\namespacemacro", kterou máme
uloženu v "\no:<nslejblík>".

\inext {def\nb endnamespace}{^^B\cbrace}{++}

Uvedená makra pracují s užitečnou zkratkou \db ewrite, která zapíše
text do "\reffile" se zpožděním (primitivem "\write"), ale expanzi 
udělá hned. Přitom neexpanduje "\nb".

\inext {def\nb ewrite}{\empty}{+-}

Enc\TeX{} od startu jmenného prostoru vkládá tedy místo každého
lokálního "<slova>" kontrolní sekvenci "\.<slovo>", která expanduje
na "\lword{<slovo>}". Jakmile se tedy objeví výskyt lokálního slova,
pracuje \db lword takto:

\inext {def\nb lword}{\empty}{+-}

Makro \db genlongword "<tmp>{<slovo>}" 
vytvoří z krátké verze slova dlouhou verzi slova a uloží ji do "<tmp>".
Výskyt "<slova>" dává o sobě vědět v parametru "\ilink" i při zápisu
do souboru svým dlouhým (jednoznačným) jménem, zatímco krátké jméno 
se tiskne.

Zbývá zařídit čtení ze souboru "\reffile". Makro 
\db refns "{<nslejblík>}" se objeví v souboru v místě začátku jmenného
prostoru a \db refnsend "{<nslejblík>}" na konci jmenného prostoru. Mezi
nimi se vyskytují "\refdg{<před>}{<slovo>}{<za>}{<k-slovo>}", přičemž
si nyní všímáme jen takových výskytů, které mají neprázdné
"<k-slovo>". Právě tyto výskyty zanesl do "\reffile" příkaz "\dl".

\inext {def\nb refns}{\empty}{+-}

Makro "\refns" si zapamatuje předchozí "<nslejblík>", který je uložen 
v makru \db currns, do sekvence "\o:<nový nslejblík>" a definuje pak "\currns"
jako "<nový nslejblík>". Připraví také výchozí stav makra "\ns:<nslejblík>"
na prázdnou hodnotu. Makro "\refdg" pak postupně plní buffer
"\ns:<nslejblík>" (viz řádky~\cite[ns1] až~\cite[ns2] v~definici makra
"\refdg" v~sekci~\cite[reference]). Konečně makro "\refnsend" vrátí
"\currns" do stavu, v jakém bylo před vstupem do stávajícího jmenného 
prostoru. 


\subsec {\tt\nb dg} a přátelé
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Makra \db dg, \db dl, \db dgn, \db dgh, \db dln, \db dlh 
uloží do "\tmpA" svůj název, spustí sken parametrů pomocí \db dgpar
a nakonec se promění ve svou interní verzi pomocí
"\csname ii\tmpA\endcsname".

\inext {def\nb dg}{\count=2 \empty}{+-}

Předchozí makra připraví čtení nepovinného parametru. Hlavní práci
provede makro \db dparam.

\ilabel [managebrackets] {managebrackets}
\ilabel [ii] {csname ii}
\inext {def\nb dparam}{\empty}{+-}

Je-li za ukončovací závorkou "]" mezera, pak je parametr "#2" prázdný (je
separovaný mezerou). V~této situaci se makro "\dparam" protočí ještě
jednou prostřednictvím makra \db nextdparam, které sežere obsah zbytku
makra "\dparam", vloží mezeru dovnitř závorky a spustí "\dparam" ještě
jednou. Nyní už je možné začít parametr "#2", tj. "<slovo>" rozdělit
na část před první čárkou, tečkou, středníkem nebo dvojtečkou a za za
tímto znakem. Část před bude v "\tmpa" a část za (včetně separátoru)
bude v "\tmpb". Tuto práci vykoná postupné volání makra \db varparam:

\inext {def\nb varparam}{\empty}{+-}

Makro "\varparam<separ>" definuje pomocné makro "\tmp#1<separ>#2 ", kterému
je předloženo "<slovo><separ> ". Je-li "#2" prázdné, pak zabral až
"<separ>" na konci, takže uvnitř "<slova>" není "<separ>". Pak v
"\tmpa" zůstává "<slovo>". Je-li uvnitř "<slova>" separátor, pak je
potřeba doplnit k "\tmpb" zbytek za separátorem včetně tohoto
separátoru. V "#2" máme "<zbytek><separ>" a my potřebujeme do "\tmpb"
uložit stávající obsah "\tmpb" před kterým předchází "<separ><zbytek>".
Tuto práci udělá \db gobblelast, kterému je předložen
"<obsah tmpb>\end<separ><zbytek><separ>". Makro definuje 
"\tmp#1<separ>" a předloží mu "<zbytek><separ>". Je tedy v "#1" holý
"<zbytek>" a do "\tmpb" se dostává "<separ><zbytek><starý obsah tmpb>". 

Po rozdělení vyhledání separátoru máme n "\tmpa" <slovo>, ovšem může
obsahovat na konci "()". Proto spustíme na řádku~\cite[managebrackets]
makro \db managebrackets, které se postará o případné oddělení těchto
závorek.  Pokud se závorky skutečně oddělily od "\tmpa", zůstávají
v~\db printbrackets.

\inext {def\nb managebrackets}{\empty}{+-}

Makro \db maybespace v závěru činnosti makra "\dparam" vytiskne za
obsahem "\tmpb" mezeru, ale jen tehdy, když je jméno makra
dvoupísmenkové ("\dg", "\dl") a nenásleduje znak "`".

\inext {def\nb maybespace}{\empty}{+-}

Na řádku~\cite[ii] vytvoří makro "\dparam" z původního příkazu
"\dg*" resp. "\dl*" jeho interní verzi "\iidg*" resp. "\iidl*".
Parametry předá expandovány, aby s nimi bylo méně práce.
Stačí tedy naprogramovat uvedená interní makra.

Makro \db iidg vloží do enc\TeX{}ové tabulky "\sword" (je to mírně
nadbytečné, totéž se provede na začátku zpracování při čtení
"\reffile" příkazem "\refdg"). Dále makro vytvoří cíl
odkazu tvaru "@<slovo>", uloží informaci do "\reffile"
ve formátu "\refdg{<před>}{<slovo>}{<za>}{}",
vytiskne "<slovo>" zvýrazněné pomocí "\printdg" a vloží poznámku pod
čáru pomocí "\printfnote".

\inext {def\nb iidg }{^^B\cbrace}{++}

Makro \db iidl nevkládá nic do enc\TeX{}ové tabulky, 
vytvoří cíl pomocí "\label [@<dlouhé slovo>]", zapíše info do
"\reffile" ve formátu "\refdg{<před>}{<d-slovo>}{<za>}{<k-slovo>}",
vytiskne "<k-slovo>" zvýrazněné pomocí "\printdg" a vloží poznámku
pomocí "\printfnote{<před>}{<d-slovo>}{<za>}".

\inext {def\nb iidl }{^^B\cbrace}{++}

Makra \db iidgh a \db iidlh dělají to samé jako jejich non-"h"
protějšky, jen netisknou slovo v místě výskytu. Lokálně tedy
předefinujeme, aby "\printdg" nedělalo nic.

\inext {def\nb iidgh}{\empty}{+-}

Makro \db iidgn předefinuje makro "\.<slovo>", které vyrábí enc\TeX,
tak, že výsledkem expanze je "\fword{<před>}{<slovo>}{<za>}" 
(namísto obvyklého "\sword{<slovo>}").

\inext {def\nb iidgn}{\empty}{+-}

Až se \db fword spustí (při prvním následujícím výskytu "<slova>"), má
za úkol provést "\iidgh", vytisknout "<slovo>" červeně a vrátit 
"\.<slovo>" do původního stavu. 

\inext {def\nb fword}{\empty}{+-}

Makro \db iidln si uloží stávající význam "\.<slovo>" do 
sekvence "\;<slovo>" a předefinuje makro "\.<slovo>", 
které vyrábí enc\TeX, tak, že výsledkem je 
"\flword{<před>}{<slovo>}{<za>}".

\inext {def\nb iidln}{\empty}{+-}

Makro \db flword má za úkol provést "\iidlh", vytisknout "<slovo>"
červeně a vrátit význam makra "\.<slovo>" do původního stavu (který je uložen
v sekvenci "\;<slovo>". Byl-li tento původní význam nedefinován, je
potřeba potlačit další činnost makra "\.<slovo>" registrováním jako
"\nword{<slovo>}", protože z enc\TeX{}ové tabulky už záznam nelze
odebrat.  

\inext {def\nb flword}{\empty}{+-}

\subsec [specfootnote] Speciální poznámky pod čarou
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Poznámky pod čarou jsou řazeny vedle sebe a obsahují jen slova, která
mají na stránce své "\dg". Protože toto řešení je vizuálně
nekompatibilní s uživatelskými poznámkami pod čarou, jednoduše je
zakážeme:

\inext {let\nb footnote=}{\empty}{+-}

Pro speciální poznámky pod čarou využiji už deklarovaný insert
"\footins". Problém je, jak odhadnout, kolik zabere vertikálního místa
v poznámkách jedno slovo, když jich může být vedle sebe
více. Dirty trick z \TeX{}booku (vkládat inserty ve výšce rovné jistému
procentu své šířky) se neujal, neboť zlom často nekonvergoval, ale osciloval.
V druhém průchodu poznámky teprve dostávají své seznamy stránek a tyto
seznamy se pak mohou dále upřesňovat, což zpětně ovlivní vertikální
sazbu. Po její změně se mění seznamy stránek a tak pořád dokola.

Rozhodl jsem se tedy pracovat pouze s průměrným koeficientem
poznámek, který budou mít všechny poznámky společný. Tento koeficient 
získám jako celkový počet řádků poznámek v celém dokumentu dělený
počtem poznámek. Každá poznámka pak \uv{překáží} v hlavním vertikálním
seznamu výškou řádku poznámek (10pt) násobenou tímto koeficientem.
Stačí tedy nastavit "\count\footins".

Aby problém určitě konvergoval, bylo nutné fixovat výše uvedený
koeficient po druhém průchodu. Kdybych jej každý následující průchod
měnil, zase se nedočkáme konvergence. Získat uvedený koeficient hned
po prvním průchodu není rozumné, protože v té době poznámky ještě
nemají vedle sebe seznamy stránek. Výchozí koeficient pro první a
druhý průchod je tedy nastaven na "\count\footins=200" (předpokládám
zhruba pět poznámek na řádku).

Pracovat s průměrem místo s každou jednotlivou poznámkou může
samozřejmě způsobit, že některé stránky jsou plnější a některé
prázdnější. Proto je potřeba mít rezervu ve "\skip\footins" a
vertikálně pružit kolem poznámkové čáry.

\inext {skip\nb footins}{\empty}{+-}

V registru \db totalfoocount se bude postupně přičítat jednička za každou
poznámku a na konci zpracování tam tedy je celkový počet poznámek.
V registru \db totalfoodim bude na konci zpracování celková výška 
všech řádků s poznámkami. 

\inext {newcount\nb totalfoocount}{\empty}{+-}

Makro \db specfootnote "{<text>}" 
vloží do insertu "\footins" jediný "\hbox{<text>}" a připočte
jedničku do "\totalfoocount".

\inext {def\nb specfootnote}{\empty}{+-} 

Protože jsem se rozhodl neměnit výstupní rutinu plainu, musel jsem se
\uv{nabourat} aspoň do její části na tisk poznámek pod čarou. Je to
provedeno předefinováním makra "\footnoterule" výstupní rutiny plainu.
Separátor "\unvbox\footins" způsobí odstranění stejného textu 
z output rutiny plainu.

\inext {def\nb footnoterule}{\empty}{+-}

Makro rozebere vertikální seznam insertů "\footins" a poskládá je
vedle sebe do boxu~4. Pak nastaví parametry sazby na praporek a
vypustí box~4 do horizontálního seznamu ("\noindent") ukončeném
"\endgraf". Tím jsou ve výstupní rutině poznámky pod čarou vysázeny.
Nakonec připočteme "\totalfoodim".

V závěru zpracování v makru "\bye" (viz řádek~\cite[write]) zapíšeme
do souboru "\reffile" informaci o~počtu poznámek "<počet>", o celkové
výšce řádků poznámek v dokumentu "<výška>" a přidáme aktuální
koeficient příspěvku poznámek do vertikálního seznamu "<koeficient>".
Informaci zapisujeme jen tehdy, když je "\indexbuffer" neprázdný,
tj. když probíhá aspoň druhý průchod. Kdybychom zapisovali i první
průchod, dostali bychom velmi zkreslené informace (poznámky v~tu
chvíli nemají vedle sebe seznamy stránek).
%
Uvedenou informaci zapsanou v předchozím průchodu 
přečteme na začátku zpracování makrem
\db refcoef "{<koeficient>}{<počet>}{<výška>}" a 
nastavíme podle toho společný koeficient všech poznámek
"\count\footins". Makro změní koeficient z výchozí 
hodnoty 200 na vypočtenou jen jednou. Při dalších průchodech už
zůstává u vypočtené hodnoty.
Pomocné makro \db gobblerest odstraní cifry za desetinou
tečkou včetně nápisu~"pt".

\inext {def\nb refcoef}{\empty}{+-}

Výstupní rutina "\plainoutput" není změněna. Potřebuji ale uvnitř
"\output" potlačit expanzi některých maker, které se objeví v argumentu
"\write". Tato makra jsou tedy uvnitř "\output" nastavena na "\relax".
Aby toto nastavení nezměnilo sazbu záhlaví, je potřeba "\makeheadline" 
provést před změnou maker a uložit si výsledek do boxu.

\inext {\nb output=}{\empty}{+-}

\subsec [secsec] Sekce, podsekce
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Nejprve zapíšeme deklarace \db secnum, \db subsecnum, 
\db sectitle, \db ifsavetoc. Poslední deklarace připraví
uživatelské \db savetocfalse.

\ifirst {docby.tex}{newcount\nb secnum}{\empty}{+-}

Makra \db sec a \db subsec mají možnost nepovinného parametru
"[<lejblík>]", za ním může a nemusí být mezera, kterou musíme ignorovat. 
Na konci parametru "<titul>" před "\par" rovněž může a nemusí být
mezera, kterou musíme ignorovat. Dá tedy práci parametry správně
načíst. Makra si uloží svůj název do "\tmpA" a spustí proces načítání
parametrů pomocí "\secparam".

\inext {def\nb sec}{\empty}{+-}

Makro \db secparam se vypořádá s případným nepovinným parametrem
"[<lejblík>]". Pokud je přítomen, uloží "<lejblík>" do pomocného makra
\db seclabel, jinak tam je prázdno. Makro \db secparamA se vypořádává
s případnou mezerou za hranatou závorkou "]" a odstraní ji.
Makro \db secparamB "<titul>\par" načte "<titul>", ale ten může mít
nežádoucí mezeru zcela na konci. S tím se vypořádá makro 
\db nolastspace ve spolupráci s makrem \db setparamC. Posledně jmenované
makro uloží už od nežádoucí mezery ošetřený "<titul>" do "\sectitle" a
spustí "\iisec" resp. "\iisubsec".

\inext {def\nb secparam}{\empty}{+-}

Makro \db iisec nejprve nastaví hodnoty "\secnum" a "\subsecnum",
dále definuje \db makelinks, kde je připravena tvorba odkazů (to
použije makro "\printsec").
Dále zavolá "\printsec" na vytištění názvu sekce.
Poté uloží informace do "\reffile" ve tvaru
"\reftocline"~"{<secnum>}{<titul>}{<strana>}" 
Nakonec se provede "\mark{<secnum> <titul>}" a 
vloží se závěrečná mezera pomocí "\printsecbelow".

\inext {def\nb iisec}{^^B\cbrace}{++}

Makro \db iisubsec, které vytváří podsekci, pracuje analogicky, jako
makro "\iisec".

\inext {def\nb iisubsec}{^^B\cbrace}{++}

Makro "\part" bylo zapracováno dodatečně ve verzi Jan. 2009. 
Registr \db partnum uchovává číslo části a makro \db thepart
toto číslo konvertuje na písmeno.

\inext {newcount\nb partnum}{\empty}{+-}

Makro \db part má svou implementaci v makru \db iipart
podobně jako například makro "\sec".

\inext {def\nb part}{\empty}{+-}

\subsec [reference] Odkazy, reference
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Klikací odkazy řeší makra \db savelink "[<lejblík>]" a a \db ilink
"[<lejblík>]{<text>}". Makro "\savelink" uloží do sazby cíl
odkazu. Cíl odkazu vystrčí do
výšky \db linkskip nad účaří. Makro "\ilink" (čti interní link) je
dokumentováno v~sekci~\cite[krizodkaz]. Konečně makro "\savepglink"
uloží cíl numerického typu (číslo stránky), který bude využit makrem
"\pglink" při odkazech na stránky.

\ifirst {docby.tex}{Odkazy, ref}{\empty}{--}

Uvedená makra jsem definoval zvlášť pro DVI výstup (jako prázdná
makra) a zvlášť pro PDF výstup. Až zase tvůrci pdf\TeX{}u změní
syntaxi nebo názvy primitivů, bude stačit pozměnit uvedená makra.
V makru "\ilink" je přímo řečeno, že se má použít modrá barva pro
vytvoření odkazů a že odkaz má být bez rámečku. Pokud to někomu
nevyhovuje, může si makro předefinovat.

Trik s předefinováním "\nb" (normální backslash) při tvorbě PDF linků
vychází ze zkušenosti, že pokud se v názvu linku objeví backslash,
některé PDF prohlížeče si s tím neporadí a chovají se podivně. Je tedy
nutné, aby argument příkazů "\savelink" a "\ilink" byl neexpandovaný.

Makro \db savepglink (definice je v předchozím výpisu) je použito v
"\headline" každé stránky, takže vytvoří cíl \uv{nahoře} na každé
stránce. Makro \db pglink "<number>" přečte "<number>" (může být ve
tvaru numerického registru i přímo jako číslo) a vytvoří link na
stránku s tímto číslem. Číslo samotné je vytištěno modře a dá se na ně
kliknout. Ke čtení numerického registru je použit primitiv "\afterassignment"
a pomocné makro \db dopglink.

V souboru "\jobname.ref" se prostřednictvím makra
"\labeltext[<lejblík>]{<text>}" uloží řádek, který obsahuje
"\reflabel"~"{<lejblík>}{<text>}{<strana>}".  Makrem \db reflabel tyto
údaje přečtu a zapíšu do kontrolních sekvencí "^^X<lejblík>" a
"^^Y<lejblík>". Tyto kontrolní sekvence jsou následně využity
v~makrech \db numref a \db pgref.  
Za povšimnutí stojí, že pokud je "<text>" prázdný
(to jsou například všechny případy dokumentovaných slov), pak
kontrolní sekvenci "^^X<lejblík>" vůbec nedefinuji, abych šetřil
pamětí, kterou má \TeX{} rezervovánu na kontrolní sekvence.

\inext {reflabel}{\empty}{+-}

Makro \db labeltext "[<lejblík>]{<text>}", jak bylo před chvílí
řečeno, uloží do souboru potřebné údaje. Jednak zapíše PDF link pomocí
makra "\savelink" a dále uloží do souboru "\reffile" potřebné údaje.
K tomu je makro \db writelabel "[<lejblík>]{<text>}", které 
pracuje se zpožděným "\write" (aby číslo strany bylo správně). 
V okamžiku načtení parametru
"<text>" jej potřebuji expandovat, protože tam obvykle bývá něco jako
"\the\secnum". Pro vyřešení tohoto problému jsem
na chvíli prohodil parametry ("<lejblík>" totiž nechci
expandovat) a zavedl pomocné makro 
\db writelabelinternal "{<text>}{<lejblík>}".
První část, tj. "\writelabel{<text>}" expanduji pomocí "\edef".

\inext {labeltext}{\empty}{+-}

Makro \db label je už definováno jednoduše jako \uv{prázdný}
"\labeltext".

\inext {label}{\empty}{+-}

Makro \db cite "[<lejblík>]" vytiskne klikatelný text. Při chybném
"<lejblíku>" vytiskne varování na terminál. Makro je dokumentováno 
v~sekci~\cite[krizodkaz].

\inext {cite}{\empty}{+-}

S odkazy souvisí makro \db api "{<slovo>}", které vloží
"\label[+<slovo>]" dá o sobě vědět ještě jednou do "\reffile".

\inext {def\nb api}{\empty}{+-}

Makro \db apitext obsahuje text tištěný vedle "<slova>" do obsahu a
rejstříku. 

Při činnosti makra \db bye zapíšeme do souboru "\reffile" údaje 
pro "\refcoef" (řádek~\cite[write]) a dále se zabýváme testem
konzistence referencí.

\ilabel [texttoc] {text\nb tocbuffer}
\ilabel [vypust] {indexbuffer}
\ilabel [write] {write\nb reffile}
\inext {def\nb bye}{^^B\cbrace}{++}

Test konzistence vypadá následovně: nejprve
uzavřeme zápis do souboru "\reffile", pak
pomocí "\setrefchecking" předefinujeme
kontrolní sekvence vyskytující se v "\reffile" a soubor znovu
načteme. Nyní makra v něm napsaná dělají test a pokud narazí na
problém, provedou "\continuefalse". Můžeme tedy pomocí "\ifcontinue"
zjistit, jak test dopadl. Po přečtení souboru je potřeba udělat ještě
důkladnou kontrolu všech automatických odkazů. Proč je tato kontrola 
vyřešena vypuštěním "\indexbuffer" do vstupní fronty bude jasné po prostudování
makra \db setrefchecking.

\ilabel[jerelax] {=\nb relax}
\inext {def\nb setrefchecking}{\empty}{+-}

Zde předefinujeme makro "\refcoef", aby nedělalo nic. 
Dále nová verze "\reflabel" kontroluje, zda odkaz je na stejné stránce, jako byl
a má stejný text. 
Nové makro "\refuseword" pracuje jako jeho originální protějšek, jen místo
sekvencí "w:<slovo>" plní sekvence "-<slovo>". Tyto sekvence už známe,
nyní je využijeme jinak. Šetříme pamětí \TeX{}u, proto nezakládáme
sekvence nové. Nejprve je nutné těmto sekvencím nastavit výchozí
hodnotu "\relax", což je provedeno na řádku~\cite[jerelax].
Pak znovu předefinuji sekvenci "\,", aby provedla test shodnosti sekvence
"w:<slovo>" se sekvencí "-<slovo>" a v makru "\bye" na
řádku~\cite[vypust] spustím tento test expandováním makra 
"\indexbuffer\relax". Když makro najde nekonzistenci, ohlásí chybu a
uteče pomocí \db ignoretorelax.
Dále je předefinováno makro "\refdg", aby pouze
zapisovalo do "\tocbuffer". Ostatní makra z "\reffile" také zapisují
do "\tocbuffer". Stávající verzi "\tocbuffer" uložíme do "\text" a
"\tocbuffer" se při načtení "\reffile" vytvoří znovu. Na
řádku~\cite[texttoc], zda se nezměnil obsah.

\subsec Tvorba obsahu, rejstříku a záložek
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Obsah i rejstřík se mohou pomocí "\dotoc" a "\doindex" objevit kdekoli
v dokumentu (třeba na začátku, na konci, uprostřed...). Musíme být
připraveni je kdykoli vytisknout. Soubor "\reffile" z minulého běhu 
můžeme otevřít ke čtení jen na začátku, pak jej mažeme a začínáme
znova zapisovat. Při čtení ze souboru "\reffile" tedy musíme uložit
všechny potřebné informace k sazbě obsahu i rejstříku. Používáme na to
makro "\tocbuffer" a "\indexbuffer". Na začátku tyto \uv{buffery}
vyprázdníme. Makro \db addtext "<text>\to<buffer>" budeme používat na
vkládání "<textu>" do "<bufferu>", čímž buffery postupně naplníme.

\inext {def\nb tocbuffer}{\empty}{+-}

V souboru \db reffile se vyskytují tyto příkazy:

{\def\begtthook{\langleactive\catcode`\!=0\mubytein=1}
\begtt
\reftocline{<číslo>}{<název>}{<strana>}  % údaje o sekci a subsekci pro obsah
\refdg{<před>}{<slovo>}{<za>}{<k-slovo>}  % údaj o použití \dg, \dl
\refapiword{<slovo>}                   % údaj o výskytu \api{<slovo>}
\refuseword{<slovo>}{<strana>}          % údaj o přímém výskytu <slova>
\reflabel{<lejblík>}{<text>}{<strana>}     % viz sekci !cite[reference], odkazy, reference
\refcoef{<koeficient>}{<počet>}{<výška>}  % viz sekci !cite[specfootnote], spec. poznámky
\refns{<nslejblík>}                     % viz sekci !cite[ns], jmenné prostory
\refnsend{<nslejblík>}                  % viz sekci !cite[ns], jmenné prostory
\endtt
\par}

Při čtení souboru "\reffile" ukládáme potřebné údaje do
bufferů. Nejprve se zaměříme na {\bf obsah} a definujeme 
\db reftocline "{<číslo>}{<název>}{<strana>}".

\inext {def\nb reftocline}{\empty}{+-}

V \db tocbuffer tedy máme postupně údaje o všech sekcích a podsekcích v
za sebou jdoucích sekvencích \db dotocline "{<číslo>}{<název>}{<strana>}".
Mezi sekcí a subsekcí rozlišíme jen podle toho, zda
parametr "<číslo>" obsahuje tečku. K tomu slouží pomocné makro 
\db istocsec.

\inext {def\nb dotocline}{\empty}{+-}

Kdybychom spustili makro "\tocbuffer", dostaneme obsah. Ale ten se
neskládá jen z údajů o~sekcích a podsekcích. Ještě je potřeba přečíst
\db refdg a \db refapiword, abychom mohli vkládat do obsahu i údaje 
o~dokumentovaných slovech.

\ilabel [right] {right}
\ilabel [ns1] {\nb dl}
\ilabel [ns2] {locword}
\inext {def\nb refdg}{\empty}{+-}

Makro "\refdg" pracuje s parametry "{<před>}{<slovo>}{<za>}{<k-slovo>}",
kde "<před>" je text před slovem, "<slovo>" je dlouhé slovo, "<za>" obsahuje
případné závorky "()". Je-li dlouhé slovo rozdílné od krátkého slova
(při použití "\dl"), obsahuje "<k-slovo>" krátké slovo, jinak je tento
parametr prázdný.
Makro "\refdg" ukládá informace nejen do "\tocbuffer",
ale také do "\indexbuffer". Rovněž při prázdném "<k-slovo>" makro
ukládá "\sword" do enc\TeX{}ové tabulky a při
neprázdném "<k-slovo>" makro cosi kutí se jmennými prostory. 
Nyní je ale naše pozornost věnována tvorbě
obsahu.  Ten vytvoří makro \db dotoc.

\inext {def\nb dotoc}{\empty}{+-}

{\bf Rejstřík} je vybudován z bufferu \db indexbuffer, ve kterém je seznam
deklarovaných slov v dokumentu. Každé slovo je v bufferu zapsáno jako
kontrolní sekvence (to zabere v paměti \TeX{}u nejmíň místa) a je
odděleno od další sekvence oddělovačem. Před zatříděním podle abecedy
jsou položky v~"\indexbuffer" odděleny čárkami za položkami, po
zatřídění jsou položky odděleny "\," před položkami. Takže obsah
"\indexbuffer" vypadá zhruba takto:

{\def\begtthook{\langleactive}
\begtt
před zatříděním:  \-<slovo1> , \-<slovo2> , \-<slovo3> , \-<slovo4> , ...
po zatřídění:     \, \-<slovoA> \, \-<slovoB> \, \-<slovoC> \, \-<slovoD> ...
\endtt
\par}

\noindent Zde zápis "\-<slovo>" znamená jednu kontrolní sekvenci.
Každá taková kontrolní sekvence je makrem tvaru "<před>\right<za>".
To zařídí řádek~\cite[right]. Rejstřík vytiskneme makrem \db doindex.

\ilabel [calculatedimone] {calculatedimone}
\inext {def\nb doindex }{^^B\cbrace}{++}

Příkaz "\calculatedimone" s následujícím testem "\dimen1" souvisí se
sazbou do dvou sloupců, což necháme na sekci~\cite[dvasloupce].  Makro
tedy založí příkazem "\sec" sekci nazvanou "\titindex" a pokud je
"\indexbuffer" neprázdný, spustí sazbu rejstříku. Nejprve se příkazem
"\sortindex" setřídí "\indexbuffer" podle abecedy (viz sekci~\cite[abeceda]). 
Pak makro "\doindex" založí
dvousloupcovou sazbu ("\begmulti 2") a oddělovači "\," přidělí význam
"\doindexentry". Nakonec vypustí "\indexbuffer" do vstupní fronty,
takže další práci opakovaně provede makro \db doindexentry
"\-<slovo>", které se postará o tisk slova v~rejstříku.

\inext {def\nb doindexentry}{\empty}{+-}

Makro "\doindexentry" pomocí \db ignoretwo odstraní z kontrolní
sekvence "\-<slovo>" úvodní dva znaky "\-", takže v "\tmp" zůstane "<slovo>".
Pokud "<slovo>" začíná backslashem, uděláme z něj makrem 
\db remakebackslash sekvenci "\nb", neboť přímý backslash není uložen
v PDF odkazech (zlobí některé PDF prohlížeče, viz sekci~\cite[reference].
Nakonec se vytiskne položka v rejstříku už známým makrem "\printindexentry".

Při tvorbě {\bf strukturovaných záložek} je potřeba vědět, kolik má
každý uzel potomků. Tento údaj je počítaný při čtení "\reffile"
voláním makra \db addbookmark "<uzel>" (viz makra "\reftocline" a "\refdg").
Parametr "<uzel>" může být číslo sekce, nebo dvojčíslí "<sekce>.<podsekce>".
V makru \db currb je "<uzel>", ke kterému je potřeba přičítat potomka
a \db currsecb je případný nadřazený "<uzel>" sekce.
Makro "\addbookmark" připočte jedničku k hodnotě makra "\bk:<uzel>".

\inext {def\nb addbookmark}{\empty}{+-}

Makro \db bookmarks založí skupinu, předefinuje "\dotocline" a
"\ptocentry" (tj.~makra obsažená v~"\tocbuffer") vloží první záložku 
s názvem dokumentu a spustí "\tocbuffer".

\inext {def\nb bookmarks}{^^B\cbrace}{++}

Makro \db setoutline "[<lejblík>]{<text>}{<prefix>}" vytvoří záložku 
"<prefix><text>" a prolinkuje ji s cílem označeným "<lejblík>". 
V "\tempnum" musí být uložen počet potomků záložky.

\inext {def\nb setoutline}{\empty}{+-}

V tomto makru je použito konverzní makro \db cnvbookmark, které je
implicitně neaktivní. Uživatel může například nastavit 
"\let\cnvbookmark=\lowercase"
a nechat konvertovat pomocí "\lccode" znak "č" na "c", znak "ž" na
"z", atd. Nastavení "\lccode" musí mít v "\bookmarkshook".

Dále je text před vložením do záložky podroben konverzi \db nobraces, 
která ve spolupráci s makrem \db nobrA sundá případné závorky "{}". 
Takže, pokud máme třeba "{\tt text} v \TeX{}u",
po konverzi dostáváme "text v TeXu".

\subsec [abeceda] Abecední řazení rejstříku
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Tuto práci provede makro "\sortindex". Původně bylo v \docbytex{}u
implementováno algoritmem bubblesort, což vyšlo na šest řádků makrokódu
(prezentováno na tutoriálu \TeX{}perience~2008), ale pro větší
rejstříky to bylo pomalé. Např. pro rejstřík tohoto dokumentu to
vygenerovalo 52 tisíc dotazů na porovnání a trvalo to asi dvě
vteřiny. Můj syn Mirek byl pozorný
posluchač tutoriálu, takže nabyté znalosti okamžitě využil a přepsal
třídicí makro na mergesort. Ten na stejně velkém rejstříku generuje 
1600 dotazů na porovnání, tedy třicetkrát méně. Cena za to je
skutečnost, že makro už nemá jen šest řádků, ale je mírně
komplikovanější. Od možnosti použít quicksort jsme upustili, protože
implementace by vyžadovala vyšší paměťové nároky na inputstack
\TeX{}u.

Nejprve deklarujeme podmínku pro výsledek srovnání dvou položek
\db ifAleB a vytvoříme pomocná makra \db nullbuf, \db return a 
\db fif. Pomocné makro "\return" ve spolupráci se zakrytým "\fi"
uvnitř "\fif" budeme používat pro únik z košatých hluboce vnořených
podmínek typu "\if..\else..\fi". Jak uvidíte, makro pracuje na úrovni
expandprocesoru a nebude potřeba psát žádné "\expandafter".

\inext {newif\nb ifAleB}{\empty}{+-}

Makro \db sortindex vypustí do vstupní fronty celý "\indexbuffer",
přimaluje k němu "\end,\end", pronuluje "\indexbuffer" a spustí 
"\mergesort".

\inext {def\nb sortindex}{^^B\cbrace}{++}

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é ("\indexbuffer" 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
"\indexbuffer". V dalším průchodu znovu vyvrhne "\indexbuffer" 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 "\indexbuffer" a ukončit činnost. Pomocí "\gobblerest"
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 indexbuffer}
\ilabel [napercarky] {napercarky}
\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}

Vlastní srovnání dvou položek dělá makro 
\db isAleB "<polA><polB>". Položky jsou tvaru kontrolní
sekvence "\-<slovoA>" a "\-<slovoB>". 
Makro konvertuje své parametry pomocí "\string" na řadu znaků a
expanduje na "\testAleB"~"<slovoA>\relax<slovoB>\relax".
Navíc je na tento test aplikováno "\lowercase", 
neboť nerozlišujeme při řazení mezi velkými a malými písmeny.

\ilabel [teckanula] {0\nb relax}
%\ilabel [teckajedna] {2.1}
\inext {def\nb isAleB }{^^B\cbrace}{++}

Makro \db testAleB "<slovoA>\relax<slovoB>\relax" zjistí, zda je 
"<slovoA>" menší než "<slovoB>". Makro volá 
samo sebe, pokud jsou první porovnávané znaky stejné. Rekurze určitě
skončí, neboť na řádku~\cite[teckanula]
jsou k porovnávaným slovům připojeny různé ocasy.

\inext {def\nb testAleB}{^^B\cbrace}{++}

Makro \db napercarky vloží mezi položky do "\indexbuffer" separátory "\,".
To se provede uvnitř "\edef\indexbuffer" na řádku~\cite[napercarky].

\inext {def\nb napercarky}{\empty}{+-}


\subsec Transformace seznamu stránek
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Každý výskyt "<slova>"
uloží do "\reffile" údaj \db refuseword "{<slovo>}{<strana>}", který
přečteme na začátku zpracování v dalším průchodu:

\inext {def\nb refuseword}{^^B\cbrace}{++}

V sekvenci "\w:<slovo>" tedy máme seznam stránek s výskyty "<slova>",
stránky jsou odděleny čárkami. Seznam může vypadat třeba takto:

\begtt
2,5,5,10,11,12,12,13,13,13,27
\endtt

Cílem je takovýto seznam stránek vytisknout ve formátu 
"2, 5, 10--13, 27", tj. odstranit duplicity a nahradit souvisle jdoucí
řadu stránek zápisem ve tvaru "<od>--<do>". Tuto práci dělá makro
\db listofpages "{<slovo>}", které předhodí makru "\transf" expandovaný seznam
stránek ukončený ",0,".

\inext {def\nb listofpages}{^^B\cbrace}{++}

Makro "\transf" vyloučí ze seznamu stránek ty, které jsou rovny
\db dgnum a \db apinum. Nechceme totiž, aby se v seznamu opakovala hlavní
stránka "<slova>" a podtržená stránka. Tyto stránky jsou vytištěny už
dříve. Deklarujeme uvedené registry:

\inext {newcount\nb apinum}{\empty}{+-}

Kromě toho jsme deklarovali pomocné \db tempnum (aktuálně zpracovávaná
stránka), \db ifdash (zda zpracováváme souvislou skupinu stránek 
a vytiskli jsme "--") a 
\db iffirst  (zda vkládáme první číslo, tj. není nutné vložit čárku).

Makro \db transf "<seznam stránek>,0," spustí cyklus pomocí \db cykltransf.

\inext {def\nb transf}{def\nb carka}{++}

Makro "\cykltransf" je takový malý stavový automat. Věřím, že mu čtenář
porozumí bez dalšího komentáře. 

\subsec [dvasloupce] Více sloupců
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Sazba do více sloupců je kompletně převzata z \TeX{}booku naruby,
strany 244--246. 

\ilabel [dimen1] {dimen1<2}
\inext {newdimen\nb colsep}{TBN}{++}

Zde navíc řešíme problém, že na začátku přepnutí do
dvou sloupců pomocí \db begmulti "2" si makro na řádku~\cite[dimen1]
zkontroluje, zda není blízko dna stránky a v takovém případě zahájí
dva sloupce až na nové stránce. Ovšem vypadá hloupě, pokud se kvůli
tomu ulomí nadpis \uv{Rejstřík} od jeho obsahu. Je tedy potřeba
provést podobné měření stránky už před tiskem nadpisu \uv{Rejstřík}.
K tomu slouží makro \db calculatedimone spuštěné na 
řádku~\cite[calculatedimone] v makru "\doindex".

\inext {def\nb calculatedimone}{\empty}{+-}

\subsec Závěrečná nastavení, kategorie
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

Kategorie je rozumné nastavit až na konci souboru {\tt docby.tex}.
Na rozdíl od plainu přidáváme aktivní kategorii pro znak palce a
nastavujeme podtržítko na obyčejnou kategorii, protože se ve
zdrojových kódech programů často používá a vůbec ne ve významu
matematického indexu. Kdyby mu tento význam zůstal, byly by jen
potíže.

Podtržítko je další problém. Skoro vždy chceme, aby se ve 
vnitřních makrech chovalo jako normální podtržítko, ale když tiskneme text s
podtržítkem fontem, který na dané pozici podtržítko nemá (to je Knuthův
odkaz), pak by se to mělo udělat plainovským makrem "\_", Toto makro tedy
schováme do \db subori a pak ho probudíme k~životu jen v~okamžiku tisku
v~makrech "\printsec", "\printsubsec", "\title" a "\normalhead".
Uživatel tedy může napsat "\sec moje\_funkce" a v~makrech se bude "\_" jako
obyčejné podtržítko, zatímco při tisku v nadpise se použije "\subori".

\inext {catcode`\nb_}{\empty}{+-}

Nastavením "\everymath" a "\everydisplay" zaručíme matematikům stále
možnost používat podtržítko ve významu indexu.

Aktivní palec spustí lokální verbatim prostředí uvnitř odstavce:

\inext {catcode`\nb}{\empty}{+-}

Makro \db langleactive nastaví aktivní kategorii pro znak je menší
({\tt<}), takže bude možné zapisovat {\tt<text>} a vytiskne se
"<text>". 

\inext {def\nb langleactive}{\empty}{+-}

V tomto dokumentu jsem "\langleactive" použil v makru
"\quotehook", protože nechat znak {\tt<} aktivní všude nedělalo dobrotu.

\doindex

\bye


