Projektová dokumentace

Links
webový prohlížeč
Mikuláš Patočka, Martin Pergel, Petr Kulhavý, Karel Kulhavý

Obsah

\maketoc

Úvod

Toto je projektová dokumentace k programu Links. Dočtete se zde o průběhu vývoje, historii, účastnících a výsledku projektu. Tištěná verze dokumentace neobsahuje projektovou korespondenci. Plnou verzi dokumentace najdete ve formátu PDF na CD s programem.

Links je prohlížeč webových stránek pro operační systémy Unix a OS/2. Prohlížeč je možno provozovat v textovém i grafickém režimu. V grafickém režimu pod systémy X-Window, SVGAlib, AtheOS a Pmshell. Prohlížeč podporuje javascript (verzi 1.1 od Netscape Corporation), protokoly HTTP 1.0 i 1.1, FTP, Finger a SSL, formáty HTML verzi 4.0 bez CSS a obrázky GIF, XBM, TIFF, JPEG a PNG.

Zadání

Předmětem projektu je webový prohlížeč napsaný v jazyce C pod operačním systém Linux. Základní engine (FTP, HTTP requester, formátovač HTML apod.) budou napsány účastníky projektu. Kód psaný jinými lidmi může být použit v případě knihoven pro zpracování datových formátů (jpeg, png, mpeg, gif, ogg atd.). Knihovny pro práci s HTTP nebo FTP nebudou použity.

Prohlížeč by měl být stabilní, jeho výstup pokud možno kvalitní (snadno čitelný) a uživatelský komfort takový, aby se prohlížeč dal používat pro každodenní, rychlé a jednoduché browsení po Internetu. Největší důraz se bude klást na stabilitu, neboť pád prohlížeče znamená velké nepříjemnosti pro uživatele.

Středně velký důraz se poklade na kvalitu výstupu (z hlediska kvality obrazu, formátování dokumentu), neboť browsery se v dnešní době používají po relativně velké procento času stráveného u počítače a pohodlí očí je předpokladem pro úspěšnou a plynulou práci u počítače. Vedle kvality výstupu bude stát i rychlost, zejména bude žádoucí, aby v typickém případě byl prohlížeči proces limitován šířkou pásma přenosové cesty a nikoliv výkonem procesoru a grafického systému. V případě konfliktu mezi kvalitou a rychlostí se bude volit kvalita, pokud ovšem by zvýšení kvality přineslo neúměrné zpomalení, rychlost bude mít přednost.

Na poslední příčce žebříčku bude umístěn uživatelský komfort, který bude minimální, ale promyšlený a především takový, aby při práci s prohlížečem nezdržoval a nevyžadoval studium zdlouhavé dokumentace k uživatelskému rozhraní. Mezi komfort řadíme i přenositelnost na běžné operační systémy, kde přenos kódu nečiní větší potíže, protože transparentnost práce v multiplatformních prostředích přináší uživateli podstatně vyšší komfort, aniž by to bylo znatelné na úkor jiných funkcí prohlížeče.

Předpokládané vlastnosti prohlížeče:

Proč jsme si tento projekt vybrali

Existuje již mnoho prohlížečů webových stránek, leč žádný neodpovídal našim představám na stabilitu, bezpečnost, kvalitu výstupu a v neposlední řadě i rychlost. Navíc většina webových prohlížečů má překombinované a zbytečně složité ovládání, které znepříjemňuje práci uživatele.

Konkurenční prohlížeče se zaměřují více na používání tzv. progresivních technologií a podporování nejnovějších featur, než na stabilitu, přenositelnost a rychlost. Co se týče interpretace javascriptu, konkurenční prohlížeče se opět zaměřují na podporování nejnovějších vymožeností jazyka (nejlépe takových, které s jinými prohlížeči nefungují) a jsou velice nestabilní. Dalo by se říci, že javascript vládne nad uživatelem, místo, aby uživatel vládl nad javascriptem. Pro všechny konkurenční prohlížeče (Netscape, Mozilla, Opera, Konqueror, Internet Explorer) existuje javascriptový kód o délce pár řádek, který učiní prohlížeč neovladatelný a je ho nutno restartovat, nebo ještě hůře provedou na uživatelův počítač útok typu DoS (ať už obrovskými nároky na paměť či spotřebováním veškerého procesorového času).

Proto jsme se rozhodli napsat vlastní webový prohlížeč. Cílem projektu bylo napsat kvalitní, rychlý, bezpečný a stabilní, přesto jednoduchý, prohlížeč webových stránek. Důraz byl kladen především na stabilitu, kvalitu výstupu a rychlost. Za žádnou cenu by neměl havarovat, znemožnit uživateli ovládání, nebo si činit nepřiměřené nároky na paměť nebo procesor. Prohlížeč měl být přenositelný na většinu Unixů a zkompilovatelný s minimálními požadavky na systém.

Účastníci projektu

Tým řešitelů, pod vedením Mgr. Davida Bednárka, se skládal z těchto členů:

Původně měl v týmu být ještě Jakub Drnec, ale ten odešel z fakulty a proto jsme zbyli jen čtyři. První rok projektu byl vedoucím Petr Merta, ale ten po roce odešel a projekt převzal Mgr. Bednárek.

Na prohlížeči se podíleli i další lidé, kteří zejména přeložili texty do rozličných cizích jazyků. Tito lidé jsou uvedeni na konci v kapitole Zásluhy.

Struktura programu

V této kapitole se dočtete hrubé rozdělení projektu na jednotlivé části a pak kdo které části psal. Detailnější popis struktury projektu najdete ve vývojové dokumentaci.

Základem celého prohlížeče je scheduler nebo též select smyčka . Zde se plánují všechny události, které mají nastat, a odtud se volají jednotlivé části prohlížeče. Select smyčka je kooperativní scheduler. Všechny části prohlížeče jsou napsány tak, aby v nich řízení nezůstávalo příliš dlouho, protože by nemohly být volány jiné části, což by se například projevovalo nereagováním na pokyny uživatele.

Další velmi důležitou částí je session , která zajišťuje management stahování, formátování a zobrazování dokumentů, ovládání, pohyb po dokumentu a vykonávání javascriptu. Session samotná nic nevykonává, pouze volá další části, které již jednotlivé činnosti provádějí. Session volá object requester, javascript, HTML parser a část zajišťující zobrazování a interakci s uživatelem.

Object requester se stará o stahování dokumentů ze sítě. Object requester volá scheduler requestů , na který je napojena souborová cache na všechny soubory stažené ze sítě a rozhraní jednotlivých protokolů (HTTP, HTTPS, FTP, finger a nahrávání z lokálního disku).

HTML parser zpracovává HTML dokumenty a převádí je do vnitřních struktur prohlížeče. View , neboli zobrazovač , se stará o zobrazování dokumentu, lámání textu a vyřizování událostí od uživatele (stisky kláves, pohyb myši, klikání ...). Krom pohybu po dokumentu ještě uživatel může používat nabídky, část, která se o toto stará se příznačně jmenuje menu . Zobrazovač volá funkce jednotlivých zobrazovacích ovladačů: terminálu, X, SVGAlib .... V grafickém režimu je potřeba sázet písmo, o to se stará část jménem fonty , která obsahuje fontovou cache a grafické rutiny pro zpracování a tisk písma.

Javascript se skládá z lexikálního analyzátoru, syntaktického analyzátoru, interpretu a vestavěných funkcí. Mezi javascriptem a session sídlí rozhraní javascriptu , které zprostředkovává přístup javascriptu k vnitřním strukturám prohlížeče (dokumentu, obrázkům, odkazům, formulářům, ...) a obsahuje funkce, kterými se zahájí a ukončí interpretace javascriptového kódu, a podobně. S javascriptem také souvisí event handlery , což jsou kusy kódy, které se volají při rozličných událostech, zejména vyvolaných uživatelem. Například při kliknutí na tlačítko, přejetí myší, nahrání dokumentu, stisknutí klávesy, změně textového políčka atd. Event handlery jsou zabudovány přímo do zobrazovače

Rozdělení práce:

\penalty -10000

Historie

Následuje vývoj "links-current":

Schůzky projektu se konaly velmi často, většinou v menze ve frontě na oběd, u oběda, v počítačové laboratoři, při seancích 0verkillu a kdykoliv jsme se viděli jsme probírali problémy projektu, nové věci, co je potřeba napsat a další. Mnoho věcí jsme též probírali mailem nebo talkem. Projekt měl tři oficiální schůzky s vedoucím, první při vypsání projektu, druhá po půl roce a třetí opět po dalším asi půl roce. Projekt jsme psali samostatně, pouze tu a tam jsme se potřebovali poradit s vedoucím. Vedoucímu jsme pravidelně psali zprávy o stavu projektu.

Problémy a~rozhodnutí

V této kapitole rozebereme problémy, se kterými jsme se při vývoji projektu potýkali, a důležitá rozhodnutí, před kterými jsme stáli, včetně jejich řešení.

Scheduler

Rozhodli jsme se napsat vlastní scheduler událostí namísto multithreadového nebo multiprocesového prohlížeče. Mikuláš kdysi asi dva dny zkoušel psát multithreadovou variantu, ale moc se mu to nelíbilo, tak to smazal a napsal vlastní scheduler. Mít vlastní scheduler je efektivnější a jelikož je kooperativní, tak jednotlivé části se mohou mezi sebou snáze přepínat a nemusí na sebe složitě čekat.

Grafická rozhraní

Při psaní ovladače pro grafický systém X-Window jsme měli možnost vybrat si z množství již existujících toolkitů, leč této možnosti jsme nevyužili a napsali jsme ovladač přímo s použitím knihovny Xlib. To z důvodu, že toolkitů je mnoho a každý používá jiný. Tudíž by byl uživatel potenciálně nucen instalovat na svůj počítač další knihovny, čímž by se instalace zbytečně komplikovala. Navíc, když je toolkitů tolik, tak není důvod použít jeden konkrétní toolkit a ne jiný. Použití toolkitu by mělo za výhodu pouze podobnost s jinými aplikacemi a usnadnění práce při programování. My jsme se ale snažili o maximální podobnost s ovládáním v textovém režimu, k čemuž nebylo možno žádný toolkit použít.

Grafické rozhraní jsme navrhli na nízké úrovni, aby bylo portabilní, jednoduché a aby bylo možno snadno přidat nový grafický ovladač. Rozhraní obsahuje elementární funkce pro nakreslení bitmapy, vybarvení plochy, nakreslení čáry, scroll a podobně. Tyto funkce lze velice snadno napsat na libovolném grafickém rozhraní.

Díky návrhu grafického rozhraní prohlížeč v okenních systémech používá pouze jedno okno. To má za výhodu snadnou predikovatelnost, kde které okno bude, okno se nemůže ztratit na vedlejší obrazovce ani nemůže být přikryto jiným oknem, čímž se zvyšuje komfort uživatele.

SVGAlib

Na starších SVGAlibách Links nemusí fungovat, neboť ty obsahují různé chyby, jako například vadný kód, který při provádění grafických operací kreslí nesmysly. Pouštění Links na starších SVGAlibách může představovat bezpečnostní riziko, protože například SVGAlib 1.2.10 se nesprávně vzdávala rootovských práv.

Za toto nemůže Links, ale návrháři SVGAlib. Já (Karel Kulhavý) jsem názoru, že SVGAlib je broken-by-design a měla by se přepsat, což ovšem není v rámci projektu Links. Jsem dále toho názoru, že VT_ACTIVATE API v kernelu Linuxu je broken by design a že by se také mělo přepsat, což ovšem není v rámci projektu Links.

I nová SVGAlib má chyby ve funkci vga\_setlinearaddressing (které se projevují například na kartě S3 Virge 3d), kvůli kterým musela být tato funkce v Links zakomentována (tak, jak je to například v programu Quake). Díky tomu je Links pomalejší v určitých případech, za což nemůže Links, ale opět SVGAlib.

Některé grafické funkce ve SVGAlib byly tak zabugované, že nefungovaly vůbec, a musely být emulovány pomocí funkcí primitivnějších, například vyplňování oblastí pomocí putpixel (2-barevné režimy). Vzhledem k tomu, že i toto rozhraní kreslilo nesmysly, a vzhledem k tomu, že 2-barevné režimy neumí zobrazit žádné barvy, bylo nakonec od nich upuštěno a byly z Links odstraněny.

Links používá akcelerační primitiva SVGAlib v případě, kdy je SVGAlib podporuje. Problém je, že SVGAlib je pro většinu karet nepodporuje, alespoň ne pro tu, ke kterým měl tým Links přístup. Vzhledem k celkové koncepci SVGAlib se dá předpokládat, že budou masivně zabugované a že tedy Links bude na některých kartách těžce shazovat systém. To není problém Links, ale SVGAlib.

Framebuffer

Psaní grafického ovladače pro framebuffer na Linuxu bylo velmi nesnadné díky velmi špatné nebo úplně chybějící dokumentaci. Proto není zaručena stoprocentní spolehlivost a to, že ovladač bude fungovat se všemi grafickými kartami na všech počítačích. Dokumentaci jsme byli velmi často nuceni nahrazovat luštěním zdrojových textů linuxového kernelu, čtením grafických ovladačů pro jednotlivé grafické karty a čtením velmi strohých komentářů v hlavičkových souborech rozhraní framebufferu. Tyto podmínky nám velmi znesnadňovaly práci a zbytečně prodlužovaly dobu vývoje. Mnohé věci jsme museli zjišťovat přímo u autorů linuxového jádra nebo empiricky ozkoušet chování a dle něj usoudit, jak se rozhraní používá. Tento způsob se nám jeví jako velmi nečistý, leč díky absenci kvalitní dokumentace k rozhraní jsme neměli jinou možnost.

Při psaní framebufferu jsme potřebovali zjišťovat pozici myši. K tomu jsme použili knihovnu gpm , pomocí které se zjišťuje stav myši i na terminálu (v textovém módu). Framebuffer je de-facto terminál s možností grafického výstupu. Framebuffer žádné vlastní rozhraní pro myš neposkytuje, pouze umožňuje grafický výstup na obrazovku. Na terminálu jiný způsob čtení myši nepřipadá v úvahu, protože ne na každém počítači má běžný uživatel přístup k zařízení myši (například /dev/mouse ). Knihovna gpm čte zařízení myši a umožňuje uživatelským programům přes socket zjišťovat polohu a stisknutí tlačítek. Naštěstí na většině počítačů s Linuxem je gpm nainstalováno a tedy ho lze použít.

Problém je ale v tom, že gpm je striktně textové, tedy se kurzor pohybuje po znacích a nikoliv po pixelech. Zkoušeli jsme číst myš po znacích a špinavým trikem podvrhnout větší rozměry obrazovky, ale to se staršími verzemi gpm nechodilo. Proto jsme udělali čtení relativních pohybů myši, které funguje se všemi verzemi. Problém je ale v tom, že myš se pohybuje příliš pomalu. Proto jsme nakone stejně museli vynásobit relativní pohyb konstantou a tedy opět není možno pohybovat s myší plynule a reálně hrozí nebezpečí, že na obrazovce bude místo, kam uživatel nebude moci kliknout, přestože to bude nutné. Částečně lze tento problém odstranit zvětšením písma a obrázků, ale bohužel ho nejde odstranit úplně. V rámci pokusů o nápravu této situace jsme ve Framebufferu umožnili pohybovat myší po pixelech klávesami F5 -- F8.

Citlivost myši si klientský program gpm bohužel nemůže nastavit, protože ji nastavuje administrátor "natvrdo" při pouštění gpm daemona. Proto jsme zvolili kompromis mezi citlivostí a přesností. Kurzor se po obrazovce pohybuje tedy přijatelně.

Teoreticky by bylo možné do gpm podporu grafiky dopsat, neboť gpm je šířené pod licencí GPL. Dopsat podporu grafiky by neměl být veliký problém, je i jistá šance, že kdyby se upravená knihovna poslala autorům, autoři by ji v příští verzi vydali i s touto grafickou podporou. Problém ale tkví v tom, že ne každý by měl na počítači nainstalovánu tuto nejnovější verzi, tedy opět bez administrátorských práv by uživatel nemohl na framebufferu myš používat. Toto by spíše bylo dlouhodobější řešení, neboť by se dalo počítat s tím, že by se grafická verze gpm rozšířila.

Pro uživatele, kteří mají administrátorská práva jsme vytvořili patch, po jehož aplikaci na gpm se kurzor bude po obrazovce pohybovat plynule. Patch je distribuován společně s prohlížečem, je uložen v souboru PATCH-gpm-1.20.0-smooth-cursor . Patch byl vyroben pro verzi gpm 1.20.0, ale s jinými verzemi pravděpodobně bude fungovat též, případně po malé úpravě.

Framebuffer se nám podařilo implementovat pouze na architektuře Intel. Měli jsme přístup ještě k počítačům architektury Sparc, na kterých též běžel Linux s framebufferem, ale tyto počítače nemají lineární mapování videopaměti, což komplikuje implementaci. Jelikož jsme neměli dokumentaci, nelineární mapování paměti jsme nepodpořili.

Javascript

Interpret jsme se rozhodli psát od základu, protože jsme došli k názoru, že interpret javascriptu v Links může být užitečný. Navíc Mgr. Bednárek na Překladačích prohlásil, že vyrábět překladač nebo interpret od základu se stane málokomu a my považujeme návrh a výrobu překladače za činnost neobyčejně zajímavou, byť poněkud náročnější.

Gramatika

Prvním problémem, se kterým jsme se setkali při psaní javascriptu, bylo sehnat normu, dle které bychom se měli řídit. Asi měsíc jsme usilovně sháněli na Internetu, ale nic jsme nemohli najít. Podařilo se nám sehnat normu ECMA 262 popisující gramatiku ECMA scriptů, ale v té době jsme ještě neměli nejmenší tušení, že existuje norma Javascript 1.3, o to menší, že se řídí gramatikou ECMA 262. Pak se kdesi podařilo najít normu Javascript 1.1 od Netscape Corporation (nikoliv na stránkách firmy Netscape), podle které jsme postupovali. O normě Javascript 1.3 jsme se dozvěděli asi rok po nalezení normy 1.1 a po začátku její implementace.

Javascript 1.1 měl gramatiku jednodušší než byla gramatika ECMA 262 --- neobsahovala dvojredukční konflikty a skoro žádné shift-redukce konflikty. V gramatice ECMA byly desítky až stovky dvojredukčních konfliktů a shift-redukčních konfliktů.

Document-object model jsme převzali z Netscape 2.0 podle nalezené dokumentace. Přidali jsme některá vylepšení.

Parser

Při navrhování parseru javascriptu jsme měli možnost napsat lexikální i syntaktický analyzátor buďto vlastní, nebo použít již existující nástroje Bison a Flex pro výrobu syntaktických a lexikálních analyzátorů.

V případě syntaktického analyzátoru jednoznačně zvítězila strojová výroba analyzátoru, neboť gramatika je pro ruční výrobu analyzátoru příliš složitá. Gramatika obsahuje 131 pravidlo a automat z Bisonu čítá 212 stavů. Výsledný syntaktický analyzátor je tedy LALR(1). V gramatice je cca 40 konfliktů typu shift-redukce, které se řeší předností operace shift. Gramatiku jsme po stažení strojově přepsali do tvaru akceptovatelném Bisonem, akce, které se mají provádět při redukcích jsme poté dopsali ručně.

Pro lexikální analýzu jsme použili nástroj Flex, protože ruční psaní automatu je zdlouhavé a většinou výsledný automat obsahuje mnoho chyb. Při použití programu Flex bylo potřeba předefinovat funkce getcungetc , protože se nepodařilo zjistit, jak jinak donutit Flex číst vstup z paměti a ne ze streamu.

S rozhodnutím použít Flex a Bison je spojen problém, co když uživatel nebude mít na svém počítači tyto nástroje? Přece jen tyto nástroje nejsou (narozdíl od překladače jazyka C) na systémech Unix úplně obvyklé. Proto jsme se rozhodli do zdrojové distribuce přiložit výstupy z uvedených nástrojů (tedy zdrojové soubory v jazyce C). V distribuci samozřejmě jsou též vstupní zdrojové texty pro nástroje Flex a Bison, takže je možno automaty kdykoliv znovu vygenerovat.

Mezikód

Na základě rady Mgr. Bednárka byl interpret javascriptu rozdělen na parser s generátorem mezikódu a interpret mezikódu, protože bez rozdělení by se v automatech generovaných Flexem a Bisonem špatně implementoval multitasking. Tudíž by se muselo čekat, až skript doběhne, a teprve pak by se mohlo pokračovat.

Formu mezikódu jsme zvolili stromovou, nyní již opravdový DAG, aniž by byly prováděny jakékoliv optimalisace. Stromový mezikód jsme si zvolili, protože strom je přímo výstupem syntaktické analýzy. Kdybychom měli generovat čtveřicový nebo trojicový mezikód, trvalo by nějaký čas jeho generování, což by zdržovalo interpretaci krátkých skriptů, které jsme chtěli být schopni interpretovat rychle. Po konsultaci s kolegou Hubičkou, který prohlásil, že stromový mezikód je lépe interpretovat zásobníkem, jsme se rozhodli napsat interpret zásobníkový.

Strom mezikódu obsahuje v každém uzlu informaci o čísle řádky, na kterém se dotyčný kus kódu nalézá, informaci o operátoru a místo pro 6 argumentů. Argumenty šlo též uložit například ve spojovém seznamu, v poli proměnlivé délky nebo v jiné datové struktuře. Jelikož operátor nemůže mít nikdy proměnný počet argumentů, tak jsme zvolili pole pevné délky, které má i tu výhodu, že přístup k prvku je v konstantním čase.

Jména jsou překládána na klíče, jejichž seznam je zahashován. Identifikátory mají klíče v rámci jednoho kontextu jednoznačné. Toto řešení bylo zvoleno pro zajištění vyšší rychlosti interpretace. Rozhraní je navrženo tak, aby byla možnost měnit velikost "adresných prostorů", zatím je velikost 128 adres, což je kompromis mezi velikostí a počtem kolizí. Podle teoretických propočtů je při kvadratické velikosti hashovacího pole střední počet pokusů na hledání konstantní. T.j. prvních 11 záznamů by mělo zkolidovat s $P\le50\ hashovací tabulky je aplikováno MFR, které vykazuje výsledky nejvýše $2\times$ horší než optimální samoudržující seznam (viz. \odkaz{RNDr. Koubek: Datové struktury}).

Identifikace pomocí klíčů sice znamená značné urychlení, ale občas naopak škodí --- například když se má vyhledat objekt definovaný v dokumentu. V mnoha případech je však výhodná, jelikož interpretace sestává zejména z vyhledávání identifikátorů a při nastavení podle normy aspoň první hledání probíhá vždy interně v javascriptu, druhé hledání při aspoň druhém přístupu taktéž (například document.object. ...).

Bezpečnost

Rozhraní javascriptu je navrženo tak, že nedovolí přístup javascriptu k "cizím" objektům. Cizí objekty jsou všechny objekty v dokumentech z jiných serverů, než je server, z kterého pochází dokument v němž běží přistupující javascript. Všechny upcally, které pracují s nějakými objekty, si striktně testují tato přístupová práva, takže javascript "cizí" objekty vůbec nevidí a má dojem, že ani neexistují.

Po upozornění, že v interpretu může přetéct mnoho věcí, rozhodli jsme se napsat "účtování paměti". Uživatel má možnost nastavit maximální velikost paměti, kterou smí javascript naalokovat. Po přetečení tohoto limitu při konci elementárního kroku interpretace, je skript (kontext) zabit a udělána na něm "čistka", aby se část paměti uvolnila a mohly pokračovat ostatní kontexty. Účtování je možné provést buďto pro každý kontext zvlášť, nebo pro všechny najednou. Kdyby se účtovalo každému kontextu zvlášť, hrozilo by nebezpečí, že by skript otevřel mnoho kontextů, jimiž by vyčerpal paměť. Proto jsme zvolili variantu účtování paměti pro všechny kontexty.

Přetečení by bylo možné kontrolovat přímo v alokační funkci, ale nastal by problém, jak skript z alokační funkce ukončit. Proto se v alokační funkci paměť naalokuje vždy a přetečení se kontroluje až na konci funkce zvykni . Jelikož tato funkce provádí pouze elementární kroky interpretace, nehrozí naalokování příliš velkého kusu paměti v jednom kroku a tedy tato metoda je bezpečná. Dle našich propočtů by v elementárním kroku obsazená paměť neměla narůst více než lineárně.

S paměťovou náročností javascriptu souvisí i potenciální nebezpečí přetečení zásobníku puštěním například nekonečné rekurse. K ošetření tohoto nebezpečí jsme zavedli omezení maximální hloubky rekurse --- uživatel má opět možnost v menu nastavit.

Kvůli možnosti vyhladovění interpretu spuštěním nekonečné smyčky, bylo rozhodnuto, že interpret musí po konečném čase vrátit řízení a přeplánovat se. Scheduluje se tedy po vygenerování mezikódu a pak po stonásobném zavolání funkce zvykni (100 je empirická konstanta, která vykazuje relativně uspokojivý poměr cena/výkon), navíc se interpretace přeruší při některých upcallech. V rámci jednoho kontextu smí běžet nejvýše jedno vlákno. Běh ve více kontextech najednou však není nikterak omezen a nastává dokonce velmi často. Počet kroků do "preempce" lze změnit konstantou v době kompilace. Bylo by možné nechat tuto konstantu měnit uživatelem za běhu, ale obávali jsme se, že někteří uživatelé by význam tohoto nastavení nepochopili a jen by zkoušeli, jaké hodnoty lze nastavit, interpret by pak buďto skripty interpretoval pomalu, nebo by měl příliš dlouhou dobu odezvy při stisku klávesy.

Po zkušenostech s ostatními prohlížeči jsme dospěli k závěru, že tato bezpečnostní opatření nestačí. Útok může být proveden například vypisováním výstrah v nekonečné smyčce, neustálou změnou URL a podobně. Právě tento typ útoku žádný existující prohlížeč nevydrží. Stačí například takovýto jednořádkový kód:

while(1)alert("Jsi BFU!");
Toto není typický DoS útok, který by například spotřeboval veškerou paměť nebo 100 \ času, proto naň patrně autoři ostatních prohlížečů nemysleli. V případě tohoto útoku je uživatel nucen neustále odklikávat okénka javascriptu, díky čemuž se nedostane k ostatním ovládacím prvkům. Nejedná se tedy útok na počítač, ale na uživatele. Některé prohlížeče (například Netscape Navigator) ani nečekají na odezvu uživatele ale vytvářejí stále další a další okénka, čímž pochopitelně znemožní používat i ostatní aplikace.

Proto jsme se rozhodli pro řešení jednoduché, leč účinné, a to umožnit uživateli v každém okénku vytvořeném javascriptem skript ukončit. V případě změny URL, otevírání a zavírání okna prohlížeče se prohlížeč uživatele zeptá, zda dovolí tuto akci javascriptu provést. Uživatel má možnost povolit, odmítnout nebo ukončit skript. Tím se znemožní javascriptu znepříjemňovat uživateli život nevyžádaným měněním URL, zavíráním okna prohlížeče nebo zaplavováním novými a novými okny.

Chyby a~upozornění

Norma javascriptu říká, co je správně a co ne, značně nejasně. Proto, pokud je to možné, chyby při interpretaci ignorujeme, navíc jsme dali k disposici možnost uživateli nastavit tolerantnost interpretu k chybám. Některé chyby rovnou ignorujeme a jen na ně upozorníme warningem --- výstrahou. Umožňujeme všechny typové konverze automaticky, stejně jako vypnutí hlášení o chybách, vypnutí celého javascriptu nebo okamžité zastavení všech v současné chvíli běžících interpretacích, nemluvě o možnosti při každém projevu oknem javascript zabít (má-li to ještě smysl).

Error znamená definitivní konec interpretace v daném kontextu, tzn. v daném kontextu jsou další skripty již ignorovány, takže u stránek na javascriptu založených a špatně napsaných nezbývá nežli kouknout do zdrojového textu stránky, pochopit, co asi skript měl znamenat, interpretovat si jej sám a provést eventuální požadované akce (například změnu URL) ručně. Zabití všech skriptů má za následek vyvolání erroru ve všech existujících kontextech, proto je na stránkách obsahujících odkazy jen přes javascript krajně nevhodné požádat o vybití skriptů.

Rozhodnutí nepokračovat po erroru v interpretaci je podporované tím, že po syntaktické chybě by bylo třeba zneplatnit některé funkce a zrušit kus stromu. Další interpretace se typicky odkazují na předchozí výsledky, takže by stejně vedla k chybě. K pokračování po sémantické chybě by bylo třeba odstraňovat problémy se zásobníky rodičů a argumentů a kouzlit s "adresovými prostory". Stačí, že podobné magie je zapotřebí při operacích break , return či continue . Vznikaly by chyby "zřetězené" nebo lépe "zavlečené" předchozími. Nepokračování po chybě je obvyklé i u ostatních browserů.

Vzhledem k tomu, že autoři javascriptů často neuvádějí objekt dokument, když přistupují k jeho prvkům, rozhodli jsme se umožnit resoluci jmen v hlavním adresním prostoru, ale pouze, když si to uživatel vyžádá. Uživatel má možnost v menu zaškrtnout povolení globální resoluce jmen. Standardně je toto nastavení zapnuté. Možnost vypínání jsme uživateli dali z toho důvodu, že globální resoluce je pomalejší nežli lokální a také proto, že to tak některé stránky vyžadují.

Obrázky

V první implementaci obrázků byl zobrazovač obrázků (dekodér a ditherovací engine) nerestartovatelný, což se ukázalo jako značný nedostatek, neboť zobrazování obrázků bylo velmi pomalé a blokovalo ostatní činnosti prohlížeče. Proto jsme museli zobrazovač obrázků přepsat do restartovatelné verze, aby bylo možno uprostřed dekódovaní a ditherování přeschedulovat.

TIFF

Rozhodli jsme se podpořit grafický formát TIFF. Tento formát se sice na webu příliš nevyskytuje, ale občas se najdou některé důležité dokumentace, které se v jiném formátu nenajdou. K dekódování jsme se použili knihovnu libtiff , protože díky mnoha variantám a rozmanitosti formátu by bylo ruční psaní dekodéru časově příliš náročné. Formát TIFF specifikuje, že dekódovat se smí až po natažení celého souboru. Tedy TIFFy se uživateli nebudou zobrazovat průběžně během natahování ze sítě. To ale není chyba Links, nýbrž vlastnost formátu TIFF.

Jiné prohlížeče TIFF standardně nepodporují, potřebují na jeho zobrazování plugin. To je ovšem na škodu, neboť TIFF není úplně nepoužívaný formát.

JPEG~2000

Při psaní dekodérů pro různé grafické formáty jsme chtěli napsat i podporu pro nový standard JPEG 2000, který nás zaujal svojí vysokou kompresí. Byli jsme toho názoru, že tento formát bude v budoucnosti zajisté používán, tedy jeho podpora by byla dobrou investicí do budoucnosti. Bohužel jsme ale nenalezli žádnou open source knihovnu podporující tento formát. Ruční psaní dekodéru waveletů by byla časově poněkud náročná činnost, proto jsme od podpory tohoto formátu upustili. Nicméně až bude k disposici platformě nezávislá knihovna podporující JPEG 2000, nebude problém díky flexibilnímu návrhu rozhraní pro obrázky tento formát do prohlížeče přidat.

Ostatní

Rozhodli jsme se umístit všechny datové soubory a spustitelný kód do jednoho binárního souboru z důvodu přenositelnosti. Tímto je uživatel zproštěn problémů, kam umístit data k prohlížeči, a je vyřešen problém s hledáním dat (každý uživatel chce data umístit typicky do jiného adresáře, tedy po překopírování binárního souboru by Links nešel spustit). Takto stačí překopírovat jeden binární soubor na jiný počítač se stejnou platformou a prohlížeč tam poběží.

Jako jazyk, ve kterém bude projekt napsán, jsme si vybrali jazyk C, protože C je univerzální programovací jazyk, který charakterizují úsporné výrazy, moderní řízení běhu, struktura údajů a bohatství operátorů. Obecnost jazyka C jej činí vhodnějším a efektivnějším pro mnohé úlohy než jiné "mocnější" jazyky. Řídili jsme se normou ANSI C, abychom dosáhli přenositelnosti na co nejvíce systémů.

Historie

V historii se ukládá celá zformátovaná stránka včetně pozice kurzoru na stránce a obsahu všech formulářů. Tedy když uživatel jde v historii zpět, ocitne se na přesně stejném místě, odkud šel na novou stránku. Obsah formulářů se neztratí ani při reloadu stránky, jak je tomu u jiných prohlížečů.

Přenositelnost

Aby byl projekt dobrý, museli jsme zaručit přenositelnost kódu. Proto jsme se psali kód v ANSI C. Nicméně některé části musely být alespoň částečně platformně závislé. Přesto jsme museli zaručit přenositelnost. Z toho důvodu jsme použili nástroje AutoconfAutomake , pomocí nichž je možné vyrobit na konkrétním počítači makefile "na míru". Bez použití těchto nástrojů by bylo velice pracné vytvořit přenositelný Makefile a zajistit kompilaci na různých systémech.

V distribuci dodáváme vygenerovaný skript configure , který slouží pro upravení konfigurace pro konkrétní počítač. Mimo to dodáváme také vstupní soubory pro programy AutoconfAutomake , aby bylo možno skript kdykoliv znovu vygenerovat.

Překlady

Links má přeložena menu do mnoha jazyků. Již od začátku projektu jsme s touto vlastností počítali. Proto jsme byli hned v počátcích projektu postaveni před rozhodnutí, jakým způsobem překlady realisovat. Pro překlad řetězců existuje nástroj gettext , který jsme během vývoje používali. Ten se ale ukázal jako omezující, protože není přenositelný, neumí jiné kódové stránky než ISO 8859-2 a v libc různé od glibc 2 obsahuje mnoho chyb.

Z toho důvodu jsme gettext zavrhli a napsali jsme si vlastní systém překódování jazyků. Jazyky se přidávají při kompilaci, když se provede nějaká změna, tak se spustí skript, který vygeneruje zdrojové soubory v jazyce C. Podobně funguje systém překladu znakových sad.

Ovládání

Ovládání prohlížeče jsme zvolili pomocí jednoduchých interaktivních nabídek. V počátcích prohlížeče, kdy ještě fungoval pouze v textovém módu, jsme se inspirovali textovým prohlížečem Lynx, který se ovládá pomocí horkých kláves. Toto ovládání není příliš šikovné, protože si uživatel musí pamatovat množství kláves pro všechny možné funkce. My jsme zachovali zpětnou kompatibilitu ovládání s prohlížečem Lynx (horké klávesy jsou tedy stejné), protože byl v té době rozšířený a uživatelé byli na jeho ovládání zvyklí. Navíc jsme přidali jednoduchá interaktivní menu, odkud uživatel může všechny funkce vyvolat. Ti, kteří si nepamatují množství horkých kláves, mají možnost snadného ovládání. V textovém módu jsme i umožnili používat myš (pomocí knihovny libgpm). To usnadňuje ovládání ještě více. V grafickém módu jsme ovládání poněkud pozměnili, klade se větší důraz na myš, například pohyb po odkazech a výběr odkazu klávesami nefunguje a musí se použít myši.

Snažili jsme se, aby ovládání zabíralo minimální část obrazovky (což má velikou cenu zejména v textovém módu, kde je malé rozlišení), proto na první pohled menu není vidět a vyvolává se klávesou escape. U jiných prohlížečů nám vadí překombinované ovládání, ve kterém se nejen špatně orientuje, ale také zabírá nezanedbatelnou část obrazovky. V Links zabírá obrazovku pouze stavový řádek (dole) a titulek stránky (nahoře). Kategoricky jsme odmítli lištu pro zadávání URL i lištu s ikonami, protože zabírají místo a funkce lze vyvolat snáze stisknutím klávesy, nežli trefováním se myší do tlačítka.

Fonty

Při psaní grafické části prohlížeče jsme byli postaveni před problém, jaké použít fonty při sázení textu. Požadavek byl snadná čitelnost a škálovatelnost. V zásadě jsme měli možnosti použít již existující fonty --- například z X-Window nebo z Ghostscriptu, nebo distribuovat vlastní fonty. My jsme si vybrali vlastní fonty z důvodu přenositelnosti a nezávislosti na ostatních programech a nastavení uživatelova počítače. Dále jsme měli na výběr zda použít vektorové fonty, nebo bitmapové. My jsme si vybrali variantu bitmapových fontů zejména z toho důvodu, že aby bylo možno vektorové fonty dostatečně antialiasovat, bylo by nutné je vygenerovat na mnohem větší rozlišení než je rozlišení našich bitmapových fontů. To by zabralo velmi mnoho času, navíc by se takto vygenerovaná bitmapa musela ještě převzorkovat, což by také zabralo hodně času. K přidání nebo úpravě fontu by uživatel potřeboval speciální typografické nástroje pro práci s vektorovými fonty, takto mu stačí libovolný grafický program nebo scanner. Pokud by někdo chtěl přidat předlohu z knihy, potřeboval by specialisovaný software pro vektorisaci rastrového formátu, takto stačí libovolný grafický program (například Gimp).

Bitmapové fonty jsou součástí binárního souboru, což opět zlepšuje přenositelnost, protože se fonty nemusí hledat v různých adresářích a také se usnadňuje instalace. Fonty jsou uloženy ve velkém rozlišení ve formátu PNG (který podstatně redukuje jejich velikost) a při zobrazování se antialiasují, aby byla zlepšena jejich čitelnost i při malých velikostech (prakticky ozkoušeno: při velikosti 8 pixelů je antialiasovaný font čitelný a font z X je již nečitelný). Pro lepší čitelnost jsou použity fonty computer modern z Ghostscriptu. Uživatel si dále může plynule nastavit velikost písma, což zajisté ocení uživatelé s vadou zraku.

Výsledek projektu

Výsledkem projektu je jeden binární soubor, který se spustí a funguje jak v textovém, tak v grafickém režimu. Kód je psán přenositelně, takže ho je možné bez problémů zkompilovat na všech Unixech i na OS/2. V grafickém módu je využit zejména grafický systém X-Window, který je na jmenovaných operačních systémech nejpoužívanější a nejpřenositelnější. To též umožňuje pouštění prohlížeče přes síť na vzdáleném počítači. Dále jsou podporovány i grafické systémy SVGAlib (na Linuxu) a Pmshell (na OS/2).

Veškerý kód je napsán v jazyce ANSI C a to tak, aby byl přenosný mezi platformami. Ke kompilaci doporučujeme kompilátor GCC a program GNU Make, nicméně jiné kompilátory by měly fungovat také. K výrobě překladače a interpretu JavaScriptu byly použity nástroje Bison a Flex. Dále pro snadnější kompilaci a přenositelnost mezi platformami byly použity programy Autoconf a Automake.

Pro textový výstup nebyly použity žádné terminálové knihovny, jelikož jsou nepřenositelné. Proto se výstup zobrazuje pomocí standardních ANSI terminal escape sekvencí s možností zapnutí různých nestandardních rozšíření v menu, například barvy, různé druhy rámečků, tvar kurzoru.

Javascript

Poznámky k~implementaci upcallů a~vnitřních funkcí

Tato kapitola obsahuje odchylky implementace od normy javascriptu. Zejména zde najdete seznam věcí, které jsme implementovali jinak, a pak které jsme implementovali navíc oproti normě Javascript 1.1 od Netscape Corporation.

V gramatice jsme museli povolit neukončení statementu středníkem, tj. znejednoznačnění zdrojových textů, umožnění zběsilého mixování operátoru pole a operátoru member (a$[\ ]$.b nebo a$[\ ][\ ]$ ) a umožnění otevření komentáře ve zdrojovém textu ( Tento skript nevydržel žádný nám dostupný prohlížeč. Všechny prohlížeče se staly neovladatelnými. Některé zběsile vytvářely nová a nová okénka, některé čekaly na uživatelovo odklepnutí. Ale všechny testované prohlížeče bylo nutno po tomto skriptu pro opětovnou použitelnost restartovat.

Links u těchto skriptů netrpí nejmenšími obtížemi, neboť uživatel má u každého dialogu vytvořeného javascriptem možnost interpretaci všech javascriptů ukončit. Tedy se objeví alert a po stisku "Ukončit skript" může uživatel dále pokračovat v práci s prohlížečem.






Tento skript provede útok na paměť neustálou alokací. Neútočí nejen na prohlížeč, ale dokonce na uživatelův počítač. S prohlížečem Netscape 4.77 na Linuxu způsobí uživateli nepříjemnou čtvrthodinku rozsvíceného disku a velmi pomalých reakcí počítače. Ostatní prohlížeče též spadly nebo přestaly reagovat a začaly masivně zatěžovat systém, avšak u prohlížeče Netscape 4.77 byly důsledky nejfatálnější.

Links tento skript brzy skončí, neboť vyčerpá paměť přidělenou javascriptu. Uživatel má možnost tento limit na paměť v menu nastavit.






Výše uvedený skript předpokládá, že bude uložen v souboru furt-dokola.html . Jediný testovaný prohlížeč, který po interpretaci tohoto skriptu nespadl ani nepřestal být ovladatelným, byl prohlížeč Opera na operačním systému Linux, který po lehkých obtížích byl dále použitelný.

Links opět tento skript nečiní potíže, neboť při každé změně URL vyvolané javascriptem je uživatel dotázán, zda si přeje změnu povolit nebo zakázat. Uživatel má opět možnost v dialogu okamžitě ukončit interpretaci všech skriptů. Navíc pokud je URL stejné jako URL aktuální stránky, nic se neprovede. V tomto případě se tedy nebude nic dít. Útočník může toto opatření ovšem jednoduše obejít, že vytvoří dva skripty, které na sebe navzájem budou odkazovat. V tom případě bude při každé změně URL uživatel dotázán a tedy bude mít možnost "útok" ukončit.






Tento skript je lehkou obměnou předchozího, předpokládáme, že skript je uložen v souboru okno-furt.html . Rozdíl je pouze v tom, že skript otevírá nová a nová okna, čímž zahltí systém, nebo přinejmenším učiní prohlížeč nepoužitelným. Opět ani jeden z testovaných prohlížečů neustál. V případě IE měl operační systém Windows 2000 vážné problémy s tolika okny, což zanechalo trvalé následky na spuštěném Task manageru, který nešel zavřít, neboť jeho okno se začalo zobrazovat bez horní čtvrtiny.

Našemu prohlížeči skript opět nečinil problémy, neboť před každým otevřením (nebo i zavřením) okna je uživatel dotázán na potvrzení. Tedy se zobrazilo okénko, zda si uživatel přeje otevřít nové okno a uživatel měl opět možnost ukončit interpretaci skriptů.





}
Nekonečná rekurse je v novějších prohlížečích již ošetřena. Prohlížeče Opera a Mozilla nic neudělaly, ostatní prohlížeče (Netscape, IE, Konqueror) téměř
okamžitě spadly. 

Pokud se tento skript spustí v Links, záhy se objeví dialog, že javascript překročil limit maximálního zanoření funkcí, a skript je násilně ukončen. Limit si uživatel opět může dle svých potřeb nastavit v menu.

Uvedené potíže prohlížečů považujeme za velmi závažné bezpečnostní díry. Jsme toho názoru, že toto by se v žádném případě korektnímu prohlížeči nemělo stát. S touto filosofií jsme při navrhování javascriptu již od začátku počítali a proto jsme prohlížeč proti všem útokům ze strany javascriptu obrnili. Javascript je striktně napsán s cílem, aby uživatel měl za všech okolností plnou vládu nad skriptem.

Použité knihovny

Při psaní projektu jsme se snažili používat co nejméně cizích knihoven, aby kód byl co nejvíce přenosný a aby uživatel nemusel na svůj systém nejprve instalovat megabyty rozličných knihoven, když chce používat Links. Z vlastní zkušenosti jsme se přesvědčili, že různé verze knihoven jsou mezi sebou navzájem nekompatibilní (i zpětně). Knihy také obsahují různé chyby a bezpečnostní díry, které by se takto zavlekly do prohlížeče Links.

Proto jsme použili pouze knihovny pro dekódování obrázků (jpeg a png) a pro práci s protokolem SSL. Tyto knihovny jsou velmi rozšířené a poměrně stabilní a vzhledem ke složitosti problémů, které řeší, by se nevyplatilo psát vlastní kód, který by mohl obsahovat více chyb než časem a praxí prověřený kód knihoven. Navíc psaní těchto knihovních funkcí by vyžadovalo mnoho času studia dokumentací popisující tyto standardy, nemluvě o času nutném k testování správnosti implementace.

V textovém režimu nejsou potřeba žádné speciální knihovny a stačí pouze standardní knihovna libc . Ke kompilaci v grafickém režimu jsou nutné ještě tyto knihovny:

Následující knihovny jsou nepovinné, leč doporučené. Bez nich nebudou fungovat u knihovny uvedené funkce prohlížeče.

Vývoj a~testování

Prostředí používané k~vývoji

Links byl vyvíjen většinu času na operačním systému Linux, část (některý kód Mikuláše Patočky) byla vyvíjena na OS/2. Ke kompilaci jsme používali zejména kompilátor GCC (převážně verze 2.95.x a 2.96.x) a nástroj GNU Make (verzi 3.79). K ladění jsme používali zejména program GDB, dále pak ladící výpisy a logy. Veškerý kód byl psán v editoru VIM. Mezi podpůrné programy, které jsme při vývoji použili patří Autoconf (verze 2.13) a Automake (verze 1.4). Parser javascriptu byl napsán s pomocí nástrojů Flex (verze 2.5.2) a Bison (verze 1.24 a 1.28). Rozhraní X-Window bylo vyvíjeno zejména na Linux XFree86 verze 3.3.6 a 4.0.2. Rozhraní SVGAlib bylo testováno se SVGAlib 1.9.x a 1.4.x. Fonty byly zpracovávány programy GIMP a ImageMagick.

Testování přenositelnosti

Přenositelnost programu jsme testovali na Unixech a strojích dostupných v počítačových laboratořích a na našich (a námi dostupných) počítačích. Testy na Alphě jsme prováděli přes účet na www.testdrive.compaq.com.

Ostatní deklarované podporované operační systémy jsou bohužel jen z doslechu, neboť jsme neměli možnost je otestovat. Dozvěděli jsme se je od uživatelů, kteří nám nadšeně psali, že Links běží i na takovýchto systémech.

Zkoušeli jsme kompilovat překladači:

Testování programu, hledání chyb a optimalisace

Při vývoji jsme použili metodu regresivního testování kódu. Tato metoda je například s úspěchem využívána při vývoji kompilátoru GCC. V našem případě spočívá v testování prohlížeče a při jakémkoliv problému (pád, memory leak, zacyklení, přepsání zásobníku či jakákoliv jiná chyba) zjištění přímé příčiny a uložení podmínek, při kterých problém nastal. Tedy uložení stažení a uložení HTML stránky na disk a uložení kláves, které byly stisknuty. Poté je možno kdykoliv opět vyvolat všechny situace, kdy nastal nějaký problém či chyba. To umožňuje kontrolu, že daná chyba byla doopravdy odstraněna a že pozdějšími úpravami kódu nebyla chyba zavlečena znovu. Stačí pustit automatizovaný skript, který testuje prohlížeč na problematických vstupech.

Tento postup jsme zavedli poté, co jsme zjistili, že některé chyby se opakují. Prohlížeč jsme testovali velmi intensivně, neboť jsme během vývoje nepoužívali prakticky žádný jiný prohlížeč k zobrazování webových stránek.

K odstraňování memory leaků a střílení do paměti jsme používali vlastní technologie. Napsali jsme obaly kolem funkcí malloc, free, realloc, .... Tyto funkce kolem naalokované oblasti vytvoří rudou zónu a uloží informace, na kterém řádku byla paměť naalokována a kolik bytů bylo naalokováno. Do neinicialisované paměti se uloží vzorek, aby se dříve přišlo na používání naalokované, ale neinicialisované paměti (vzorek většinou vyvolá chybu nebo pád programu). Při uvolňování paměti se testuje konzistence rudé zóny, uvolněná paměť se vyplní předem daným vzorkem a na konci programu se zjišťuje, zda se uvolnily všechny bloky paměti.

Tímto mechanismem se nám podařilo velmi účinně detekovat a odstraňovat memory leaky, zápisy mimo naalokovanou oblast (například přetečení pole) a zjišťovat používání nenainicialisované či již odalokované paměti. K tomuto účelu již sice existuje nástroj --- knihovna Electric fence , ale tato knihovna je velmi neefektivní a nepoužitelně zpomaluje program a také do programu zavléká chyby, které by bez použití této knihovny nevznikly. Proto jsme tuto knihovnu vesměs nepoužívali.

Pro dosažení maximálního výkonu a nejoptimálnějšího kódu (zejména u grafických rutin) jsme používali technologii profilování kódu. Program jsme zkompilovali s podporou profilovacích informací, poté jsme prohlížeč intensivně testovali na graficky velmi náročných vstupech. Pomocí programu gprof jsme pak zjistili, kolik času se stráví v které funkci a jak dlouho která funkce trvá. Tak jsme získali velmi cenné informace pro následné intensivní ruční optimalisování kódu založené na znalosti překladačů a strojového kódu. Tímto způsobem se nám podařilo velmi účinně zoptimalisovat kód.

Doporučené nástroje ke kompilaci

Při psaní interpretu javascriptu jsme použili nástroje FlexBison pro výrobu automatů pro lexikální a syntaktickou analýzu. Tyto nástroje nejsou potřeba při kompilaci, protože v distribuci dodáváme již výstupy z těchto nástrojů --- zdrojové texty automatů v jazyce C.

Ke kompilaci je potřeba program Make a libovolný kompilátor jazyka ANSI C (doporučujeme GCC).

Pro zajištění přenositelnosti jsme užili nástrojů AutoconfAutomake . Tyto nástroje slouží k vygenerování souboru Makefile . Programy AutoconfAutomake vytvoří platformně nezávislý skript configure , který se spustí při instalaci a který vygeneruje soubor Makefile . Nástroje Autoconf ani Automake nejsou potřebné při instalaci, neboť dodáváme již vygenerovaný skript configure .

Dále jsme si vytvořili několik skriptů pro generování fontů, překladů a tabulek znakových sad. Tyto skripty by měly být přenosné na systémech Unix, ale opět nejsou potřeba při instalaci, protože v distribučním balíku jsou již těmito skripty vygenerované zdrojové soubory jazyka C.

Kód přejatý od jiných autorů

Všechny jazykové překlady s výjimkou angličtiny a češtiny nepsal nikdo z týmu autorů. Překlady jsou přejaty od nadšenců, kteří nám je poslali.

Závěr

Myslíme si, že projekt splnil svůj účel, protože nejen, že se nám podařilo napsat kvalitní webový prohlížeč a naučili jsme se a ozkoušeli jsme si spoustu zajímavých věcí, ale hlavně jsme se naučili skupinové komunikaci, specifikovat rozhraní a psát dokumentaci. Což si myslíme, že byl hlavní cíl tohoto projektu.

Projekt nám přinesl zdokonalení se v programování v jazyce C, poznání, jak se programovat má a jak se programovat nemá. Naučili jsme se, že výsledný kód má běžet co nejrychleji, nemá obsahovat žádné chyby, má dodržovat normy a standardy, kód má být portabilní, funkce programu se mají omezit jen na nezbytně nutné minimum dostačující k efektivní práci uživatele. Program má být monolitický a heterogenní. Má se programovat s vědomím, že jakákoliv chyba nalezená v programu může být považována za totální selhání programu.

Při programování by se nemělo podléhat creeping featurismu (creeping featurism znamená nabalování nových funkcí na stávající program jako sníh na sněhovou kouli), nemá se programovat s chybami tak, že se program napíše chybně a pak se na základě bugreportů opravuje. Nemá se programovat v rozporu s RFC a standardy, prosazovat metodiku a strukturovanost na úkor rychlosti a efektivity. Neměla by se prosazovat čitelnost kódu na úkor rychlosti, obcházet chyby v jiných knihovnách a programech na úkor jednoduchosti, spolehlivosti nebo rychlosti. Program nemá vykonávat zbytečné operace, které nic neprovádějí. Data se nemají filtrovat přes vrstvy byrokratických rozhraní a to ani pod záminkou metodičnosti a/nebo strukturovanosti návrhu nebo programu nebo čitelnosti kódu. Nemají se připouštět chyby v programu pod záminkou, že je vestavěné samotestovací mechanismy odhalí nebo odstraní. Nemá se programovat odtažitě od fungování reálného počítače. Do programu se nemají přidávat nové funkce v případě, že není bezchybný. Programátor nemá ukončit programování v okamžiku, kdy kód funguje, ale má si ho po sobě v maximální možné míře překontrolovat. Programátor nesmí připustit existenci testerů, kteří budou program testovat, nesmí brát na lehkou váhu dopad případných chyb v kódu. Program se nemá při programování uspěchávat a programátor nemá být nucen zkracovat time to market.

Problémy při vývoji

Pří vývoji projektu jsme zjistili, že poctivost se hrubě nevyplácí. Konkrétně se jedná o dodržování standardů. Prohlížeč sice funguje přesně podle RFC a specifikací protokolů, ale jelikož 90 \ špatně, mnoho serverů nedodržuje protokoly, tak se často stává, že na takovýchto stránkách prohlížeč zobrazí méně než ostatní prohlížeče, které jsou nestabilní a standardy nedodržují. Nicméně jsme se rozhodli i nadále se řídit standardy, neboť jedině tak se dá principiálně dosáhnout rozumné interoperability a řešení spočívající v emulaci chyb ostatních programů se brzo ukázalo jako neschůdné, neboť chyby v ostatních programech si brzo po zavedení takovéhoto přístupu začnou navzájem odporovat.

Nejvíce se tento problém projevil asi při vývoji interpretu javascriptu. Protože implementace javascriptu od různých firem se velmi liší a autoři prohlížečů i autoři stránek pramálo dodržují standardy.

Plány do budoucna

Chtěli bychom Links vyvíjet i nadále, protože si myslíme, že vždycky je co zlepšovat. O tom nás rovněž přesvědčují reakce části našich uživatelů v mailing-listu (links-list@linuxfromscratch.org ). Například bychom mohli podpořit CSS v HTML, plovoucí objekty, případně rozšířit javascript o nové konstrukce, aby zobrazoval více špatně napsaných stránek.

V nejbližší budoucnosti hodláme v javascriptu implementovat konstrukci eval , odalokovávání nepotřebných částí stromu za běhu, eventuálně kompresi zdrojového kódu udržovaného v paměti (například kód stejného znění udržovat pouze jednou). Mimo to chceme rozšířit stávající document object model například o document.all , document.scripts a další.

Použité materiály

Javascript

  1. zápisky z Datových struktur
  2. zápisky z Překladačů
  3. zápisky z Pravděpodobnostních algoritmů
  4. Proceedings of the SIGPLAN 82 Symposium on Compiler Constructions, Vol. 17, Num. 6
  5. info flex, info bison
  6. norma Javascript 1.1 od Netscape Corporation, Javascript 1.3
  7. norma ECMA--262
  8. konsultace s Mgr. Marešem, Doc. Sgallem, Mgr. Bednárkem a kolegou Hubičkou
  9. A. Motwani, P. Raghawan: Randomized algorithms
  10. Aho, Sethi, Ullmann: Compilers: Principles, Techniques and Tools
  11. K. Mehlhorn: Data structures and algorithms
  12. David Gries: Kompilátory číslicových počítačov

Grafika

  1. konsultace s RNDr. Pelikánem
  2. Josef Pelikán: Pokročilá 2D počítačová grafika (studijní texty k přednášce na MFF UK)
  3. Josef Pelikán: Počítačová grafika 1 (studijní texty k přednášce na MFF UK)
  4. Charles Poynton: Gamma FAQ
    (http://www.informap.net/$\sim$poynton/GammaFAQ.html )
  5. Charles Poynton: Color FAQ
    (http://www.informap.net/$\sim$poynton/ColorFAQ.html )
  6. normy a standardy: JFIF 1.02, ITU T.81, CCIR Recommendation 601, RFC 2083, ISO DIS 10918-1, IEC 61966-2-1, ISO 9241

Grafické drivery

  1. Adrian Nye: Xlib Programming Manual
  2. konsultace s autory framebufferu s SVGAlib
  3. zdrojové texty Linux kernelu
  4. konsultace s Mgr. Martinem Beranem

Zásluhy

Zde je seznam lidí, kteří se nějakým způsobem podíleli na vývoji prohlížeče. Zejména se jedná o překlady do cizích jazyků. Svým způsobem se na projektu podílela i spousta dalších lidí, kteří nás upozorňovali na různé chyby, ti zde uvedeni nejsou, neboť by se na tyto stránky nevešli. To ovšem nic nemění na jejich zásluhách při testování prohlížeče.

Tímto bychom tedy chtěli poděkovat všem, kteří se jakkoliv na vývoji prohlížeče podíleli, ať už testováním, hlášením či opravováním chyb, překladem do cizího jazyka, vlastním kódem, nebo jen posíláním nápadů, co zlepšit.

\halign{ #\hfil&\quad#\hfil\cr Unai Uribarri&Historie\cr Uwe Hermann&Manuálová stránka, přepínač příkazové řádky\cr &"-version", otvírání odkazu v novém xtermu\cr Alexander Mai&Podpora pro xterm pod OS/2, opravení includů\cr &pro AIX, aktualizace manuálových stránek\cr Dakshinamurthy Karra&přenesení na Win NT, ukládání goto history\cr Oleg Deribas&Titulek okna a podpora clipboardu v OS/2\cr Arkadiusz Sochala&Polský překlad\cr Dmitrij M. Klimov&Rámečky v KOI8-R, Ruský překlad\cr Jurij Raškovskij&Aktualizace ruského překladu\cr beckers&Německý překlad\cr Armon Red&Islandský překlad\cr Wojtek Bojd\o l&Aktualizace polského překladu\cr Serge Winitzki&Aktualizace ruského překladu\cr Aurimas Mikalauskas&Litevský překlad\cr Martin Norback&Švédský překlad\cr Jimenez Martinez,&\cr Angel Luis,&\cr David Mediavilla,&\cr Ezquibela&Španělský překlad\cr Suveg Gabor&Maďarský překlad\cr Gianluca Montecchi&Italský překlad\cr Sergej Boruševskij&No-proxy-for, Ctrl-W doplňování, SSL\cr Fabrice Haberer-Proust&Francouzský překlad\cr Cristiano Guadagnino&Aktualizovaný italský překlad\cr Fabio Junior Beneditto&Překlad do brazilské portugalštiny\cr Kaloian Doganov&Bulharský překlad\cr Baris Metin&Turecký překlad\cr Dmitrij Pinčukov&Ukrajinský překlad\cr Taniel Kirikal&Estonský překlad\cr zas@norz.org&Aktualizovaný francouzský překlad\cr Alberto García&Galícijský překlad\cr Radovan Staš&Slovenský překlad\cr Marco Bodrato&Podpora Twintermu\cr Kaloian Doganov&Aktualizace bulharského překladu\cr Olexander Kunytsa&Aktualizace ukrajinského překladu\cr Mediavilla David&Aktualizace španělského překladu\cr Simos Xenitellis,&\cr Alejandros Diamandidis&Řecké kódové stránky a překlad\cr Stefan de Groot&Holandský překlad\cr Carles&Katalánský překlad\cr Ionel Mugurel Ciobîcă&Rumunský překlad\cr Petr Baudiš&Používání "imgtitle" pokud není přítomen "alt",\cr &přidání tagu "LISTING", aktualizace manuálové stránky\cr Muhamad Faizal&Indonéský překlad\cr Peter Naulls&Podpora pro RiscOS\cr Jonas Fonseca&Dánský překlad\cr Miroslav Rudišin&Aktualizace slovenského překladu\cr }