C Dili – 15. Konu

C ve MS-DOS/Windows ile Ekran Duzeni

Simdiye kadar kacindigim bir konu ise, ekrani silme, cursor’un yerini
ogrenme yada degistirme, ekranin calisma modunu degistirme gibi konular
iceren ekran duzenidir. Aslinda C nin bir parcasini olusturmamakla
birlikte, bu konu programcilar icin cok onemlidir.

C ye sonradan eklenen bir ‘uzanti’ oldugu, ve sadece MS yada PC-DOS ile
calisan bilgisayarlarda kullanilabilecegi icin, burada gorecegimiz
int86() fonksiyonu, su anda sadece Microsoft C, ve Turbo C tarafindan
desteklenmektedir. Derleyiciniz baska ise, bu fonksiyon cagirilis metodunu
degistirmeniz gerekebilir.

Cok sayida degisik turde ekran tipleri ile kullanilabilecegi icin, C de
tanimlanmis, hazir ekran fonksiyonlari yoktur. Bu fonksiyonlar,
kullanilacak cihazin yapisina gore tanimlanabilir. Bu konu icerisinde,
elimizdekinin bir IBM-PC yada uyumlu bilgisayar oldugunu kabul edecegiz.

Ekrana Nasil Eriselim?

Temelde, 3 cesit yoldan ekrana erisebiliriz:

1) bir BIOS interruptu ile,
2) DOS’un ANSI.SYS i ile,
3) Direk donanima ‘karisarak’.

Her bir metodun avantaj ve dezavantajlari vardir. Daha derine dalmadan once, dilerseniz bu ‘interrupt’ lafinin manasini cozelim:

Interrupt

IBM PC ailesi, donanim yada yazilim tarafindan yaratilabilecek interruptlar
ile idare edilebilir. Bir interrupt olustugunda, bilgisayarin calismasi, bu
interruptu halledebilecek bir rutine yollanir. Bu rutinlerin baslangic
adresleri, ‘interrupt vektor tablosu’nda saklanir. Bu tablo, bilgisayarin
hafizasinin en alt kesiminde, ilk bir kilobytelik yerde bulunur. Bu sahada
255 ayri interrupt icin yer ayrilmistir.

Ornegin, 5. interrupt olustugunda, sistem ilk olarak butun registerleri
(birazdan anlatacagim) saklar, ve bu ilk 1K lik tablodan,
5. “kutu” ya bakip buradaki adresi okur. Sonra, buradan ogrendigi adrese
atlar ve orada ne islemler varsa yapar. Bunlar bitince, tekrar kaldigi
isleme geri doner.

Donanim Interruptlari (Hardware Interrupts): Bunlar, sistem tarafindan
cagirilan rutinlerdir. Ornegin sistem, her saniyede 18.2 kere bir interrupt
ile saatini ilerletmektedir. Bu cagirim, yada interrupt, donanim tarafindan
yaratilmaktadir. Diger bir baska interrupt ise, 9. klavye interruptudur.
Her tusa basildiginda, bu donanim interruptu olusur.

Yazilim Interruptlari (Software Interrupts): Bunlar ise, herhangi bir
programin cagirabilecegi bir rutinler kutuphanesidir. Ekrana birsey yazmak
gerektigine, yada silmek gerektiginde, bunu bir interrupt cagirarak
yapariz.

BIOS nedir? (BIOS==Basic Input/Output System)

BIOS’un gorevi, bilgisayarin yapmasi gereken temel servisleri yerine
getirmektir. Genis anlamda, BIOS IBM’in icindeki yongalarda bulunan
rutinler kutuphanesidir. BIOS, DOS ile donanim arasinda bir yerde bulunur.
Bir taraftan, bir programdan yapilmasi gereken standart BIOS komutunu alir.
Programimiz, BIOS a bu istegi, bir interrupt vasitasi
ile bildirir. BIOS un diger tarafi ise, bilgisayarin donanim parcalari
(ekran, disk drive, seri port, vs.) ile iliski kurar. BIOS’un bu
tarafi ise, dikkati cekmek icin bir interrupt yaratan bir donanim ile
konusur.

DOS nedir?

DOS ise, bir baska kutuphanedir. Ozellikle diske erisimde uzmanlasmis olan
DOS, bundan baska ekrana yazma, yaziciya bilgi yollama, vs. gibi servisleri
de kapsar. DOS’un da ayni BIOS gibi interruptlari ve sagladigi bircok
servis vardir. Aslinda DOS, cogu bu servisler icin BIOS’dan yardim
gormektedir.

Aklinizda bulunsun: BIOS yongalarda bulunur, DOS ise sonradan yuklenir.

Simdi, BIOS ile nasil ekran kontrolu yapabilecegimizi gorelim. Bir kere,
butun BIOS ekran fonksiyonlari, bir interrupt ile cagirilir, bunun da interrupt numarasi 16 dir. Herhangi bir BIOS fonksiyonunu kullanmak icin yapmamiz gerekenler, once bazi registerleri degistirmek,
onaltinci interruptu cagirmak, ve sonuclari zevkle seyretmektir.

Register?

IBM-PC ailesinin kullandigi 8088 yongasinin ve ondan sonra gelen tüm Intel ve AMD yongalarının, calismasinda kullandigi bazi ozel sahalar vardir. Bu sahalara “register” ismi verilir. IBM-PC de, toplam
olarak ondort tane register vardir. PC bunlari, aritmetik islemler, karsilastirmalar gibi islerde kullanir. Bunlardan dort tanesini BIOS interruptlari ile kullanacagiz. Bu kullanacaklarimizin
isimleri, AX,BX,CX ve DX dir. Bunlar ayni birer degisken gibi iclerinde
degerler tasiyabilirler. Bu registerlerin bir ozelligi ise, ister tam olarak, yani butun AX’i birden, istersek de yarim yarim (AH ve AL yi) degerlerini degistirmemiz mumkundur.

Yani, dilersek AX in icine bir 16 bitlik veri koyabiliriz, yada AL veAH lerin iclerine sekizer bitlik veri koyabiliriz. Hep AX i kullandigima bakmayin, BX i BL ve BH, CX i CH ve CL diye, DX i DL ve
DH diye ayirmamiz mumkun.

Dilerseniz soyle dusunun: Sayet CX dersek, asagidaki butun yapiyi kastediyoruz:
   +--+--+--+--+--+--+--+--+  +--+--+--+--+--+--+--+--+
   |                       |  |                       |
   +--+--+--+--+--+--+--+--+  +--+--+--+--+--+--+--+--+
   CH                            CL
   Fakat, CH yada CL dersek yarisini kastediyoruz. Yani CX=5 desek, yukaridaki 
   kutulara:
 
 
   +--+--+--+--+--+--+--+--+  +--+--+--+--+--+--+--+--+
   | 0  0  0  0  0  0  0  0|  | 0  0  0  0  0  1  0  1|
   +--+--+--+--+--+--+--+--+  +--+--+--+--+--+--+--+--+
   CH                            CL
 

koymus oluruz.. (binary 101, 5 e esittir) Fakat CH=6 desek,

   +--+--+--+--+--+--+--+--+  +--+--+--+--+--+--+--+--+
   | 0  0  0  0  0  1  1  0|  | 0  0  0  0  0  1  0  1|
   +--+--+--+--+--+--+--+--+  +--+--+--+--+--+--+--+--+
   CH                            CL

 

CL nin eski degerine dokunmamis oluruz. Bir onceki ornekte icine ‘101’
koydugumuz icin, CL hala o degerde kaldi. Aslinda butun bunlari bilmemize
luzum yok, fakat ileride isinize yarayabilir.

Cursor Pozisyonunu Ayarlamak:

Dilerseniz ilk olarak ekranin istedigimiz bir yerine atlayip, oraya
birseyler yazmayi deneyelim. Bunun icin cursor, yani, bundan sonra
yazilacak noktanin degistirilmesi gereklidir. (Cursor, yanip sonen bir
alt-cizgi gorumundedir, ve donanim ile kontrol edilir.)

POSDEGIS.C:
=========================================================
#include <dos.h>
void yerlestir(satir,kolon)     /* Bu fonksiyon, cursoru istedigimiz    */
   unsigned satir,kolon;           /* bir yere koyar */
   {
   union REGS giris_register,cikis_register;
   
   giris_register.h.ah = 2;        /* 2: set-cursor-position fonksiyonu*/
   giris_register.h.dh = satir;
   giris_register.h.dl = kolon;
   giris_register.h.bh = 0;        /* hangi sayfayi degistirelim?      */
   int86(16,&giris_register,&cikis_register);    /* cagiralim, yapsin  */
}
==========================================================
 

Ilk satirda gordugunuz #include <dos.h>, bu programda sart. Cunku daha
sonra gelen ‘union’ u tanimliyor. Bu union ile, iki tane degisken
tanimliyoruz, bunlar giris_register ve cikis_register olarak. Daha
sonra, bunlarin gereken elemanlarina verileri atiyoruz. Burada, hangi
elemana hangi verinin konacagi, ve servis numarasi (bizde 2) gibi verileri,
ya MS-DOS Technical Reference Manual’dan yada Peter
Norton’un Programmer’s Guide To the IBM-PC den bulabilirsiniz. En son
olarak, int86 fonksiyonu ile, 16. interruptu cagiriyoruz. Sistem ilk
olarak gidip o hafizanin ilk 1K sindaki tablodan 16. interruptun
rutinlerinin baslangic adresini ogreniyor. Daha sonra o adrese atlayip,
ikinci fonksiyonunun yerine geciyor, ve register degerlerine gore
istedigimizi yerine getiriyor.

Ozet: Cursor’u Yerlestirme Fonksiyonu
Interrupt no: 16
Servis No: 2
Gereken Veriler: AH=Servis numarasi, yani 2,
DH=satir numarasi,
DL=kolon numarasi,
BH=Kullanilacak Sayfa Numarasi

Bu sayfa numarasi parametresini merak edebilirsiniz. Normal bir monokrom
ekranin, sadece bir sayfasi vardir. Fakat ornegin CGA (Color Graphics
Adaptor) modunda, yani renkli adaptoru ‘text’ yada metin modunda calistiginda,
sayet satira-40 karakter modundaysa 8 sayfa, sayet
satira-80 karakter modundaysa, 4 sayfayi kullanabilir. Herhangi bir anda bu
sayfalardan biri ekranda gosterilebilir. (Evet – sayfa degistirmek icin bir
baska fonksiyon cagirmak gerekli.) Bazi programlar bu ozelligi, bir sayfayi
kullaniciya gosterirken, bir digerini hazirlayarak, super-hizli ekran
goruntuleri saglamakta kullanirlar. Ikinci merak edebileceginiz sey,

Cursor Pozisyonunu Okumak

olabilir. Bu da, yukaridaki yaziyi anladiysaniz, son derece kolaydir. Bu
sefer, interrupt’u cagirdiktan sonra donen degerlerle de ilgilenmekteyiz:

POSOGREN.C:
   =========================================================
   #include <dos.h>
 
void posogren(satir, kolon)  /* Bu fonksiyon, cursorun yerini BIOS yardimi 
   */
   unsigned *satir, *kolon;     /* ile ogrenir */
   {
   union REGS giris,cikis; 
   giris.h.ah = 3;     /* fonksiyon 3 - cursorun yerini oku */
   giris.h.bh = 0;     /* 0 inci sayfa.. */ 
   int86(16,&giris,&cikis);
 
   *satir = cikis.h.dh;    /* 3. fonksiyondan donen degerler:  */
   *kolon = cikis.h.dl;    /* DH icinde, cursorun satir no su, */
}                           /* ve DL icinde kolon numarasi..    */
   =================================================================

 

Bu programi calistiran ana program, soyle olabilir:

main()
   {
   int a,b;
   posogren(&a,&b);
   printf(" Program calistiginda cursor %d. satir, %d. kolonda 
   idi\n",a,b);
   }
 

a ve b nin adreslerinin gecirildigine dikkatinizi cekerim.

REGS Union’un Parcalari

Iki programdir gordugunuz REGS isimli union’un parcalari, bize herhangi bir
registerin herhangi bir parcasina erismemizi saglar. Sayet registerin
yarisinin degerini degistirmek istiyorsak, yukaridaki gibi, degiskenden
sonra ‘h’ koyariz, giris.h. gibi.. Bundan sonra ise, hangi registerin
degismesini istedigimizi soyleriz: giris.h.cl gibi. Sayet bir registerin
yarim yarim yerine tumden degistirmek istersek,
‘h’ yerine ‘x’ kullanmamiz gerekir: giris.x.bx gibi..

Ekran Tipini Ayarlamak

Yazdiginiz program, sadece seksen kolonluk bir ekranda calismak icin
duzenlenmis olabilir. Bilmeyen bir kullanici da, ekrani 40 kolona ayarli
iken, programi calistirmayi deneyebilir. Bu tip olaylara mani olmak icin,
programinizin basinda, ekrani istediginiz tipe ayarlayabilirsiniz. Bunun
icin, sifirinci servisi kullanabilirsiniz:

EKRANAYA.C:
   =============================================================
   #include <dos.h>
ekranayar(tip)      /* Bu fonksiyon, ekrani istegimiz tipe ayarlar */
short tip;
{
   union REGS giris,cikis; 
   giris.h.ah = 0;  /* 0 inci servis - mod degistirmek */
   giris.h.al = tip;   /* CGA; 0: b/w text 40x25,  1: 16 renk 40x25
   2: b/w text 80x25        3: 16 renk 80x25
   4: 4 renk Gra 320x200    5: 4 gri Gra 320x200
   6: b/w Gra 640x200
   MONO: 7: b/w text 80x25    */ 
 int86(16,&giris,&cikis); /* ayarlayalim */
   }
   ==============================================================
 

Burada, ekranin yeni tipini belirtmemiz gerekli. Bunun icin, 0 ila 15
arasinda bir deger vermemiz gerekiyor. Bu degerlerin 0 ila 6 arasindakiler,
CGA (renkli) icin, 7, monokrom icin, ve 8-10 arasi PCJr icin, ve sonrasi
EGA icindir. EGA, 8 ve 9 haric diger butun ekran modlarini destekler.

Ekrani Silmek

Gordunuz bile! Ekrani silmek, iki yoldan olabilir. Birincisi, ekranin
modunu degistirmek. Degistirdiginiz mod, su anki mod bile olsa, yine de
ekran silinir. Yegane dezavantaj, Compaq tipi makinelerde bu islem uzun
zaman alir. Dolayisi ile, bu isi dogru yapmamiz gerekir:

EKRANSIL.C:
   ==============================================================
#include <dos.h>
void ekransil()          /* bu rutin, ekrani siler */
{
   union REGS gir; 
   gir.h.ah = 6;       /* ekrani yukari kaydir: servis no su 6
   ekrani asagi kaydir: servis no 7 dir. */
   gir.h.al = 0;       /* kac satir scroll edecegi 'donecegi'
   sifir olunca, butun ekrani siler */
   gir.h.ch = 0;       /* sol ust kosenin satir no su */
   gir.h.cl = 0;       /* sol ust kosenin kolon no su */
   gir.h.dh = 23;      /* sag alt kosenin satir no su */
   gir.h.dl = 79;      /* sag alt kosenin kolon no su */
   gir.h.bh = 7;       /* yeni yaratilacak satirlar icin renk degeri   */ 
   int86(16,&gir,&gir);
}
==============================================================

Altinci BIOS servisi sayesinde, ekrani yukari kaydirma metodu ile
silmekteyiz. Ayni servis sayesinde, CX ve DX de gordugunuz degerleri
degistirerek, ekranin sadece bir parcasini ‘scroll’ etmek yani
kaydirmak mumkundur. Kaydirma yonunu servis numarasini 6 yada 7 yaparak
degistirebilirsiniz. Burada gordugunu gir.h.bh deki deger ise, yeni
acilacak satirlarin ‘attribute’ yani, rengi ve ozellikleri
parlak, yanip sonen, vs.) dir. Ayrica, yukaridaki ornekte,
gir.h.ch = 0;
gir.h.cl = 0;
yerine, sadece
gir.x.cx = 0;
diyebilirdik.

Baska Interruptlar

Bu orneklerde dikkat etmisinizdir – her int86() yi cagirisimizda, ilk
parametre olarak 16 yi belirttik. Bu istedigimiz interrupt’un
numarasidir. Daha once soyledigim gibi BIOS un ekran fonksiyonlarinin hepsi
interrupt 16 ile cagirilir. Fakat tabi, programlarimiz bununla
sinirli kalmak zorunda degildir, kullanabilecegimiz daha bircok interrupt
vardir. Dilerseniz, su programa bir bakin:

PRINTSCR.C:
==========================================================
#include <dos.h>
main()
{
  union REGS in;      /* buna ihtiyacimiz yok, ama tanimlamamiz lazim */
  int86(5,&in,&in);   /* print-screen yapalim */
} ==========================================================

bu program, gorevi ekrani oldugu gibi yaziciya gondermek olan interrupt 5 i
kullanmaktadir. Artik klavyeden PRINTSCREEN tusuna bastiginiza, sistemin ne
yaptigini biliyorsunuz.

DOS ve ANSI.SYS ile Ekran Duzeni

Umarim simdi size tumuyle degisik bir ekrana erisme metodu gosterirsem bana
kizmassiniz. Bu ikinci metodun birincisi ile neredeyse hicbir
alakasi yok. Bu metod sayesinde, programiniz, modem ile bagli uzak bir terminalden calisabilir, DOS’un yonlendirme metodlarindan (TYPE A.TXT > PRN gibi) faydalanabilir. ANSI bir terminali olursa, herhangi bir Unix sisteminde calisabilir. Nasil mi? Cok kolay – yaptigimiz, DOS
ekrana birsey gonderirken, ekran idarecisinin anlayabilecegi komutlari
kullanmak. Sadece DOS için: Yegane sorun, bu idarecinin siz yukleyinceye kadar calismaz
olmasi. Peki, nasil yukleyebiliriz? Sistemi actiginiz diskte, CONFIG.SYS
isimli bir kutuk olmasi lazim. Yoksa yaratin, ve icine:

DEVICE=ANSI.SYS

satirini koyun. Bundan sonra, DOS disketinde bulunan ANSI.SYS isimli
kutugun, sistemi actiginiz diskte bulunmasini saglayin. Son olarak da,
ANSI.SYS i yuklemek icin, CTRL-ALT-DEL e basin. Alet acildiginda, size fark
ettirmeden bu idareci yuklenecektir. Bundan sonra, dilerseniz
printf icinde, dilerseniz herhangi baska bir DOS u kullanan rutin ile ANSI
yi kullanabilirsiniz. (Anafikir: printf, ekrana yazmak icin, diger bircok C
fonksiyonu gibi, DOS’u kullanir.)

ANSI ile cursorun yerini degistirmek:

Ilk once, butun ANSI komutlari, bir ESC, yani ASCII 27 ile baslarlar.
Ornegin, cursorun yerini degistirmek icin, gereken komut ESC [#;#h dir. Ilk
# isaretinin yerine satir numarasi, ikincinin yerine de kolon konur. Bu,
bir programda soyle gorunebilir:

printf(“\x1b[%d;%dh”,satir,kolon);

(Ondalik 27 = Hex 1B )

satiri dikkatle incelerseniz, ilk once \x1b ile ESC karakterini, daha sonra
[, sonra ilk rakami, sonra ; ve ikinci rakami, ve son olarak da h isaretini
gorebilirsiniz. ANSI nin komut yapisi son derece sabit oldugundan, araya
bosluklar katarsaniz, programiniz calismayabilir.

ANSI ile Ekrani Silmek

Ekrani silmek kolay: ESC [2j yi ekrana yollamaniz yeterli:
printf(“\x1B[2j”);
araya bosluk koymamaya dikkat etmelisiniz. Ayrica kucuk ve buyuk harfler
farklidir.

Ekranin Rengini Ayarlamak

Bunun icin ESC [#;#m komutunu vermeniz gerekiyor. Ilk #, ekrandaki
yazilarin rengi, ikincisi ise arka planin rengidir. Bu renk kodlari
sunlardir:

30 siyah yazilar
31 kirmizi yazilar
32 yesil yazilar
33 sari yazilar
34 mavi yazilar
35 magenta yazilar (kirmizimsi)
36 cyan yazilar (mavimsi)
37 Beyaz yazilar
40 siyah arka plan
41 kirmizi arka plan
42 yesil arka plan
43 sari arka plan
44 mavi arka plan
45 magenta arka plan
46 cyan arka plan
47 beyaz arka plan

Diger ozellikler icin, ESC [#m girmeniz gerekli: # yerine,
0 normal
1 parlak
4 alt cizgi (monokrom da)
5 yanip sonen
7 ters renkler
8 gorunmez

DOS mu, BIOS mu kullansak

DOS, ve ekran idarecisi ANSI.SYS, BIOS a nazaran daha yavas calisir, fakat
bircok ortamda kullanilabileceginden, kalici programlar icin
daha uygun bir cozumdur. Ornegin oyunlar gibi yasam sureleri birkac ay olan
urunler ise, BIOS yada hatta direk erisim metodlarini kullanabilirler. ANSI
nin dezavantaji, kullanicinin ANSI.SYS i yuklemesinin gerektigidir. Bu da,
yeni kullanicilari panige kaptiran
bir durumdur.

Diger Interruptlar

Gordugunuz gibi BIOS ile ilgilenirken, sadece 2 interrupt kullandik. Ekran
fonksiyonlarini saglayan 16. interrupt, ve ekranin kopyasini yaziciya
gonderen 5. interrupt. Bunun gibi daha bircok interrupt vardir, ve bize cok
cesitli servisler sunarlar.

Ayrica, dilersek kendi interruptlarimizi da yazabiliriz. Bos olarak
tanimlanmis bir interrupt vektorunu degistirip, kendi rutinimizin adresini
ona verebiliriz. Yada, ornegin sidekick gibi programlarin yaptigi gibi
klavyenin yarattigi interrupt sonucunda cagirilan rutini degistirebiliriz,
ve diledigimiz baska birseyin yapilmasini saglayabiliriz. Bu tip programlar
ilk olarak basilan tusun kendilerini harekete gecirecek tus olup olmadigini
kontrol ederler, sayet degilse kontrolu eski interrupt rutinine gecirirler.

Mutlu Son!

Bu kitabı beğendiniz mi? Beğendiyseniz bana 2 satır birşey yazar mısınız? turgut
(at işareti) kalfaoglu.com dur email adresim..
Niye mi email adresimi boyle garip yazıyorum?
Çünkü açık açık yazınca spam’ciler hemen buluyor 🙁

Sağlıcakla ve bol programlamayla kalın!

Turgut Kalfaoglu

Bir Sonraki Konu