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