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 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.
/* Disk üzerinde dosya şeklinde disket saklama. Uyarlama 2.00. * © Fedon Kadifeli 1989-1993. * Derleyici: Microsoft C. Uyarlama 8.00. */ #include <stdio.h> #include <stdlib.h> #include <conio.h> /* MS-CL */ #define M_OKU (0x25) /* mutlak disk okuma kesinti kodu */ #define M_YAZ (0x26) /* mutlak disk yazma kesinti kodu */ #define SEKTOR ((size_t)512) /* sektör boyu */ #define IOS ((size_t)48) /* bellek tampon boyu (sektör) */ #define BBS (1024/SEKTOR) /* 1K’lik bloklar */ #define MAKS_DB (66) /* en uzun dosya ismi boyu */ typedef unsigned char BAYT; /* 8 bit */ BAYT tam1 [IOS*SEKTOR], tam2 [IOS*SEKTOR]; /* karşılaştırma işlemi */ int esit (register BAYT * a, register BAYT * b, register size_t u) { while (u--) if (*a++ != *b++) return 0; /* uyuşmuyor */ return 1; /* uyuşuyor */ } /* esit */ /* mutlak disk girdi ve çıktı */ size_t mdisk (BAYT kesno, BAYT surno, size_t seksay, size_t sekno, BAYT * aktadr) { size_t dondeg; __asm { push di ; yazmaçları push si ; sakla push bp mov ah,kesno ; kesinti numarası (M_OKU, M_YAZ) mov al,surno ; disket sürücü numarası sub al,'A' ; 'A' -> 0, 'B' -> 1 mov cx,seksay ; sektör sayısı mov dx,sekno ; sektör numarası mov bx,aktadr ; aktarma adresi cmp ah,M_OKU jne else ; eğer M_YAZ ise int M_OKU jmp SHORT devam else: int M_YAZ devam: pushf pop ax ; bayrakları al and ax,1 ; hata biti (kesinti dönüş değeri) popf ; bayrakları geri al pop bp ; yazmaçları pop si ; geri al pop di mov dondeg,ax } return !dondeg; /* 0 hata; 1 tamam */ } /* mdisk */ /* menü seçeneklerini sor */ int mensor (void) { int sec; static char * scnklr [] = { "\n", " 1. Sakla\tDisket --> Disk", " 2. Yukle\tDisket <-- Disk", " 3. Karsilastir\tDisket <-> Disk" }; printf("\n\n\t%s\n\t%s\n\t%s\n\nSecenek:", scnklr[1], scnklr[2], scnklr[3]); if ((sec = _getch()) == '1' || sec == 'S' || sec == 's') sec = 1; else if (sec == '2' || sec == 'Y' || sec == 'y') sec = 2; else if (sec == '3' || sec == 'K' || sec == 'k') sec = 3; else sec = 0; puts(scnklr[sec]); return sec; } /* mensor */ /* kullanılacak disket sürücüsünü sor */ int sursor (void) { int sur; printf("Disket surucusu (A/B): "); if ((sur = toupper(_getch())) != 'A' && sur != 'B') sur = 0; printf(sur ? "%c:\n" : "\n", sur); return sur; } /* sursor */ /* kullanılacak disk dosyasının adını sor */ char * dossor (void) { static char da [MAKS_DB+3] = { MAKS_DB+1 }; printf("Disk dosya adi: "); _cgets(da); putchar('\n'); return da[2] ? da+2 : NULL; } /* dossor */ int main (void) { int secenek, surucu; char * da; FILE * dg; int b; size_t i, d1, d2; printf("Disk uzerinde dosya seklinde disket saklama." " Uyarlama 2.00.\n(C) Fedon Kadifeli 1989-1993.\n"); while ((secenek = mensor()) != 0) while ((surucu = sursor()) != 0) while ((da = dossor()) != NULL) { i = 0; d1 = 1; b = 0; /* 1 nolu seçenek : Disket --> Disk */ if (secenek == 1) { if ((dg = fopen(da,"rb")) != NULL) { fclose(dg); printf("'%s' dosyasi zaten var!\n", da); continue; } if ((dg = fopen(da,"wb")) == NULL) { printf("'%s' dosyasi acilamiyor!\n", da); continue; } while (mdisk(M_OKU, (BAYT)surucu, IOS, i, tam1) && (d1=fwrite((void *)tam1, SEKTOR, IOS, dg)==IOS) != 0) printf("\r%d", (i+=IOS)/BBS); printf(d1 ? (i?" adet blok '%s' dosyasina aktarildi.\n" :". Disket okunamadi!\a\n") : ". '%s' dosyasinda yazma hatasi!\a\n", da); } else { /* 2 veya 3 nolu seçenek */ if ((dg = fopen(da,"rb")) == NULL) { printf("'%s' dosyasi acilamiyor!\n", da); continue; } /* 2 nolu seçenek : Disket <-- Disk */ if (secenek == 2) { while (fread((void *)tam1, SEKTOR, IOS, dg) == IOS && (d1=mdisk(M_YAZ, (BAYT)surucu, IOS, i, tam1)) != 0) printf("\r%d", (i+=IOS)/BBS); printf(d1 ? " adet blok diskete aktarildi.\n" : ". Diskette yazma hatasi!\a\n"); } else { /* 3 nolu seçenek : Disket <-> Disk */ while ((d1=mdisk(M_OKU, (BAYT)surucu, IOS, i, tam1)) & (d2=fread((void *)tam2, SEKTOR, IOS, dg)==IOS) && (b =esit(tam1, tam2, IOS*SEKTOR)) != 0) printf("\r%d", (i+=IOS)/BBS); printf( !b ? ". Karsilastirma hatasi!\a\n" : d1 ? ". Dosya disketten kisa!\a\n" : d2 ? ". Disket dosyadan kisa!\a\n" : " adet blok uyusuyor.\n"); } } /* if */ fclose(dg); } /* while */ printf("\nIslem tamamlandi\n"); return 0; } /* 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) surno
da
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).
Menü 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ü (
veya
A:
) 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.