Amiga C

24. Bölüm

Cenker Özkurt

C yolculuğumuz devam ediyor. Bu ay da aynı şekilde yeni örneklerimiz ile yazımızı sürdürüyoruz.

Hatırlayacağınız gibi, geçen ay Menudesign adı altında bir örnek program üzerinde çalışmıştık. Bu örnek ile kendi utility program arşivimizi hazırlayabiliyor ve çalıştırabiliyorduk. Bu örneğimizin en büyük faydası, bizlerin de artık kendi utility programlarımızı hazırlayabileceğimizi görmüş olmamız.

Yeni örneklerimize geçmeden önce, Compile ve Link işlemleri için kullanabileceğimiz parametre listesini vermek istiyorum. Bu parametreler ile programımızın hafıza modelini, hangi hafıza bölgesinde bulunacağını, asssembler listesini isteyip istemediğimizi belirtebiliyoruz. Bu sayede, örneğin programımızın assembler listesini incelememiz mümkün olabiliyor. Dikkat edin; Assembler listesi dedim!! Dikkat!! Dikkat!!.. Buradan da anlaşılacağı gibi, C derleyicimiz aynı zamanda bir assembler derleyicisi. Yazmış olduğumuz C programı, Compile vasıtasıyla assembler'a çevrilir. Fakat siz bu assembler listesini göremezsiniz. Görebilmeniz, için aşağıda vermiş olduğum parametre listesini kullanmanız gerekiyor.

Compiler Parametreleri:
-a	Assemble etmeden uzantısı .asm olan dosyayı yarat
-c	Link etmeden uzantısı .o olan dosyayı yarat
-s	Uyarı mesajlarını yazmadan compile et
-t	C source cümlelerini assembler listesine at
+c	Geniş code'lu hafıza modelini kullan
+d	Geniş data'lı hafıza modelini kullan
+l	Integer ve sabitleri 32 bit'lik long'a çevir

Link Parametreleri:
-lname      İhtiyaç olan module'ü name.lib'te ara 
+C[cdb]     Code, data ya da bss'leri chip hafızaya yükle 
+F[cdb]     Code, data ya da bss'leri fast hafızaya yükle
Compiler ve Linker parametreleri ayrı ayrı verilmiştir. Örneğin bir programımızın asssembler listesini görmek istersek, compile sırasında;
cc -a prog.c
yazmalıyız. Bu sayede Compile programı C programının asssembler listesini çıkaracaktır. İstersek bu üste üzerinde değişiklik yaparak yeniden compile edebiliriz. Gelecek ay bu konu üzerinde daha geniş olarak duracağız ve C programlarımızda asssembler programlanmızı çağırmayı öğreneceğiz.

Yukarıdaki parametreler Aztec C Versiyon 3.6 içindir. Elinde yeni versiyon 5.0'i olanlar bu parametreleri şu şekilde kullanacaklar:

cc -3 -a prog.c
Bu konudaki geniş bilgiyi disketinizdeki doküman dosyalarından öğrenebilirsiniz. Link işlemleri sırasında, programımızı istediğimiz hafıza bölgesine (Chip ya da Fast) atabiliriz. Bu işlem özellikle assembler programları yazdığımızda işimize yarayacaktır.

Şimdi bu ayki örneklerimize geçebiliriz. İlk örneğimiz, joystick ya da joystick portlarımızı kontrol için. Programı çalıştırdıktan sonra joystick'imizi hareket ettirerek hangi yönün sağlam ya da bozuk olduğunu öğrenmemiz mümkün. Programımız tamamı aşağıda olduğu gibi:

#define PORT 2

short *joy=0xdff008+2*PORT;
char*cia=0xbfe001;
main()
  while(1) {
    if(*joy&2) printf("SOL"); 
    if(*joy&512) printf("SAG");
    if((*joy>>1^*joy)&1)printf("ASAGI");
    if((*joy>>1^*joy)&256)printf("YUKARI");
    if(!(*cia&64*PORT))printf("ATES");
    printf("\n");
  }
}
İlk satırdaki önişlemci komutu ile, PORT macro sabitini belirliyoruz. Burada 2 sayısı 2. portu kullanacağımızı belirtiyor. Aynı şekilde 1. portu da kontrol etmemiz mümkün.

Diğer satırda 'joy' değişkeni short tipinde tanımlanıyor. Aynı zamanda bu değişkeni pointer olarak tanımlayarak joystick portunu görüntülemesini de sağlıyoruz. Portu görmemizi sağlayan adres, hex olarak 0xdff008+2*PORT'dir. short tipindeki değişkenler, 2 byte'lık bir yer kaplamaktadır. Bu adres de aynı şekilde bize 16 bitlik bir sayı ile geri döneceğinden, biz de short olarak tanımladık. Tanımlarken short yerine WORD tipi yazmanız da mümkün. Çünkü short ve WORD tamamen aynı özelliklere sahiptir. Fakat WORD tipi kullanırken, programınızın başına #include <exec/types.h> yazmanız gerekir. WORD bu dosya içerisinde short olarak define edilmektedir.

İkinci satırda 'fire' tuşunu kontrol için 'cia' değişkenini 0xbfe001 adresini gÖrüntüleyecek şekilde tanımlıyoruz. Sonraki satırlarda ana programa girerek 'while' komutu ile sonsuz bir döngüye giriyoruz. Döngü içerisinde 'if' satırları ile joy değişkeninin bit durumunu kontrol ediyoruz. Örneğin joystick'i sola çekerek 0xdff008+2*PORT adresinin 2. bit'inin '1' olup olmadığını öğrenerek durumu ekrana yazıyoruz. Diğer satırlarda da aynı şekilde bu adreslerin bit durumlarını kontrol ederek döngüye devam ediyoruz. Döngüden çıkmak için klasik hareket 'Ctrl-C' yapıyoruz.

Bu ayki ikinci örneğimiz günün tarihini ve saati öğrenmemizi sağlayan kısa bir program. Bu iş için iki komut kullanıyoruz. Komutlar Aztec firmasının hazırlamış olduğu kütüphanede mevcut, ilk komut timer'dan zamana karşılık bir değer okuyor. Timer bilgisayarımızın içerisinde devamlı çalışan bir sayıcı olarak çalışıyor. Daha sonra biz bu değeri okuyarak 26 byte'lık bir diziye çeviriyoruz. Diziyi ekrana yazarak sonucu görüyoruz.

main()
{
long *tloc;
long *clock;

/* Timer'dan zamana karsilik bir deger okur */
time(tloc);
/* Bu degeri 26 karakterlik ASCII'ye cevirir */
clock=ctime(tloc);

printf("%s\n",clock);
}
Diğer programımız ikinci örneğimizin daha gelişmişi. Program çalıştıktan sonra bir window açarak tarih, saat ve hafıza durumunu görüntülüyor. Ayrıca programı AmigaDos'tan run komutu ile MultiTask olarak çalıştırmak mümkün. Şimdi programımıza bir göz atalım:
/* STATUS (c) 9.1.1992 by CENKER OZKURT */
#include <stdio.h>
#include <exec/exec.h>
#include <exec/execbase.h>
#include <graphics/gfxbase.h>
#include <intuition/intuitionbase.h>
#include <exec/memory.h>

struct NewWindow windef = { 
  200, 0, 440, 22,
  -1,-1,
  CLOSEWINDOW,
  WINDOWCLOSE|WINDOWDRAG,
  NULL, NULL,
  NULL,
  NULL, NULL, 0, 0, 0, 0,
  WBENCHSCREEN
};

struct GfxBase *GfxBase;
struct IntuitionBase *IntuitionBase; 
struct Window *win; 
struct RastPort *rp;

main()
{
long *tloc;
long *clock;
long c[24];
char *msg;
chara[100];
int ChipFree,FastFree;

IntuitionBase = OpenLibrary ("intuition.library", 0);
GfxBase = OpenLibrary ("graphics.library", 0); 
win = OpenWindow (&windef); 
rp=win->RPort;

SetTaskPri(FindTask((char *) 0), -128);
SetWindowTitles(win,"STATUS(c)1992 by Cenker OZKURT",0); 
while(1) { 
  if(msg = GetMsg (win -> UserPort)) {
     ReplyMsg (msg);
     CloseWindow(win);
     CloseLibrary(GfxBase);
     CloseLibrary(IntuitionBase);
     return;
  }
  time(tloc);
  clock=ctime(tloc);
  strncpy(c,cIock,24);
  ChipFree = AvailMem (MEMF_CHIP);
  FastFree = AvailMem (MEMF_FAST);
  sprintf(a,"%s CHIP=%d FAST=%d",c,ChipFree,FastFree);
  Move(rp,23,18);
  Text(rp,a,strlen(a));
}
}
Programın ilk satırlarında #include önişlem komutları ile gerekli olan macrolar ve fonksiyonlar tanımlanıyor. Struct satırlarında kullanılan yapılar belirleniyor. Main() fonksiyonu içerisinde Intuition ve Graphics Library'leri açılıyor. OpenWindow() ile window'umuz hazırlanıyor ve SetTaskPri() ile çalışmaya başlayan programın task'lar arasındaki öncelik sırası belirleniyor. -128 en düşük değeri belirtiyor. Öncelik sırası -128 ile +127 arasında ayarlanabilir.

Sonraki satırda aynı şekilde sonsuz döngüye giriyoruz. GetMsg() fonksiyonu ile window'dan mesaj gelip gelmediğini kontrol ediyoruz. Window'u kapama mesajı geldiğinde 'if' bloklarına girerek programdan çıkıyoruz. Aksi takdirde alt satırlara geçilerek tarih, zaman ve hafıza durumunu öğreniyor ve window'a yazıyoruz.

Bu ayki üçüncü ve son programımız da C'de kayan yıldızlar! Birçok demoda karşımıza çıkan bu yıldızları ben de C'de sizler için hazırladım. Programımız çalıştıktan sonra ekranın ortasından bize doğru yıldızlar kayacaktır. Programımızın bazı avantajları da bulunmakta. Bunların başında kayan yıldızların hızını ve sayısını ayarlamak geliyor. Bununla birlikte yıldızların hangi noktadan bize doğru geleceğini belirleyebiliyoruz. Programın mantık kısmını anlamayı size bırakıyorum. Eğer bunu anlayabilirseniz yıldızları tersine sizden uzaklaştırabilirsiniz. Şimdi programımızı inceleyebiliriz:

/* Programming by Cenker OZKURT */

#include <exec/types.h> 
#include <intuition/intuition.h>
#include <graphics/gfxbase.h>

#define NSTARS    30

struct IntuitionBase *IntuitionBase; 
struct GfxBase *GfxBase;

struct NewScreen scrdef = {
  0,0,320,256,
  1,   /* # planes */
  -1,-1,
  NULL,
  CUSTOMSCREEN,
  NULL, NULL, NULL, NULL
};

struct NewWindow windef = {
  0, 0, 320, 256,
  -1,-1,
  CLOSEWINDOW,
  WINDOWCLOSE,
  NULL, NULL, NULL, NULL, NULL,
  0,0,0,0,
  CUSTOMSCREEN
};

struct Window *win;
struct Screen *scr;
struct RastPort *rp;
int x[NSTARS], y[NSTARS], z[NSTARS];
int xo[NSTARS], yo[NSTARS];

long seed;

main()
{
int xs, ys; 
long *msg; 
int magic, inc; 
register int i, fz;

magic=128; 
inc=6;

openstuff ();
SetRast(rp, 0L);
SetRGB4 (&(scr -> ViewPort), 0L, 0L, 0L, 0L);
SetRGB4 (&(scr -> ViewPort), 1L, 15L, 15L, 15L);

for (i=0; i<NSTARS; i++) point(i);

while(1) {
  for(i=0; i<NSTARS; i++) {
      if ((z[i] = inc) <= 0) point(i);
      fz = z[i];
      xs = x[i] * magic / fz + 160;
      ys = y[i] * magic / fz+ 128;
      SetAPen (rp, 0L);
      WritePixel (rp, (long) xo[i], (long) yo[-i]);
      if (xs < 0 || xs > 319 || ys < 0 | ys > 255) {
          point(i);
      }
      else {
          SetAPen (rp, 1L);
          WritePixel (rp, xs, ys);
          xo[i] = xs; yo[i] - ys;
      }
  }
  if (msg = GetMsg (win -> UserPort)) {
      ReplyMsg (msg);
      break;
  }
}
closestuff ();
}

point(i)
register int i;
{
  x[i] = rnd (256) - 128;
  y[i] = rnd (150) - 75;
  z[i] = 255;
}

openstuff()
{
if (!(IntuitionBase = OpenLibrary ("intuition.library",0L))) {
  printf ("Intuition open failed.");
  closestuff();
}

if (!(GfxBase = OpenLibrary ("graphics.library", 0L))) {
  printf ("graphics open failed.\n");
  closestuff();
}

if (!(scr = OpenScreen (&scrdef))) {
  printf ("Can't open screen.\n");
  closestuff();
}

windef.Screen = scr;
if (!(win = OpenWindow (&windef))) {
  printf ("Window painted shut.\n");
  closestuff();
}

rp = &(scr -> RastPort);
}

closestuff ()
{
if (win) CloseWindow(win);
if (scr) CloseScreen(scr);
if (GfxBase) CloseLibrary(GfxBase);
if (IntuitionBase) CloseLibrary(IntuitionBase);
}

rnd(max)
int max;
{
int result - (int)(seed % max);
long datevec[3], *DateStamp();

if (seed == 0L) {
  DateStamp (datevec);
  seed = (UWORD) (datevec[1] * datevec[2]);
} else {
 if (seed > 0x80000000L) seed = ((seed << 1) ^ 0x1D872B41L);
 else seed <<= 1;
}
return (result);
}
Program açıklamamıza geçelim. İlk olarak #include dosyaları ve struct satırları işleniyor. Aradaki,
#define NSTARS 30
satırı ile yıldız sayısını 30 tane olarak belirliyoruz. Bu sayı ile oynamanız mümkün. Diğer satırlarda Screen ve Window yapılan belirlenerek tek plane'lik bir ekran açılıyor. Tek planelik bir ekranda 2 adet rengimiz mevcut. Taban rengini siyah, yazı rengimizi ise beyaz olarak main() içerisindeki SetRG4() fonksiyonları ile tanımlıyoruz. Diğer satırlarda ise yıldız koordinatlarını ve ivmesini saklamak için integer olarak değişkenler kullanıyoruz.

main() içerisinde kullanılacak olan değişkenler de tanımlandıktan sonra, openstuff() ile bütün ekran ve library'ler hazırlanıyor.

SetRast(rp, 0L);
satırı ile açılan window'un, çerçeve rengini zemin renk olarak seçiyoruz.
SetRGB4 (&(scr -> ViewPort), 0L, 0L, 0L, 0L);
SetRGB4 (&(scr -> ViewPort), 1L, 15L, 15L, 15L);
Yukarıdaki satırlarda da zemin ve kalem rengi paletten seçiliyor. Sayıların yanındaki 'L' karakteri, değerin LONG olarak değerlendirileceğini belirtiyor, "(long) 1" ile "1L" arasında bir fark yok. Her iki yazım şekli de tip değişimini sağlıyor.

Diğer satırlarda yıldızlar belirlenerek bize doğru kaymaya başlıyorlar. Yıldız sayısını azalttığımızda hız biraz daha artacaktır, Window'umuzun sol üst köşesini kliklediğimizde programımız sona erecektir.

Program içerisindeki rnd() fonksiyonunu, rastgele sayı üretmek için kullanıyoruz, rnd(100) verdiğimizde, fonksiyon -100 ile 100 arasında bir sayı ile geri dönecektir. Bu altrutini siz de kendi programlarınızda rahatlıkla kullanabilirsiniz.

Programlarımız bu aylık da bu kadar. Gelecek ay C'de assembler rutinlerinin nasıl kullanıldığını sizlere göstereceğim. Şimdilik hepinize iyi çalışmalar..