Magic Disk 64

home to index to html: MD9211-KURSE-FLOPPY-KURS_6.1.html
              Floppy-Kurs:              
      "Es rappelt in der Kiste..."      
                (Teil 6)                
----------------------------------------
Hallo und herzlich Willkommen zum  sech-
sten Teil unseres Floppykurses. Wir wol-
len unsere Kenntnisse auch  hier  wieder
vertiefen  und zwei weitere Beispielpro-
gramme kennenlerenen. Eines, um das  Di-
rectory  auf  dem  Bildschirm anzuzeigen
und eines um gelöschte Files  wieder  zu
retten.                                 
BEISPIEL 1: DIRECTORY ANZEIGEN          
Unser erstes Programmbeispiel soll  eine
Routine  sein, mit der Sie das Directory
der eingelegten Diskette ohne  Speicher-
verlust  einlesen  können.  Dies ist ein
Hinweis auf eine besondere Eigenheit der
Floppy. Wenn wir  uns  nämlich  das  In-
haltsverzeichnis  einer Diskette einfach
nur anzeigen lassen  wollen,  so  können
wir  durch Angabe des Filenamens "$" die
Floppy dazu bewegen, uns sehr  viel  Ar-
beit  abzunehmen.  Sie beginnt dann näm-
lich  damit,  alle  Directoryblöcke  von
selbst einzulesen und sie für uns aufzu-
bereiten. Ein  direktes  "herumpfuschen"
auf  der  Diskette  mittels  der  Block-
Befehle entfällt.                       
Wollen wir uns  nun  verdeutlichen,  was
passiert,  wenn  wir wie gewohnt das Di-
rectory mit LOAD"$",8  in  den  Speicher
des  Computers laden. Wie schon erwähnt,
ist das Dollarzeichen für die Floppy das
Kennzeichen für eine spezielle Aufberei-
tung des  isketteninhalts. Sie sendet an
den  C64  nun Daten, die dieser, wie bei
auch beim Laden eines normalen Programms
in seinen Basic-Speicher  schreibt.  Der
Computer   behandelt  das  Directory  im
Prinzip  also  wie  ein  Basic-Programm.
Dies  wird  dadurch  bestätigt,  daß das
eingelesene Directory auch wie  ein  Ba-
sic-Programm,  mit  dem  Befehl LIST auf
dem Bildschirm angezeigt wird. Sie  kön-
nen  es  sogar  mit  NEW wieder löschen,
oder mit RUN  starten,  was  jedoch  nur
einen  Syntax-Error  bewirkt, da das Di-
rectory ja  keine  echten  Basic-Befehle
enthält.  Sinnigerweise  übermittelt die
Floppy in der Directoryliste als  erstes
auch  immer die Blockanzahl eines Files,
was für das Basic des C64 einer  Zeilen-
nummer  entspricht.  Diese Zeilennummern
sind zwar nicht immer in  einer  numeri-
schen  Reihenfolge, jedoch macht das Ba-
sic unseres Computers da  keinen  Unter-
schied.  Der interne Aufbau eines Basic-
Programms erlaubt es  tatsächlich,  Zei-
lennummern wahllos zu vergeben. Wenn wir
ein  Programm  direkt  eingeben  ist das
natürlich nicht möglich, da die Eingabe-
routine  des  Betriebssystems  die Zeile
anhand der Zeilennummer  automatisch  an
der  logisch richtigen Position des Pro-
gramms einfügt.                         
Der langen Rede kurzer Sinn ist, daß wir
beim  Öbermitteln des Directorys von der
Floppy darauf achten müssen,  daß  diese
es  uns  in  einer Form schickt, die ei-
gentlich nur der Basic-Programm-Speicher
versteht, so daß  die  LIST-Routine  das
'Directory-Programm'  listen  kann. Des-
halb gibt e) einige Bytes, die  für  uns
wertlos  sind  und überlesen werden müs-
sen. Hierzu erkläre  ich  Ihnen  einfach
einmal den Aufbau des Files, das uns die
Floppy  bei  Angabe  des  Filenamens "$"
übermittelt.  Zuerst  erhalten  wir  von
ihr,  wie  bei jedem File, daß normaler-
weise mittels LOAD in den  Speicher  des
Computers  gelangt, eine Adresse, an die
das "Programm" geladen werden soll. Dies
ist die Basic-Startadresse  $0801  (dez.
2049)  im Low/High-Byteformat. Wir benö-
tigen diese natürlich nicht, und  können
sie  deshalb  überlesen.  Von nun an ist
der Aufbau  einer  jeden  Directoryzeile
gleich. Zuerst werden dabei zwei Linkby-
tes übertragen, die der  Basic-Interpre-
ter benötigt, um die einzelnen Zeilen zu
verketten.   Beide  können  wir  getrost
überlesen.  Als  nächstes  erhalten  wir
dann  die  Blockanzahl in Low/High-Byte-
Darstellung, was  für  den  Basic-Inter-
preter   einer  Zeilennummer  entpräche.
Diese Nummer müssen wir nun erst  einmal
umrechnen,  bevor  wir sie ausgeben kön-
nen. Hieran anschließend folgen nun  ein
oder  mehrere  Spacezeichen,  sowie  der
Filename und die  Filekennung  im  Klar-
text.  Alle diese letzten Zeichen werden
im ASCII-Code übertragen, so daß wir sie
lediglich mit PRINT ausgeben müssen.  Am
Ende  bekommen  wir  dann noch eine Null
übermittelt, die  das  Ende   der   (Ba-
sic-)Zeile kennzeichnet. An ihrer Stelle
müssen  wir  lediglich  einen Zeilenvor-
schub ausgeben (ein PRINT  ohne  Parame-
ter).  Das  Ende des Files ist natürlich
dann erreicht, wenn  die  Statusvariable
ST  gleich  64 ist. Im Prinzip ist alles
also ganz einfach. Hier ist das entspre-
chende  Basic-Programm,  Sie  finden es 
auf dieser MD unter dem Namen "FK.DIR": 
 10 gosub200                            
 20 end                                 
 30 :                                   
 31 :                                   
 90 rem *****************               
 91 rem * zeichen lesen *               
 92 rem *****************               
 93 :                                   
100 get#1,a$                            
110 ifa$=""thena=0:return               
120 a=asc(a$):return                    
130 :                                   
131 :                                   
190 rem **********************          
191 rem * directory anzeigen *          
192 rem **********************          
193 :                                   
200 print"{clr}";:open1,8,0,"$"         
210 fori=1to4:get#1,a$:next             
215 :                                   
220 gosub100:bl=a                       
230 gosub100:bl=bl+256*a                
240 print bl;                           
250 get#1,a$:printa$;                   
260 ifa$<>""then250                     
270 print                               
280 fori=1to2:get#1,a$:next             
290 ifst=0then220                       
300 close1                              
310 return                              
In den Zeilen  100-120  sehen  Sie  eine
Routine,  die  uns ein Byte mittels GET#
einliest und es als numerischen Wert  in
der  Variablen  "a"  abspeichert.  Diese
Routine ist deshalb notwendig,  da  eine
Umwandlung  des Strings "a$" bei dem By-
tewert 0 einen "illegal quantity  error"
verursacht.  Das  liegt  daran,  daß ein
String, der nur den Bytewert 0 als  Zei-
chen   enthält,  einem  Leerstring  ent-
spricht. Deshalb muß  mit  der  IF-THEN-
Abfrage  überprüft  werden,  ob "a$" ein
Leerstring ist, oder nicht.             
Ab Zeile 200 sehen wir nun das Programm,
das  das  Directory einliest und auf dem
Bildschirm ausgibt. In  Zeile  200  wird
zunächst  einmal der Bildschirm gelöscht
und der Filekanal, der uns das Directory
sendet, geöffnet.  Ich  habe  hier  ganz
bewußt die Sekundäradresse 0 benutzt, da
sie  der Floppy ja automatisch mitteilt,
daß wir ein Lesefile öffnen (sh. voheri-
ge  Teile  dieses  Kurses). In Zeile 210
werden nun die Startadresse und die bei-
den  Linkbytes  der ersten Zeile überle-
sen.                                    
Danach  beginnt  die  Hauptschleife  des
Unterprogramms.  In  den  Zeilen 220 und
230 lesen wir hier  zunächst  mit  Hilfe
unserer   "Zeichen  lesen"-Unterroutine,
Low- und High-Byte der Blockanzahl  aus,
verrechnen  diese  beiden  Werte  zu der
reellen Blockanzahl und speichern sie in
der Variablen  "bl"  (Wert=Lowbyte+256*-
Highbyte). Die Blockanzahl wird jetzt in
Zeile 240 auf dem Bildschirm ausgegeben.
Wir  hängen an den PRINT-Befehl ganz be-
wußt ein Semikolon an, damit der folgen-
de  Text  direkt  hinter der Blockanzahl
ausgegeben wird. Dies geschieht  in  den
Zeilen  250  und 260. Dort lesen wir je-
weils ein Zeichen mittels GET# ein,  und
geben es anschließend auf dem Bildschirm
aus.  War  das  eingelesene  Zeichen ein
Leerstring, entspricht es dem Bytewert 0
und die Zeile ist zu Ende. Jetzt wird in
Zeile 270 eine Leerzeile ausgegeben, daß
der Cursor am Anfang der nächsten  Zeile
steht.  In  Zeile  280 werden die beiden
Linkbytes der folgenden  Directory-Zeile
überlesen.  In  der  IF-THEN-Abfrage  in
Zeile 290 wird überprüft,  ob  das  Ende
des  Files  schon  überlesen wurde. Wenn
nicht, wird an  den  Anfang  der  Haupt-
schleife  verzeigt und alles beginnt von
vorne. Wenn doch, so wird der  Filekanal
geschlossen und zum aufrufenden Programm
zurückverzweigt.                        
BEISPIEL 2: GELOESCHTE FILES RETTEN     
Um Sie in die Benutzung der Blockbefehle
weiter einzuführen, wollen wir uns jetzt
einem weiteren Programmbeispiel in BASIC
zuwenden. Wir wollen ein einfaches  "UN-
DELETE"-Programm schreiben. Mit ihm soll
es  möglich  sein, versehentlich mit dem
Floppybefehl "SCRATCH" ("S:")  gelöschte
Dateien  wiederherzustellen. Hierzu wol-
len wir zunächst einmal klären, was  die
Floppy  eigentlich  macht,  wenn sie ein
File löschen soll.  Als  erstes  bekommt
Sie  einen  Befehl  übermittelt, der sie
dazu auffordert ein (oder auch  mehrere)
Files  zu  löschen.  Als Beispiel wollen
wir einmal ein  File  mit  Namen  "TEST"
heranziehen. Der entsprechende Floppybe-
fehl an den Befehlskanal muß also lauten
"S:TEST". Hieraufhin beginnt die  Floppy
nun,  das  Inhaltsverzeichnis der einge-
legten  Diskette  nach  einer  Datei  zu
durchsuchen, die den Namen "TEST" trägt.
Wird  sie  gefunden, so trägt die Lösch-
Routine des Floppy-Betriebssystems ledi-
glich  den Wert 0 als Filetyp für dieses
File ein, und sucht nun alle Blocks  he-
raus,  die  von  dem File belegt werden.
Jetzt holt sich die Floppy die  BAM  der
Diskette  in  den Speicher, kennzeichnet
alle vom File belegten  Datenblocks  als
'unbelegt'  und  schreibt die BAM wieder
zurück auf die Diskette. Der  Filetyp  0
entspricht dem Filetyp "DEL", der norma-
lerweise im Directory nicht  mehr  ange-
zeigt  wird.  An  dieser Leerstelle wird
das File einfach übersprungen. Im  Prin-
zip  sind  aber noch alle seine Informa-
tionen auf der Diskette  enthalten.  Zu-
mindest  einmal  solange, bis Sie wieder
ein neues File auf die Diskette  schrei-
ben.  Dann nämlich sucht sich die Floppy
den ersten freien  Directoryeintrag  he-
raus, der in unserem Fall, der des Files
"TEST" ist, und trägt dort das neue File
ein.  Desweiteren kann es dann auch pas-
sieren, daß  die  Datenblocks,  die  von
"TEST"  belegt wurden möglicherweise von
denen des neuen Files überschrieben wer-
den.  Ein  UNDELETE-Programm hat deshalb
nur dann einen Sinn,  wenn  noch  nichts
neues auf die Diskette geschrieben wurde
(obwohl  es  auch andere Programme gibt,
die selbst dann noch das eine oder ande-
re  retten  können  - hierauf kommen wir
später zurück). Es  muß  lediglich  alle
Einträge  im  Directory  nach Filetyp-0-
Einträgen durchsuchen und  diese  Anzei-
gen.  Hieraufhin  muß  vom Benutzer ent-
schieden  werden,  welchen  Filetyp  das
alte  File  hatte  (dies ist die einzige
Information, die über selbiges  verloren
ging).  Ist dieser angegeben, so braucht
unser Programm nur noch den Entsprechen-
den Code in den Fileeintrag zu schreiben
und  alle Blocks des Files zu verfolgen,
die von ihm belegt wurden und sie  aber-
mals  als 'belegt' zu kennzeichnen. Dies
kann man über  die  umständliche  Metode
tun, indem man aus den Bytes 1 und 2 des
Fileeintrags  Track  und  Sektor  ersten
Datenblocks ermittelt, und nun alle ver-
ketteten  Blöcke  (nächster  Block steht
immer in den ersten beiden  Bytes  eines
Datenblocks)  heraussucht uns diese mit-
tels Block-Allocate-Befehl  ("B-A")  als
belegt  kennzeichnet. Die zweite Methode
ist  einfach  den  Validate-Befehl   der
Floppy zu benutzen. Dieser sucht nämlich
automatisch  alle  Blocks  von  gültigen
Fileeinträgen im  Directory  heraus  und
kennzeichnet  sie  als  'belegt'.  Beide
Methoden haben ihre Vor- und  Nachteile.
Benutzen wir die erste Methode, so haben
wir  bei höherem Programmieraufwand eine
weitaus  höhere   Arbeitsgeschwindigkeit
(da nur die Blocks eines Files herausge-
sucht werden müssen und nicht aller  Fi-
les  der  Diskette,  was  sich vor allem
dann bemerkbar macht, wenn Sie besonders
viele Files  auf  der  Diskette  haben).
Andererseits  ist  es bei dieser Methode
nicht so einfach, die Blocks eines  REL-
Files   wiederzubelegen,  da  diese  mit
zusätzlichen Side-Sektor-Blöcken  arbei-
ten,  die  ebenfalls gesucht werden müs-
sen. Das aber wiederum macht der Valida-
te-Befehl für uns. Ausserdem arbeitet er
bei  Disketten mit wenigen Files weitaus
schneller als unsere Routine, da  er  ja
ein  Floppyprogramm ist und ein zeitrau-
bender  Datenaustausch  zwischen  Floppy
und  C64 entfällt. Da wir unser Programm
in BASIC schreiben wollen,  ist  er  be-
stimmt  immer  noch etwas schneller. Ich
werde mich in meinem Beispiel nun jedoch
auf die "von Hand"-Methode  beschränken.
Wenn  Sie  möchten,  können Sie das Pro-
gramm ja so erweitern, daß z.B. bei  we-
niger  als  fünf  Files  automatisch der
Validate-Befehl benutzt wird und im  an-
deren Fall die "von Hand"-Routine.      
Zunächst  will ich Ihnen nun eine Unter-
routine vorstellen, die uns das Inhalts-
verzeichnis  einliest  und alle Informa-
tionen   darüber   in   Variablenfeldern
ablegt.  Sie  steht  in dem Beispielpro-
gramm "FK.UNDEL" auf dieser  MD  in  den
Zeilen  200-510.  Wir  benötigen sie, um
die einzelnen Fileeinträge zu  isolieren
und  feststellen zu können, welcher Ein-
trag einem DEL-File entspricht. Ich habe
die Routine jedoch so ausgelegt, daß Sie
sie auch für andere Zwecke benutzen kön-
nen, da sie so ziemlich alle Informatio-
nen des Directorys ausliest.            
Vorher sind jedoch noch einige Anmerkun-
gen zu der Routine zu machen. Vorab  sei
gesagt,  daß  in den Zeilen 600-620 die-
selbe Routine steht, wie  wir  sie  auch
schon  im  Dir-Programm  benutzten.  Sie
liest ein Zeichen ein, und wandelt es in
einen Bytewert um, der  nach  Aufruf  in
der  Variablen  "a"  steht.  Desweiteren
benötigen wir noch einige  Variablenfel-
der,  die im Hauptprogramm mit Hilfe der
DIM-Anweisung dimensioniert werden  müs-
sen. Hier eine Liste der Felder:        
Name Elemente Inhalt                    
----------------------------------------
TY$    144    Filetyp                   
FT     144    Starttrack des Files      
FS     144    Startsektor des Files     
BL     144    Blockanzahl des Files     
NA$    144    Name des Files            
DT      18    Tracknummern des Dirs     
DS      18    Sektorennummern des Dirs  
Die ersten fünf Felder aus dieser  Liste
dienen  ausschließlich  der  Speicherung
von Informationen über ein File. Da  das
Directory  maximal 144 Einträge beinhal-
ten kann, werden alle diese  Felder  auf
maximal  144 Elemente dimensioniert. Die
Felder DT und DS werden benutzt um Track
und Sektor der  Folgeblocks  des  Direc-
torys zu speichern. Rein theoretisch ist
das  zwar  nicht  unbedingt notwenig, da
die  Folge  der  Directoryblöcke   immer
gleich  ist (Block 1 in 18/1, Block 2 in
18/4, etc.), jedoch ist so einfacher mit
den  Blocks  zu  handhaben.  Im  Prinzip
könnten  wir  auch das Feld DT wegfallen
lassen, da das Directory IMMER in  Track
18 steht, jedoch kann es sich ja auch um
eine  manipulierte Diskette handeln, die
das Directory woanders stehen hat  (hie-
rauf  wollen  wir  in einem der nächsten
Teile des Floppykurses zurückkommen).   
Nun  möchte  ich  Ihnen die Routine, mit
denen  wir  die   Diretcoryinformationen
einlesen nicht länger vorenthalten. Hier
der erste Teil von Zeile 200 bis 295:   
200 print"Gelesene Files:"              
210 open1,8,15,"i":open2,8,2,"#"        
220 print#1,"u1 2 0 18 0"               
230 gosub600:tr=a                       
240 gosub600:se=a                       
245 :                                   
250 dn$="":id$=""                       
260 print#1,"b-p 2 143"                 
270 fori=0to15:get#2,a$:dn$=dn$+a$:next 
280 print#1,"b-p 2 162"                 
290 fori=1to5:get#2,a$:id$=id$+a$:next  
295 :                                   
In diesem Teil unserer Unterroutine wer-
den die Vorbereitungen zum Einlesen  des
Directorys getroffen, sowie der  Disket-
tenname und  die  ID  in  die  Variablen
"dn$" und "id$" eingelesen. Diese  Vari-
ablen können Sie im Hauptprogramm  eben-
falls weiterverwenden.                  
Nachdem also in Zeile 200  ein  Informa-
tionstext ausgegeben wurde,  öffnen  wir
in Zeile 210 den Befehlskanal und  einen
Pufferkanal. Ersterer erhält  die  File-
nummer 1, letzterer  die  Filenummer  2.
Beim Öffnen des Befehlskanals  initiali-
sieren wir  die  Diskette  auch  gleich-
zeitig. In Zeile 220 senden wir nun  den
ersten Befehl an  die  Floppy.  Der  U1-
Befehl in dieser  Zeile  liest  uns  den
Dir-Header-Block (Track 18, Sektor 0) in
den Puffer. In Zeile 230 und  240  lesen
wir nun die ersten beiden  Bytes  dieses
Blocks ein, und ordnen sie den Variablen
TR und SE zu, die als Variablen für  den
aktuellen Track/Sektor  benutzt  werden.
Sie enthalten nun Track und  Sektor  des
ersten Directoryblocks.  Bevor  wir  uns
jedoch daran machen  dieses  auszulesen,
nehmen wir uns aus dem  Dir-Header-Block
noch den Diskettennamen und  ID  heraus.
In  Zeile  250   werden   diese   beiden
Variablen zunächst einmal gelöscht.  Als
nächstes positionieren wir  den  Puffer-
zeiger auf die  Position  144  des  Dir-
Header-Blocks.  Die  16  dort  folgenden
Bytes enthalten den Namen der  Diskette,
der mit Hilfe der Schleife in Zeile  270
in dn$ eingelesen wird. Ebenso wird  mit
der ID verfahren. Sie  steht  in  den  5
Bytes ab Position 163. In Zeile 280 wird
darauf positioniert und der  String  id$
wird in Zeile 290 eingelesen. Kommen wir
nun zum zweiten Teil der Routine, in dem
die Directoryeinträge eingelesen werden:
299 q=0                                 
300 print#1,"u1 2 0";tr;se              
305 a=int(q/8):dt(a)=tr:ds(a)=se        
310 gosub600:tr=a                       
320 gosub600:se=a                       
330 forj=1to8                           
335 printq                              
340 gosub600:ty(q)=a                    
350 gosub600:ft(q)=a                    
360 gosub600:fs(q)=a                    
370 x$=""                               
380 fori=1to16:get#2,a$:x$=x$+a$:next   
390 na$(q)=x$                           
400 fori=1to9:get#2,a$:next             
410 gosub600:bl(q)=a                    
420 gosub600:bl(q)=bl(q)+a*256          
425 get#2,a$:get#2,a$                   
430 q=q+1                               
440 next j                              
450 iftr<>0then300                      
460 :                                   
470 close1:close2                       
480 q=q-1                               
500 ifna$(q)=""thenq=q-1:goto500        
510 return                              
In Zeile 299 wird nun zunächst die Lauf-
variable  "q"  initialisiert.  Sie  gibt
später an, wieviele Einträge  in  diesem
Directory gefunden wurden. Der U1-Befehl
in Zeile 300 liest nun den ersten Direc-
toryblock ein, dessen Track  und  Sektor
ja noch in TR und SE stehen.  Anschlies-
send  werden  beide  Variablen   im   0.
Element  von  "dt"  und  "ds"  abgelegt.
Hierbei wird die  Hilfsvaiable  "a"  als
Indexvariable verwendet.  Ihr  wird  der
Wert (q dividiert durch  8)  zugeordnet,
da in einem Block ja  immer  8  Fileein-
träge stehen. In den Zeilen 310 und  320
werden  nun  schon  einmal  Track-   und
Sektornummer des Folgeblocks in  TR  und
SE eingelesen.                          
 Bitte Teil 2 des Floppy-Kurses laden ! 
Valid HTML 4.0 Transitional Valid CSS!