\input cwebmac

\input csmac % Makra pro češtinu
\pageheight=9.5in \fullpageheight=9.8in  \setpage
%\nocon % omit table of contents
\datethis % print date on listing

\def\begitems{\medskip\bgroup\catcode`\*=13 \narrower\narrower}
\def\enditems{\par\egroup\medskip}
{\catcode`\*=13 \gdef*{\par\noindent\llap{$\bullet$\ }\ignorespaces}}



\N{1}{1}PROGRAM VLNA.
Program čte vstupní textový soubor a nahrazuje za specifikovanými
jednopísmennými slovy (např.~v, k, u) mezery symbolem \uv{\.{\char126}}. To
zabrání při následném zpracování \TeX{}em zlomit řádek na nevhodných
místech, která jsou v rozporu s typografickou normou.

Program sestává z těchto hlavních celků:
\Y\B\X3:Hlavičkové soubory k načtení\X\6
\X4:Globální deklarace\X\6
\X6:Pomocné funkce\X\6
\X26:Vlnkovací funkce \PB{\\{tie}}\X\6
\X5:Hlavní program\X\par
\fi

\M{2}Definujeme \PB{\.{BANNER}}, což je text, který se objevi při startu
programu a obsahuje číslo verze programu.
Zde je názorně vidět, že míchání dvou jazyků se nevyhneme. Při tisku
textů na terminál nesmíme předpokládat, že tam budou české fonty.
V~této dokumentaci se setkáme se třemi jazyky: angličtinou (většinou
v~kódu programu, cestinou v~/* komentářích */ a češtinou jinde.
Tu cestinu si vynutil fakt, že DOS-ovská varianta \.{tangle} a
\.{weave} se nesnáší s~akcentovanými písmeny v~/* komentářích */.
A~nyní už slíbený (vícejazyčný) \PB{\.{BANNER}}.
\Y\B\4\D$\.{BANNER}$ \5
\.{"This\ is\ program\ vln}\)\.{a,\ version\ 1.2,\ (c)\ }\)\.{1995,\ 2002\ Petr%
\ Olsa}\)\.{k\\n"}\par
\fi

\M{3}V programu jsou použity knihovní funkce, jejíchž prototypy jsou
definovány ve třech standardních hlavičkových souborech.
\Y\B\4\X3:Hlavičkové soubory k načtení\X${}\E{}$\6
\8\#\&{include} \.{<stdio.h>}\6
\8\#\&{include} \.{<string.h>}\6
\8\#\&{include} \.{<stdlib.h>}\par
\U1.\fi

\M{4}Definujeme konstanty pro návratový kód. \PB{\.{OK}} pro úspěšný běh,
\PB{\.{WARNING}} při výskytu aspoň jedné varovné zprávy, \PB{\.{IO\_ERR}} pro
chybu
v~přístupu ke vtupním nebo výstupním souborům, \PB{\.{BAD\_OPTIONS}} pro
syntaktickou chybu na příkazové řádce a \PB{\.{BAD\_PROGRAM}} pro případ
havárie programu. Ta by neměla nikdy nastat. Proměnná \PB{\\{status}} bude
obsahovat návratový kód a proměnná \PB{\\{prog\_name}} bude ukazovat na text
nultého parametru příkazové řádky.
\Y\B\4\D$\.{OK}$ \5
\T{0}\par
\B\4\D$\.{WARNING}$ \5
\T{1}\par
\B\4\D$\.{IO\_ERR}$ \5
\T{2}\par
\B\4\D$\.{BAD\_OPTIONS}$ \5
\T{3}\par
\B\4\D$\.{BAD\_PROGRAM}$ \5
\T{4}\par
\Y\B\4\X4:Globální deklarace\X${}\E{}$\6
\&{char} ${}{*}\\{prog\_name};{}$\6
\&{int} \\{status};\par
\As7, 15, 16, 20, 25\ETs33.
\U1.\fi

\M{5}Základní rozvržení funkce \PB{\\{main}}.
\Y\B\4\X5:Hlavní program\X${}\E{}$\6
\&{int} ${}\\{main}(\\{argc},\39\\{argv}){}$\1\1\6
\&{int} \\{argc};\6
\&{char} ${}{*}{*}\\{argv};\2\2{}$\6
${}\{{}$\1\6
\X9:Lokální proměnné funkce \PB{\\{main}}\X;\6
${}\\{prog\_name}\K\\{argv}[\T{0}];{}$\6
${}\\{status}\K\.{OK};{}$\6
\X8:Načtení parametrů příkazového řádku\X;\6
\&{if} ${}(\R\\{silent}){}$\1\5
${}\\{fprintf}(\\{stderr},\39\.{BANNER});{}$\2\6
\X21:Inicializace datových struktur\X;\6
\X11:Zpracování souborů\X;\6
\&{return} \\{status};\6
\4${}\}{}$\2\par
\U1.\fi

\N{1}{6}Parametry příkazového řádku.
Program čte z~příkazového řádku postupně (nepovinné) parametry,
které začínají znakem \uv{\.{-}}. Pak následují jména vstupních a výstupních
souborů.
\begitems
* \.{-f} \dots\ program pracuje jako filtr (viz sekce \PB{$\X11:Zpracování
souborů\X$}). Není-li tento parametr použit, program pracuje v tzv.
standardním režimu, kdy jednotlivé soubory jsou vstupní i výstupní.
* \.{-s} \dots\ program nevypíše \PB{\.{BANNER}}, ani sumarizaci, ani varování,
při nichž není program předčasně ukončen.  Všechny tyto výpisy
směřují do \PB{\\{stderr}}, takže pokud program pracuje v režimu \uv{filtr},
není nutné tento parametr použít.
* \.{-r} \dots\ program maže pracovní soubor (soubory), které vytváří
ve standardním režimu (tj. není použit \.{-f}). V reřimu filter nemá
tento parametr vliv.
* \.{-v} \dots\ parametr definuje skupinu písmen, které budou
interpretovány jako neslabičné předložky.
Např. \.{-v KkSsVvZzOoUuAI}. Pokud není parametr uveden, je použita
skupina uvedená v tomto příkladě.
* \.{-m} \dots\ program neprovádí kontrolu math/text módů, tj. vlnkuje i
uvnitř matematického módu \TeX{}u. (Implicite tam nevlnkuje).
* \.{-n} \dots\ prorgram neprovádí kontrolu verbatim módu, tj. vlnkuje i
uvnitř verbatim módu definovaném běžnými prostředími. Imlicite ve
verbatim prostředí nevlnkuje.
* \.{-l} \dots\ La\TeX{} režim. Při kontrole text-math-verbatim módů jsou
brány v úvahu další sekvence, obvyklé v La\TeX{}ových dokumentech.
* \.{-w} \dots\ WEB režim. Ohraničení verbatim módu je doplněno znaky
používanými v dokumentech WEB (např. tento dokument). Důsledek: program
vlnkuje dokumentační část každé sekce, ale nikoli kód.
\enditems

Definujeme funkci \PB{\\{printusage}}, které tiskne (při chybě) stručný přehled
možných parametrů. Nepodařilo se mi zjistit, jak se ve WEBu napíše
kulturně dlouhý string obsahující \.{\char92n} s formátovacími
požadavky. Byl jsem nucen to takto nehezky zapsat.
\Y\B\4\X6:Pomocné funkce\X${}\E{}$\6
\&{void} \\{printusage}(\,)\1\1\2\2\6
${}\{{}$\1\6
${}\\{fprintf}(\\{stderr},\39\.{"usage:\ vlna\ [opt]\ [}\)\.{filenames]\\n"}%
\.{"\ \ opt\ -f\ :\ \ filter\ }\)\.{mode:\ file1\ file2\ ..}\)\.{.\
file1->file2\\n"}\.{"\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ }\)\.{\ \ \ \ \ \
file1\ \ \ \ \ \ \ ..}\)\.{.\ file1->stdout\\n"}\.{"\ \ \ \ \ \ \ \ \ \ \ \ \ \
\ \ \ \ \ }\)\.{\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ ..}\)\.{.\ stdin->stdout%
\\n"}\.{"\ \ \ \ \ \ \ \ \ \ \ \ nofilte}\)\.{r:\ file1\ [file2\ file}\)\.{3\
...]\ all\ are\ in/ou}\)\.{t\\n"}\.{"\ \ \ \ \ \ -s\ :\ \ silent:}\)\.{\ no\
messages\ to\ stde}\)\.{rr\\n"}\.{"\ \ \ \ \ \ -r\ :\ \ rmbacku}\)\.{p:\ if\
nofilter,\ remo}\)\.{ves\ temporary\ files\\}\)\.{n"}\.{"\ \ \ \ \ \ -v\
charset\ :\ }\)\.{\ set\ of\ lettres\ to\ a}\)\.{dd\ tie,\ default:\ KkS}\)%
\.{sVvZzOoUuAI\\n"}\.{"\ \ \ \ \ \ -m\ :\ \ nomath:}\)\.{\ ignores\ math\ modes%
\\}\)\.{n"}\.{"\ \ \ \ \ \ -n\ :\ \ noverb:}\)\.{\ ignores\ verbatim\ mo}\)%
\.{des\\n"}\.{"\ \ \ \ \ \ -l\ :\ \ LaTeX\ m}\)\.{ode\\n"}\.{"\ \ \ \ \ \ -w\ :%
\ \ web\ mod}\)\.{e\\n"});{}$\6
\4${}\}{}$\2\par
\As10, 17, 18, 19, 22, 23, 36, 38, 41, 42, 44, 45, 47, 49, 51, 52, 53\ETs55.
\U1.\fi

\M{7}Proměnné \PB{\\{isfilter}}, \PB{\\{silent}}, \PB{\\{rmbackup}}, \PB{%
\\{nomath}}, \PB{\\{noverb}},
\PB{\\{latex}}, resp. \PB{\\{web}} říkají, že je nastaven parametr \.{-f}, %
\.{-s},
\.{-r}, \.{-m}, \.{-n}, \.{-l}, resp. \.{-w}.  Proměnná \PB{\\{charset}}
ukazuje buď na implicitní skupinu znaků \PB{\\{charsetdefault}}, nebo (při
použití parametru \.{-v}) na text uvedený v příkazovém řádku.
\Y\B\4\X4:Globální deklarace\X${}\mathrel+\E{}$\6
\&{int} \\{isfilter}${}\K\T{0},{}$ \\{silent}${}\K\T{0},{}$ \\{rmbackup}${}\K%
\T{0},{}$ \\{nomath}${}\K\T{0},{}$ \\{noverb}${}\K\T{0},{}$ \\{web}${}\K%
\T{0},{}$ \\{latex}${}\K\T{0};{}$\6
\&{char} \\{charsetdefault}[\,]${}\K\.{"KkSsVvZzOoUuAI"};{}$\6
\&{char} ${}{*}\\{charset}\K\\{charsetdefault}{}$;\par
\fi

\M{8}\B\X8:Načtení parametrů příkazového řádku\X${}\E{}$\6
\&{while} ${}(\\{argc}>\T{1}\W\\{argv}[\T{1}][\T{0}]\E\.{'-'}){}$\5
${}\{{}$\1\6
\&{if} ${}(\\{argv}[\T{1}][\T{2}]\I\T{0}){}$\1\5
${}\\{printusage}(\,),\39\\{exit}(\.{BAD\_OPTIONS});{}$\2\6
\&{switch} (\\{argv}[\T{1}][\T{1}])\5
${}\{{}$\1\6
\4\&{case} \.{'f'}:\5
${}\\{isfilter}\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'s'}:\5
${}\\{silent}\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'r'}:\5
${}\\{rmbackup}\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'v'}:\6
\&{if} ${}(\\{argc}<\T{2}){}$\1\5
${}\\{printusage}(\,),\39\\{exit}(\.{BAD\_OPTIONS});{}$\2\6
${}\\{argv}\PP;{}$\6
${}\\{argc}\MM;{}$\6
${}\\{charset}\K\\{argv}[\T{1}];{}$\6
\&{break};\6
\4\&{case} \.{'m'}:\5
${}\\{nomath}\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'n'}:\5
${}\\{noverb}\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'l'}:\5
${}\\{latex}\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'w'}:\5
${}\\{web}\K\T{1};{}$\6
\&{break};\6
\4\&{default}:\5
${}\\{printusage}(\,),\39\\{exit}(\.{BAD\_OPTIONS}){}$;\C{ nezn\'am\'y parametr
}\6
\4${}\}{}$\2\6
${}\\{argc}\MM;{}$\6
${}\\{argv}\PP;{}$\6
\4${}\}{}$\2\par
\U5.\fi

\N{1}{9}Zpracování souborů.  Parametr \PB{\.{MAXLEN}} definuje maximální možnou
délku jména souboru, který vytvoříme jako přechodný, nebo zálohový.
Dále deklarujeme proměnné typu \uv{stream}.
\Y\B\4\D$\.{MAXLEN}$ \5
\T{120}\par
\Y\B\4\X9:Lokální proměnné funkce \PB{\\{main}}\X${}\E{}$\6
\&{FILE} ${}{*}\\{infile},{}$ ${}{*}\\{outfile};{}$\6
\&{char} \\{backup}[\.{MAXLEN}];\6
\&{int} \|j;\par
\U5.\fi

\M{10}Definujeme funkci pro výpis chybového hlášení při neúspěšném otevření
souboru.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{ioerr}(\|f)\1\1\6
\&{char} ${}{*}\|f;\2\2{}$\6
${}\{{}$\1\6
${}\\{fprintf}(\\{stderr},\39\.{"\%s:\ cannot\ open\ fil}\)\.{e\ \%s\\n"},\39%
\\{prog\_name},\39\|f);{}$\6
\4${}\}{}$\2\par
\fi

\M{11}Způsob zpracování souborů rozlišíme podle režimu daným přepínačem \.{-f}.
\Y\B\4\X11:Zpracování souborů\X${}\E{}$\6
\&{if} (\\{isfilter}) \X12:Zpracování v režimu filter\X\6
\&{else} \X13:Zpracování všech souborů příkazové řádky\X\par
\Q6.
\U5.\fi

\M{12}V režimu \PB{$\\{isfilter}\E\T{1}$} je další zpracování závislé na počtu
souborů v
příkazové řádce:
\begitems
* nula souborů -- vstup je \PB{\\{stdin}} a výstup je \PB{\\{stdout}},
* jeden soubor -- je vstupní, výstup je \PB{\\{stdout}},
* dva soubory -- první je vstupní, druhý výstupní,
* více souborů -- program skončí s chybou.
\enditems
\Y\B\4\X12:Zpracování v režimu filter\X${}\E{}$\6
${}\{{}$\1\6
\&{if} ${}(\\{argc}>\T{3}){}$\1\5
${}\\{printusage}(\,),\39\\{exit}(\.{BAD\_OPTIONS});{}$\2\6
${}\\{infile}\K\\{stdin};{}$\6
${}\\{outfile}\K\\{stdout};{}$\6
\&{if} ${}(\\{argc}\G\T{2}){}$\1\5
${}\\{infile}\K\\{fopen}(\\{argv}[\T{1}],\39\.{"r"});{}$\2\6
\&{if} ${}(\\{infile}\E\NULL){}$\1\5
${}\\{ioerr}(\\{argv}[\T{1}]),\39\\{exit}(\.{IO\_ERR});{}$\2\6
\&{if} ${}(\\{argc}\E\T{3}){}$\1\5
${}\\{outfile}\K\\{fopen}(\\{argv}[\T{2}],\39\.{"w"});{}$\2\6
\&{if} ${}(\\{outfile}\E\NULL){}$\1\5
${}\\{ioerr}(\\{argv}[\T{2}]),\39\\{exit}(\.{IO\_ERR});{}$\2\6
\&{if} ${}(\\{argc}\G\T{2}){}$\1\5
${}\\{filename}\K\\{argv}[\T{1}];{}$\2\6
\&{else}\1\5
${}\\{filename}\K\NULL;{}$\2\6
${}\\{tie}(\\{infile},\39\\{outfile});{}$\6
\&{if} ${}(\\{outfile}\I\\{stdout}){}$\1\5
\\{fclose}(\\{outfile});\2\6
\&{if} ${}(\\{infile}\I\\{stdin}){}$\1\5
\\{fclose}(\\{infile});\2\6
\4${}\}{}$\2\par
\U11.\fi

\M{13}V~režimu \PB{$\\{isfilter}\E\T{0}$} jsou jednotlivé soubory v~příkazovém
řádku
interpretovány jako vstupní i výstupní. Více souborů v~příkazovém řádku má
stejný efekt, jako opakované volání programu na jednotlivé soubory.
V~\UNIX/u lze tedy např. napsat \.{\jobname\ *.tex} a program doplní vlnky do
všech souborů s~příponou~\.{tex}. Toto neplatí v~DOSu, protože interpretace
masky je v~\UNIX/u starostí shellu a nikoli programu samotného. Náš program
masku nebude interpretovat. Je-li v~tomto režimu nulový počet souborů,
program se ukončí s~chybou.
\Y\B\4\X13:Zpracování všech souborů příkazové řádky\X${}\E{}$\6
${}\{{}$\1\6
\&{if} ${}(\\{argc}\E\T{1}){}$\1\5
${}\\{printusage}(\,),\39\\{exit}(\.{BAD\_OPTIONS});{}$\2\6
\&{while} ${}(\\{argc}>\T{1}){}$\5
${}\{{}$\1\6
${}\\{argc}\MM;{}$\6
${}\\{argv}\PP;{}$\6
\X14:Přejmenuj vstup \PB{\\{argv}[\T{0}]} na \PB{\\{backup}} a otevři jej jako %
\PB{\\{infile}}\X;\6
\&{if} ${}(\\{infile}\E\NULL){}$\5
${}\{{}$\1\6
\\{ioerr}(\\{argv}[\T{0}]);\6
\&{continue};\6
\4${}\}{}$\2\6
${}\\{outfile}\K\\{fopen}(\\{argv}[\T{0}],\39\.{"w"});{}$\6
\&{if} ${}(\\{outfile}\E\NULL){}$\5
${}\{{}$\1\6
\\{ioerr}(\\{argv}[\T{0}]);\6
${}\\{rename}(\\{backup},\39\\{argv}[\T{0}]);{}$\6
${}\\{status}\K\.{WARNING};{}$\6
\&{continue};\6
\4${}\}{}$\2\6
${}\\{filename}\K\\{argv}[\T{0}];{}$\6
${}\\{tie}(\\{infile},\39\\{outfile});{}$\6
${}\\{fclose}(\\{outfile}),\39\\{fclose}(\\{infile});{}$\6
\&{if} (\\{rmbackup})\1\5
\\{remove}(\\{backup});\2\6
\4${}\}{}$\2\6
\4${}\}{}$\2\par
\U11.\fi

\M{14}Při \PB{$\\{isfilter}\E\T{0}$} program přejmenuje každý  zpracovávaný
soubor tak, že
změní poslední písmeno názvu souboru na znak \.{\char126}. Tento
přejmenovaný soubor bude otevřen jako vstupní a výstupem bude původní
soubor. Vstupní soubor při \PB{$\\{rmbackup}\E\T{0}$} zůstane zachován jako
záloha.

Proč vlnku nepřidáváme na konec názvu souboru, ale měníme ji za poslední
znak souboru? Protože chceme, aby program fungoval i v tak nemožných
systémech, jako je DOS.
\Y\B\4\X14:Přejmenuj vstup \PB{\\{argv}[\T{0}]} na \PB{\\{backup}} a otevři jej
jako \PB{\\{infile}}\X${}\E{}$\6
$\\{infile}\K\NULL;{}$\6
${}\|j\K\\{strlen}(\\{argv}[\T{0}])-\T{1};{}$\6
\&{if} ${}(\|j\G\.{MAXLEN}\V\\{argv}[\T{0}][\|j]\E\.{'\~'}){}$\5
${}\{{}$\1\6
\&{if} ${}(\R\\{silent}){}$\1\5
${}\\{fprintf}(\\{stderr},\39\.{"\%s:\ the\ conflict\ of}\)\.{\ file\ name\ \%s%
\\n"},\39\\{prog\_name},\39\\{argv}[\T{0}]);{}$\2\6
\4${}\}{}$\2\6
\&{else}\5
${}\{{}$\1\6
${}\\{strcpy}(\\{backup},\39\\{argv}[\T{0}]);{}$\6
${}\\{backup}[\|j]\K\.{'\~'};{}$\6
\\{remove}(\\{backup});\6
${}\|j\K\\{rename}(\\{argv}[\T{0}],\39\\{backup});{}$\6
\&{if} ${}(\|j\E\T{0}){}$\1\5
${}\\{infile}\K\\{fopen}(\\{backup},\39\.{"r"});{}$\2\6
\4${}\}{}$\2\par
\U13.\fi

\N{1}{15}Patterny.  Abychom mohli účelně definovat chování programu
v~různých situacích, zavedeme datovou strukturu \PB{\.{PATTERN}}. Zhruba
řečeno, budeme sledovat vstup znak po znaku a pokud bude část vstupu
souhlasit s~definovaným patternem, provedeme námi požadovanou
akci. Například nejčastější aktivitu, přidání vlnky uvnitř řádku,
spustíme v~okamžiku, kdy vstupní text odpovídá patternu \uv{\.{\ (v\
p}}, kde \uv{\.{\ }} znamená jedna nebo více mezer a tabelátorů,
\uv{\.{(}} je nula nebo více otevíracích závorek všeho druhu,
\uv{\.{v}} znamená jedno písmeno z~množiny předložek (viz \PB{\\{charset}}) a
\uv{\.{p}} zde znamená libovolné písmeno. Příklad zde není zcela přesný.
Přesně jsou všechny patterny pro náš program definovány v~závěrečných
sekcích tohoto povídání.

Pattern bude znamenat konečnou sekvenci tzv. pozic patternu (\PB{\.{PATITEM}}).
Cykly uvnitř pozic pro jednoduchost nepřipustíme. Každá pozice obsahuje
řetězec znaků, uvažovaný pro danou pozici (v~příkladu pozice~\uv{\.{\ }} by
obsahovala mezeru a tabelátor, zatímco pozice \.{v} odpovídá \PB{\\{charset}}).
Každá pozice má svůj přepínač (\PB{\\{flag}}), který obsahuje informaci o~tom,
zda shodu testovaného znaku s~některým prvkem v~množině znaků
budeme považovat za úspěch či neúspěch a zda pozice se ve zkoumaném
řetězci může vyskytovat právě jednou nebo opakovaně. Jako druhý případ
stačí implementovat \uv{nula nebo více} protože \uv{jedna nebo více} lze
popsat pomocí dvou pozic, první \uv{právě jednou} a následující \uv{nula
nebo více}. Jednotlivé pozice jsou zřetězeny ukazatelem \PB{\\{next}}, poslední
pozice má \PB{$\\{next}\E\NULL$}. Stejně tak jednotlivé patterny budeme
sestavovat do seznamů a budou rovněž zřetězeny ukazatelem \PB{\\{next}}.

Pattern kromě řetězu pozic obsahuje ukazatel na funkci (proceduru) \PB{%
\\{proc}},
která se má vykonat v~případě, že testovaný řetězec vyhovuje patternu.

\Y\B\4\D$\.{ONE}$ \5
\T{1}\C{ flag: prave jeden vyskyt }\par
\B\4\D$\.{ANY}$ \5
\T{2}\C{ flag: nula nebo vice }\par
\B\4\D$\.{ONE\_NOT}$ \5
${-}{}$\T{1}\C{ flag: prave jednou, znak nesmi byt v mnozine }\par
\B\4\D$\.{ANY\_NOT}$ \5
${-}{}$\T{2}\C{ flag: nula nebo vice, znak nesmi byt v mnozine }\par
\Y\B\4\X4:Globální deklarace\X${}\mathrel+\E{}$\6
\&{typedef} \&{struct} \&{PATITEM} ${}\{{}$\C{ jedna pozice patternu }\1\6
\&{char} ${}{*}\\{str}{}$;\C{ seznam znaku na teto pozici }\6
\&{int} \\{flag};\C{ vyznam seznamu znaku }\6
\&{struct} \&{PATITEM} ${}{*}\\{next}{}$;\C{ nasledujici pozice patternu }\2\6
${}\}{}$ \&{PATITEM};\6
\&{typedef} \&{struct} \&{PATTERN} ${}\{{}$\C{ jeden pattern }\1\6
\&{PATITEM} ${}{*}\\{patt}{}$;\C{ ukazatel na prvni pozici }\7
${}\&{void}({*}\\{proc})(\,){}$;\C{ procedura spustena pri souhlasu patternu }\7
\&{struct} \&{PATTERN} ${}{*}\\{next}{}$;\C{ nasledujici v seznamu vsech
patternu }\2\6
${}\}{}$ \&{PATTERN};\par
\fi

\M{16}Deklarujeme některé globální proměnné pro práci s~patterny. \PB{\\{lapi}}
je pole
obsahující ukazatele na aktuální pozice v~otevřených patternech. Říkáme,
že \uv{pattern je otevřen}, pokud zkoumaný řetězec s~ním {\it začíná\/}
souhlasit. Pattern se uzavře, pokud nastane jedna ze dvou možností:
zkoumaný řetězec s~mím souhlasí až do konce (v~takovém případě se provede
procedura \PB{\\{proc}}), nebo při vyšetřování dalších znaků ze zkoumaného
řetězce přestane řetězec s~patternem souhlasit.

V~dané chvíli může být pattern otevřen několikrát. Např. pattern \.{abac}
je při stringu \.{aba} při výskytu druhého \.{a} otevřen podruhé. Proto
pole obsahuje ukazatele na právě aktuální pozici patternu a nikoli na
pattern jako takový.

V~poli \PB{\\{lapi}} budou na počátku samá \PB{$\NULL$} (to se při překladu
inicializuje
samo) a přemazání ukazatele na pozici konstantou \PB{$\NULL$} budeme považovat
za zavření patternu. Vedle pole \PB{\\{lapi}} souměrně udržujeme pole \PB{%
\\{lapt}},
do něhož budeme ukládat ukazatele na odpovídající otevřený pattern. Tuto
informaci použijeme v~případě, že potřebujeme např, znát \PB{\\{proc}}
patternu.

\PB{\\{listpatt}} bude ukazovat na začátek aktuálního seznamu patternů. Seznamy
budeme mít dva. Jeden se použije, nacházíme-li se mimo komentář a druhý
v~případě, že se nacházíme v~prostoru \TeX{}ovského komentáře (tj. za
procentem). Starty těchto seznamů patternů jsou \PB{\\{normallist}} a
\PB{\\{commentlist}} a aktivní \PB{\\{listpatt}} má vždy jednu z~těchto dvou
hodnot.

Proměnné \PB{\\{lastpt}} a \PB{\\{lastpi}} použijeme pro budování řetězové
struktury
patternů.

Proměnná \PB{\|c} obsahuje právě testovaný znak ze vstupu (který se rovněž
přepíše do bufferu \PB{\\{buff}}). Z~bufferu občas ukládáme data do výstupního
proudu. Děláme to ale vždy jen v~okamžiku, kdy není otevřen žádný
pattern. Tehdy totiž \uv{nehrozí} situace, že by nějaká procedura vyvolaná
souhlasem patternu požadovala v~tomto bufferu nějaké změny se zpětnou
platností. O~vyprázdnění bufferu se začneme zajímat až v~okamžiku, kdy je
zaplněn aspoň na hodnotu \PB{\.{BUFI}}, abychom proceduru přepisu bufferu do
výstupního proudu neaktivovali zbytečně často.
\Y\B\4\D$\.{MAXPATT}$ \5
\T{200}\C{ maximalni pocet patternu }\par
\B\4\D$\.{MAXBUFF}$ \5
\T{500}\C{ velikost bufferu pro operace }\par
\B\4\D$\.{BUFI}$ \5
\T{300}\C{ velikost stredniho zaplneni }\par
\Y\B\4\X4:Globální deklarace\X${}\mathrel+\E{}$\6
\&{PATITEM} ${}{*}\\{lapi}[\.{MAXPATT}]{}$;\C{ pole ukazatelu na aktualni
pozice }\6
\&{PATTERN} ${}{*}\\{lapt}[\.{MAXPATT}]{}$;\C{ pole odpovidajicich ukazatelu na
patterny }\6
\&{PATTERN} ${}{*}\\{listpatt},{}$ ${}{*}\\{normallist},{}$ ${}{*}%
\\{commentlist},{}$ ${}{*}\\{pt},{}$ ${}{*}\\{lastpt}\K\NULL;{}$\6
\&{PATITEM} ${}{*}\\{pi},{}$ ${}{*}\\{lastpi}\K\NULL;{}$\6
\&{char} \|c;\C{ zrovna nacetny znak }\6
\&{char} \\{buff}[\.{MAXBUFF}];\C{ prechodny buffer }\6
\&{int} \\{ind};\C{ aktualni pozice prechodneho bufferu }\par
\fi

\M{17}Nyní definujeme pomocné funkce \PB{\\{setpattern}}, \PB{\\{setpi}} a \PB{%
\\{normalpattern}}.
Tyto funkce alokují paměť pomocí standardní funkce \PB{\\{malloc}}. Abychom
mohli
ohlídat případnou chybu při alokaci, budeme allokovat paměť zprostředkovaně
pomocí funkce \PB{\\{myalloc}}.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} ${}{*}\\{myalloc}(\\{size}){}$\1\1\6
\&{int} \\{size};\2\2\6
${}\{{}$\1\6
\&{void} ${}{*}\|p;{}$\7
${}\|p\K\\{malloc}(\\{size});{}$\6
\&{if} ${}(\|p\E\NULL){}$\5
${}\{{}$\1\6
${}\\{fprintf}(\\{stderr},\39\.{"\%s,\ no\ memory,\ mall}\)\.{oc\ failed\\n"},%
\39\\{prog\_name});{}$\6
\\{exit}(\.{BAD\_PROGRAM});\6
\4${}\}{}$\2\6
\&{return} \|p;\6
\4${}\}{}$\2\par
\fi

\M{18}Funkce \PB{\\{setpattern}} alokuje paměťové místo struktury \PB{%
\&{PATTERN}} a napojí
ji pomocí proměnné \PB{\\{lastpt}} na už alokovaný řetěz patternů.
Vrátí ukazatel na nově alokované místo. Jednotlivé pozice patternu se musí
následovně alokovat pomocí \PB{\\{setpi}}.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{PATTERN} ${}{*}{}$\\{setpattern}(\\{proc})\6
${}\&{void}({*}\\{proc})(\,);{}$\7
${}\{{}$\1\6
\&{PATTERN} ${}{*}\\{pp};{}$\7
${}\\{pp}\K\\{myalloc}(\&{sizeof}(\&{PATTERN}));{}$\6
${}\\{pp}\MG\\{proc}\K\\{proc};{}$\6
${}\\{pp}\MG\\{next}\K\NULL;{}$\6
${}\\{pp}\MG\\{patt}\K\NULL;{}$\6
\&{if} ${}(\\{lastpt}\I\NULL){}$\1\5
${}\\{lastpt}\MG\\{next}\K\\{pp};{}$\2\6
${}\\{lastpt}\K\\{pp};{}$\6
${}\\{lastpi}\K\NULL;{}$\6
\&{return} \\{pp};\6
\4${}\}{}$\2\par
\fi

\M{19}Funkce \PB{\\{setpi}} alokuje paměťové místo pro jednu pozici patternu.
Provede
zřetězení tak, aby první pozice řetězu pozic byla zaznamenána v položce
\PB{\\{patt}} ve struktuře \PB{\&{PATTERN}} a další byly provázány položkou %
\PB{\\{next}} ve
struktuře \PB{\&{PATITEM}}. Poslední pozice má \PB{$\\{next}\E\NULL$}.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} ${}\\{setpi}(\\{str},\39\\{flag}){}$\1\1\6
\&{char} ${}{*}\\{str};{}$\6
\&{int} \\{flag};\2\2\6
${}\{{}$\1\6
\&{PATITEM} ${}{*}\|p;{}$\7
${}\|p\K\\{myalloc}(\&{sizeof}(\&{PATITEM}));{}$\6
${}\|p\MG\\{str}\K\\{str};{}$\6
${}\|p\MG\\{flag}\K\\{flag};{}$\6
${}\|p\MG\\{next}\K\NULL;{}$\6
\&{if} ${}(\\{lastpi}\E\NULL){}$\1\5
${}\\{lastpt}\MG\\{patt}\K\|p;{}$\2\6
\&{else}\1\5
${}\\{lastpi}\MG\\{next}\K\|p;{}$\2\6
${}\\{lastpi}\K\|p;{}$\6
\4${}\}{}$\2\par
\fi

\M{20}Připravme si půdu pro funkci \PB{\\{normalpattern}}. Tato funkce alokuje
strukturu pro jeden pattern včetně pozic patternu na základě vstupního
stringu. Každá pozice patternu obsahuje v~množině znaků jediný znak a má
\PB{$\\{flag}\K\.{ONE}$}. Znaky ve vstupním stringu odpovídají po řadě
jednotlivým
pozicím. Vytvoří se vlastně jakýsi absolutní pattern, tj. testovaný řetězec
se musí přesně shodovat s~uvedeným stringem. Výjimku tvoří znak \PB{\.{"."}},
který se interpretuje jako nula nebo více mezer. Chceme-li tečku
vnutit do patternu, napíšeme dvě tečky za sebou.

Nejdříve deklarujeme pole všech možných jednopísmenných stringů.
\Y\B\4\X4:Globální deklarace\X${}\mathrel+\E{}$\6
\&{char} \\{strings}[\T{512}];\6
\&{int} \|i;\par
\fi

\M{21}Inicializujeme toto pole (znak, nula, znak, nula, atd...).
\Y\B\4\X21:Inicializace datových struktur\X${}\E{}$\6
\&{for} ${}(\|i\K\T{0};{}$ ${}\|i<\T{256};{}$ ${}\|i\PP){}$\5
${}\{{}$\1\6
${}\\{strings}[\T{2}*\|i]\K{}$(\&{char}) \|i;\6
${}\\{strings}[\T{2}*\|i+\T{1}]\K\T{0};{}$\6
\4${}\}{}$\2\par
\As34, 37, 39, 40, 43, 46, 48, 50\ETs54.
\U5.\fi

\M{22}Definujme funkci \PB{\\{normalpattern}}.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{PATTERN} ${}{*}\\{normalpattern}(\\{proc},\39\\{str}{}$)\6
${}\&{void}({*}\\{proc})(\,);{}$\6
\&{char} ${}{*}\\{str};{}$\7
${}\{{}$\1\6
\&{PATTERN} ${}{*}\\{pp};{}$\6
\&{int} \|j${}\K\T{0};{}$\7
${}\\{pp}\K\\{setpattern}(\\{proc});{}$\6
\&{while} (\\{str}[\|j])\5
${}\{{}$\1\6
\&{if} ${}(\\{str}[\|j]\E\.{'.'}){}$\5
${}\{{}$\1\6
${}\|j\PP;{}$\6
\&{if} ${}(\\{str}[\|j]\I\.{'.'}){}$\5
${}\{{}$\1\6
${}\\{setpi}(\\{blankscr},\39\.{ANY});{}$\6
\&{continue};\6
\4${}\}{}$\2\6
\4${}\}{}$\2\6
${}\\{setpi}({\AND}\\{strings}{}$[(\&{unsigned} \&{char}) \\{str}[\|j]${}*%
\T{2}],\39\.{ONE});{}$\6
${}\|j\PP;{}$\6
\4${}\}{}$\2\6
\&{return} \\{pp};\6
\4${}\}{}$\2\par
\fi

\M{23}Funkce \PB{\\{match}}. Definujeme funkci, která na základě hodnoty znaku %
\PB{\|c}
(proměnná \PB{\|c} je definována jako globální), a pozice patternu \PB{\|p}
(parametr
funkce) vrátí informaci o tom, zda znak souhlasí s patternem. Záporná čísla
\PB{\.{FOUND}}, resp. \PB{\.{NOFOUND}} znamenají, že je třeba uzavřít pattern s
tím, že
vzor odpovídá, resp. neodpovídá patternu. Nezáporné číslo vrátí v případě,
že zkoumaný vstup stále souhlasí s patternem, ale není ještě
rozhodnuto. Velikost návratové hodnoty v takovém případě udává, o kolik
pozic je třeba se posunout v patternu, abychom měli ukazatel na pozici
patternu v souhlase s novou situací, způsobenou znakem \PB{\|c}.

Pokud je \PB{\|c} v množině znaků pro danou pozici \PB{$\|p\MG\\{str}$}, bude %
\PB{$\|m\E\T{1}$}, jinak
je \PB{$\|m\E{-}\T{1}$}. Pokud tímto číslem pronásobíme hodnotu \PB{$\|p\MG%
\\{flag}$}, nemusíme
větvení podle \PB{$\|p\MG\\{flag}$} programovat dvakrát. Hodnoty \PB{\\{flag}}
jsou totiž
symetrické podle nuly, např. \PB{$\.{ANY}\E{-}\.{ANY\_NOT}$}.
\Y\B\4\D$\.{FOUND}$ \5
${-}{}$\T{1}\par
\B\4\D$\.{NOFOUND}$ \5
${-}{}$\T{2}\par
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{int} \\{match}(\|p)\1\1\6
\&{PATITEM} ${}{*}\|p;\2\2{}$\6
${}\{{}$\1\6
\&{int} \|m;\7
\&{if} ${}(\\{strchr}(\|p\MG\\{str},\39\|c)\I\NULL){}$\1\5
${}\|m\K\T{1}{}$;\C{ Znak nalezen }\2\6
\&{else}\1\5
${}\|m\K{-}\T{1}{}$;\C{ Znak nenalezen }\2\6
\&{switch} ${}(\|m*\|p\MG\\{flag}){}$\5
${}\{{}$\1\6
\4\&{case} \.{ANY}:\5
\&{return} \T{0};\C{ Souhas, neni nutny posun }\6
\4\&{case} \.{ONE}:\6
\&{if} ${}(\|p\MG\\{next}\E\NULL){}$\1\5
\&{return} \.{FOUND};\2\6
\&{return} \T{1};\C{ Souhas, nutny posun o 1 }\6
\4\&{case} \.{ONE\_NOT}:\5
\&{return} \.{NOFOUND};\C{ Nesouhlas }\6
\4\&{case} \.{ANY\_NOT}:\5
\X24:Vrať hodnotu podle následující pozice patternu\X;\6
\4${}\}{}$\2\6
\&{return} \T{0};\C{ Tady bychom nikdy nemeli byt, return pro potlaceni
varovani }\6
\4${}\}{}$\2\par
\fi

\M{24}O kolik pozic je třeba se posunout a s jakým výsledkem zjistíme
rekurzivním voláním funkce \PB{\\{match}}.
\Y\B\4\X24:Vrať hodnotu podle následující pozice patternu\X${}\E{}$\6
\&{switch} ${}(\|m\K\\{match}(\|p\MG\\{next})){}$\5
${}\{{}$\1\6
\4\&{case} \.{NOFOUND}:\5
\&{return} \.{NOFOUND};\6
\4\&{case} \.{FOUND}:\5
\&{return} \.{FOUND};\6
\4\&{default}:\5
\&{return} \T{1}${}+\|m;{}$\6
\4${}\}{}$\2\par
\U23.\fi

\N{1}{25}Vlnkovací funkce.
Nejprve připravíme globální deklarace pro \uv{vlnkovací} funkci \PB{\\{tie}}.
Funkce \PB{\\{tie}} \uv{ovlnkuje} vstupní soubor \PB{\\{infile}} a vytvoří
soubor
\PB{\\{outfile}}.  Při \PB{$\\{silent}\K\T{0}$} tiskne závěrečnou zprávu o
zpracování. V této
zprávě se objeví jméno souboru, které se funkce \uv{dozví} prostřednictvím
globální proměnné \PB{\\{filename}}. Proměnná \PB{\\{numline}} počítá řádky,
proměnná
\PB{\\{numchanges}} sčítá změny, tj. počet doplněných vlnek.
Proměnná \PB{\\{mode}} nabývý některé z hodnot \PB{\.{TEXTMODE}}, \PB{%
\.{MATHMODE}},
\PB{\.{DISPLAYMODE}} a \PB{\.{VERBMODE}} podle stavu ve čteném textu.
\Y\B\4\D$\.{TEXTMODE}$ \5
\T{0}\par
\B\4\D$\.{MATHMODE}$ \5
\T{1}\par
\B\4\D$\.{DISPLAYMODE}$ \5
\T{2}\par
\B\4\D$\.{VERBMODE}$ \5
\T{3}\par
\Y\B\4\X4:Globální deklarace\X${}\mathrel+\E{}$\6
\&{char} ${}{*}\\{filename}{}$;\C{ jmeno zpracovavaneho souboru }\6
\&{long} \&{int} \\{numline}${},{}$ \\{numchanges};\C{ pro zaverecnou
statistiku }\6
\&{int} \\{mode};\par
\fi

\M{26}Nyní definujeme vlnkovací funkci \PB{\\{tie}}. Veškerá činnost se opírá o
strukturu patternů. Výhodné je (z důvodu rychlosti) \uv{natvrdo} zde
implementovat jen přepínání mezi stavem čtení z oblasti komentáře
(\PB{$\\{listpatt}\E\\{commentlist}$}) a mimo komentář (\PB{$\\{listpatt}\E%
\\{normallist}$});
\Y\B\4\X26:Vlnkovací funkce \PB{\\{tie}}\X${}\E{}$\6
\&{void} ${}\\{tie}(\\{input},\39\\{output}){}$\1\1\6
\&{FILE} ${}{*}\\{input},{}$ ${}{*}\\{output};\2\2{}$\6
${}\{{}$\1\6
\&{int} \\{ap};\C{ ap je pocet otevrenych patternu }\6
\&{register} \&{int} \|k${},{}$ \|m${},{}$ \|n;\6
\&{int} \\{ic};\6
\&{PATTERN} ${}{*}\\{pp};{}$\6
\&{PATITEM} ${}{*}\\{pi};{}$\7
\X27:Inicializace proměnných při startu funkce \PB{\\{tie}}\X;\6
\&{while} ${}(\R\\{feof}(\\{input})){}$\5
${}\{{}$\1\6
\X30:Otevři nové patterny\X;\6
\&{if} ${}(\\{ap}\E\T{0}\W\\{ind}>\.{BUFI}\W\|c\I\.{'\\\\'}){}$\1\5
\X28:Vyprázdni buffer\X;\2\6
\&{if} ${}(\\{ind}\G\.{MAXBUFF}){}$\5
${}\{{}$\1\6
${}\\{fprintf}(\\{stderr},\39\.{"Operating\ buffer\ ov}\)\.{erflow,\ is\
anything\ }\)\.{wrong?\\n"});{}$\6
\\{exit}(\.{BAD\_PROGRAM});\6
\4${}\}{}$\2\6
\&{if} ${}((\\{ic}\K\\{getc}(\\{input}))\E\.{EOF}{}$)\C{ opravil Cejka Rudolf }%
\1\6
\&{break};\2\6
${}\\{buff}[\\{ind}\PP]\K\|c\K\\{ic};{}$\6
\&{if} ${}(\|c\E\.{'\\n'}){}$\1\5
${}\\{numline}\PP,\39\\{listpatt}\K\\{normallist};{}$\2\6
\&{if} ${}(\|c\E\.{'\%'}\W\\{mode}\I\.{VERBMODE}\W\\{buff}[\\{ind}-\T{2}]\I\.{'%
\\\\'}){}$\1\5
${}\\{listpatt}\K\\{commentlist};{}$\2\6
\X29:Projdi otevřené patterny\X;\6
\4${}\}{}$\2\6
\X28:Vyprázdni buffer\X;\6
\&{if} ${}(\R\\{web}){}$\1\5
\\{checkmode}(\,);\C{ zaverecna kontrola modu }\2\6
\&{if} ${}(\R\\{silent}){}$\1\5
\X32:Tiskni závěrečnou zprávu\X;\2\6
\4${}\}{}$\2\par
\U1.\fi

\M{27}\B\X27:Inicializace proměnných při startu funkce \PB{\\{tie}}\X${}\E{}$\6
\&{for} ${}(\|k\K\T{0};{}$ ${}\|k<\.{MAXPATT};{}$ ${}\|k\PP){}$\1\5
${}\\{lapi}[\|k]\K\NULL;{}$\2\6
${}\|c\K\.{'\\n'};{}$\6
${}\\{buff}[\T{0}]\K\\{mode}\K\\{ap}\K\T{0};{}$\6
${}\\{ind}\K\T{1};{}$\6
${}\\{numline}\K\T{1};{}$\6
${}\\{numchanges}\K\T{0};{}$\6
${}\\{mode}\K\.{TEXTMODE}{}$;\par
\A35.
\U26.\fi

\M{28}Při manipulaci s bufferem byl použit jeden trik. Veškeré načtené znaky
začínají až od \PB{\\{buff}[\T{1}]}, zatímco \PB{\\{buff}[\T{0}]} je rovno
nule. Je to proto, že
některé algoritmy se vrací o jeden znak zpět za svůj pattern, aby zjistily,
zda tam není symbol \uv{\.{\char92}} (například na výskyt sekvence
\.{\char92\char37} je třeba reagovat jinak, než na výskyt obyčejného
procenta). Kdybychm zazačali od \PB{\\{buff}[\T{0}]}, v některých situacích
bychom se ptali, zda \PB{$\\{buff}[{-}\T{1}]\E\.{'\\\\'}$}, tj. sahali bychom
na neošetřené
místo v paměti.
\Y\B\4\X28:Vyprázdni buffer\X${}\E{}$\6
${}\{{}$\1\6
${}\\{buff}[\\{ind}]\K\T{0};{}$\6
${}\\{fputs}({\AND}\\{buff}[\T{1}],\39\\{output});{}$\6
${}\\{ind}\K\T{1};{}$\6
\4${}\}{}$\2\par
\U26.\fi

\M{29}Při procházení otevřenými patterny posunujeme v poli \PB{\\{lapi}} pozice
jednotlivých patternů podle pokynů funkce \PB{\\{match}}, případně pattern
zavřeme
a případně vyvoláme proceduru patternu.

Některé patterny v poli \PB{\\{lapi}} už mohou být zavřeny, takže je nutno s
tímto
polem pracovat jako s jakýmsi děravým sýrem.
\Y\B\4\X29:Projdi otevřené patterny\X${}\E{}$\6
$\|n\K\\{ap};{}$\6
${}\|k\K\T{0};{}$\6
\&{while} (\|n)\5
${}\{{}$\1\6
\&{while} ${}(\\{lapi}[\|k]\E\NULL){}$\1\5
${}\|k\PP{}$;\C{ zastav se na prvnim ukazateli na pattern }\2\6
\&{switch} ${}(\|m\K\\{match}(\\{lapi}[\|k])){}$\5
${}\{{}$\1\6
\4\&{case} \.{FOUND}:\5
${}({*}\\{lapt}[\|k]\MG\\{proc})(\,){}$;\C{ Pattern nalezen, spustit proceduru
}\6
\4\&{case} \.{NOFOUND}:\5
${}\\{lapi}[\|k]\K\NULL{}$;\C{ Deaktivace patternu }\6
${}\\{ap}\MM;{}$\6
\&{break};\6
\4\&{default}:\6
\&{while} ${}(\|m\MM){}$\1\5
${}\\{lapi}[\|k]\K\\{lapi}[\|k]\MG\\{next}{}$;\C{ dalsi pozice patternu }\2\6
\4${}\}{}$\2\6
${}\|k\PP;{}$\6
${}\|n\MM;{}$\6
\4${}\}{}$\2\par
\U26.\fi

\M{30}Při otevírání nových patternů, které nejsou v tuto chvíli zablokovány,
se hned vypořádáme s takovými patterny, které nám dávají rovnou odpověď
typu \PB{\.{FOUND}} nebo \PB{\.{NOFOUND}}. V takových případech ani nezanášíme
ukazatel
na pozici do pole \PB{\\{lapi}}.
\Y\B\4\X30:Otevři nové patterny\X${}\E{}$\6
$\\{pp}\K\\{listpatt};{}$\6
\&{while} ${}(\\{pp}\I\NULL){}$\5
${}\{{}$\1\6
\&{switch} ${}(\|m\K\\{match}(\\{pp}\MG\\{patt})){}$\5
${}\{{}$\1\6
\4\&{case} \.{FOUND}:\5
${}({*}\\{pp}\MG\\{proc})(\,){}$;\C{ spustit proceduru }\6
\4\&{case} \.{NOFOUND}:\5
\&{break};\6
\4\&{default}:\5
\X31:Vytvoř ukazatel na nový pattern a \PB{\&{break}}\X;\6
\4${}\}{}$\2\6
${}\\{pp}\K\\{pp}\MG\\{next};{}$\6
\4${}\}{}$\2\par
\U26.\fi

\M{31}Není-li hned známa odpověď, zda pattern vyhovuje či nikoli,
překontrolujeme nejdříve, zda už není pattern ve stejné pozici otevřený.
Pak najdeme první \uv{díru} v tabulce \PB{\\{lapi}} a tam uhnízdíme nový
ukazatel
na pozici v patternu.
\Y\B\4\X31:Vytvoř ukazatel na nový pattern a \PB{\&{break}}\X${}\E{}$\6
$\\{pi}\K\\{pp}\MG\\{patt};{}$\6
\&{while} ${}(\|m\MM){}$\1\5
${}\\{pi}\K\\{pi}\MG\\{next};{}$\2\6
${}\|n\K\\{ap};{}$\6
${}\|k\K\T{0};{}$\6
\&{while} (\|n)\5
${}\{{}$\1\6
\&{if} ${}(\\{lapi}[\|k]\E\\{pi}){}$\1\5
\&{break};\2\6
\&{if} ${}(\\{lapi}[\|k\PP]\I\NULL){}$\1\5
${}\|n\MM;{}$\2\6
\4${}\}{}$\2\6
\&{if} ${}(\R\|n){}$\5
${}\{{}$\1\6
${}\|k\K\T{0};{}$\6
\&{while} ${}(\\{lapi}[\|k]\I\NULL){}$\1\5
${}\|k\PP;{}$\2\6
\&{if} ${}(\|k\G\.{MAXPATT}){}$\5
${}\{{}$\1\6
${}\\{fprintf}(\\{stderr},\39\.{"I\ cannot\ allocate\ p}\)\.{p,\ is\ anything\
wrong}\)\.{?\\n"});{}$\6
\\{exit}(\.{BAD\_PROGRAM});\6
\4${}\}{}$\2\6
${}\\{lapt}[\|k]\K\\{pp};{}$\6
${}\\{lapi}[\|k]\K\\{pi};{}$\6
${}\\{ap}\PP;{}$\6
\4${}\}{}$\2\par
\U30.\fi

\M{32}Poslední věcí ve funci \PB{\\{tie}} je tisk závěrečné statistiky
zpracování.
\Y\B\4\X32:Tiskni závěrečnou zprávu\X${}\E{}$\6
$\\{fprintf}(\\{stderr},\39\.{"\~\~\~\ file:\ \%s\\t\ \ lin}\)\.{es:\ \%ld,\
changes:\ \%l}\)\.{d\\n"},\39\\{filename},\39\\{numline},\39\\{numchanges}){}$;%
\par
\U26.\fi

\N{1}{33}Inicializace patternů.
Po vytvoření předchozího kódu opírajícího se o~patterny máme nyní v~ruce
poměrně silný nástroj na definování různých činností programu prostým
vytvořením patternu a příslušné jeho procedury. Pokud budeme chtít
v~budoucnu nějaký rys programu přidat, pravděpodobně to bude snadné.

Nejprve deklarujeme některé často používané skupiny znaků v~patternech.

\Y\B\4\X4:Globální deklarace\X${}\mathrel+\E{}$\6
\&{char} \\{tblanks}[\,]${}\K\.{"\ \~\\t"};{}$\6
\&{char} \\{blanks}[\,]${}\K\.{"\ \\t"};{}$\6
\&{char} \\{blankscr}[\,]${}\K\.{"\ \\t\\n"};{}$\6
\&{char} \\{tblankscr}[\,]${}\K\.{"\ \~\\t\\n"};{}$\6
\&{char} \\{nochar}[\,]${}\K\.{"\%\~\\n"};{}$\6
\&{char} \\{cr}[\,]${}\K\.{"\\n"};{}$\6
\&{char} \\{prefixes}[\,]${}\K\.{"[(\{\~"};{}$\6
\&{char} \\{dolar}[\,]${}\K\.{"\$"};{}$\6
\&{char} \\{backslash}[\,]${}\K\.{"\\\\"};{}$\6
\&{char} \\{openbrace}[\,]${}\K\.{"\{"};{}$\6
\&{char} \\{letters}[\,]${}\K\.{"abcdefghijklmnopqrs}\)\.{tuvwxyzABCDEFGHIJKLM}%
\)\.{NOPQRSTUVWXYZ"};{}$\6
\&{PATTERN} ${}{*}\\{vlnkalist},{}$ ${}{*}\\{mathlist},{}$ ${}{*}%
\\{parcheck},{}$ ${}{*}\\{verblist}{}$;\par
\fi

\M{34}Začneme definicí nejčastěji používaného patternu na vlnkování uvnitř
řádku. Připomeňme, že opakované volání funkce \PB{\\{setpattern}} vytváří
interně
seznam patternů, přičemž o~jejich propojení se nemusíme starat. Vyzvedneme
si z~návratového kódu funkce pouze ukazatel na první položku seznamu
\PB{\\{normallist}}. Stejně tak opakované volání funkce \PB{\\{setpi}} vytváří
seznam
pozic pro naposledy deklarovaný pattern.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
$\\{vlnkalist}\K\\{setpattern}(\\{vlnkain});{}$\6
${}\\{setpi}(\\{tblankscr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{tblanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{prefixes},\39\.{ANY});{}$\6
${}\\{setpi}(\\{charset},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{nochar},\39\.{ONE\_NOT}){}$;\par
\fi

\M{35}\B\X27:Inicializace proměnných při startu funkce \PB{\\{tie}}\X${}%
\mathrel+\E{}$\6
$\\{listpatt}\K\\{normallist}\K\\{vlnkalist}{}$;\par
\fi

\M{36}\B\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{vlnkain}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{char} \|p;\7
${}\\{ind}\MM;{}$\6
${}\|p\K\\{buff}[\\{ind}\MM];{}$\6
\&{while} ${}(\\{strchr}(\\{blanks},\39\\{buff}[\\{ind}])\I\NULL){}$\1\5
${}\\{ind}\MM;{}$\2\6
${}\\{ind}\PP;{}$\6
${}\\{buff}[\\{ind}\PP]\K\.{'\~'};{}$\6
${}\\{buff}[\\{ind}\PP]\K\|p;{}$\6
${}\\{numchanges}\PP;{}$\6
\4${}\}{}$\2\par
\fi

\M{37}Podobně pro tvorbu vlnky \uv{přes řádek} vytvoříme pattern a kód
procedury.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
\\{setpattern}(\\{vlnkacr});\6
${}\\{setpi}(\\{tblankscr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{tblanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{prefixes},\39\.{ANY});{}$\6
${}\\{setpi}(\\{charset},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{cr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{nochar},\39\.{ONE\_NOT}){}$;\par
\fi

\M{38}V proceduře k tomuto patternu musíme ošetřit případ typu
\uv{\.{a\char126v\char92np}},
kdy nelze prostě přehodit \uv{\.{\char92n}} za \uv{\.{v}}, protože
bychom roztrhli
mezeru svázanou vlnkou už dříve. Proto musíme vyhledat vhodné místo pro
roztržení řádku, které bude až {\it před\/} znakem \uv{\.{a}}. Při důsledném
ošetření tohoto fenoménu můžeme dokonce narazit na situaci
\uv{\.{\char92n\ v\char126v\char126v\char92np}},  kde nemůžeme vložit
\uv{\.{\char92n}} před první výskyt \uv{\.{v}}, protože bychom dostali
\uv{\.{\char92n\char92n}}, tedy prázdný
řádek. Ten je v \TeX{}u interperetován odlišně. V této výjimečné
situaci pouze zrušíme stávající (v pořadí druhé) \uv{\.{\char92n}} a
nebudeme vytvářet nové. Na výstupu bude soubor o jeden řádek kratší.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{vlnkacr}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{char} \|p;\6
\&{int} \|i${},{}$ \|j;\7
${}\\{ind}\MM;{}$\6
${}\|p\K\\{buff}[\\{ind}\MM];{}$\6
\&{while} ${}(\\{strchr}(\\{blankscr},\39\\{buff}[\\{ind}])\I\NULL){}$\1\5
${}\\{ind}\MM;{}$\2\6
${}\|i\K\\{ind}{}$;\C{ misto predlozky, kterou chceme vazat }\6
\&{while} ${}(\|i\G\T{0}\W(\\{strchr}(\\{blankscr},\39\\{buff}[\|i])\E%
\NULL)){}$\1\5
${}\|i\MM;{}$\2\6
${}\|j\K\|i;{}$\6
\&{while} ${}(\|i\G\T{0}\W(\\{strchr}(\\{blanks},\39\\{buff}[\|i])\I\NULL)){}$%
\1\5
${}\|i\MM;{}$\2\6
\&{if} ${}(\|i\G\T{0}\W\\{buff}[\|i]\E\.{'\\n'}){}$\1\5
${}\|j\K{-}\T{1};{}$\2\6
\&{if} ${}(\|j\G\T{0}){}$\1\5
${}\\{buff}[\|j]\K\.{'\\n'};{}$\2\6
\&{else}\1\5
${}\\{numline}\MM;{}$\2\6
${}\\{ind}\PP;{}$\6
${}\\{buff}[\\{ind}\PP]\K\.{'\~'};{}$\6
${}\\{buff}[\\{ind}\PP]\K\|p;{}$\6
${}\\{numchanges}\PP;{}$\6
\4${}\}{}$\2\par
\fi

\M{39}Nyní vytvoříme patterny pro případy typu \.{\char92uv\char`\{v lese\char`%
\}}.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
\\{setpattern}(\\{vlnkain});\C{ na radku }\6
${}\\{setpi}(\\{tblankscr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{backslash},\39\.{ONE});{}$\6
${}\\{setpi}(\\{letters},\39\.{ONE});{}$\6
${}\\{setpi}(\\{letters},\39\.{ANY});{}$\6
${}\\{setpi}(\\{openbrace},\39\.{ONE});{}$\6
${}\\{setpi}(\\{prefixes},\39\.{ANY});{}$\6
${}\\{setpi}(\\{charset},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{nochar},\39\.{ONE\_NOT});{}$\6
\\{setpattern}(\\{vlnkacr});\C{ pres radek }\6
${}\\{setpi}(\\{tblankscr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{backslash},\39\.{ONE});{}$\6
${}\\{setpi}(\\{letters},\39\.{ONE});{}$\6
${}\\{setpi}(\\{letters},\39\.{ANY});{}$\6
${}\\{setpi}(\\{openbrace},\39\.{ONE});{}$\6
${}\\{setpi}(\\{prefixes},\39\.{ANY});{}$\6
${}\\{setpi}(\\{charset},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{cr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{nochar},\39\.{ONE\_NOT}){}$;\par
\fi

\M{40}Vytvoříme patterny a proceduru pro potlatčení tvorby vlnky u písmen těsně
následujících sekvence \.{\char92TeX} a \.{\char92LaTeX}. Tj. nechceme, aby
např z textu \uv{\.{Vlastnosti~\char92TeX~u~jsou...}} jsme dostali text
s nesprávně vázaným písmenem
\uv{\.{Vlastnosti~\char92TeX~u\char126jsou...}}.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
$\\{normalpattern}(\\{tielock},\39\.{"\\\\TeX"});{}$\6
${}\\{setpi}(\\{blankscr},\39\.{ONE});{}$\6
${}\\{normalpattern}(\\{tielock},\39\.{"\\\\LaTeX"});{}$\6
${}\\{setpi}(\\{blankscr},\39\.{ONE}){}$;\par
\fi

\M{41}Procedura \PB{\\{tielock}} obsahuje nečistý trik. Při provádění procedury
je
právě načten znak z \PB{\\{blankscr}} a je uložen do buff. Testy na otevírání
nových patternů pro tento znak teprve budou následovat a testují se na
hodnotu proměnné \PB{\|c}. Stačí tedy změnit hodnotu \PB{\|c} a vlnkovací
patterny se
neotevřou.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{tielock}(\,)\1\1\2\2\6
${}\{{}$\1\6
${}\|c\K\T{1};{}$\6
\4${}\}{}$\2\par
\fi

\M{42}Ošetříme nyní přechod do/z matematického režimu \TeX{}u. Uvnitř math
módu vlnky neděláme. Při zjištěném nesouladu v přechodech mezi
math-módy spustíme následující proceduru.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{printwarning}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\R\\{silent}){}$\1\5
${}\\{fprintf}(\\{stderr},\39\.{"\~!\~\ warning:\ text/m}\)\.{ath/verb\ mode\
mismat}\)\.{ch,\ \ file:\ \%s,\ \ line}\)\.{:\ \%ld\\n"},\39\\{filename},\39%
\\{numline}-(\|c\E\.{'\\n'}\?\T{1}:\T{0}));{}$\2\6
${}\\{status}\K\.{WARNING};{}$\6
\4${}\}{}$\2\par
\fi

\M{43}Začneme patterny pro přechod do/z matematického režimu, ohraničeného
jedním dolarem, nebo v La\TeX{}u příslušnými sekvencemi.  Sekvence
La\TeX{}u \.{\char92(} a \.{\char92)} nejsou zahrnuty, protože bývají
často předefinovány k jiným užitečnějším věcem.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
\&{if} ${}(\R\\{nomath}){}$\5
${}\{{}$\1\6
${}\\{mathlist}\K\\{setpattern}(\\{onedollar});{}$\6
${}\\{setpi}(\\{dolar},\39\.{ONE});{}$\6
${}\\{setpi}(\\{dolar},\39\.{ONE\_NOT});{}$\6
\&{if} (\\{latex})\5
${}\{{}$\1\6
${}\\{normalpattern}(\\{mathin},\39\.{"\\\\begin.\{math\}"});{}$\6
${}\\{normalpattern}(\\{mathout},\39\.{"\\\\end.\{math\}"});{}$\6
\4${}\}{}$\2\6
\4${}\}{}$\2\par
\fi

\M{44}\B\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{mathin}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{mode}\I\.{TEXTMODE}){}$\1\5
\\{printwarning}(\,);\2\6
${}\\{mode}\K\.{MATHMODE};{}$\6
${}\\{normallist}\K\\{listpatt}\K\\{mathlist};{}$\6
\4${}\}{}$\2\7
\&{void} \\{mathout}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{mode}\I\.{MATHMODE}){}$\1\5
\\{printwarning}(\,);\2\6
${}\\{mode}\K\.{TEXTMODE};{}$\6
${}\\{normallist}\K\\{listpatt}\K\\{vlnkalist};{}$\6
\4${}\}{}$\2\par
\fi

\M{45}Při programování procedury \PB{\\{onedollar}} nesmíme zapomenout na
výskyt
sekvence \.{\char92\$}. V tom případě akci ignorujeme. Podobně u sekvence
\.{\$\$} souhlasí ten druhý dolar s naším patternem, ale to už jsme uvnitř
display módu. V takovém případě také nic neděláme.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{onedollar}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{buff}[\\{ind}-\T{3}]\E\.{'\\\\'}\V(\\{buff}[\\{ind}-\T{3}]\E\.{'%
\$'}\W\\{buff}[\\{ind}-\T{4}]\I\.{'\\\\'})){}$\1\5
\&{return};\2\6
\&{if} ${}(\\{mode}\E\.{DISPLAYMODE}){}$\1\5
\\{printwarning}(\,);\2\6
\&{else}\5
${}\{{}$\1\6
\&{if} ${}(\\{mode}\E\.{TEXTMODE}){}$\1\5
\\{mathin}(\,);\2\6
\&{else}\1\5
\\{mathout}(\,);\2\6
\4${}\}{}$\2\6
\4${}\}{}$\2\par
\fi

\M{46}Pokud najdeme prázdný řádek, překontrolujeme, zda náhodou nejsme v
math-módu. Pokud ano, vypíšeme varování a přejdeme do textového módu.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
$\\{parcheck}\K\\{setpattern}(\\{checkmode});{}$\6
${}\\{setpi}(\\{cr},\39\.{ONE});{}$\6
${}\\{setpi}(\\{blanks},\39\.{ANY});{}$\6
${}\\{setpi}(\\{cr},\39\.{ONE}){}$;\par
\fi

\M{47}\B\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{checkmode}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{mode}\I\.{TEXTMODE}){}$\5
${}\{{}$\1\6
\\{printwarning}(\,);\6
${}\\{mode}\K\.{TEXTMODE};{}$\6
${}\\{normallist}\K\\{listpatt}\K\\{vlnkalist};{}$\6
\4${}\}{}$\2\6
\4${}\}{}$\2\par
\fi

\M{48}Nyní ošetříme výskyt dvou dolarů, tj. vstup do/z display módu.
Rovněž mysleme na La\TeX{}isty a jejich prostředí pro display-mód. Protože
je možná alternativa s hvězdičkou na konci názvu prostředí, raději už
uzavírací závorku do patternu nezahrnujeme.

\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
\&{if} ${}(\R\\{nomath}){}$\5
${}\{{}$\1\6
${}\\{normalpattern}(\\{twodollars},\39\.{"\$\$"});{}$\6
\&{if} (\\{latex})\5
${}\{{}$\1\6
${}\\{normalpattern}(\\{displayin},\39\.{"\\\\begin.\{displaymat}\)\.{h"});{}$\6
${}\\{normalpattern}(\\{displayin},\39\.{"\\\\begin.\{equation"});{}$\6
${}\\{normalpattern}(\\{displayout},\39\.{"\\\\end.\{displaymath"});{}$\6
${}\\{normalpattern}(\\{displayout},\39\.{"\\\\end.\{equation"});{}$\6
\4${}\}{}$\2\6
\4${}\}{}$\2\par
\fi

\M{49}\B\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{displayin}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{mode}\I\.{TEXTMODE}){}$\1\5
\\{printwarning}(\,);\2\6
${}\\{mode}\K\.{DISPLAYMODE};{}$\6
${}\\{normallist}\K\\{listpatt}\K\\{parcheck};{}$\6
\4${}\}{}$\2\7
\&{void} \\{displayout}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{mode}\I\.{DISPLAYMODE}){}$\1\5
\\{printwarning}(\,);\2\6
${}\\{mode}\K\.{TEXTMODE};{}$\6
${}\\{normallist}\K\\{listpatt}\K\\{vlnkalist};{}$\6
\4${}\}{}$\2\7
\&{void} \\{twodollars}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{buff}[\\{ind}-\T{3}]\E\.{'\\\\'}){}$\1\5
\&{return};\2\6
\&{if} ${}(\\{mode}\E\.{DISPLAYMODE}){}$\1\5
\\{displayout}(\,);\2\6
\&{else}\1\5
\\{displayin}(\,);\2\6
\4${}\}{}$\2\par
\fi

\M{50}Následuje ošetření tzv. verbatim módu. Pro plain i La\TeX{} jsou
nejčastější
závorky pro verbatim mod tyto (variantu s \.{\char92begtt} používám
s oblibou já).
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
\&{if} ${}(\R\\{noverb}){}$\5
${}\{{}$\1\6
${}\\{verblist}\K\\{normalpattern}(\\{verbinchar},\39\.{"\\\\verb"});{}$\6
${}\\{setpi}(\\{blankscr},\39\.{ANY});{}$\6
${}\\{setpi}(\\{blankscr},\39\.{ONE\_NOT});{}$\6
${}\\{normalpattern}(\\{verbin},\39\.{"\\\\begtt"});{}$\6
\&{if} (\\{latex})\1\5
${}\\{normalpattern}(\\{verbin},\39\.{"\\\\begin.\{verbatim"});{}$\2\6
\4${}\}{}$\2\6
\&{if} (\\{web})\5
${}\{{}$\1\6
${}\\{normalpattern}(\\{verbin},\39\.{"@<"});{}$\6
${}\\{normalpattern}(\\{verbin},\39\.{"@d"});{}$\6
\4${}\}{}$\2\6
\&{if} ${}(\R\\{noverb}){}$\5
${}\{{}$\1\6
${}\\{verboutlist}[\T{0}]\K\\{setpattern}(\\{verbout});{}$\6
${}\\{setpi}(\\{verbchar},\39\.{ONE});{}$\6
${}\\{verboutlist}[\T{1}]\K\\{normalpattern}(\\{verbout},\39\.{"%
\\\\endtt"});{}$\6
\&{if} (\\{latex})\1\5
${}\\{verboutlist}[\T{2}]\K\\{normalpattern}(\\{verbout},\39\.{"\\\\end%
\{verbatim"});{}$\2\6
\4${}\}{}$\2\6
\&{if} (\\{web})\5
${}\{{}$\1\6
${}\\{verboutlist}[\T{3}]\K\\{normalpattern}(\\{verbout},\39\.{"@\ "});{}$\6
${}\\{normalpattern}(\\{verbout},\39\.{"@*"});{}$\6
${}\\{normalpattern}(\\{verbout},\39\.{"@>|"});{}$\6
\4${}\}{}$\2\par
\fi

\M{51}Procedura \PB{\\{verbinchar}} se od \uv{společné} procedury \PB{%
\\{verbin}} liší v
tom, že zavede do stringu \PB{\\{verbchar}} momentální hodnotu proměnné \PB{%
\|c}.
Proto druhý výskyt této hodnoty verbatim režim ukončí.
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{int} \\{prevmode};\6
\&{PATTERN} ${}{*}\\{prevlist},{}$ ${}{*}\\{verboutlist}[\T{4}];{}$\6
\&{char} \\{verbchar}[\T{2}];\7
\&{void} \\{verbinchar}(\,)\1\1\2\2\6
${}\{{}$\1\6
${}\\{prevmode}\K\\{mode};{}$\6
${}\\{verbchar}[\T{0}]\K\|c;{}$\6
${}\|c\K\T{1};{}$\6
${}\\{listpatt}\K\\{normallist}\K\\{verboutlist}[\T{0}];{}$\6
${}\\{prevlist}\K\\{listpatt}\MG\\{next};{}$\6
${}\\{listpatt}\MG\\{next}\K\NULL;{}$\6
${}\\{mode}\K\.{VERBMODE};{}$\6
\4${}\}{}$\2\par
\fi

\M{52}Při programování \uv{obecné} funkce \PB{\\{verbin}} musíme dbát na to,
aby
zůstal aktivní pouze odpovídající \uv{výstupní} pattern k danému
vstupnímu. Také si zapamatujeme mód, ze kterého jsme do verbatim
oblasti vstoupili, abychom se k němu mohli vrátit (např. uvnitř
math. módu může být
\.{\char92hbox} a v něm lokálně verbatim konstrukce).
\Y\B\4\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{verbin}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{int} \|i;\7
${}\|i\K\T{0};{}$\6
${}\\{prevmode}\K\\{mode};{}$\6
\&{switch} (\|c)\5
${}\{{}$\1\6
\4\&{case} \.{'t'}:\5
${}\|i\K\T{1};{}$\6
\&{break};\6
\4\&{case} \.{'m'}:\5
${}\|i\K\T{2};{}$\6
\&{break};\6
\4\&{case} \.{'<'}:\5
;\6
\4\&{case} \.{'d'}:\5
${}\|i\K\T{3};{}$\6
\&{if} ${}(\\{buff}[\\{ind}-\T{3}]\E\.{'@'}){}$\1\5
\&{return};\C{ dvojity @ ignorovat }\2\6
\&{break};\6
\4${}\}{}$\2\6
${}\\{listpatt}\K\\{normallist}\K\\{verboutlist}[\|i];{}$\6
${}\\{prevlist}\K\\{listpatt}\MG\\{next};{}$\6
\&{if} ${}(\|c\I\.{'<'}\W\|c\I\.{'d'}){}$\1\5
${}\\{listpatt}\MG\\{next}\K\NULL;{}$\2\6
${}\\{mode}\K\.{VERBMODE};{}$\6
\4${}\}{}$\2\par
\fi

\M{53}\B\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{verbout}(\,)\1\1\2\2\6
${}\{{}$\1\6
\&{if} ${}(\\{mode}\I\.{VERBMODE}){}$\1\5
\&{return};\2\6
\&{if} ${}(\\{web}\W\\{buff}[\\{ind}-\T{2}]\E\.{'@'}\W\\{buff}[\\{ind}-\T{3}]\E%
\.{'@'}){}$\1\5
\&{return};\2\6
${}\\{mode}\K\\{prevmode};{}$\6
${}\\{normallist}\MG\\{next}\K\\{prevlist};{}$\6
\&{switch} (\\{mode})\5
${}\{{}$\1\6
\4\&{case} \.{DISPLAYMODE}:\5
${}\\{normallist}\K\\{listpatt}\K\\{parcheck};{}$\6
\&{break};\6
\4\&{case} \.{MATHMODE}:\5
${}\\{normallist}\K\\{listpatt}\K\\{mathlist};{}$\6
\&{break};\6
\4\&{case} \.{TEXTMODE}:\5
${}\\{normallist}\K\\{listpatt}\K\\{vlnkalist};{}$\6
\&{break};\6
\4${}\}{}$\2\6
\4${}\}{}$\2\par
\fi

\M{54}Nyní implementujeme vlastnost dříve používaného programu vlnka, tj. že
lze jeho činnost vypnout a opět zapnout v komentářích. Vytváříme druhý
nezávislý seznam patternů a proto nejprve pronulujeme \PB{\\{lastpt}}.
\Y\B\4\X21:Inicializace datových struktur\X${}\mathrel+\E{}$\6
$\\{lastpt}\K\T{0};{}$\6
${}\\{commentlist}\K\\{normalpattern}(\\{tieoff},\39\.{"\%.\~.-"});{}$\6
${}\\{normalpattern}(\\{tieon},\39\.{"\%.\~.+"}){}$;\par
\fi

\M{55}\B\X6:Pomocné funkce\X${}\mathrel+\E{}$\6
\&{void} \\{tieoff}(\,)\1\1\2\2\6
${}\{{}$\1\6
${}\\{normallist}\K\NULL;{}$\6
\4${}\}{}$\2\7
\&{void} \\{tieon}(\,)\1\1\2\2\6
${}\{{}$\1\6
${}\\{normallist}\K\\{vlnkalist};{}$\6
\4${}\}{}$\2\par
\fi

\M{56}Další plánovaná vylepšení. Program by mohl číst definici svého chování
nejen z~příkazové řádky, ale v~mnohem kompletnější podobě, včetně
uživatelsky definovaných patternů, z komentářové oblasti ve čteném souboru.
Parametry zde uvedené by mohly mít vyšší prioritu, než parametry
z~příkazové řádky a mohl by se třeba rozšiřovat seznam sekvencí, za nimiž
písmena nemají být vázana vlnkou (zatím je implemenováno na pevno jen
\.{\char92TeX} a \.{\char92LaTeX}).

\fi

\N{1}{57}Rejstřík.


\fi


\inx
\fin
\con
