diff options
Diffstat (limited to 'Master/texmf-dist/doc/generic/docbytex/docby.d')
-rw-r--r-- | Master/texmf-dist/doc/generic/docbytex/docby.d | 2643 |
1 files changed, 2643 insertions, 0 deletions
diff --git a/Master/texmf-dist/doc/generic/docbytex/docby.d b/Master/texmf-dist/doc/generic/docbytex/docby.d new file mode 100644 index 00000000000..9ae289c94da --- /dev/null +++ b/Master/texmf-dist/doc/generic/docbytex/docby.d @@ -0,0 +1,2643 @@ + +%% DocBy.\TeX{} -- nástroj na dokumentování zdrojových kódů + +\def\projectversion{\dbtversion} +\def\headtitle{DocBy.\TeX} + +\showboxbreadth=1500 \showboxdepth=2 + +\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{}. Formát může být "plain" nebo +"csplain". V takovém případě se \docbytex{} ohlásí na terminálu +těmito slovy: + +\def\begtthook{\catcode`\!=0} +\begtt +This is DocBy.TeX, version !dbtversion, modes: enc+PDF+plain +nebo: +This is DocBy.TeX, version !dbtversion, modes: enc+PDF+csplain +\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 "plain/csplain". + +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{} +zahrnut. Poznáte to podle možnosti použít přepínač "-enc" v případě +generování formátu. Zajistěte ve své \TeX{}ové distribuci, aby byl v době +generování formátu tento přepínač použit. Jak to udělat závisí na +distribuci. Univerzální, ale ne příliš elegantní postup, může vypadat +takto: + +\begtt +generování formátu: +pdfetex -enc -ini -jobname pdfcsplain csplain.ini +zpracování dokumentu: +pdfetex -fmt pdfcsplain dokument.tex +\endtt + +Formát samozřejmě můžete generovat jen jednou a příkaz na zpracování +dokumentu pak můžete opakovat. Pokud postupujete podle výše uvedené +ukázky, uloží se formát "pdfcsplain.fmt" s podporou enc\TeX{}u do +aktuálního adresáře, odkud jej příkaz "pdfetex -fmt pdfcsplain" čte. +Elegantnější asi je uložit formát někam do \TeX{}ové distribuce, ovšem +to je závislé na použité distribuci. + +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 "csplain"\api{csplain}, je-li použit tento +formát. V takovém případě se zapne české dělení slov a některé názvy +(např. \uv{Rejstřík}) jsou vypisovány v češtině. Slováci mohou po +načtení "docby.tex" přepnout do slovenštiny pomocí "\shyph" a mohou si +tyto názvy předefinovat (viz sekci~\cite[nazvy]). +Pokud je použit formát "plain",\api{plain} \docbytex{} zůstane u vzorů dělení +pro angličtinu a názvy (např. \uv{Index}) zůstávají anglické. + +\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 + +Inicializujeme csplain mód: + +\inext {^^B\nb ifx\nb chyph\nb undefined \nb else}{\empty}{+-} + +Inicializujeme enc\TeX{}ový mód: + +\inext {ifx\nb mubyte}{\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 + + |