1
2\input csmac % Makra pro �e�tinu
3\pageheight=9.5in \fullpageheight=9.8in  \setpage
4%\nocon % omit table of contents
5\datethis % print date on listing
6
7\def\begitems{\medskip\bgroup\catcode`\*=13 \narrower\narrower}
8\def\enditems{\par\egroup\medskip}
9{\catcode`\*=13 \gdef*{\par\noindent\llap{$\bullet$\ }\ignorespaces}}
10
11
12@* PROGRAM VLNA.
13Program �te vstupn� textov� soubor a nahrazuje za specifikovan�mi
14jednop�smenn�mi slovy (nap�.~v, k, u) mezery symbolem \uv{\.{\char126}}. To
15zabr�n� p�i n�sledn�m zpracov�n� \TeX{}em zlomit ��dek na nevhodn�ch
16m�stech, kter� jsou v rozporu s typografickou normou.
17
18Program sest�v� z t�chto hlavn�ch celk�:
19@c
20@<Hlavi�kov� soubory k na�ten�@>@/
21@<Glob�ln� deklarace@>@/
22@<Pomocn� funkce@>@/
23@<Vlnkovac� funkce |tie|@>@/
24@<Hlavn� program@>
25
26@ Definujeme |BANNER|, co� je text, kter� se objevi p�i startu
27programu a obsahuje ��slo verze programu.
28Zde je n�zorn� vid�t, �e m�ch�n� dvou jazyk� se nevyhneme. P�i tisku
29text� na termin�l nesm�me p�edpokl�dat, �e tam budou �esk� fonty.
30V~t�to dokumentaci se setk�me se t�emi jazyky: angli�tinou (v�t�inou
31v~k�du programu, cestinou v~/* koment���ch */ a �e�tinou jinde.
32Tu cestinu si vynutil fakt, �e DOS-ovsk� varianta \.{tangle} a
33\.{weave} se nesn�� s~akcentovan�mi p�smeny v~/* koment���ch */.
34A~nyn� u� sl�ben� (v�cejazy�n�) |BANNER|.
35@d BANNER "This is program vlna, version 1.5, (c) 1995, 2002, 2009, 2010 Petr Olsak\n"
36
37@ V programu jsou pou�ity knihovn� funkce, jej�ch� prototypy jsou
38definov�ny ve t�ech standardn�ch hlavi�kov�ch souborech.
39@<Hlavi�kov� ...@>=
40#include <stdio.h>
41#include <string.h>
42#include <stdlib.h>
43
44@ Definujeme konstanty pro n�vratov� k�d. |OK| pro �sp�n� b�h,
45|WARNING| p�i v�skytu aspo� jedn� varovn� zpr�vy, |IO_ERR| pro chybu
46v~p��stupu ke vtupn�m nebo v�stupn�m soubor�m, |BAD_OPTIONS| pro
47syntaktickou chybu na p��kazov� ��dce a |BAD_PROGRAM| pro p��pad
48hav�rie programu. Ta by nem�la nikdy nastat. Prom�nn� |status| bude
49obsahovat n�vratov� k�d a prom�nn� |prog_name| bude ukazovat na text
50nult�ho parametru p��kazov� ��dky.
51@d OK 0
52@d WARNING 1
53@d IO_ERR 2
54@d BAD_OPTIONS 3
55@d BAD_PROGRAM 4
56@<Glob�ln� deklarace@>=
57char *prog_name;
58int status;
59
60@ Z�kladn� rozvr�en� funkce |main|.
61@<Hlavn� program@>=
62int main (int argc, char **argv)
63{
64  @<Lok�ln� prom�nn� funkce |main|@>;
65  prog_name=argv[0]; status = OK;
66  @<Na�ten� parametr� p��kazov�ho ��dku@>;
67  if (!silent) fprintf (stderr, BANNER);
68  @<Inicializace datov�ch struktur@>;
69  @<Zpracov�n� soubor�@>;
70  return status;
71}
72
73@* Parametry p��kazov�ho ��dku.
74Program �te z~p��kazov�ho ��dku postupn� (nepovinn�) parametry,
75kter� za��naj� znakem \uv{\.{-}}. Pak n�sleduj� jm�na vstupn�ch a v�stupn�ch
76soubor�.
77\begitems
78* \.{-f} \dots\ program pracuje jako filtr (viz sekce |@<Zpracov�n�
79  soubor�@>|). Nen�-li tento parametr pou�it, program pracuje v tzv.
80  standardn�m re�imu, kdy jednotliv� soubory jsou vstupn� i v�stupn�.
81* \.{-s} \dots\ program nevyp�e |BANNER|, ani sumarizaci, ani varov�n�,
82  p�i nich� nen� program p�ed�asn� ukon�en.  V�echny tyto v�pisy
83  sm��uj� do |stderr|, tak�e pokud program pracuje v re�imu \uv{filtr},
84  nen� nutn� tento parametr pou��t.
85* \.{-r} \dots\ program ma�e pracovn� soubor (soubory), kter� vytv���
86  ve standardn�m re�imu (tj. nen� pou�it \.{-f}). V re�imu filter nem�
87  tento parametr vliv.
88* \.{-v} \dots\ parametr definuje skupinu p�smen, kter� budou
89  interpretov�ny jako neslabi�n� p�edlo�ky.
90  Nap�. \.{-v KkSsVvZzOoUuAI}. Pokud nen� parametr uveden, je pou�ita
91  skupina uveden� v tomto p��klad�.
92* \.{-x} \dots\ parametr vymezuje pomoc� hexadecim�ln�ho z�pisu string,
93  kter� program vkl�d� na vyhledan� m�sta. Implicitn� vkl�d� vlnku.
94  Nap��klad \.{-x C2A0} zp�sob�, �e program bude vkl�dat m�sto vlnky dva byty,
95  prvn� s k�dem \.{C2} a druh� s k�dem \.{A0}.
96* \.{-m} \dots\ program neprov�d� kontrolu math/text m�d�, tj. vlnkuje i
97  uvnit� matematick�ho m�du \TeX{}u. (Implicite tam nevlnkuje).
98* \.{-n} \dots\ prorgram neprov�d� kontrolu verbatim m�du, tj. vlnkuje i
99  uvnit� verbatim m�du definovan�m b�n�mi prost�ed�mi. Imlicite ve
100  verbatim prost�ed� nevlnkuje.
101* \.{-l} \dots\ La\TeX{} re�im. P�i kontrole text-math-verbatim m�d� jsou
102  br�ny v �vahu dal�� sekvence, obvykl� v La\TeX{}ov�ch dokumentech.
103* \.{-w} \dots\ WEB re�im. Ohrani�en� verbatim m�du je dopln�no znaky
104  pou��van�mi v dokumentech WEB (nap�. tento dokument). D�sledek: program
105  vlnkuje dokumenta�n� ��st ka�d� sekce, ale nikoli k�d.
106\enditems
107
108Definujeme funkci |printusage|, kter� tiskne (p�i chyb�) stru�n� p�ehled
109mo�n�ch parametr�. Nepoda�ilo se mi zjistit, jak se ve WEBu nap�e
110kulturn� dlouh� string obsahuj�c� \.{\char92n} s form�tovac�mi
111po�adavky. Byl jsem nucen to takto nehezky zapsat.
112@<Pomocn� funkce@>=
113static void printusage (void)
114{
115  fprintf(stderr,
116    "usage: vlna [opt] [filenames]\n"
117    "  opt -f :  filter mode: file1 file2 ... file1->file2\n"
118    "                         file1       ... file1->stdout\n"
119    "                                     ... stdin->stdout\n"
120    "            nofilter: file1 [file2 file3 ...] all are in/out\n"
121    "      -s :  silent: no messages to stderr\n"
122    "      -r :  rmbackup: if nofilter, removes temporary files\n"
123    "      -v charset :  set of lettres to add tie, default: KkSsVvZzOoUuAI\n"
124    "      -x code : code for tie symbol, default: 7E, example -x C2A0\n"
125    "      -m :  nomath: ignores math modes\n"
126    "      -n :  noverb: ignores verbatim modes\n"
127    "      -l :  LaTeX mode\n"
128    "      -w :  web mode\n");
129}
130
131@ Prom�nn� |isfilter|, |silent|, |rmbackup|, |nomath|, |noverb|,
132|latex|, resp. |web| ��kaj�, �e je nastaven parametr \.{-f}, \.{-s},
133\.{-r}, \.{-m}, \.{-n}, \.{-l}, resp. \.{-w}.  Prom�nn� |charset|
134ukazuje bu� na implicitn� skupinu znak� |charsetdefault|, nebo (p�i
135pou�it� parametru \.{-v}) na text uveden� v p��kazov�m ��dku.
136@<Glob�ln� deklarace@>=
137int isfilter=0, silent=0, rmbackup=0, nomath=0, noverb=0, web=0, latex=0;
138char charsetdefault[]="KkSsVvZzOoUuAI";
139char *charset=charsetdefault;
140
141@ String |tiestr| obsahuje string, kter�m se m� nahradit vyhledan�
142m�sto. Pokud nen� pou�it parametr \.{-u}, je tento string jadnoznakov�
143a obsahuje vlnku. Jinak obsahuje string konvertovan� z parametru \.{-u}.
144String m� d�lku |tiestrlen| bez ohledu na to, zda obsahuje nebo
145neobsahuje nulov� znaky (C-�kov� konvence pro stringy nen� pou�ita).
146@<Glob�ln� deklarace@>=
147unsigned char tiestr[MAXLEN];
148int tiestrlen;
149
150@ @<Na�ten� parametr� ...@>=
151tiestr[0] = '~';
152tiestrlen = 1;
153while (argc>1 && argv[1][0] == '-') {
154  if (argv[1][2] != 0) printusage (), exit (BAD_OPTIONS);
155  switch(argv[1][1]) {
156  case 'f': isfilter = 1; break;
157  case 's': silent = 1; break;
158  case 'r': rmbackup = 1; break;
159  case 'v': if (argc<2) printusage (), exit (BAD_OPTIONS);
160    argv++; argc--; charset = argv[1]; break;
161  case 'x': if (argc<2) printusage (), exit (BAD_OPTIONS);
162    argv++; argc--; settiestr(argv[1]); break;
163  case 'm': nomath = 1; break;
164  case 'n': noverb = 1; break;
165  case 'l': latex = 1; break;
166  case 'w': web = 1; break;
167  default: printusage (), exit (BAD_OPTIONS);
168          /* nezn\'am\'y parametr */
169  }
170  argc--; argv++;
171}
172
173@ Vy�e��me konverzi k�du zapsan�ho za parametrem \.{-x} na string |tiestr|.
174@<Pomocn� funkce@>=
175static unsigned char hexnum(char c) {
176  if (c >= '0' && c <= '9') return c - '0';
177  if (c >= 'A' && c <= 'F') return c - 'A' + 10;
178  if (c >= 'a' && c <= 'f') return c - 'a' + 10;
179  printusage (), exit (BAD_OPTIONS);
180}
181static void settiestr(char *s) {
182  int i, j;
183  i = strlen(s);
184  if ((i > 2*MAXLEN) || i%2 == 1) printusage (), exit (BAD_OPTIONS);
185  tiestrlen = i/2;
186  j = 0;
187  for (i=0; i<tiestrlen; i++) {
188     tiestr[i] = hexnum(s[j++]) << 4;
189     tiestr[i] += hexnum(s[j++]);
190  }
191}
192
193@* Zpracov�n� soubor�.  Parametr |MAXLEN| definuje maxim�ln� mo�nou
194d�lku jm�na souboru, kter� vytvo��me jako p�echodn�, nebo z�lohov�.
195D�le deklarujeme prom�nn� typu \uv{stream}.
196@d MAXLEN 120
197@<Lok�ln� prom�nn� funkce...@>=
198FILE *infile, *outfile;
199char backup[MAXLEN];
200int j;
201
202@ Definujeme funkci pro v�pis chybov�ho hl�en� p�i ne�sp�n�m otev�en�
203souboru.
204@<Pomocn� funkce@>=
205static void ioerr (char *f)
206{
207   fprintf(stderr, "%s: cannot open file %s\n", prog_name, f);
208}
209
210@ Zp�sob zpracov�n� soubor� rozli��me podle re�imu dan�m p�ep�na�em \.{-f}.
211@<Zpracov�n� soubor�@>=
212if (isfilter)  @<Zpracov�n� v re�imu filter@> @/
213else   @<Zpracov�n� v�ech soubor� p��kazov� ��dky@>
214
215@ V re�imu |isfilter==1| je dal�� zpracov�n� z�visl� na po�tu soubor� v
216p��kazov� ��dce:
217\begitems
218* nula soubor� -- vstup je |stdin| a v�stup je |stdout|,
219* jeden soubor -- je vstupn�, v�stup je |stdout|,
220* dva soubory -- prvn� je vstupn�, druh� v�stupn�,
221* v�ce soubor� -- program skon�� s chybou.
222\enditems
223@<Zpracov�n� v re�imu filter@>=
224{
225  if (argc > 3) printusage (), exit (BAD_OPTIONS) ;
226  infile = stdin; outfile = stdout;
227  if (argc >= 2) infile = fopen (argv[1], "r");
228  if (infile == NULL)  ioerr (argv[1]), exit (IO_ERR);
229  if (argc == 3) outfile = fopen(argv[2], "wb");
230  if (outfile == NULL) ioerr (argv[2]), exit (IO_ERR);
231  if (argc >= 2) filename = argv[1];
232  else filename = NULL;
233  tie (infile, outfile);
234  if (outfile != stdout) fclose (outfile);
235  if (infile != stdin) fclose (infile);
236}
237
238@ V~re�imu |isfilter==0| jsou jednotliv� soubory v~p��kazov�m ��dku
239interpretov�ny jako vstupn� i v�stupn�. V�ce soubor� v~p��kazov�m ��dku m�
240stejn� efekt, jako opakovan� vol�n� programu na jednotliv� soubory.
241V~\UNIX/u lze tedy nap�. napsat \.{\jobname\ *.tex} a program dopln� vlnky do
242v�ech soubor� s~p��ponou~\.{tex}. Toto neplat� v~DOSu, proto�e interpretace
243masky je v~\UNIX/u starost� shellu a nikoli programu samotn�ho. N� program
244masku nebude interpretovat. Je-li v~tomto re�imu nulov� po�et soubor�,
245program se ukon�� s~chybou.
246@<Zpracov�n� v�ech soubor� p��kazov� ��dky@>=
247{
248  if (argc==1) printusage (), exit(BAD_OPTIONS);
249  while (argc>1) {
250     argc--; argv++;
251     @<P�ejmenuj vstup |argv[0]| na |backup| a otev�i jej jako |infile|@>;
252     if (infile == NULL) {
253       ioerr (argv[0]); continue;
254     }
255     outfile = fopen (argv[0], "wb");
256     if (outfile == NULL) {
257       ioerr (argv[0]);
258       rename (backup, argv[0]);
259       status = WARNING;
260       continue;
261     }
262     filename = argv[0];
263     tie (infile, outfile);
264     fclose (outfile), fclose (infile);
265     if (rmbackup) remove (backup);
266   }
267}
268
269@ P�i |isfilter==0| program p�ejmenuje ka�d�  zpracov�van� soubor tak, �e
270zm�n� posledn� p�smeno n�zvu souboru na znak \.{\char126}. Tento
271p�ejmenovan� soubor bude otev�en jako vstupn� a v�stupem bude p�vodn�
272soubor. Vstupn� soubor p�i |rmbackup==0| z�stane zachov�n jako z�loha.
273
274Pro� vlnku nep�id�v�me na konec n�zvu souboru, ale m�n�me ji za posledn�
275znak souboru? Proto�e chceme, aby program fungoval i v tak nemo�n�ch
276syst�mech, jako je DOS.
277@<P�ejmenuj vstup...@>=
278infile = NULL;
279j = strlen (argv[0]) - 1;
280if (j >= MAXLEN || argv[0][j] == '~') {
281   if (!silent) fprintf (stderr, "%s: the conflict of file name %s\n",
282      prog_name, argv[0]);
283}
284else {
285  strcpy (backup, argv[0]);
286  backup[j] = '~';
287  remove (backup);
288  j = rename (argv[0], backup);
289  if (j == 0) infile = fopen (backup, "r");
290}
291
292@* Patterny.  Abychom mohli ��eln� definovat chov�n� programu
293v~r�zn�ch situac�ch, zavedeme datovou strukturu |PATTERN|. Zhruba
294�e�eno, budeme sledovat vstup znak po znaku a pokud bude ��st vstupu
295souhlasit s~definovan�m patternem, provedeme n�mi po�adovanou
296akci. Nap��klad nej�ast�j�� aktivitu, p�id�n� vlnky uvnit� ��dku,
297spust�me v~okam�iku, kdy vstupn� text odpov�d� patternu \uv{\.{\ (v\
298p}}, kde \uv{\.{\ }} znamen� jedna nebo v�ce mezer a tabel�tor�,
299\uv{\.{(}} je nula nebo v�ce otev�rac�ch z�vorek v�eho druhu,
300\uv{\.{v}} znamen� jedno p�smeno z~mno�iny p�edlo�ek (viz |charset|) a
301\uv{\.{p}} zde znamen� libovoln� p�smeno. P��klad zde nen� zcela p�esn�.
302P�esn� jsou v�echny patterny pro n� program definov�ny v~z�v�re�n�ch
303sekc�ch tohoto pov�d�n�.
304
305Pattern bude znamenat kone�nou sekvenci tzv. pozic patternu (|PATITEM|).
306Cykly uvnit� pozic pro jednoduchost nep�ipust�me. Ka�d� pozice obsahuje
307�et�zec znak�, uva�ovan� pro danou pozici (v~p��kladu pozice~\uv{\.{\ }} by
308obsahovala mezeru a tabel�tor, zat�mco pozice \.{v} odpov�d� |charset|).
309Ka�d� pozice m� sv�j p�ep�na� (|flag|), kter� obsahuje informaci o~tom,
310zda shodu testovan�ho znaku s~n�kter�m prvkem v~mno�in� znak�
311budeme pova�ovat za �sp�ch �i ne�sp�ch a zda pozice se ve zkouman�m
312�et�zci m��e vyskytovat pr�v� jednou nebo opakovan�. Jako druh� p��pad
313sta�� implementovat \uv{nula nebo v�ce} proto�e \uv{jedna nebo v�ce} lze
314popsat pomoc� dvou pozic, prvn� \uv{pr�v� jednou} a n�sleduj�c� \uv{nula
315nebo v�ce}. Jednotliv� pozice jsou z�et�zeny ukazatelem |next|, posledn�
316pozice m� |next==NULL|. Stejn� tak jednotliv� patterny budeme
317sestavovat do seznam� a budou rovn� z�et�zeny ukazatelem |next|.
318
319Pattern krom� �et�zu pozic obsahuje ukazatel na funkci (proceduru) |proc|,
320kter� se m� vykonat v~p��pad�, �e testovan� �et�zec vyhovuje patternu.
321
322@d ONE      1        /* flag: prave jeden vyskyt */
323@d ANY      2        /* flag: nula nebo vice */
324@d ONE_NOT -1        /* flag: prave jednou, znak nesmi byt v mnozine */
325@d ANY_NOT -2        /* flag: nula nebo vice, znak nesmi byt v mnozine */
326
327@<Glob�ln� deklarace@>=
328typedef struct PATITEM {     /* jedna pozice patternu */
329   char *str;                /* seznam znaku na teto pozici */
330   int flag;                 /* vyznam seznamu znaku */
331   struct PATITEM *next ;    /* nasledujici pozice patternu */
332} PATITEM;
333typedef struct PATTERN {     /* jeden pattern */
334   PATITEM *patt;            /* ukazatel na prvni pozici */
335   void (*proc)(void);       /* procedura spustena pri souhlasu patternu */
336   struct PATTERN *next ;    /* nasledujici v seznamu vsech patternu */
337} PATTERN;
338
339@ Deklarujeme n�kter� glob�ln� prom�nn� pro pr�ci s~patterny. |lapi| je pole
340obsahuj�c� ukazatele na aktu�ln� pozice v~otev�en�ch patternech. ��k�me,
341�e \uv{pattern je otev�en}, pokud zkouman� �et�zec s~n�m {\it za��n�\/}
342souhlasit. Pattern se uzav�e, pokud nastane jedna ze dvou mo�nost�:
343zkouman� �et�zec s~m�m souhlas� a� do konce (v~takov�m p��pad� se provede
344procedura |proc|), nebo p�i vy�et�ov�n� dal��ch znak� ze zkouman�ho
345�et�zce p�estane �et�zec s~patternem souhlasit.
346
347V~dan� chv�li m��e b�t pattern otev�en n�kolikr�t. Nap�. pattern \.{abac}
348je p�i stringu \.{aba} p�i v�skytu druh�ho \.{a} otev�en podruh�. Proto
349pole obsahuje ukazatele na pr�v� aktu�ln� pozici patternu a nikoli na
350pattern jako takov�.
351
352V~poli |lapi| budou na po��tku sam� |NULL| (to se p�i p�ekladu inicializuje
353samo) a p�emaz�n� ukazatele na pozici konstantou |NULL| budeme pova�ovat
354za zav�en� patternu. Vedle pole |lapi| soum�rn� udr�ujeme pole |lapt|,
355do n�ho� budeme ukl�dat ukazatele na odpov�daj�c� otev�en� pattern. Tuto
356informaci pou�ijeme v~p��pad�, �e pot�ebujeme nap�, zn�t |proc|
357patternu.
358
359|listpatt| bude ukazovat na za��tek aktu�ln�ho seznamu pattern�. Seznamy
360budeme m�t dva. Jeden se pou�ije, nach�z�me-li se mimo koment�� a druh�
361v~p��pad�, �e se nach�z�me v~prostoru \TeX{}ovsk�ho koment��e (tj. za
362procentem). Starty t�chto seznam� pattern� jsou |normallist| a
363|commentlist| a aktivn� |listpatt| m� v�dy jednu z~t�chto dvou hodnot.
364
365Prom�nn� |lastpt| a |lastpi| pou�ijeme pro budov�n� �et�zov� struktury
366pattern�.
367
368Prom�nn� |c| obsahuje pr�v� testovan� znak ze vstupu (kter� se rovn�
369p�ep�e do bufferu |buff|). Z~bufferu ob�as ukl�d�me data do v�stupn�ho
370proudu. D�l�me to ale v�dy jen v~okam�iku, kdy nen� otev�en ��dn�
371pattern. Tehdy toti� \uv{nehroz�} situace, �e by n�jak� procedura vyvolan�
372souhlasem patternu po�adovala v~tomto bufferu n�jak� zm�ny se zp�tnou
373platnost�. O~vypr�zdn�n� bufferu se za�neme zaj�mat a� v~okam�iku, kdy je
374zapln�n aspo� na hodnotu |BUFI|, abychom proceduru p�episu bufferu do
375v�stupn�ho proudu neaktivovali zbyte�n� �asto.
376@d MAXPATT 200       /* maximalni pocet patternu */
377@d MAXBUFF 500      /* velikost bufferu pro operace */
378@d BUFI 300         /* velikost stredniho zaplneni */
379@<Glob�ln� deklarace@>=
380PATITEM *lapi[MAXPATT];      /* pole ukazatelu na aktualni pozice */
381PATTERN *lapt[MAXPATT];      /* pole odpovidajicich ukazatelu na patterny */
382PATTERN *listpatt, *normallist, *commentlist, *pt, *lastpt=NULL;
383PATITEM *lastpi=NULL;
384char c;             /* zrovna nacetny znak */
385char buff[MAXBUFF]; /* prechodny buffer */
386int ind;            /* aktualni pozice prechodneho bufferu */
387
388@ Dne 30. 4. 2009 jsem p�idal mo�nost �ten� vstupu, kter� obsahuje nulov� byty.
389Takov� nuly se p�episuj� do v�stupu, ale program si jich nev��m� p�i
390proch�zen� pattern�. T�m je mo�no program pou��t na soubory k�dovan�
391v UTF16, a�koli patterny obsahuj� jen jednobytov� ASCII znaky.
392Buffer |buff| m��e obsahovat i nulov� byty, kter� je t�eba p�epsat do v�stupu.
393Na druh� stran� buffer |buffnz| obsahuje jen nenulov� byty, na kter� se
394n�kdy pt�me p�i pohledu dozadu. Nejdel�� pohled dozadu je o �ty�i byty.
395Ud�l�m tedy |buffnz| osmibytov�, za�nu jej plnit od |buffnz|[4]
396a kdykoli je buffer zcela zapln�n, p�esunu horn� �ty�i byty na spodn� a d�le
397pokra�uji v pln�n� bufferu od pozice |buffnz|[4].
398@<Glob�ln� deklarace@>=
399char buffnz[8];
400int inz;
401
402@ Nyn� definujeme pomocn� funkce |setpattern|, |setpi| a |normalpattern|.
403Tyto funkce alokuj� pam� pomoc� standardn� funkce |malloc|. Abychom mohli
404ohl�dat p��padnou chybu p�i alokaci, budeme allokovat pam� zprost�edkovan�
405pomoc� funkce |myalloc|.
406@<Pomocn� funkce@>=
407static void *myalloc (int size)
408{
409  void *p;
410  p = malloc (size);
411  if (p == NULL)
412  {
413    fprintf (stderr, "%s, no memory, malloc failed\n", prog_name);
414    exit (BAD_PROGRAM) ;
415  }
416  return p;
417}
418
419@ Funkce |setpattern| alokuje pam�ov� m�sto struktury |PATTERN| a napoj�
420ji pomoc� prom�nn� |lastpt| na u� alokovan� �et�z pattern�.
421Vr�t� ukazatel na nov� alokovan� m�sto. Jednotliv� pozice patternu se mus�
422n�sledovn� alokovat pomoc� |setpi|.
423@<Pomocn� funkce@>=
424static PATTERN *setpattern (void (*proc)(void))
425{
426  PATTERN *pp;
427  pp = myalloc (sizeof (PATTERN));
428  pp->proc = proc;
429  pp->next = NULL;
430  pp->patt = NULL;
431  if (lastpt != NULL) lastpt->next = pp;
432  lastpt = pp;
433  lastpi = NULL;
434  return pp;
435}
436
437@ Funkce |setpi| alokuje pam�ov� m�sto pro jednu pozici patternu. Provede
438z�et�zen� tak, aby prvn� pozice �et�zu pozic byla zaznamen�na v polo�ce
439|patt| ve struktu�e |PATTERN| a dal�� byly prov�z�ny polo�kou |next| ve
440struktu�e |PATITEM|. Posledn� pozice m� |next==NULL|.
441@<Pomocn� funkce@>=
442static void setpi (char *str, int flag)
443{
444  PATITEM* p;
445  p = myalloc (sizeof (PATITEM));
446  p->str = str; p->flag = flag;
447  p->next = NULL;
448  if (lastpi == NULL) lastpt->patt = p;
449  else lastpi->next = p;
450  lastpi = p;
451}
452
453@ P�ipravme si p�du pro funkci |normalpattern|. Tato funkce alokuje
454strukturu pro jeden pattern v�etn� pozic patternu na z�klad� vstupn�ho
455stringu. Ka�d� pozice patternu obsahuje v~mno�in� znak� jedin� znak a m�
456|flag=ONE|. Znaky ve vstupn�m stringu odpov�daj� po �ad� jednotliv�m
457pozic�m. Vytvo�� se vlastn� jak�si absolutn� pattern, tj. testovan� �et�zec
458se mus� p�esn� shodovat s~uveden�m stringem. V�jimku tvo�� znak |"."|,
459kter� se interpretuje jako nula nebo v�ce mezer. Chceme-li te�ku
460vnutit do patternu, nap�eme dv� te�ky za sebou.
461
462Nejd��ve deklarujeme pole v�ech mo�n�ch jednop�smenn�ch string�.
463@<Glob�ln� deklarace@>=
464char strings[512];
465int i;
466
467@ Inicializujeme toto pole (znak, nula, znak, nula, atd...).
468@<Inicializace datov�ch struktur@>=
469for (i=0; i<256; i++) {
470  strings[2*i] = (char) i; strings[2*i+1] = 0;
471}
472
473@ Definujme funkci |normalpattern|.
474@<Pomocn� funkce@>=
475static PATTERN *normalpattern (void (*proc)(void), const char *str)
476{
477  PATTERN *pp;
478  int j=0;
479  pp = setpattern (proc);
480  while (str[j]) {
481    if (str[j]=='.') {
482      j++;
483      if (str[j]!='.') {
484        setpi (blankscr, ANY);
485        continue;
486      }
487    }
488    setpi (&strings[(unsigned char)str[j]*2], ONE);
489    j++;
490  }
491  return pp;
492}
493
494@ Funkce |match|. Definujeme funkci, kter� na z�klad� hodnoty znaku |c|
495(prom�nn� |c| je definov�na jako glob�ln�), a pozice patternu |p| (parametr
496funkce) vr�t� informaci o tom, zda znak souhlas� s patternem. Z�porn� ��sla
497|FOUND|, resp. |NOFOUND| znamenaj�, �e je t�eba uzav��t pattern s t�m, �e
498vzor odpov�d�, resp. neodpov�d� patternu. Nez�porn� ��slo vr�t� v p��pad�,
499�e zkouman� vstup st�le souhlas� s patternem, ale nen� je�t�
500rozhodnuto. Velikost n�vratov� hodnoty v takov�m p��pad� ud�v�, o kolik
501pozic je t�eba se posunout v patternu, abychom m�li ukazatel na pozici
502patternu v souhlase s novou situac�, zp�sobenou znakem |c|.
503
504Pokud je |c| v mno�in� znak� pro danou pozici |p->str|, bude |m==1|, jinak
505je |m==-1|. Pokud t�mto ��slem pron�sob�me hodnotu |p->flag|, nemus�me
506v�tven� podle |p->flag| programovat dvakr�t. Hodnoty |flag| jsou toti�
507symetrick� podle nuly, nap�. |ANY==-ANY_NOT|.
508@d FOUND   -1
509@d NOFOUND -2
510@<Pomocn� funkce@>=
511static int match (PATITEM *p)
512{
513  int m;
514  if (strchr (p->str, c) != NULL) m = 1;  /* Znak nalezen */
515  else m = -1;                            /* Znak nenalezen */
516  switch (m * p->flag) {
517  case ANY: return 0;                  /* Souhas, neni nutny posun */
518  case ONE: if (p->next == NULL) return FOUND;
519            return 1;                    /* Souhas, nutny posun o 1 */
520  case ONE_NOT: return NOFOUND;          /* Nesouhlas */
521  case ANY_NOT: @<Vra� hodnotu podle n�sleduj�c�...@>;
522  }
523  return 0; /* Tady bychom nikdy nemeli byt, return pro potlaceni varovani */
524}
525
526@ O kolik pozic je t�eba se posunout a s jak�m v�sledkem zjist�me
527rekurzivn�m vol�n�m funkce |match|.
528@<Vra� hodnotu podle n�sleduj�c� pozice patternu@>=
529switch (m = match (p->next)) {
530case NOFOUND: return NOFOUND;
531case FOUND: return FOUND;
532default: return 1 + m;
533}
534
535@* Vlnkovac� funkce.
536Nejprve p�iprav�me glob�ln� deklarace pro \uv{vlnkovac�} funkci |tie|.
537Funkce |tie| \uv{ovlnkuje} vstupn� soubor |infile| a vytvo�� soubor
538|outfile|.  P�i |silent=0| tiskne z�v�re�nou zpr�vu o zpracov�n�. V t�to
539zpr�v� se objev� jm�no souboru, kter� se funkce \uv{dozv�} prost�ednictv�m
540glob�ln� prom�nn� |filename|. Prom�nn� |numline| po��t� ��dky, prom�nn�
541|numchanges| s��t� zm�ny, tj. po�et dopln�n�ch vlnek.
542Prom�nn� |mode| nab�v� n�kter� z hodnot |TEXTMODE|, |MATHMODE|,
543|DISPLAYMODE| a |VERBMODE| podle stavu ve �ten�m textu.
544@d TEXTMODE 0
545@d MATHMODE 1
546@d DISPLAYMODE 2
547@d VERBMODE 3
548@<Glob�ln� deklarace@>=
549char *filename;     /* jmeno zpracovavaneho souboru */
550long int numline, numchanges;   /* pro zaverecnou statistiku */
551int mode;
552
553@ Nyn� definujeme vlnkovac� funkci |tie|. Ve�ker� �innost se op�r� o
554strukturu pattern�. V�hodn� je (z d�vodu rychlosti) \uv{natvrdo} zde
555implementovat jen p�ep�n�n� mezi stavem �ten� z oblasti koment��e
556(|listpatt==commentlist|) a mimo koment�� (|listpatt==normallist|);
557@<Vlnkovac� funkce |tie|@>=
558static void tie (FILE *input, FILE *output)
559{
560  int ap;  /* ap je pocet otevrenych patternu */
561  register int k, m, n;
562  int ic;
563  PATTERN *pp;
564  PATITEM *pi;
565
566  @<Inicializace prom�nn�ch p�i startu funkce |tie|@>;
567
568  while (!feof(input)) {
569    if (ap == 0  && ind > BUFI && c !='\\') @<Vypr�zdni buffer@>;
570    @<Otev�i nov� patterny@>;  /* 1. 2. 2010: prohozene poradi */
571    if (ind >= MAXBUFF) {
572      fprintf (stderr, "Operating buffer overflow, is anything wrong?\n");
573      exit (BAD_PROGRAM);
574    }
575    if ((ic = getc(input)) == EOF)  /* opravil Cejka Rudolf */
576      break;
577    buff[ind++] = c = ic;
578    if (c == 0) continue;     /* 30. 4. 2009 */
579    if (inz>=8) {
580      for (inz=0; inz<4; inz++) buffnz[inz] = buffnz[inz+4];
581      inz=4;
582    }
583    buffnz[inz++] = c;
584    if (c == '\n') numline++, listpatt = normallist;
585    if (c == '%' && mode!=VERBMODE && buffnz[inz-2] != '\\') listpatt = commentlist;
586    @<Projdi otev�en� patterny@>;
587  }
588  @<Vypr�zdni buffer@>;
589  if (!web) checkmode ();   /* zaverecna kontrola modu */
590  if (!silent) @<Tiskni z�v�re�nou zpr�vu@>;
591}
592
593@ @<Inicializace prom�nn�ch p�i ...@>=
594for (k=0; k<MAXPATT; k++) lapi[k] = NULL;
595c = '\n';
596buff[0] = 1; mode = ap = 0;  ind = 1;
597for(inz=0; inz<4; inz++) buffnz[inz] = 0;
598inz = 4;
599numline = 1; numchanges = 0;
600mode = TEXTMODE;
601
602@ P�i manipulaci s bufferem byl pou�it jeden trik. Ve�ker� na�ten� znaky
603za��naj� a� od |buff[1]|, zat�mco |buff[0]| je rovno nule. Je to proto, �e
604n�kter� algoritmy se vrac� o jeden znak zp�t za sv�j pattern, aby zjistily,
605zda tam nen� symbol \uv{\.{\char92}} (nap��klad na v�skyt sekvence
606\.{\char92\char37} je t�eba reagovat jinak, ne� na v�skyt oby�ejn�ho
607procenta). Kdybychm zaza�ali od |buff[0]|, v n�kter�ch situac�ch
608bychom se ptali, zda |buff[-1]=='\\'|, tj. sahali bychom na neo�et�en�
609m�sto v pam�ti. Od 30. 4. 2009 tento probl�m pominul, proto�e se pt�me dozadu pouze
610v~|buffnz|, ale vlastnost d��ve implementovanou v |buff| jsem ponechal beze zm�ny.
611@<Vypr�zdni buffer@>=
612{
613  fwrite (&buff[1], ind-1, 1, output);
614  ind = 1;
615}
616
617@ P�i proch�zen� otev�en�mi patterny posunujeme v poli |lapi| pozice
618jednotliv�ch pattern� podle pokyn� funkce |match|, p��padn� pattern zav�eme
619a p��padn� vyvol�me proceduru patternu.
620
621N�kter� patterny v poli |lapi| u� mohou b�t zav�eny, tak�e je nutno s t�mto
622polem pracovat jako s jak�msi d�rav�m s�rem.
623@<Projdi otev�en� patterny@>=
624n = ap; k = 0;
625while (n) {
626  while (lapi[k]==NULL) k++;  /* zastav se na prvnim ukazateli na pattern */
627  switch (m = match (lapi[k])) {
628  case FOUND:   (*lapt[k]->proc)();  /* Pattern nalezen, spustit proceduru */
629  case NOFOUND: lapi[k] = NULL;  /* Deaktivace patternu */
630                ap--; break;
631  default:  while (m--) lapi[k] = lapi[k]->next;  /* dalsi pozice patternu */
632  }
633  k++; n--;
634}
635
636@ P�i otev�r�n� nov�ch pattern�, kter� nejsou v tuto chv�li zablokov�ny,
637se hned vypo��d�me s takov�mi patterny, kter� n�m d�vaj� rovnou odpov��
638typu |FOUND| nebo |NOFOUND|. V takov�ch p��padech ani nezan��me ukazatel
639na pozici do pole |lapi|.
640@<Otev�i nov� patterny@>=
641pp = listpatt;
642if (c) while (pp != NULL) {
643  switch (m = match (pp->patt)) {
644  case FOUND:    (*pp->proc)();   /* spustit proceduru */
645  case NOFOUND: break;
646  default: @<Vytvo� ukazatel na nov� pattern a |break|@>;
647  }
648  pp=pp->next;
649}
650
651@ Nen�-li hned zn�ma odpov��, zda pattern vyhovuje �i nikoli,
652p�ekontrolujeme nejd��ve, zda u� nen� pattern ve stejn� pozici otev�en�.
653Pak najdeme prvn� \uv{d�ru} v tabulce |lapi| a tam uhn�zd�me nov� ukazatel
654na pozici v patternu.
655@<Vytvo� ukazatel na nov� pattern...@>=
656pi = pp->patt;
657while (m--) pi = pi->next;
658n = ap;  k = 0;
659while (n) {
660  if (lapi[k]==pi) break;
661  if (lapi[k++] != NULL) n--;
662}
663if (!n) {
664  k = 0;
665  while (lapi[k] != NULL) k++;
666  if (k >= MAXPATT) {
667    fprintf (stderr, "I cannot allocate pp, is anything wrong?\n");
668    exit (BAD_PROGRAM);
669  }
670  lapt[k] = pp;  lapi[k] = pi; ap++;
671}
672
673@ Posledn� v�c� ve funci |tie| je tisk z�v�re�n� statistiky zpracov�n�.
674@<Tiskni z�v�re�nou zpr�vu@>=
675fprintf (stderr, "~~~ file: %s\t  lines: %ld, changes: %ld\n",
676   filename, numline,  numchanges);
677
678@* Inicializace pattern�.
679Po vytvo�en� p�edchoz�ho k�du op�raj�c�ho se o~patterny m�me nyn� v~ruce
680pom�rn� siln� n�stroj na definov�n� r�zn�ch �innost� programu prost�m
681vytvo�en�m patternu a p��slu�n� jeho procedury. Pokud budeme cht�t
682v~budoucnu n�jak� rys programu p�idat, pravd�podobn� to bude snadn�.
683
684Nejprve deklarujeme n�kter� �asto pou��van� skupiny znak� v~patternech.
685
686@<Glob�ln� deklarace@>=
687char tblanks[] = " ~\t";
688char blanks[] =  " \t";
689char blankscr[] = " \t\n";
690char tblankscr[] = " ~\t\n";
691char nochar[] = "%~\n";
692char cr[] = "\n";
693char prefixes[] = "[({~";
694char dolar[] = "$";
695char backslash[] = "\\";
696char openbrace[] = "{";
697char letters[] = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
698PATTERN *vlnkalist, *mathlist, *parcheck, *verblist ;
699
700@ Za�neme definic� nej�ast�ji pou��van�ho patternu na vlnkov�n� uvnit�
701��dku. P�ipome�me, �e opakovan� vol�n� funkce |setpattern| vytv��� intern�
702seznam pattern�, p�i�em� o~jejich propojen� se nemus�me starat. Vyzvedneme
703si z~n�vratov�ho k�du funkce pouze ukazatel na prvn� polo�ku seznamu
704|normallist|. Stejn� tak opakovan� vol�n� funkce |setpi| vytv��� seznam
705pozic pro naposledy deklarovan� pattern.
706@<Inicializace datov�ch struktur@>=
707vlnkalist = setpattern (vlnkain);
708setpi (tblankscr, ONE);
709setpi (tblanks,   ANY);
710setpi (prefixes,  ANY);
711setpi (charset,   ONE);
712setpi (blanks,    ONE);
713setpi (blanks,    ANY);
714setpi (nochar,    ONE_NOT);
715
716@ @<Inicializace prom�nn�ch p�i ...@>=
717listpatt = normallist = vlnkalist;
718
719@ Vlo�en� vlnky znamen� vykonat n�sleduj�c� pr�ci: Zapamatovat si znak za skupinou mezer
720(do prom�nn� |p|). Pokud p�ed t�mto znakem p�edch�z� nulov� byte, pou�ijeme ho pozd�ji, proto
721si jej ulo��me do prom�nn� |z|. D�le se posuneme v bufferu vlevo p�es v�echny mezery, tabel�tory
722(p�esn�ji |blanks|) a p�eskakujeme p�itom v�echny nulov� byty. Index |ind| se zastav�
723na p�edlo�ce. Posuneme jej doprava za p�edlo�ku (++|ind|) a pokud tam je nulov� byte a prvn� znak
724|tiestr| nen� nulov�, posuneme se a� za tento nulov� byte. D�le vlo��me string |tiestr|,
725neboli vlnku. Nakonec p�ipoj�me zapamatovan� znak |p|, ov�em pokud p�ed n�m byla nula,
726vlo��me ji je�t� p�ed znak |p|.
727@<Pomocn� funkce@>=
728static void vlnkain(void)
729{
730  int i;
731  char p, z;
732  ind--;
733  p = buff[ind--];
734  z = buff[ind];
735  while (!buff[ind] || (strchr(blanks, buff[ind]) !=NULL)) ind--;
736  if (!buff[++ind] && tiestr[0]) ind++;
737  for (i=0; i<tiestrlen; i++) buff[ind++] = tiestr[i];
738  i = tiestrlen;                     /* nulu pred p vlozime, pokud je z==0 a */
739  if (!tiestr[0]) i--;               /* pocet vlozenych znaku z tiestr */
740  if (!z && (i%2)) buff[ind++] = 0;  /* je sudy */
741  buff[ind++] = p;
742  numchanges++;
743}
744
745@ Podobn� pro tvorbu vlnky \uv{p�es ��dek} vytvo��me pattern a k�d
746procedury.
747@<Inicializace dat...@>=
748setpattern (vlnkacr);
749setpi (tblankscr, ONE);
750setpi (tblanks,   ANY);
751setpi (prefixes,  ANY);
752setpi (charset,   ONE);
753setpi (blanks,    ANY);
754setpi (cr,        ONE);
755setpi (blanks,    ANY);
756setpi (nochar,    ONE_NOT);
757
758@ V procedu�e k tomuto patternu mus�me o�et�it p��pad typu
759\uv{\.{a\char126v\char92np}},
760kdy nelze prost� p�ehodit \uv{\.{\char92n}} za \uv{\.{v}}, proto�e
761bychom roztrhli
762mezeru sv�zanou vlnkou u� d��ve. Proto mus�me vyhledat vhodn� m�sto pro
763roztr�en� ��dku, kter� bude a� {\it p�ed\/} znakem \uv{\.{a}}. P�i d�sledn�m
764o�et�en� tohoto fenom�nu m��eme dokonce narazit na situaci
765\uv{\.{\char92n\ v\char126v\char126v\char92np}},  kde nem��eme vlo�it
766\uv{\.{\char92n}} p�ed prvn� v�skyt \uv{\.{v}}, proto�e bychom dostali
767\uv{\.{\char92n\char92n}}, tedy pr�zdn�
768��dek. Ten je v \TeX{}u interperetov�n odli�n�. V t�to v�jime�n�
769situaci pouze zru��me st�vaj�c� (v po�ad� druh�) \uv{\.{\char92n}} a
770nebudeme vytv��et nov�. Na v�stupu bude soubor o jeden ��dek krat��.
771@<Pomocn� funkce@>=
772static void vlnkacr(void)
773{
774  char p, z;
775  int i, j;
776  ind--;
777  p = buff[ind--];
778  z = buff[ind];
779  while (!buff[ind] || (strchr(blankscr, buff[ind]) !=NULL)) ind--;
780  i = ind;  /* misto predlozky, kterou chceme vazat */
781  while (i >= 0 && (strchr(blankscr, buff[i]) == NULL)) i--;
782  j = i;
783  while (i >= 0 && (!buff[ind] || (strchr(blanks, buff[i]) != NULL))) i--;
784  if (i >= 0 && buff[i] == '\n') j = -1;
785  if (j >= 0)  buff[j] = '\n';
786  else numline--;
787  if (!buff[++ind] && tiestr[0]) ind++;
788  for (i=0; i<tiestrlen; i++) buff[ind++] = tiestr[i];
789  i = tiestrlen;
790  if (!tiestr[0]) i--;
791  if (!z && (i%2)) buff[ind++] = 0;
792  buff[ind++] = p;
793  numchanges++;
794}
795
796@ Nyn� vytvo��me patterny pro p��pady typu \.{\char92uv\char`\{v lese\char`\}}.
797@<Inicializace dat...@>=
798setpattern (vlnkain);    /* na radku */
799setpi (tblankscr, ONE);
800setpi (backslash, ONE);
801setpi (letters,   ONE);
802setpi (letters,   ANY);
803setpi (openbrace, ONE);
804setpi (prefixes,  ANY);
805setpi (charset,   ONE);
806setpi (blanks,    ONE);
807setpi (blanks,    ANY);
808setpi (nochar,    ONE_NOT);
809
810setpattern (vlnkacr);    /* pres radek */
811setpi (tblankscr, ONE);
812setpi (backslash, ONE);
813setpi (letters,   ONE);
814setpi (letters,   ANY);
815setpi (openbrace, ONE);
816setpi (prefixes,  ANY);
817setpi (charset,   ONE);
818setpi (blanks,    ANY);
819setpi (cr,        ONE);
820setpi (blanks,    ANY);
821setpi (nochar,    ONE_NOT);
822
823
824
825@ Vytvo��me patterny a proceduru pro potlat�en� tvorby vlnky u p�smen t�sn�
826n�sleduj�c�ch sekvence \.{\char92TeX} a \.{\char92LaTeX}. Tj. nechceme, aby
827nap� z textu \uv{\.{Vlastnosti~\char92TeX~u~jsou...}} jsme dostali text
828s nespr�vn� v�zan�m p�smenem
829\uv{\.{Vlastnosti~\char92TeX~u\char126jsou...}}.
830@<Inicializace dat...@>=
831normalpattern (tielock, "\\TeX");
832setpi (blankscr, ONE);
833normalpattern (tielock, "\\LaTeX");
834setpi (blankscr, ONE);
835
836@ Procedura |tielock| obsahuje ne�ist� trik. P�i prov�d�n� procedury je
837pr�v� na�ten znak z |blankscr| a je ulo�en do |buff|. Testy na otev�r�n�
838nov�ch pattern� pro tento znak teprve budou n�sledovat a testuj� se na
839hodnotu prom�nn� |c|. Sta�� tedy zm�nit hodnotu |c| a vlnkovac� patterny se
840neotev�ou.
841@<Pomocn� funkce@>=
842static void tielock (void)
843{
844  c = 1;
845}
846
847@ O�et��me nyn� p�echod do/z matematick�ho re�imu \TeX{}u. Uvnit� math
848m�du vlnky ned�l�me. P�i zji�t�n�m nesouladu v p�echodech mezi
849math-m�dy spust�me n�sleduj�c� proceduru.
850@<Pomocn� funkce@>=
851static void printwarning (void)
852{
853  if (!silent)
854    fprintf (stderr,
855      "~!~ warning: text/math/verb mode mismatch,  file: %s,  line: %ld\n",
856      filename, numline - (c=='\n'?1:0));
857  status = WARNING;
858}
859
860@ Za�neme patterny pro p�echod do/z matematick�ho re�imu, ohrani�en�ho
861jedn�m dolarem, nebo v La\TeX{}u p��slu�n�mi sekvencemi.  Sekvence
862La\TeX{}u \.{\char92(} a \.{\char92)} nejsou zahrnuty, proto�e b�vaj�
863�asto p�edefinov�ny k jin�m u�ite�n�j��m v�cem.
864@<Inicializace datov�ch ...@>=
865if (!nomath) {
866  mathlist = setpattern (onedollar);
867  setpi (dolar, ONE);
868  setpi (dolar, ONE_NOT);
869  if (latex) {
870    normalpattern (mathin, "\\begin.{math}");
871    normalpattern (mathout, "\\end.{math}");
872  }
873}
874
875@ @<Pomocn� funkce@>=
876static void mathin (void)
877{
878  if (mode!=TEXTMODE) printwarning ();
879  mode = MATHMODE;
880  normallist = listpatt = mathlist;
881}
882static void mathout (void)
883{
884  if (mode!=MATHMODE) printwarning ();
885  mode = TEXTMODE;
886  normallist = listpatt = vlnkalist;
887}
888
889@ P�i programov�n� procedury |onedollar| nesm�me zapomenout na v�skyt
890sekvence \.{\char92\$}. V tom p��pad� akci ignorujeme. Podobn� u sekvence
891\.{\$\$} souhlas� ten druh� dolar s na��m patternem, ale to u� jsme uvnit�
892display m�du. V takov�m p��pad� tak� nic ned�l�me.
893@<Pomocn� funkce@>=
894static void onedollar (void)
895{
896  if (buffnz[inz-3]=='\\' || (buffnz[inz-3]=='$' && buffnz[inz-4]!='\\')) return;
897  if (mode==DISPLAYMODE) printwarning ();
898  else {
899    if (mode==TEXTMODE) mathin();
900    else mathout();
901  }
902}
903
904@ Pokud najdeme pr�zdn� ��dek, p�ekontrolujeme, zda n�hodou nejsme v
905math-m�du. Pokud ano, vyp�eme varov�n� a p�ejdeme do textov�ho m�du.
906@<Inicializace dat...@>=
907parcheck = setpattern (checkmode);
908setpi (cr, ONE);
909setpi (blanks, ANY);
910setpi (cr, ONE);
911
912@ @<Pomocn� funkce@>=
913static void checkmode (void)
914{
915  if (mode!=TEXTMODE) {
916    printwarning ();
917    mode = TEXTMODE;
918    normallist = listpatt = vlnkalist;
919  }
920}
921
922@ Nyn� o�et��me v�skyt dvou dolar�, tj. vstup do/z display m�du.
923Rovn� mysleme na La\TeX{}isty a jejich prost�ed� pro display-m�d. Proto�e
924je mo�n� alternativa s hv�zdi�kou na konci n�zvu prost�ed�, rad�ji u�
925uzav�rac� z�vorku do patternu nezahrnujeme.
926
927@<Inicializace dat...@>=
928if (!nomath) {
929  normalpattern (twodollars, "$$");
930  if (latex) {
931    normalpattern (displayin, "\\begin.{displaymath");
932    normalpattern (displayin, "\\begin.{equation");
933    normalpattern (displayout, "\\end.{displaymath");
934    normalpattern (displayout, "\\end.{equation");
935  }
936}
937
938@ @<Pomocn� funkce@>=
939static void displayin (void)
940{
941  if (mode!=TEXTMODE) printwarning ();
942  mode = DISPLAYMODE; normallist = listpatt = parcheck;
943}
944static void displayout (void)
945{
946  if (mode!=DISPLAYMODE) printwarning();
947  mode = TEXTMODE; normallist =  listpatt = vlnkalist;
948}
949static void twodollars (void)
950{
951  if (buffnz[inz-3]=='\\') return;
952  if (mode==DISPLAYMODE) displayout ();
953  else displayin ();
954}
955
956@ N�sleduje o�et�en� tzv. verbatim m�du. Pro plain i La\TeX{} jsou nej�ast�j��
957z�vorky pro verbatim mod tyto (variantu s \.{\char92begtt} pou��v�m
958s oblibou j�).
959@<Inicializace dat...@>=
960if (!noverb) {
961  verblist = normalpattern (verbinchar, "\\verb");
962  setpi (blankscr, ANY);
963  setpi (blankscr, ONE_NOT);
964  normalpattern (verbin, "\\begtt");
965  if (latex) normalpattern (verbin, "\\begin.{verbatim");
966}
967if (web) {
968  normalpattern (verbin, "@@<");
969  normalpattern (verbin, "@@d");
970}
971if (!noverb) {
972  verboutlist[0] = setpattern (verbout);
973  setpi (verbchar, ONE);
974  verboutlist[1] = normalpattern (verbout, "\\endtt");
975  if (latex) verboutlist[2] = normalpattern (verbout, "\\end{verbatim");
976}
977if (web) {
978  verboutlist[3] = normalpattern (verbout, "@@ ");
979  normalpattern (verbout, "@@*");
980  normalpattern (verbout, "@@>|");
981}
982
983
984@ Procedura |verbinchar| se od \uv{spole�n�} procedury |verbin| li�� v
985tom, �e zavede do stringu |verbchar| moment�ln� hodnotu prom�nn� |c|.
986Proto druh� v�skyt t�to hodnoty verbatim re�im ukon��.
987@<Pomocn� funkce@>=
988int prevmode;
989PATTERN *prevlist, *verboutlist[4];
990char verbchar[2];
991static void verbinchar (void)
992{
993  prevmode = mode;
994  verbchar[0] = c;
995  c = 1;
996  listpatt = normallist = verboutlist[0];
997  prevlist = listpatt->next;
998  listpatt->next = NULL;
999  mode = VERBMODE;
1000}
1001
1002@ P�i programov�n� \uv{obecn�} funkce |verbin| mus�me db�t na to, aby
1003z�stal aktivn� pouze odpov�daj�c� \uv{v�stupn�} pattern k dan�mu
1004vstupn�mu. Tak� si zapamatujeme m�d, ze kter�ho jsme do verbatim
1005oblasti vstoupili, abychom se k n�mu mohli vr�tit (nap�. uvnit�
1006math. m�du m��e b�t
1007\.{\char92hbox} a v n�m lok�ln� verbatim konstrukce).
1008@<Pomocn� funkce@>=
1009static void verbin (void)
1010{
1011  int i;
1012  i = 0;
1013  prevmode = mode;
1014  switch (c) {
1015  case 't': i = 1; break;
1016  case 'm': i = 2; break;
1017  case '<': ;
1018  case 'd': i = 3;
1019       if (buffnz[inz-3]=='@@') return;  /* dvojity @@ ignorovat */
1020       break;
1021  }
1022  listpatt = normallist = verboutlist[i];
1023  prevlist = listpatt->next;
1024  if (c != '<' && c != 'd')  listpatt->next = NULL;
1025  mode = VERBMODE;
1026}
1027
1028@ @<Pomocn� funkce@>=
1029static void verbout (void)
1030{
1031  if (mode!=VERBMODE) return;
1032  if (web && buffnz[inz-2] == '@@' && buffnz[inz-3] == '@@') return;
1033  mode = prevmode;
1034  normallist->next = prevlist;
1035  switch (mode) {
1036  case DISPLAYMODE: normallist = listpatt = parcheck; break;
1037  case MATHMODE: normallist = listpatt = mathlist; break ;
1038  case TEXTMODE:  normallist = listpatt = vlnkalist; break;
1039  }
1040}
1041
1042@ Nyn� implementujeme vlastnost d��ve pou��van�ho programu vlnka, tj. �e
1043lze jeho �innost vypnout a op�t zapnout v koment���ch. Vytv���me druh�
1044nez�visl� seznam pattern� a proto nejprve pronulujeme |lastpt|.
1045@<Inicializace dat...@>=
1046lastpt = 0;
1047commentlist = normalpattern (tieoff, "%.~.-");
1048normalpattern (tieon, "%.~.+");
1049
1050@ @<Pomocn� funkce@>=
1051static void tieoff (void)
1052{
1053  normallist = NULL;
1054}
1055static void tieon (void)
1056{
1057  normallist = vlnkalist;
1058}
1059
1060@ Dal�� pl�novan� vylep�en�. Program by mohl ��st definici sv�ho chov�n�
1061nejen z~p��kazov� ��dky, ale v~mnohem kompletn�j�� podob�, v�etn�
1062u�ivatelsky definovan�ch pattern�, z koment��ov� oblasti ve �ten�m souboru.
1063Parametry zde uveden� by mohly m�t vy��� prioritu, ne� parametry
1064z~p��kazov� ��dky a mohl by se t�eba roz�i�ovat seznam sekvenc�, za nimi�
1065p�smena nemaj� b�t v�zana vlnkou (zat�m je implemenov�no na pevno jen
1066\.{\char92TeX} a \.{\char92LaTeX}).
1067
1068@* Rejst��k.
1069
1070
1071