§1  VLNA  PROGRAM VLNA 1

16. června 2012 v 18:51

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

Program sestává z těchto hlavních celků:

⟨ Hlavičkové soubory k načtení 3 ⟩

⟨ Globální deklarace 4 ⟩

⟨ Pomocné funkce 6 ⟩

⟨ Vlnkovací funkce tie 29 ⟩

⟨ Hlavní program 5 ⟩

2. Definujeme , 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 a se nesnáší s akcentovanými písmeny v /* komentářích */. A nyní už slíbený (vícejazyčný) .

#define

3. V programu jsou použity knihovní funkce, jejíchž prototypy jsou definovány ve třech standardních hlavičkových souborech. ⟨ Hlavičkové soubory k načtení 3 ⟩ ≡ #include #include #include

Tento kód je použit v sekci 1.

4. Definujeme konstanty pro návratový kód. pro úspěšný běh, při výskytu aspoň jedné varovné zprávy, pro chybu v přístupu ke vtupním nebo výstupním souborům, pro syntaktickou chybu na příkazové řádce a pro případ havárie programu. Ta by neměla nikdy nastat. Proměnná status bude obsahovat návratový kód a proměnná prog name bude ukazovat na text nultého parametru příkazové řádky.

#define  0
#define  1
#define  2
#define  3
#define  4

⟨ Globální deklarace 4 ⟩ ≡ char ∗prog name; int status;

Viz také sekce 7, 8, 17, 18, 19, 23, 28 a 36. Tento kód je použit v sekci 1.

2  PROGRAM VLNA  VLNA §5

5. Základní rozvržení funkce main. ⟨ Hlavní program 5 ⟩ ≡

int main(int argc, char ∗∗argv) {

⟨ Lokální proměnné funkce main 11 ⟩; prog name = argv[0]; status = ; ⟨ Načtení parametrů příkazového řádku 9 ⟩; if (¬silent) fprintf (stderr, ); ⟨ Inicializace datových struktur 24 ⟩; ⟨ Zpracování souborů 13 ⟩; return status;

}

Tento kód je použit v sekci 1.

§6  VLNA  PARAMETRY PŘÍKAZOVÉHO ŘÁDKU 3

6. Parametry příkazového řádku. Program čte z příkazového řádku postupně (nepovinné) parametry, které začínají znakem ţ �. Pak následují jména vstupních a výstupních souborů.

• … program pracuje jako filtr (viz sekce ⟨ Zpracování souborů 13 ⟩). Není-li tento parametr použit, program pracuje v tzv. standardním režimu, kdy jednotlivé soubory jsou vstupní i výstupní.

• … program nevypíše , ani sumarizaci, ani varování, při nichž není program předčasně ukončen. Všechny tyto výpisy směřují do stderr, takže pokud program pracuje v režimu ţfiltr�, není nutné tento parametr použít.

• … program maže pracovní soubor (soubory), které vytváří ve standardním režimu (tj. není použit ). V reřimu filter nemá tento parametr vliv.

• … parametr definuje skupinu písmen, které budou interpretovány jako neslabičné předložky. Např. . Pokud není parametr uveden, je použita skupina uvedená v tomto příkladě.

• … parametr vymezuje pomocí hexadecimálního zápisu string, který program vkládá na vyhledaná místa. Implicitně vkládá vlnku. Například způsobí, že program bude vkládat místo vlnky dva byty, první s kódem a druhý s kódem .

• … program neprovádí kontrolu math/text módů, tj. vlnkuje i uvnitř matematického módu TEXu. (Implicite tam nevlnkuje).

• … 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.

• … LaTEX režim. Při kontrole text-math-verbatim módů jsou brány v úvahu další sekvence, obvyklé v LaTEXových dokumentech.

• … 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.

Definujeme funkci 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í s formátovacími požadavky. Byl jsem nucen to takto nehezky zapsat. ⟨ Pomocné funkce 6 ⟩ ≡

static void printusage(void ) {

fprintf (stderr,

); }

Viz také sekce 10, 12, 20, 21, 22, 25, 26, 39, 41, 44, 45, 47, 48, 50, 52, 54, 55, 56 a 58. Tento kód je použit v sekci 1.

7. Proměnné isfilter, silent, rmbackup, nomath, noverb, latex, resp. web říkají, že je nastaven parametr , , , , , , resp. . Proměnná charset ukazuje buď na implicitní skupinu znaků charsetdefault, nebo (při použití parametru ) na text uvedený v příkazovém řádku. ⟨ Globální deklarace 4 ⟩ +≡

int isfilter = 0, silent = 0, rmbackup = 0, nomath = 0, noverb = 0, web = 0, latex = 0; char charsetdefault[ ] = ; char ∗charset = charsetdefault;

4  PARAMETRY PŘÍKAZOVÉHO ŘÁDKU  VLNA §8

8. String tiestr obsahuje string, kterým se má nahradit vyhledané místo. Pokud není použit parametr , je tento string jadnoznakový a obsahuje vlnku. Jinak obsahuje string konvertovaný z parametru . String má délku tiestrlen bez ohledu na to, zda obsahuje nebo neobsahuje nulové znaky (C-čková konvence pro stringy není použita). ⟨ Globální deklarace 4 ⟩ +≡

unsigned char tiestr[ ]; int tiestrlen;

9. ⟨ Načtení parametrů příkazového řádku 9 ⟩ ≡ tiestr[0] = ; tiestrlen = 1; while (argc > 1 ∧ argv[1][0] ≡ ) {

if (argv[1][2] ≠ 0) printusage( ), exit( ); switch (argv[1][1]) { case : isfilter = 1;

break ; case : silent = 1;

break ; case : rmbackup = 1;

break ; case :

if (argc < 2) printusage( ), exit( ); argv^{++} ; argc^{−}; charset = argv[1]; break ;

case :

if (argc < 2) printusage( ), exit( ); argv^{++} ; argc^{−}; settiestr(argv[1]); break ;

case : nomath = 1;

break ; case : noverb = 1;

break ; case : latex = 1;

break ; case : web = 1;

break ; default : printusage( ), exit( ); /∗ neznámý parametr ∗/ } argc^{−}; argv^{++} ;

}

Tento kód je použit v sekci 5.

10. Vyřešíme konverzi kódu zapsaného za parametrem na string tiestr. ⟨ Pomocné funkce 6 ⟩ +≡

static unsigned char hexnum(char c) {

if (c ≥ ∧ c ≤ ) return c − ;

if (c ≥  ∧ c ≤ ) return c −  + 10;
if (c ≥  ∧ c ≤ ) return c −  + 10;

printusage( ), exit( ); } static void settiestr(char ∗s) {

int i, j; i = strlen(s); if ((i > 2 ∗ ) ∨ i % 2 ≡ 1) printusage( ), exit( ); tiestrlen = i/2; j = 0; for (i = 0; i < tiestrlen; i^{++} ) {

tiestr[i] = hexnum(s[j^{++} ]) ≪ 4; tiestr[i] += hexnum(s[j^{++} ]);

} }

6  ZPRACOVÁNÍ SOUBORŮ  VLNA §11

11. Zpracování souborů. Parametr 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 ţstream�.

#define  120

⟨ Lokální proměnné funkce main 11 ⟩ ≡ FILE ∗infile, ∗outfile; char backup[ ]; int j;

Tento kód je použit v sekci 5.

12. Definujeme funkci pro výpis chybového hlášení při neúspěšném otevření souboru. ⟨ Pomocné funkce 6 ⟩ +≡

static void ioerr (char ∗f) {

fprintf (stderr, , prog name, f); }

13. Způsob zpracování souborů rozlišíme podle režimu daným přepínačem . ⟨ Zpracování souborů 13 ⟩ ≡

if (isfilter) ⟨ Zpracování v režimu filter 14 ⟩ else ⟨ Zpracování všech souborů příkazové řádky 15 ⟩

Tento kód je citován v sekci 6. Tento kód je použit v sekci 5.

14. V režimu isfilter ≡ 1 je další zpracování závislé na počtu souborů v příkazové řádce:

• nula souborů – vstup je stdin a výstup je stdout,

• jeden soubor – je vstupní, výstup je stdout,

• dva soubory – první je vstupní, druhý výstupní,

• více souborů – program skončí s chybou.

⟨ Zpracování v režimu filter 14 ⟩ ≡

{ if (argc > 3) printusage( ), exit( ); infile = stdin; outfile = stdout; if (argc ≥ 2) infile = fopen(argv[1], ); if (infile ≡ Λ) ioerr (argv[1]), exit( ); if (argc ≡ 3) outfile = fopen(argv[2], ); if (outfile ≡ Λ) ioerr (argv[2]), exit( ); if (argc ≥ 2) filename = argv[1]; else filename = Λ; tie(infile, outfile); if (outfile ≠ stdout) fclose(outfile); if (infile ≠ stdin) fclose(infile);

}

Tento kód je použit v sekci 13.

§15  VLNA  ZPRACOVÁNÍ SOUBORŮ 7

15. V režimu isfilter ≡ 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 UNIXu lze tedy např. napsat a program doplní vlnky do všech souborů s příponou . Toto neplatí v DOSu, protože interpretace masky je v UNIXu 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. ⟨ Zpracování všech souborů příkazové řádky 15 ⟩ ≡

{ if (argc ≡ 1) printusage( ), exit( ); while (argc > 1) {

argc^{−}; argv^{++} ; ⟨ Přejmenuj vstup argv[0] na backup a otevři jej jako infile 16 ⟩; if (infile ≡ Λ) { ioerr (argv[0]); continue ;

}

outfile = fopen(argv[0], );

if (outfile ≡ Λ) { ioerr (argv[0]); rename(backup, argv[0]); status = ; continue ;

}

filename = argv[0]; tie(infile, outfile); fclose(outfile), fclose(infile); if (rmbackup) remove(backup);

} }

Tento kód je použit v sekci 13.

16. Při isfilter ≡ 0 program přejmenuje každý zpracovávaný soubor tak, že změní poslední písmeno názvu souboru na znak . Tento přejmenovaný soubor bude otevřen jako vstupní a výstupem bude původní soubor. Vstupní soubor při rmbackup ≡ 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. ⟨ Přejmenuj vstup argv[0] na backup a otevři jej jako infile 16 ⟩ ≡

infile = Λ;

j = strlen(argv[0]) − 1;

if (j ≥ ∨ argv[0][j] ≡ ) {

if (¬silent) fprintf (stderr, , prog name, argv[0]); } else {

strcpy(backup, argv[0]);

backup[j] = ; remove(backup); j = rename(argv[0], backup); if (j ≡ 0) infile = fopen(backup, );

}

Tento kód je použit v sekci 15.

8  PATTERNY  VLNA §17

17. Patterny. Abychom mohli účelně definovat chování programu v různých situacích, zavedeme datovou strukturu . 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 ţ �, kde ţ � znamená jedna nebo více mezer a tabelátorů, ţ � je nula nebo více otevíracích závorek všeho druhu, ţ � znamená jedno písmeno z množiny předložek (viz charset) a ţ � 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 ( ). Cykly uvnitř pozic pro jednoduchost nepřipustíme. Každá pozice obsahuje řetězec znaků, uvažovaný pro danou pozici (v příkladu pozice ţ � by obsahovala mezeru a tabelátor, zatímco pozice odpovídá charset). Každá pozice má svůj přepínač (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 ţnula nebo více� protože ţjedna nebo více� lze popsat pomocí dvou pozic, první ţprávě jednou� a následující ţnula nebo více�. Jednotlivé pozice jsou zřetězeny ukazatelem next, poslední pozice má next ≡ Λ. Stejně tak jednotlivé patterny budeme sestavovat do seznamů a budou rovněž zřetězeny ukazatelem next.

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

#define  1  /∗ flag: prave jeden vyskyt ∗/
#define  2  /∗ flag: nula nebo vice ∗/
#define  −1  /∗ flag: prave jednou, znak nesmi byt v mnozine ∗/
#define  −2  /∗ flag: nula nebo vice, znak nesmi byt v mnozine ∗/

⟨ Globální deklarace 4 ⟩ +≡

typedef struct PATITEM { /∗ jedna pozice patternu ∗/ char ∗str; /∗ seznam znaku na teto pozici ∗/ int flag; /∗ vyznam seznamu znaku ∗/ struct PATITEM ∗next; /∗ nasledujici pozice patternu ∗/

} PATITEM ;

typedef struct PATTERN { /∗ jeden pattern ∗/ PATITEM ∗patt; /∗ ukazatel na prvni pozici ∗/ void (∗proc)(void ); /∗ procedura spustena pri souhlasu patternu ∗/ struct PATTERN ∗next; /∗ nasledujici v seznamu vsech patternu ∗/

§18  VLNA  PATTERNY 9

} PATTERN ; 18. Deklarujeme některé globální proměnné pro práci s patterny. lapi je pole obsahující ukazatele na aktuální pozice v otevřených patternech. Říkáme, že ţpattern je otevřen�, pokud zkoumaný řetězec s ním 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 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 je při stringu při výskytu druhého otevřen podruhé. Proto pole obsahuje ukazatele na právě aktuální pozici patternu a nikoli na pattern jako takový.

V poli lapi budou na počátku samá Λ (to se při překladu inicializuje samo) a přemazání ukazatele na pozici konstantou Λ budeme považovat za zavření patternu. Vedle pole lapi souměrně udržujeme pole 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 proc patternu.

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 TEXovského komentáře (tj. za procentem). Starty těchto seznamů patternů jsou normallist a commentlist a aktivní listpatt má vždy jednu z těchto dvou hodnot.

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

Proměnná c obsahuje právě testovaný znak ze vstupu (který se rovněž přepíše do bufferu 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ž ţ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 , abychom proceduru přepisu bufferu do výstupního proudu neaktivovali zbytečně často.

#define  200  /∗ maximalni pocet patternu ∗/
#define  500  /∗ velikost bufferu pro operace ∗/
#define  300  /∗ velikost stredniho zaplneni ∗/

⟨ Globální deklarace 4 ⟩ +≡

PATITEM ∗lapi[  ];  /∗ pole ukazatelu na aktualni pozice ∗/
PATTERN ∗lapt[  ];  /∗ pole odpovidajicich ukazatelu na patterny ∗/

PATTERN ∗listpatt, ∗normallist, ∗commentlist, ∗pt, ∗lastpt = Λ;

PATITEM ∗lastpi = Λ;

char c; /∗ zrovna nacetny znak ∗/

char buff[ ]; /∗ prechodny buffer ∗/

int ind; /∗ aktualni pozice prechodneho bufferu ∗/

19. Dne 30. 4. 2009 jsem přidal možnost čtení vstupu, který obsahuje nulové byty. Takové nuly se přepisují do výstupu, ale program si jich nevšímá při procházení patternů. Tím je možno program použít na soubory kódované v UTF16, ačkoli patterny obsahují jen jednobytové ASCII znaky. Buffer buff může obsahovat i nulové byty, které je třeba přepsat do výstupu. Na druhé straně buffer buffnz obsahuje jen nenulové byty, na které se někdy ptáme při pohledu dozadu. Nejdelší pohled dozadu je o čtyři byty. Udělám tedy buffnz osmibytový, začnu jej plnit od buffnz[4] a kdykoli je buffer zcela zaplněn, přesunu horní čtyři byty na spodní a dále pokračuji v plnění bufferu od pozice buffnz[4]. ⟨ Globální deklarace 4 ⟩ +≡

char buffnz[8];

int inz; 20. Nyní definujeme pomocné funkce setpattern, setpi a normalpattern. Tyto funkce alokují paměť pomocí standardní funkce malloc. Abychom mohli ohlídat případnou chybu při alokaci, budeme allokovat paměť zprostředkovaně pomocí funkce myalloc. ⟨ Pomocné funkce 6 ⟩ +≡

static void ∗myalloc(int size) {

void ∗p; p = malloc(size); if (p ≡ Λ) {

fprintf (stderr, , prog name); exit( );

} return p;

}

21. Funkce setpattern alokuje paměťové místo struktury PATTERN a napojí ji pomocí proměnné lastpt na už alokovaný řetěz patternů. Vrátí ukazatel na nově alokované místo. Jednotlivé pozice patternu se musí následovně alokovat pomocí setpi. ⟨ Pomocné funkce 6 ⟩ +≡

static PATTERN ∗setpattern(void (∗proc)(void )) {

PATTERN ∗pp; pp = myalloc(sizeof (PATTERN )); pp proc = proc; pp next = Λ; pp patt = Λ; if (lastpt ≠ Λ) lastpt next = pp; lastpt = pp; lastpi = Λ; return pp;

}

22. Funkce 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 patt ve struktuře PATTERN a další byly provázány položkou next ve struktuře PATITEM . Poslední pozice má next ≡ Λ. ⟨ Pomocné funkce 6 ⟩ +≡

static void setpi(char ∗str, int flag) {

PATITEM ∗p; p = myalloc(sizeof (PATITEM )); p str = str; p flag = flag; p next = Λ; if (lastpi ≡ Λ) lastpt patt = p; else lastpi next = p; lastpi = p;

} 23. Připravme si půdu pro funkci 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á flag = . 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 , 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ů. ⟨ Globální deklarace 4 ⟩ +≡

char strings[512];

int i;

24. Inicializujeme toto pole (znak, nula, znak, nula, atd...). ⟨ Inicializace datových struktur 24 ⟩ ≡

for (i = 0; i < 256; i^{++} ) { strings[2 ∗ i] = (char ) i; strings[2 ∗ i + 1] = 0;

}

Viz také sekce 37, 40, 42, 43, 46, 49, 51, 53 a 57. Tento kód je použit v sekci 5.

25. Definujme funkci normalpattern. ⟨ Pomocné funkce 6 ⟩ +≡

static PATTERN ∗normalpattern(void (∗proc)(void ), const char ∗str)

{ PATTERN ∗pp; int j = 0; pp = setpattern(proc); while (str[j]) {

if (str[j] ≡ ) { j^{++} ; if (str[j] ≠ ) {

setpi(blankscr, ); continue ;

} } setpi(& strings[(unsigned char ) str[j] ∗ 2], ); j^{++} ;

}

return pp; } 26. Funkce match. Definujeme funkci, která na základě hodnoty znaku c (proměnná c je definována jako globální), a pozice patternu p (parametr funkce) vrátí informaci o tom, zda znak souhlasí s patternem. Záporná čísla , resp. 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 c.

Pokud je c v množině znaků pro danou pozici p str, bude m ≡ 1, jinak je m ≡ −1. Pokud tímto číslem pronásobíme hodnotu p flag, nemusíme větvení podle p flag programovat dvakrát. Hodnoty flag jsou totiž symetrické podle nuly, např. ≡ − .

#define  −1
#define  −2

⟨ Pomocné funkce 6 ⟩ +≡ static int match(PATITEM ∗p) {

int m;

if (strchr(p str, c) ≠ Λ) m = 1; /∗ Znak nalezen ∗/

else m = −1; /∗ Znak nenalezen ∗/

switch (m ∗ p flag) {

case : return 0; /∗ Souhas, neni nutny posun ∗/

case :

if (p next ≡ Λ) return ;

return 1; /∗ Souhas, nutny posun o 1 ∗/ case : return ; /∗ Nesouhlas ∗/ case : ⟨ Vrať hodnotu podle následující pozice patternu 27 ⟩; } return 0; /∗ Tady bychom nikdy nemeli byt, return pro potlaceni varovani ∗/

}

27. O kolik pozic je třeba se posunout a s jakým výsledkem zjistíme rekurzivním voláním funkce match. ⟨ Vrať hodnotu podle následující pozice patternu 27 ⟩ ≡

switch (m = match(p next)) {

case  : return  ;
case  : return  ;

default : return 1 + m;

}

Tento kód je použit v sekci 26.

§28  VLNA  VLNKOVACÍ FUNKCE 13

28. Vlnkovací funkce. Nejprve připravíme globální deklarace pro ţvlnkovací� funkci tie. Funkce tie ţovlnkuje� vstupní soubor infile a vytvoří soubor outfile. Při silent = 0 tiskne závěrečnou zprávu o zpracování. V této zprávě se objeví jméno souboru, které se funkce ţdozví� prostřednictvím globální proměnné filename. Proměnná numline počítá řádky, proměnná numchanges sčítá změny, tj. počet doplněných vlnek. Proměnná mode nabývý některé z hodnot , , a podle stavu ve čteném textu.

#define  0
#define  1
#define  2
#define  3

⟨ Globální deklarace 4 ⟩ +≡ char ∗filename; /∗ jmeno zpracovavaneho souboru ∗/ long int numline, numchanges; /∗ pro zaverecnou statistiku ∗/ int mode;

29. Nyní definujeme vlnkovací funkci tie. Veškerá činnost se opírá o strukturu patternů. Výhodné je (z důvodu rychlosti) ţnatvrdo� zde implementovat jen přepínání mezi stavem čtení z oblasti komentáře (listpatt ≡ commentlist) a mimo komentář (listpatt ≡ normallist); ⟨ Vlnkovací funkce tie 29 ⟩ ≡

static void tie(FILE ∗input, FILE ∗output)

{ int ap; /∗ ap je pocet otevrenych patternu ∗/ register int k, m, n; int ic; PATTERN ∗pp; PATITEM ∗pi; ⟨ Inicializace proměnných při startu funkce tie 30 ⟩; while (¬feof (input)) {

if (ap ≡ 0 ∧ ind > ∧ c ≠ ) ⟨ Vyprázdni buffer 31 ⟩;

⟨ Otevři nové patterny 33 ⟩; /∗ 1. 2. 2010: prohozene poradi ∗/

if (ind ≥ ) { fprintf (stderr, ); exit( );

}

if ((ic = getc(input)) ≡ ) /∗ opravil Cejka Rudolf ∗/

break ; buff[ind^{++} ] = c = ic; if (c ≡ 0) continue ; /∗ 30. 4. 2009 ∗/ if (inz ≥ 8) {

for (inz = 0; inz < 4; inz^{++} ) buffnz[inz] = buffnz[inz + 4];

inz = 4; } buffnz[inz^{++} ] = c; if (c ≡ ) numline^{++} , listpatt = normallist; if (c ≡ ∧ mode ≠ ∧ buffnz[inz − 2] ≠ ) listpatt = commentlist; ⟨ Projdi otevřené patterny 32 ⟩;

}

⟨ Vyprázdni buffer 31 ⟩;

if (¬web) checkmode( ); /∗ zaverecna kontrola modu ∗/ if (¬silent) ⟨ Tiskni závěrečnou zprávu 35 ⟩;

}

Tento kód je použit v sekci 1.

14  VLNKOVACÍ FUNKCE  VLNA §30

30. ⟨ Inicializace proměnných při startu funkce tie 30 ⟩ ≡ for (k = 0; k < ; k^{++} ) lapi[k] = Λ; c = ; buff[0] = 1; mode = ap = 0; ind = 1; for (inz = 0; inz < 4; inz^{++} ) buffnz[inz] = 0; inz = 4; numline = 1; numchanges = 0; mode = ;

Viz také sekci 38. Tento kód je použit v sekci 29.

31. Při manipulaci s bufferem byl použit jeden trik. Veškeré načtené znaky začínají až od buff[1], zatímco buff[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 ţ � (například na výskyt sekvence je třeba reagovat jinak, než na výskyt obyčejného procenta). Kdybychm zazačali od buff[0], v některých situacích bychom se ptali, zda buff[−1] ≡ , tj. sahali bychom na neošetřené místo v paměti. Od 30. 4. 2009 tento problém pominul, protože se ptáme dozadu pouze v buffnz, ale vlastnost dříve implementovanou v buff jsem ponechal beze změny. ⟨ Vyprázdni buffer 31 ⟩ ≡

{ fwrite(& buff[1], ind − 1, 1, output); ind = 1;

}

Tento kód je použit v sekci 29.

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

Některé patterny v poli 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. ⟨ Projdi otevřené patterny 32 ⟩ ≡

n = ap; k = 0; while (n) {

while (lapi[k] ≡ Λ) k^{++} ; /∗ zastav se na prvnim ukazateli na pattern ∗/ switch (m = match(lapi[k])) {

case  : (∗lapt[k] proc)( );  /∗ Pattern nalezen, spustit proceduru ∗/
case  : lapi[k] = Λ;  /∗ Deaktivace patternu ∗/

ap^{−}; break ;

default :

while (m^{−}) lapi[k] = lapi[k] next; /∗ dalsi pozice patternu ∗/ } k^{++} ; n^{−};

}

Tento kód je použit v sekci 29.

33. 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 nebo . V takových případech ani nezanášíme ukazatel na pozici do pole lapi. ⟨ Otevři nové patterny 33 ⟩ ≡

pp = listpatt; if (c)

while (pp ≠ Λ) { switch (m = match(pp patt)) { case : (∗pp proc)( ); /∗ spustit proceduru ∗/ case : break ; default : ⟨ Vytvoř ukazatel na nový pattern a break 34 ⟩; } pp = pp next;

}

Tento kód je použit v sekci 29.

34. 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í ţdíru� v tabulce lapi a tam uhnízdíme nový ukazatel na pozici v patternu. ⟨ Vytvoř ukazatel na nový pattern a break 34 ⟩ ≡

pi = pp patt; while (m^{−}) pi = pi next; n = ap; k = 0; while (n) {

if (lapi[k] ≡ pi) break ; if (lapi[k^{++} ] ≠ Λ) n^{−};

} if (¬n) {

k = 0;

while (lapi[k] ≠ Λ) k^{++} ; if (k ≥ ) {

fprintf (stderr, ); exit( );

}

lapt[k] = pp;

lapi[k] = pi;

ap^{++} ; }

Tento kód je použit v sekci 33.

35. Poslední věcí ve funci tie je tisk závěrečné statistiky zpracování. ⟨ Tiskni závěrečnou zprávu 35 ⟩ ≡

fprintf (stderr, , filename, numline, numchanges);

Tento kód je použit v sekci 29.

16  INICIALIZACE PATTERNŮ  VLNA §36

36. 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. ⟨ Globální deklarace 4 ⟩ +≡

char tblanks[ ] = ; char blanks[ ] = ; char blankscr[ ] = ; char tblankscr[ ] = ; char nochar[ ] = ; char cr [ ] = ; char prefixes[ ] = ; char dolar[ ] = ; char backslash[ ] = ; char openbrace[ ] = ; char letters[ ] = ; PATTERN ∗vlnkalist, ∗mathlist, ∗parcheck, ∗verblist;

37. Začneme definicí nejčastěji používaného patternu na vlnkování uvnitř řádku. Připomeňme, že opakované volání funkce 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 normallist. Stejně tak opakované volání funkce setpi vytváří seznam pozic pro naposledy deklarovaný pattern. ⟨ Inicializace datových struktur 24 ⟩ +≡

vlnkalist = setpattern(vlnkain); setpi(tblankscr, ); setpi(tblanks, ); setpi(prefixes, ); setpi(charset, ); setpi(blanks, ); setpi(blanks, ); setpi(nochar, );

§39  VLNA  INICIALIZACE PATTERNŮ 17

38. ⟨ Inicializace proměnných při startu funkce tie 30 ⟩ +≡ listpatt = normallist = vlnkalist; 39. Vložení vlnky znamená vykonat následující práci: Zapamatovat si znak za skupinou mezer (do proměnné p). Pokud před tímto znakem předchází nulový byte, použijeme ho později, proto si jej uložíme do proměnné z. Dále se posuneme v bufferu vlevo přes všechny mezery, tabelátory (přesněji blanks) a přeskakujeme přitom všechny nulové byty. Index ind se zastaví na předložce. Posuneme jej doprava za předložku (++ind) a pokud tam je nulový byte a první znak tiestr není nulový, posuneme se až za tento nulový byte. Dále vložíme string tiestr, neboli vlnku. Nakonec připojíme zapamatovaný znak p, ovšem pokud před ním byla nula, vložíme ji ještě před znak p. ⟨ Pomocné funkce 6 ⟩ +≡

static void vlnkain(void ) {

int i; char p, z; ind^{−}; p = buff[ind^{−}]; z = buff[ind]; while (¬buff[ind] ∨ (strchr(blanks, buff[ind]) ≠ Λ)) ind^{−}; if (¬buff[^{++} ind] ∧ tiestr[0]) ind^{++} ; for (i = 0; i < tiestrlen; i^{++} ) buff[ind^{++} ] = tiestr[i]; i = tiestrlen; /∗ nulu pred p vlozime, pokud je z==0 a ∗/ if (¬tiestr[0]) i^{−}; /∗ pocet vlozenych znaku z tiestr ∗/ if (¬z ∧ (i % 2)) buff[ind^{++} ] = 0; /∗ je sudy ∗/ buff[ind^{++} ] = p; numchanges^{++} ;

}

40. Podobně pro tvorbu vlnky ţpřes řádek� vytvoříme pattern a kód procedury. ⟨ Inicializace datových struktur 24 ⟩ +≡

setpattern(vlnkacr); setpi(tblankscr, ); setpi(tblanks, ); setpi(prefixes, ); setpi(charset, ); setpi(blanks, ); setpi(cr , ); setpi(blanks, ); setpi(nochar, ); 41. V proceduře k tomuto patternu musíme ošetřit případ typu ţ �, kdy nelze prostě přehodit ţ � za ţ �, 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ž před znakem ţ �. Při důsledném ošetření tohoto fenoménu můžeme dokonce narazit na situaci ţ �, kde nemůžeme vložit ţ � před první výskyt ţ �, protože bychom dostali ţ �, tedy prázdný řádek. Ten je v TEXu interperetován odlišně. V této výjimečné situaci pouze zrušíme stávající (v pořadí druhé) ţ � a nebudeme vytvářet nové. Na výstupu bude soubor o jeden řádek kratší. ⟨ Pomocné funkce 6 ⟩ +≡

static void vlnkacr(void ) {

char p, z;

int i, j;

ind^{−};

p = buff[ind^{−}];

z = buff[ind];

while (¬buff[ind] ∨ (strchr(blankscr, buff[ind]) ≠ Λ)) ind^{−}; i = ind; /∗ misto predlozky, kterou chceme vazat ∗/ while (i ≥ 0 ∧ (strchr(blankscr, buff[i]) ≡ Λ)) i^{−}; j = i; while (i ≥ 0 ∧ (¬buff[ind] ∨ (strchr(blanks, buff[i]) ≠ Λ))) i^{−}; if (i ≥ 0 ∧ buff[i] ≡ ) j = −1; if (j ≥ 0) buff[j] = ; else numline^{−}; if (¬buff[^{++} ind] ∧ tiestr[0]) ind^{++} ; for (i = 0; i < tiestrlen; i^{++} ) buff[ind^{++} ] = tiestr[i]; i = tiestrlen; if (¬tiestr[0]) i^{−}; if (¬z ∧ (i % 2)) buff[ind^{++} ] = 0; buff[ind^{++} ] = p; numchanges^{++} ;

}

42. Nyní vytvoříme patterny pro případy typu . ⟨ Inicializace datových struktur 24 ⟩ +≡

setpattern(vlnkain); /∗ na radku ∗/ setpi(tblankscr, ); setpi(backslash, ); setpi(letters, ); setpi(letters, ); setpi(openbrace, ); setpi(prefixes, ); setpi(charset, ); setpi(blanks, ); setpi(blanks, ); setpi(nochar, ); setpattern(vlnkacr); /∗ pres radek ∗/ setpi(tblankscr, ); setpi(backslash, ); setpi(letters, ); setpi(letters, ); setpi(openbrace, ); setpi(prefixes, ); setpi(charset, ); setpi(blanks, ); setpi(cr , ); setpi(blanks, ); setpi(nochar, ); 43. Vytvoříme patterny a proceduru pro potlatčení tvorby vlnky u písmen těsně následujících sekvence a . Tj. nechceme, aby např z textu ţ � jsme dostali text s nesprávně vázaným písmenem ţ �. ⟨ Inicializace datových struktur 24 ⟩ +≡

normalpattern(tielock, ); setpi(blankscr, ); normalpattern(tielock, ); setpi(blankscr, );

44. Procedura tielock obsahuje nečistý trik. Při provádění procedury je právě načten znak z 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é c. Stačí tedy změnit hodnotu c a vlnkovací patterny se neotevřou. ⟨ Pomocné funkce 6 ⟩ +≡

static void tielock(void ) {

c = 1; }

45. Ošetříme nyní přechod do/z matematického režimu TEXu. 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. ⟨ Pomocné funkce 6 ⟩ +≡

static void printwarning(void ) {

if (¬silent)

fprintf (stderr, ,

filename, numline − (c ≡ ? 1 : 0)); status = ;

}

46. Začneme patterny pro přechod do/z matematického režimu, ohraničeného jedním dolarem, nebo v LaTEXu příslušnými sekvencemi. Sekvence LaTEXu a nejsou zahrnuty, protože bývají často předefinovány k jiným užitečnějším věcem. ⟨ Inicializace datových struktur 24 ⟩ +≡

if (¬nomath) { mathlist = setpattern(onedollar); setpi(dolar, ); setpi(dolar, ); if (latex) {

normalpattern(mathin, ); normalpattern(mathout, );

} }

47. ⟨ Pomocné funkce 6 ⟩ +≡ static void mathin(void ) {

if (mode ≠ ) printwarning( ); mode = ; normallist = listpatt = mathlist;

} static void mathout(void ) {

if (mode ≠ ) printwarning( ); mode = ; normallist = listpatt = vlnkalist;

} 48. Při programování procedury onedollar nesmíme zapomenout na výskyt sekvence . 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. ⟨ Pomocné funkce 6 ⟩ +≡

static void onedollar(void )

{ if (buffnz[inz − 3] ≡ ∨ (buffnz[inz − 3] ≡ ∧ buffnz[inz − 4] ≠ )) return ; if (mode ≡ ) printwarning( ); else {

if (mode ≡ ) mathin( );

else mathout( ); }

}

49. 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. ⟨ Inicializace datových struktur 24 ⟩ +≡

parcheck = setpattern(checkmode); setpi(cr , ); setpi(blanks, ); setpi(cr , );

50. ⟨ Pomocné funkce 6 ⟩ +≡ static void checkmode(void ) {

if (mode ≠ ) { printwarning( ); mode = ; normallist = listpatt = vlnkalist;

} }

51. Nyní ošetříme výskyt dvou dolarů, tj. vstup do/z display módu. Rovněž mysleme na LaTEXisty 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. ⟨ Inicializace datových struktur 24 ⟩ +≡

if (¬nomath) { normalpattern(twodollars, ); if (latex) {

normalpattern(displayin, ); normalpattern(displayin, ); normalpattern(displayout, ); normalpattern(displayout, );

} } 52. ⟨ Pomocné funkce 6 ⟩ +≡

static void displayin(void ) {

if (mode ≠ ) printwarning( ); mode = ; normallist = listpatt = parcheck;

} static void displayout(void ) {

if (mode ≠ ) printwarning( ); mode = ; normallist = listpatt = vlnkalist;

} static void twodollars(void ) {

if (buffnz[inz − 3] ≡ ) return ; if (mode ≡ ) displayout( ); else displayin( );

}

53. Následuje ošetření tzv. verbatim módu. Pro plain i LaTEX jsou nejčastější závorky pro verbatim mod tyto (variantu s používám s oblibou já). ⟨ Inicializace datových struktur 24 ⟩ +≡

if (¬noverb) { verblist = normalpattern(verbinchar, ); setpi(blankscr, ); setpi(blankscr, ); normalpattern(verbin, ); if (latex) normalpattern(verbin, );

} if (web) {

normalpattern(verbin, ); normalpattern(verbin, );

} if (¬noverb) {

verboutlist[0] = setpattern(verbout); setpi(verbchar, ); verboutlist[1] = normalpattern(verbout, ); if (latex) verboutlist[2] = normalpattern(verbout, );

} if (web) {

verboutlist[3] = normalpattern(verbout, ); normalpattern(verbout, ); normalpattern(verbout, );

} 54. Procedura verbinchar se od ţspolečné� procedury verbin liší v tom, že zavede do stringu verbchar momentální hodnotu proměnné c. Proto druhý výskyt této hodnoty verbatim režim ukončí. ⟨ Pomocné funkce 6 ⟩ +≡

int prevmode; PATTERN ∗prevlist, ∗verboutlist[4]; char verbchar[2]; static void verbinchar(void ) {

prevmode = mode; verbchar[0] = c; c = 1; listpatt = normallist = verboutlist[0]; prevlist = listpatt next; listpatt next = Λ; mode = ;

}

55. Při programování ţobecné� funkce verbin musíme dbát na to, aby zůstal aktivní pouze odpovídající ţ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 a v něm lokálně verbatim konstrukce). ⟨ Pomocné funkce 6 ⟩ +≡

static void verbin(void ) {

int i; i = 0; prevmode = mode; switch (c) { case : i = 1;

break ; case : i = 2;

break ; case : ; case : i = 3;

if (buffnz[inz − 3] ≡ ) return ; /∗ dvojity @ ignorovat ∗/ break ;

} listpatt = normallist = verboutlist[i]; prevlist = listpatt next; if (c ≠ ∧ c ≠ ) listpatt next = Λ; mode = ;

} 56. ⟨ Pomocné funkce 6 ⟩ +≡

static void verbout(void ) {

if (mode ≠ ) return ;

if (web∧ buffnz[inz − 2] ≡ ∧ buffnz[inz − 3] ≡ ) return ; mode = prevmode; normallist next = prevlist; switch (mode) { case : normallist = listpatt = parcheck;

break ; case : normallist = listpatt = mathlist;

break ; case : normallist = listpatt = vlnkalist;

break ; }

}

57. 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 lastpt. ⟨ Inicializace datových struktur 24 ⟩ +≡

lastpt = 0; commentlist = normalpattern(tieoff , ); normalpattern(tieon, );

58. ⟨ Pomocné funkce 6 ⟩ +≡ static void tieoff (void ) {

normallist = Λ; } static void tieon(void ) {

normallist = vlnkalist; }

59. 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  a  ).

24  REJSTŘÍK  VLNA §60

60. Rejstřík.

: \underline{17}, 25, 26, 37, 40, 42, 49, 53. : \underline{17}, 26. ap: \underline{29}, 30, 32, 34. argc: \underline{5}, 9, 14, 15. argv: \underline{5}, 9, 14, 15, 16. backslash: \underline{36}, 42. backup: \underline{11}, 15, 16. : \underline{4}, 9, 10, 14, 15. : \underline{4}, 20, 29, 34. : \underline{2}, 5, 6. blanks: \underline{36}, 37, 39, 40, 41, 42, 49. blankscr: 25, \underline{36}, 41, 43, 44, 53. buff: \underline{18}, 19, 29, 30, 31, 39, 41, 44. buffnz: \underline{19}, 29, 30, 31, 48, 52, 55, 56. : \underline{18}, 29. c: \underline{10}, \underline{18}. charset: \underline{7}, 9, 17, 37, 40, 42. charsetdefault: \underline{7}. checkmode: 29, 49, \underline{50}. commentlist: \underline{18}, 29, 57. cr : \underline{36}, 40, 42, 49. displayin: 51, \underline{52}. : \underline{28}, 48, 52, 56. displayout: 51, \underline{52}. dolar: \underline{36}, 46. : 29. exit: 9, 10, 14, 15, 20, 29, 34. f: \underline{12}. fclose: 14, 15. feof : 29. filename: 14, 15, \underline{28}, 35, 45. flag: \underline{17}, \underline{22}, 23, 26. fopen: 14, 15, 16. : \underline{26}, 27, 32, 33. fprintf : 5, 6, 12, 16, 20, 29, 34, 35, 45. fwrite: 31. getc: 29. hexnum: \underline{10}. i: \underline{10}, \underline{23}, \underline{39}, \underline{41}, \underline{55}. ic: \underline{29}. ind: \underline{18}, 29, 30, 31, 39, 41. infile: \underline{11}, 14, 15, 16, 28. input: \underline{29}. inz: \underline{19}, 29, 30, 48, 52, 55, 56. : \underline{4}, 14. ioerr : \underline{12}, 14, 15. isfilter: \underline{7}, 9, 13, 14, 15, 16. j: \underline{10}, \underline{11}, \underline{25}, \underline{41}. k: \underline{29}. lapi: \underline{18}, 30, 32, 33, 34. lapt: \underline{18}, 32, 34. lastpi: \underline{18}, 21, 22. lastpt: \underline{18}, 21, 22, 57. latex: \underline{7}, 9, 46, 51, 53. letters: \underline{36}, 42. listpatt: \underline{18}, 29, 33, 38, 47, 50, 52, 54, 55, 56. m: \underline{26}, \underline{29}. main: \underline{5}. malloc: 20. match: \underline{26}, 27, 32, 33. mathin: 46, \underline{47}, 48. mathlist: \underline{36}, 46, 47, 56. : \underline{28}, 47, 56. mathout: 46, \underline{47}, 48. : \underline{18}, 29. : 8, 10, \underline{11}, 16. : \underline{18}, 30, 34. mode: \underline{28}, 29, 30, 47, 48, 50, 52, 54, 55, 56. myalloc: \underline{20}, 21, 22. n: \underline{29}. next: \underline{17}, 21, 22, 26, 27, 32, 33, 34, 54, 55, 56. nochar: \underline{36}, 37, 40, 42. : \underline{26}, 27, 32, 33. nomath: \underline{7}, 9, 46, 51. normallist: \underline{18}, 29, 37, 38, 47, 50, 52, 54, 55, 56, 58. normalpattern: 20, 23, \underline{25}, 43, 46, 51, 53, 57. noverb: \underline{7}, 9, 53. numchanges: \underline{28}, 30, 35, 39, 41. numline: \underline{28}, 29, 30, 35, 41, 45. : \underline{4}, 5. : \underline{17}, 23, 25, 26, 37, 40, 42, 43, 46, 49, 53. : \underline{17}, 26, 37, 40, 42, 46, 53. onedollar: 46, \underline{48}. openbrace: \underline{36}, 42. outfile: \underline{11}, 14, 15, 28. output: \underline{29}, 31. p: \underline{20}, \underline{22}, \underline{26}, \underline{39}, \underline{41}. parcheck: \underline{36}, 49, 52, 56. PATITEM : \underline{17}, 18, 22, 26, 29. patt: \underline{17}, 21, 22, 33, 34. PATTERN : \underline{17}, 18, 21, 22, 25, 29, 36, 54. pi: \underline{29}, 34. pp: \underline{21}, \underline{25}, \underline{29}, 33, 34. prefixes: \underline{36}, 37, 40, 42. prevlist: \underline{54}, 55, 56. prevmode: \underline{54}, 55, 56. printusage: \underline{6}, 9, 10, 14, 15. printwarning: \underline{45}, 47, 48, 50, 52. proc: 17, 18, 21, 25, 32, 33. prog name: \underline{4}, 5, 12, 16, 20. pt: \underline{18}. remove: 15, 16. rename: 15, 16. rmbackup: \underline{7}, 9, 15, 16. s: \underline{10}. setpattern: 20, \underline{21}, 25, 37, 40, 42, 46, 49, 53. setpi: 20, 21, \underline{22}, 25, 37, 40, 42, 43, 46, 49, 53. settiestr: 9, \underline{10}. silent: 5, \underline{7}, 9, 16, 28, 29, 45. size: \underline{20}.

§60  VLNA  REJSTŘÍK 25

status: \underline{4}, 5, 15, 45. stderr: 5, 6, 12, 16, 20, 29, 34, 35, 45. stdin: 14. stdout: 14. str: \underline{17}, \underline{22}, \underline{25}, 26. strchr: 26, 39, 41. strcpy: 16. strings: \underline{23}, 24, 25. strlen: 10, 16. tblanks: \underline{36}, 37, 40. tblankscr: \underline{36}, 37, 40, 42. : \underline{28}, 30, 47, 48, 50, 52, 56. tie: 14, 15, 28, \underline{29}, 35. tielock: 43, \underline{44}. tieoff : 57, \underline{58}. tieon: 57, \underline{58}. tiestr: \underline{8}, 9, 10, 39, 41. tiestrlen: \underline{8}, 9, 10, 39, 41. twodollars: 51, \underline{52}. verbchar: 53, \underline{54}. verbin: 53, 54, \underline{55}. verbinchar: 53, \underline{54}. verblist: \underline{36}, 53. : \underline{28}, 29, 54, 55, 56. verbout: 53, \underline{56}. verboutlist: 53, \underline{54}, 55. vlnkacr: 40, \underline{41}, 42. vlnkain: 37, \underline{39}, 42. vlnkalist: \underline{36}, 37, 38, 47, 50, 52, 56, 58. : \underline{4}, 15, 45. web: \underline{7}, 9, 29, 53, 56. z: \underline{39}, \underline{41}.

⟨ Globální deklarace 4, 7, 8, 17, 18, 19, 23, 28, 36 ⟩ Použito v sekci 1.

⟨ Hlavičkové soubory k načtení 3 ⟩ Použito v sekci 1.

⟨ Hlavní program 5 ⟩ Použito v sekci 1. ⟨ Inicializace datových struktur 24, 37, 40, 42, 43, 46, 49, 51, 53, 57 ⟩ Použito v sekci 5.

⟨ Inicializace proměnných při startu funkce tie 30, 38 ⟩ Použito v sekci 29. ⟨ Lokální proměnné funkce main 11 ⟩ Použito v sekci 5. ⟨ Načtení parametrů příkazového řádku 9 ⟩ Použito v sekci 5. ⟨ Otevři nové patterny 33 ⟩ Použito v sekci 29. ⟨ Přejmenuj vstup argv[0] na backup a otevři jej jako infile 16 ⟩ Použito v sekci 15.

⟨ Pomocné funkce 6, 10, 12, 20, 21, 22, 25, 26, 39, 41, 44, 45, 47, 48, 50, 52, 54, 55, 56, 58 ⟩ Použito v sekci 1.

⟨ Projdi otevřené patterny 32 ⟩ Použito v sekci 29. ⟨ Tiskni závěrečnou zprávu 35 ⟩ Použito v sekci 29. ⟨ Vlnkovací funkce tie 29 ⟩ Použito v sekci 1. ⟨ Vrať hodnotu podle následující pozice patternu 27 ⟩ Použito v sekci 26.

⟨ Vyprázdni buffer 31 ⟩ Použito v sekci 29.

⟨ Vytvoř ukazatel na nový pattern a break 34 ⟩ Použito v sekci 33.

⟨ Zpracování souborů 13 ⟩ Citováno v sekci 6. Použito v sekci 5.

⟨ Zpracování všech souborů příkazové řádky 15 ⟩ Použito v sekci 13. ⟨ Zpracování v režimu filter 14 ⟩ Použito v sekci 13.

VLNA

Sekce Strana

PROGRAM VLNA . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1 1 Parametry příkazového řádku . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6 3 Zpracování souborů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 11 6 Patterny . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17 8 Vlnkovací funkce . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28 13 Inicializace patternů . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 36 16 Rejstřík . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 60 24