Standart C Programlama Dili


C.7.3. Bir Örnek—Disket Saklama

Uyarı:
Kitabın bu kısmı eski bilgiler içermektedir. Ancak, okuyucunun yararına olabileceği düşünülerek aynen korunmuştur.

Bu kısımda, bir disketi olduğu gibi diske kopyalayıp geri alabilen veya disketle disk dosyasını karşılaştırabilen bir programı inceleyeceğiz. Program bir disketi blok blok okuyup diskteki tek bir dosya içine kopyalamakta veya bu işin tam tersini yapmaktadır.

Bu amaçla diskette istediğimiz bir sektörü okuyup yazabilen bir yönteme gereksinimimiz vardır. MS-DOS kesintilerinden 0x25 ve 0x26 bu işi yaparlar, ancak bir sorunları vardır: Olası bir hata durumunu bayrak yazmacının elde (carry) bitinde, hata kodunu ise AX yazmacında döndürürler. Bu arada, bayrak yazmacının eski durumunu da yığıtta saklarlar. Bu durumda, bu kesintilerden dönüldüğü zaman yığıtta fazla bir sözcük bulunmaktadır. Programa devam etmeden önce bunun geri alınması gerekir. Bu yüzden, bu kesintileri dos.h başlık dosyasında tanımlanmış _int86 fonksiyonunu kullanarak çağıramayız; birleştirici kodu yazmamız gerekir. Aşağıdaki programda mdisk fonksiyonu bu işi yapar.

  1. /*     Disk uzerinde dosya seklinde disket saklama. Uyarlama 2.00.
  2.  *     (C) Fedon Kadifeli 1989-1993.
  3.  *     Derleyici: Microsoft C. Uyarlama 8.00.
  4.  */
  5.
  6. #include  <stdio.h>
  7. #include  <stdlib.h>
  8. #include  <conio.h>               /* MS-CL */
  9.
 10. #define M_OKU   (0x25)            /* mutlak disk okuma kesinti kodu */
 11. #define M_YAZ   (0x26)            /* mutlak disk yazma kesinti kodu */
 12. #define SEKTOR  ((size_t)512)     /* sektor boyu                    */
 13. #define IOS     ((size_t)48)      /* bellek tampon boyu (sektor)    */
 14. #define BBS     (1024/SEKTOR)     /* 1K'lik bloklar                 */
 15. #define MAKS_DB (66)              /* en uzun dosya ismi boyu        */
 16.
 17. typedef unsigned char  BAYT;      /* 8 bit  */
 18.
 19. BAYT  tam1 [IOS*SEKTOR], tam2 [IOS*SEKTOR];
 20.
 21. /* karsilastirma islemi */
 22. int esit (register BAYT * a, register BAYT * b,  register size_t u)
 23. {
 24.   while (u--)
 25.     if (*a++ != *b++)
 26.       return 0;                   /* uyusmuyor */
 27.   return 1;                       /* uyusuyor  */
 28. }  /* esit */
 29.
 30. /* mutlak disk girdi/cikti */
 31. size_t mdisk (BAYT kesno, BAYT surno, size_t seksay, size_t sekno,
 32.   BAYT * aktadr)
 33. {
 34.   size_t dondeg;
 35.   __asm {
 36.        push    di                 ; yazmaclari
 37.        push    si                 ;  sakla
 38.        push    bp
 39.        mov     ah,kesno           ; kesinti numarasi (M_OKU, M_YAZ)
 40.        mov     al,surno           ; disket surucu numarasi
 41.        sub     al,'A'             ; 'A' -> 0, 'B' ->  1
 42.        mov     cx,seksay          ; sektor sayisi
 43.        mov     dx,sekno           ; sektor numarasi
 44.        mov     bx,aktadr          ; aktarma adresi
 45.        cmp     ah,M_OKU
 46.        jne     else               ; eger M_YAZ ise
 47.        int     M_OKU
 48.        jmp     SHORT devam
 49. else:  int     M_YAZ
 50. devam: pushf
 51.        pop     ax                 ; bayraklari al
 52.        and     ax,1               ; hata biti (kesinti donus degeri)
 53.        popf                       ; bayraklari geri al
 54.        pop     bp                 ; yazmaclari
 55.        pop     si                 ;  geri al
 56.        pop     di
 57.        mov     dondeg,ax
 58.   }
 59.   return !dondeg;                 /* 0 hata; 1 tamam */
 60. }  /* mdisk */
 61.
 62. /* menu seceneklerini sor */
 63. int mensor (void)
 64. {
 65.   int            sec;
 66.   static char *  scnklr [] = {
 67.     "\n",
 68.     " 1. Sakla\tDisket --> Disk",
 69.     " 2. Yukle\tDisket <-- Disk",
 70.     " 3. Karsilastir\tDisket <-> Disk" };
 71.
 72.   printf("\n\n\t%s\n\t%s\n\t%s\n\nSecenek:",
 73.     scnklr[1], scnklr[2], scnklr[3]);
 74.   if ((sec = _getch()) == '1' || sec == 'S' || sec == 's')
 75.     sec = 1;
 76.   else if (sec == '2' || sec == 'Y' || sec == 'y')
 77.     sec = 2;
 78.   else if (sec == '3' || sec == 'K' || sec == 'k')
 79.     sec = 3;
 80.   else
 81.     sec = 0;
 82.   puts(scnklr[sec]);
 83.   return sec;
 84. }  /* mensor */
 85.
 86. /* kullanilacak disket surucusunu sor */
 87. int sursor (void)
 88. {
 89.   int  sur;
 90.
 91.   printf("Disket surucusu (A/B): ");
 92.   if ((sur = toupper(_getch())) != 'A' && sur != 'B')
 93.     sur = 0;
 94.   printf(sur ? "%c:\n" : "\n", sur);
 95.   return sur;
 96. }  /* sursor */
 97.
 98. /* kullanilacak disk dosyasinin adini sor */
 99. char * dossor (void)
100. {
101.   static char  da [MAKS_DB+3] = { MAKS_DB+1 };
102.
103.   printf("Disk dosya adi: ");
104.   _cgets(da);
105.   putchar('\n');
106.   return da[2] ? da+2 : NULL;
107. }  /* dossor */
108.
109. int main (void)
110. {
111.   int     secenek, surucu;
112.   char *  da;
113.   FILE *  dg;
114.   int     b;
115.   size_t  i, d1, d2;
116.
117.   printf("Disk uzerinde dosya seklinde disket saklama."
118.     " Uyarlama 2.00.\n(C) Fedon Kadifeli 1989-1993.\n");
119.   while ((secenek = mensor()) != 0)
120.     while ((surucu = sursor()) != 0)
121.       while ((da = dossor()) != NULL) {
122.         i = 0;
123.         d1 = 1;
124.         b = 0;
125.         /* 1 nolu secenek : Disket --> Disk */
126.         if (secenek == 1) {
127.           if ((dg = fopen(da,"rb")) != NULL) {
128.             fclose(dg);
129.             printf("'%s' dosyasi zaten var!\n", da);
130.             continue;
131.           }
132.           if ((dg = fopen(da,"wb")) == NULL) {
133.             printf("'%s' dosyasi acilamiyor!\n", da);
134.             continue;
135.           }
136.           while (mdisk(M_OKU, (BAYT)surucu, IOS, i, tam1) &&
137.             (d1=fwrite((void *)tam1, SEKTOR, IOS, dg)==IOS) != 0)
138.               printf("\r%d", (i+=IOS)/BBS);
139.           printf(d1 ? (i?" adet blok '%s' dosyasina aktarildi.\n"
140.                         :".  Disket okunamadi!\a\n")
141.                     : ".  '%s' dosyasinda yazma hatasi!\a\n", da);
142.         } else {
143.         /* 2 veya 3 nolu secenek */
144.           if ((dg = fopen(da,"rb")) == NULL) {
145.             printf("'%s' dosyasi acilamiyor!\n", da);
146.             continue;
147.           }
148.           /* 2 nolu secenek : Disket <-- Disk */
149.           if (secenek == 2) {
150.             while (fread((void *)tam1, SEKTOR, IOS, dg) == IOS &&
151.               (d1=mdisk(M_YAZ, (BAYT)surucu, IOS, i, tam1)) != 0)
152.                 printf("\r%d", (i+=IOS)/BBS);
153.             printf(d1 ? " adet blok diskete aktarildi.\n"
154.                       : ".  Diskette yazma hatasi!\a\n");
155.           } else {
156.           /* 3 nolu secenek : Disket <-> Disk */
157.             while ((d1=mdisk(M_OKU, (BAYT)surucu, IOS, i, tam1)) &
158.               (d2=fread((void *)tam2, SEKTOR, IOS, dg)==IOS) &&
159.               (b =esit(tam1, tam2, IOS*SEKTOR)) != 0)
160.                 printf("\r%d", (i+=IOS)/BBS);
161.             printf(
162.               !b ? ".  Karsilastirma hatasi!\a\n" :
163.               d1 ? ".  Dosya disketten kisa!\a\n" :
164.               d2 ? ".  Disket dosyadan kisa!\a\n" :
165.                    " adet blok uyusuyor.\n");
166.           }
167.         }  /* if */
168.         fclose(dg);
169.       }  /* while */
170.   printf("\nIslem tamamlandi\n");
171.   return 0;
172. }  /* main */

esit fonksiyonu (Satır 22-28) iki tampon bölgeyi karşılaştırır, eşitse 1 döndürür, aksi takdirde 0 döndürür.

mdisk fonksiyonu (Satır 31-60) surnoda verilen sürücüdeki—bu programda, surno 'A' veya 'B' değerlerini alabilmektedir—sekno başlangıç sektör (kesim) numarasından seksay sektör sayısı kadar sektör üzerinde işlem yapar. kesno M_OKU’ya eşitse disketten bu sektörleri okuyup aktadr tampon bölgesine aktarır; kesno M_YAZ’a eşitse aktadr tampon bölgesindeki baytları disketteki ilgili sektörlere yazar. Bu fonksiyon, yukarıda anlatıldığı gibi ilgili kesintiyi çağırdıktan sonra, yığıtta saklanmış bulunan bayrakları bayrak yazmacına geri alır (Satır 53).

Menu seçeneklerini kullanıcıya mensor fonksiyonu (Satır 63-84) gösterir ve istenilen seçeneği kullanıcıdan alır. Bir numaralı seçenek, programın disketi sektör sektör okuyup, adı kullanıcıdan alınan, bir disk dosyası içine kopyalamasını sağlar. İki numaralı seçenek bu işin tersini yapar; daha önce, bir numaralı seçenek kullanılarak, disk dosyası içine aktarılmış olan bir disket görüntüsünün sektör sektör okunup formatlanmış bir diskete aktarılmasını sağlar. Üç nolu seçenek diskteki dosya ile disketi karşılaştırır; bu seçenek, bir veya iki nolu seçenekler kullanılarak yapılan bir kopyalama işleminden sonra, işlemin doğruluğunu sınamak için kullanılabilir.

Kullanılacak disket sürücüsü (“A:” veya “B:”) sursor fonksiyonu (Satır 87-96) aracılığıyla kullanıcıdan alınır. Kullanılacak disk dosyasının adı ise dossor fonksiyonu (Satır 99-107) tarafından alınır. Burada, dosya adını okumak için standart olmayan _cgets fonksiyonu kullanılmıştır. _cgets fonksiyonu kontrollü bir şekilde klavyeden bir satır okumak için kullanılabilir.

Ana fonksiyon içiçe üç döngüden oluşur; bunlar, sırasıyla, kullanıcıdan menü seçeneğini, kullanılacak sürücüyü ve dosya adını alırlar. Her bir menü seçeneği için yapılan işlem temelde aynıdır: Bir döngü içinde disk dosyası ve/veya disketten bilgi okunup gerekli işlem yapılır. (Karşılaştırma seçeneği kısmında, satır 157’nin sonunda neden && değil de & kullanılmıştır?)

Not: Bu program kullanılırken dikkat edilmesi gereken bir nokta disket kapasitesidir. İşlenen bilgi miktarı kilobayt cinsinden ekranda görüntülenir. Örneğin 1.44 megabaytlık bir disket ile işlem yapıldığında ekrandaki sayının son durumu 1440 olmalıdır. Programda kullanılan kesintinin gerçek disket kapasitesini anlaması olası değildir; MS-DOS ortamında iken en son yapılan disket işlemindeki disket kapasitesi kullanılır. Bu yüzden, herhangi bir sorun çıkmaması için, program kullanılmadan önce, kullanılacak disket tipinden bir disket sürücüye takılıp, örneğin “DIR A:” veya “CHKDSK A:” şeklinde bir MS-DOS komutu çalıştırılmalıdır. Bundan sonra, program yürütülmesi esnasında, kullanılan disketlerin kapasitesi değişmediği sürece, herhangi bir sorun çıkmayacaktır. Dikkat edilmesi gereken bir diğer nokta da, kullanılan disketlerin formatlı olması ve bozuk sektörlerin bulunmamasıdır.