A Pike programozási nyelv

Szabványos könyvtárak



A Pike szabványos könyvtárai

A Pike szabványos könyvtárai beépített modulok, melyek a Pike-ot új funkciók széles tárházával ruházza fel. Az alábbiakban a teljesség igénye nélkül, egy rövid ismertetőt tartunk az általunk fontosnak tartott modulok használatáról, hasznosságáról, majd új modulok készítéséről, Pike-hoz való hozzáadásáról is ejtünk egy két szót.

A modul a "plug-in" rövidítése : egy szoftver csomag, melyet más programozok is könnyedén használhatnak. A modulok tartalmazhatnak műveleteket, osztályokat, konstansoka és még másik modulok at is. A TAG kifejezést fogjuk használni arra a dologra, mint például függvényre, amit egy modul tartalmaz. Vannak modulok melyeket Pike-ban irnak, de C és C++ is használható erre a célra. Pike tartalmaz rengeteg hasznos modult, itt egy lista néhány izgalmasabbról :

Stdio

Ez a modult a fájlok írásakor és olvasásakor használjuk, néhány esetben az interneten keresztüli kommunkiáció közben és mikor szöveg alapú párbeszédeket folytatunk a felhasználóval.

GTK

Egy GUI (ablakokat, gombokat) létrehozó eszköz.

Image

Segít elvégezni a legszokásosabb képszerkesztő, képmanipuláló műveleteket a Pike-on belül. A támogatott műveletek között megtalálható a kivágás, beillesztés, átméretezés, arányváltoztatás, forgatás, a legtöbb lineáris szűrés, szöveg renderelése stb stb. Ezeken felül anti-aliasing-ot is használhatunk bármilyen fajta rajzoló művelet közben, mely élsimított, kiváló minőségű képet eredményez. A modul használatával időt spórolhatunk a monoton Adobe Photoshop képszerkesztések automatizálásával. Rengeteg képformátumat támogat.

Protocols

Többféle protokol. Egyik közülük a Protocols.HTTP, mely arra való, hogy a World Wide Web szerverekkel kommunikáljon, weboldal lekérés során. Más támogatott protocolok : DNS, IMAP, IRC, LDAP, LysKOM, NNTP, SMTP és TELNET.

MIME

Támogatás a MIME kódoláshoz és dekódoláshoz, melyet az elektronikus levelezésnél használunk.

Crypto

Támogatás a kriptográfiához. A Crypto Eszköztár különféle kódoló algoritmusokon felül olyan objektumokat is tartalmaz, melyekkel két összetartozó dolgot ragaszhatunk össze. Az eszköztár tartalmazza az AES(Rijandael), IDEA, DES(beleértve a tripla DES-t) és a CAST blokk rejtjelezőket, a publikus kulcs titkosítását(RSA), a MD2, MD4, MD5, DSA(DSS), HMAC és a SHA hash függvényeket, valamint el van látva néhány véletlen adat generátorral. Az eszköztár a legtöbb fajta titkosításra képes legyen szó a hálózati kapcsolatokról, digitális aláírásokról vagy fájlok vagy más adat bizalmassá tételéről.

Calendar

Támogatás a különböző naptárakhoz és dátumformátumokhoz.

Sql

Ezzel a modullal a Pike le tud futtatni SQL adatbázis lekérdezéseket saját programjainkon belül olyan adatbázis szervereken, mint mySQL, Oracle és Sybase. LDAP, gdbm és Mird támogatás viszont hiányzik belőle.

Thread

Támogatás a Pike programok szálankénti futtatásához, párhuzamosításhoz.

Process

Függvények, melyek másik processzeket vezérelnek vagy indítanak el.

Getopt

Rutinok, melyekkel interpretálhatunk és kezelhetünk parancssori beállításokat.

LR

LALR(1) elemző.

Yp

NIS (Hálózati Információs Szerver) támogatás.

Gz

Csomagolt fájlok kicsomagolásához támogatás.

Regexp

Reguláris kifejezéseket kezelő könyvtár.

GL

A Pike az OpenGL-hez is rendelkezik interfésszel, amely a legszélesebb körben elterjedt és támogatott 2D-s és 3D-s grafikus alkalmazásokhoz való környezet. Ráadásul a Pike grafikus könyvtárai támogatják a GLU-t és a GLUT-ot is. A GLU egy olyan OpenGL Utility csomag, mellyel létre lehet hozni textúra mipmaps-okat egy eredeti képhez, térkép koordinátákat lehet generálni a képernyő és a objektumtér kapcsolatából, kvadrikus felületeket lehet rajzolni valamint a NURBS felszínműveletekhez is tartalmaz eszközöket. A GLUT pedig egy olyan OpenGL eszköztár, amely az ablakrendszer független programozást támogatja.

Szövegkezelés

A Pike oly versenyképes és hatékony szövegkezeléssel rendelkezik, hogy ideális választás loggoló és szövegfolyammal dolgozó projektek alapjának választani. Minden beépített típus wide sztring biztos és képes a legújabb unicode szabványoknek megfelelő szövegformázásra, mint péládul a kis- és nagybetűk közötti váltás. Mikor fájl és protokolokkal való munkára kerül szó, a Pike Charset moduljával képes kódolni és dekódolni a szövegeket. Majdnem 500 különböző karakter szet között tud konvertálni. Ilyen karakterszetek között van az iso-8859-1-től 15-ig, az iso-2022-jp, a shiftjis, euc-jp, euc-kr, euc-cn, utf-7, utf-8, windows 1250-tól 1258-ig, a BIG5 és a GB2312. Az Unicode modul több nem szokványos Unicode műveletre is képes, mint például a szövegek normalizálása többek közt a NFC, NFD, NFKC és NFKD algoritmusokkal. Ráadásul a Pike magában foglal szintaktika ellenőrzőket, melyek közt néhány folyamatos. Ide vehetjük az SGML ellenőrzőt, a rugalmas HTML ellenőrzőt, mely még a hibás HTML kódot is képes kezelni, a DTD által validált XML ellenőrzőt, az általános célú LR, egy RCS fájl, egy C kód és egy Pike kód ellenőrzőt.

Modulhasználat

Hogy egy modul tagját használhassuk, csak írjuk a tag neve elé a modul nevét egy ponttal. Például Stdio.stdin. Ez a Stdio modul stdin tagját jelöli. Az alábbi példában egy stringet fogunk beolvasni a standard inputról a Stdio.stdin objektum gets metódusával.

string name = Stdio.stdin->gets();

A modulok egymásba is ágyazhatóak, tagjainak elérése logikusan következik, ahogy az alábbi példa is mutatja :

Protocols.HTTP.Query web_page;

Ha nem akarjuk mindig kiírni a modul nevét, importálhatjuk is a modult :

import Stdio; import Protocols.HTTP;

Eme két modul importálása után használhatjuk a stdin-t és a Query-t prefix nélkül.

string name = stdin->gets(); Query web_page;

Az import bárhol lehet a programban, de általában az elején szoktuk kiirni.

Ha két különböző importált modul ugyanolyan nevű tagját hívjuk meg, akkor a később importált modul nevét fogja odailleszteni prefixként a fordító.

import canvas_window; draw(); // keprajzolas import chess_game; draw(); // döntetlen a sakkjátszmában

Egy adott könyvtár összes modulját importálni lehet az adott könyvtár név megadásával :

import "home/blubbers/pike/all_my_modules";

Ha a modul neve elé pontot teszünk akkor Pike a modult a program futtató könyvtárban fogja keresni.

import .florble; .gnooble.droop(7,3);

Modulok létrehozása

A Pike kód együttese egy modul, általában egy fájl. C-ben és C++-ban is írhatunk modult, de ezt csak az újabb pike verzióban érhető el, és nem triviális.

Tegyük fel, egy trig-nek nevezett modult akarunk létrehozni, melynek két tagja van: a cos2 művelet, ami a cosinus négyzetét számolja ki, és a konstans pi.

Csináljunk egy filet trig.pmod néven, mely a kovetkezőket tartalmazza :

float cos2(float f) { return pow(cos(f), 2.0); } constant PI = 3.1415926535;

Most a modul fájl létezik, használhatjuk is. Ha abban a könyvtárban tartjuk, mint a programot, amiben használni szeretnénk, akkor .trig ként hivatkozhatunk rá :

int main() { write("The square of cos(pi/4) is " + .trig.cos2(.trig.PI/4) + ".\n"); return 0; }

vagy ha inkább az importot használnánk

import .trig; // importaljuk a modult ebbol a konyvtarbol int main() { write("The square of cos(pi/4) is " + cos2(.trig.PI/4) + ".\n"); return 0; }

Hogy találja meg a Pike a modulokat?

Minden modul amit használunk a programban betöltődik, mikor a program elindul. Nem számít hogy az egész modult importáljuk vagy csak egy tagját használjuk. Ez az egész még a main hívás előtt történik. A modul betöltődése azt jelenti, hogy a fájlt a program beolvassa a lemezről, és a dolgok a modulban elérhetővé válnak a program számára.

Mikor a Pike betölti a modul_név nevű modult, ebben a sorrendben fogja keresni a következő könyvtárakban :

1. Ha .-tal kezdődött a modul neve, akkor abban a könyvtárban, amiben a program meghívta a modult.

2. Abban a könyvtárban amit az import utan megadtunk stringként (import "dir_nev").

3. Az add_module_path által hozzáadott könyvtárakban.

4. A parancssorban a -M után megadott könyvtárakban.

5. A PIKE_MODULE_PATH környezeti változóban tárolt könyvtárakban.

6. A beépített modulok könyvtáraiban.

A fenti könyvtárak után az alkönyvtárakban ebben a sorrendben keresi a Pike a modult.

a, Ha létezik olyan fájl, hogy modul_név.pmod, Pike betölti a fájlt, mint egy Pike program, klónozza, és ezt a klónt használja úgy, mint modult.

b, Ha létezik olyan könyvtár, hogy modul_név.pmod, akkor a Pike létrehoz egy modult, amelynek minden könyvtárbeli modul tagja. Ha van olyan modul, melynek neve module.pmod (azaz fájlneve : module.pmod, module.pmod.pike vagy module.pmod.so), akkor inkább azokat a tagokat használja a modulból, mint amik jelen vannak a könyvtárban.

c, Ha létezik olyan fájl, hogy modul_név.pmod.pike, Pike betölti a fájlt, mint egy Pike program, klónozza, és ezt a klónt használja úgy, mint modult.

d, Ha létezik olyan fájl, hogy modul_név.pmod.so, Pike betölti a fájlt, mint egy Pike program, klónozza, és ezt a klónt használja úgy, mint modult. Ennek a fájlnak azonban dinamikusan linkelhető fordított C vagy C++ kódot tartalmazó könyvtárnak kell lennie.

GTK

a Pike GTK modulja objektum orientált felületet biztosít a GTK+ Widget library számára.

a GTK (GIMP Toolkit) egy GUI készítő programcsomag. LGPL liszenszelt, így ingyenes, nyílt forráskódú, szabadon terjeszthető. A neve azért Gimp Toolkit, mert eredetileg a GIMP képszerkesztő program fejlesztéséhez tervezték. Azóta viszont kinőtte magát, és most már sok szoftver projektben használják fel, ideértve még a GNU Network Object Model Environment (GNOME) projektet is. GTK a GDK-ra (GIMP Drawing Kit-re) épül, amely alapjában véve az alacsony szintű ablakkezelő függvények gyűjteménye, wrapperja. A GTK fő fejlesztői :

Peter Mattis : petm@xcf.berkeley.edu

Spencer Kimball : spencer@xcf.berkeley.edu

Josh MacDonald : jmacd@xcf.berkeley.edu

A Pike GTK moduljának fő fejlesztője :

Per Hedbor per@idonex.se

A Pike GTK több mint a sima GTK függvényeinek egy Pike-ba ágyazott gyűjteménye. Főként a képkezelés terén bővült új funkciókkal.

Ismerkedés a Pike GTK-val

legelőször meg kell bizonyosodnunk róla, hogy a GTK 1.2 vagy újabb verziója már fel van installálva, mikor fordítjuk a pike-ot, máskülönben a GTK modul nem lesz elérhető. Abban az esetben, ha nem vagyunk biztosak benne, hogy Pike-unk használja e a GTK-t, próbáljuk meg a

pike -e GTK.setup_gtk()

parancsot futtatni konzolból. Ha nem kapunk hibaüzenetet, akkor a GTK elérhető.

Az első program egy (nagyon) rövid példaprogram, amely létrehoz egy ablakot, és nem csinál semmit.

void main(int argc, array argv) { argv = GTK.setup_gtk( argv ); GTK.Window( GTK.WindowToplevel )->show(); GTK.main(); }

Mindegyik GTK programnak muszáj meghívnia a GTK.setup_gtk() függvényt, mielőtt bármiféle widget-et létrehoznánk (ablakos komponenst : gomb, label, stb.). Ha nem tesszük meg, hibaüzenetet kapunk.

A GTK.setup_gtk() függvény visszaad egy új argumentum tömböt, az összes argumentum, melyet a GTK használ, az argumentumok listájából kikerül.

GTK.Window(GTK.WindowToplevel) létrehoz egy új window widget példányt, melyet a show() jelenít meg a képernyőn.

GTK.main() elindítja a GTK fő végtelen ciklusát, és vár hogy egy esemény bekövetkezzen. Mivel az ablakhoz nincs semmiféle szignál kötve, a program jelen esetben soha sem fog befejeződni, csak ha manuálisan lőjjük ki a folyamatot.

Másik módja a GTK fő végtelen ciklusának elindítására, hogy -1-gyel térünk vissza a main-ből. Ennek a megközelítésnek van egy kisebb hátránya, és egy nagyobb előnye.

Az előny az, hogy tudjuk használni a normális pike backend függvényeket (mint például a nonblocking I/O-n alapuló callback-t és a timeout-ot használó call_out-ot)

A hátrány viszont az, hogy leterheli kicsit a processzort, mivel ez a megvalósításhoz szavazó mechanizmust használ. Azonban a processzor használat nagyon csekély, alig észrevehető, (kevesebb mint 0.001% CPU használat az én kétmagos Pentiumomon)

Hello World

Nézzünk egy kicsit komolyabb példát, mely egyéni widget-et, és szignált is használ :

class HelloWorldButton { inherit GTK.Button; void show_hi() { GTK.Alert( "Hi there" )->show(); } void create() { ::create( "Hello World" ); signal_connect( "clicked", show_hi ); } } class MainWindow { inherit GTK.Window; void create() { ::create( GTK.WindowToplevel ); add( HelloWorldButton()->show() ); signal_connect( "destroy", exit, 0 ); // Call exit(0) directly } } int main( int argc, array argv ) { argv = GTK.setup_gtk( argv ); MainWindow( )->show(); return -1; }

A példa kétségkívül lehetett volna sokkal rövidebb is az egyéni widgetek nélkül (a MainWindow és a HelloWorldButton), de általában jó ötlet úgy megírni a Pike GTK alkalmazásokat, hogy túlterheljük a létező widgeteket és a konstruktorukba írjuk azt a kódot ami a tartalmukra is kihat.

Azért jó, mert a MainWindow-nak nem szükséges tudnia hogy készült a HelloWorldButton, és a main-nek se kell tudnia, hogy építsen fel egy MainWindow widgetet, ezáltal nagyon könnyű megváltoztatni a al-widgeteket a későbbiekben.

az általános megközelítés ez lenne :

void show_hi() { GTK.Alert( "Hi there" )->show(); } int main( int argc, array argv ) { GTK.Window window; GTK.Button button; argv = GTK.setup_gtk( argv ); window = GTK.Window( GTK.Windowtoplevel ); button = GTK.Button( "Hello World" ); window->add( button->show() ); window->signal_connect( "destroy", exit, 0 ); button->signal_connect( "clicked", show_hi ); window->show(); return -1; }

Ahogy a program egyre komplexebbé válik, az objektum orientált megközelítést sokkal könnyebb karbantartani, mint az általánost.

A szignálok és az eseménykezelő callback függvények elmélete

A GTK egy eseményvezérelt eszközcsomag, ami azt jelenti, hogy addig alszik, míg egy esemény ki nem váltódik, és a vezérlés át nem atódik a megfelelő függvénynek.

Ezt a vezérlőátadást a szignálokkal valósítjuk meg. Mikor egy esemény kiváltódik, mint például az egér kattintása, az eseményhez megfelelő szignált hívja meg az a widget, amelyen az eseményt kiváltották. A legtöbb esetben a GTK így müködik. Vannak szignálok, amiket minden widget örököl, mint például a "destroy", és vannak olyanok, melyek widget specifikusak, mint például a "toggled" a kapcsoló gombnál.

Ahhoz, hogy egy gombot végrehajtson valamit, beállítunk hozzá egy szignálkezelőt, hogy elkapja ezeket a szignálokat, és meghivjuk a hozzá megfelelő függvényt. Ezt a signal_connect művelettel valósíthatjuk meg a widgetben.

int signal_connect( string signal_name, function callback_function mixed|void callback_argument );

A szignál név vagy egy string mint a "destroy", vagy egy, az előre definiált GTK.s_* konstansok közül. (amik amúgy stringek, GTK.s_destroy == "destroy").

A megadott függvény hívódik meg, mikor a szignált le kell kezelni. A függvény első argumentuma mindig az lesz, amit a signal_connect utolsó (opcionális) argumentumában megadtunk, a második az a widget, amely a szignált kiváltotta, az összes többi argumentum pedig szignál specifikus.

Widgetek dobozolása

Mikor alkalmazást készítünk, nem csak egy widgetet akarunk rakni egy ablakba. Első hello world példánkban csak egy widgetet használtunk, ezért elég volt egyszerűen az "add()" hívás. Azonban mikor több widgettel dolgozunk, hogy tudjuk megadni egyáltalán a widgetek helyét az ablakon belül? Itt jön képbe a dobozolás.

A dobozok (boxes) láthatatlan widget konténerek, melyekbe belerakhatjuk widgeteink. Két fajta doboz van : a vertikális és a horizontális. Mikor widgeteket rakunk egy horizontális dobozba, az objektumok balról jobbra, vagy jobbról balra kerülnek bele a hívástól függően. Vertikálisba pedig értelemszerűen felülről lefelé vagy vica versa. Bármilyen kombinácót használhatsz dobozok elhelyezésére, rakhatod őket egymás mögé, elé, egymásba, hogy a kívánt eredményhez eljuss.

A pack_start() függvény a tetejéről kezdi, és folytatja a munkát lefelé egy vertikális dobozban, míg egy horizontális dobozban balról jobbra csomagol.

pack_end() pont az ellenkezőjét csinálja, alulról felfelé egy vertikális dobozban, jobbról balra egy horizontális dobozban.

a doboz tartalma lehet egy másik konténer vagy egy widget. Sok widget már magában egy konténer, beleértve a gombot is, de általában ilyen csak a gombon belüli cimkénél szokott előfordulni.

Használva ezeket a hívásokat, a GTK tudni fogja hova akarjuk elhelyezni widgeteink, így automatikusan ki tud eszközölni átméretezést és hasonló trükkös dolgokat. Ezen felül még rengeteg módja van a widgetek dobozolasanak. Ez a módszer elég nagy rugalmassággal ajándékoz meg, a widgetek létrehozásában és elhelyezésében.

Pont emiatt a rugalmasság miatt lehet elsőre kicsit bonyolult a GTK.

A Pike GTK és a GTK különbségei

Mint már említettük, a képkezelésben vehető észre egy két újítás.

További információk

GTK Library Reference

Calendar

A második verziója a kalendárium modulnak rengeteg új képességgel bővült:

- Calendar TimeRange Objects : kényelmes objektumok, melyek bármely naptári számítást képesek elvégezni kezdve az általános gregorián évszámítástól, az ISO másodperceken át, az iszlám naptárig és a csillagidőig.

- Teljes időzóna adatbázis beleértve a regionális napkelte napnyugta értékeket és a teljes zónaeltolódás történelmet.

- Kiterjesztett Ünnep adatbázis. Mikor van a legközelebbi ortodox ünnep? Munkaszüneti nap lesz e holnap Romániában vagy nemzeti Gyásznap Finnországban?

- nyomtatási és ellenőrző lehetőségek

- Többnyelvűség támogatása. Kiirathatunk dátumot latinul vagy Argentin naptárat szünnapokkal Spanyolul.

- Modularizált és könnyű bővíthetőség más naptárokkal, ünnepeket tartalmazó adatbázisokkal és nyelvekkel.

Összeségében ez a modul új lehetőségekkel bővíti a határidő alapú, ünnepekkel foglalkozó és több fajta idő és/vagy dátum műveletekkel foglalkozó programok készítését.