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) 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).
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.