Magic Disk 64

home to index to text: MD9211-KURSE-FLOPPY-KURS_6.1.txt
              Floppy-Kurs:              
      "Es rappelt in der Kiste..."      
                (Teil 6)                

Hallo und herzlich Willkommen zum sechsten Teil unseres Floppykurses. Wir wollen unsere Kenntnisse auch hier wieder vertiefen und zwei weitere Beispielprogramme kennenlerenen. Eines, um das Directory 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 Speicherverlust einlesen können. Dies ist ein Hinweis auf eine besondere Eigenheit der Floppy. Wenn wir uns nämlich das Inhaltsverzeichnis einer Diskette einfach nur anzeigen lassen wollen, so können wir durch Angabe des Filenamens "$" die Floppy dazu bewegen, uns sehr viel Arbeit abzunehmen. Sie beginnt dann nämlich damit, alle Directoryblöcke von selbst einzulesen und sie für uns aufzubereiten. Ein direktes " herumpfuschen" auf der Diskette mittels der Block-Befehle entfällt.
Wollen wir uns nun verdeutlichen, was passiert, wenn wir wie gewohnt das Directory 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 Aufbereitung 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 Basic- Programm, mit dem Befehl LIST auf dem Bildschirm angezeigt wird. Sie können es sogar mit NEW wieder löschen, oder mit RUN starten, was jedoch nur einen Syntax-Error bewirkt, da das Directory 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 Zeilennummer entspricht. Diese Zeilennummern sind zwar nicht immer in einer numerischen Reihenfolge, jedoch macht das Basic unseres Computers da keinen Unterschied. Der interne Aufbau eines Basic-Programms erlaubt es tatsächlich, Zeilennummern wahllos zu vergeben. Wenn wir ein Programm direkt eingeben ist das natürlich nicht möglich, da die Eingaberoutine des Betriebssystems die Zeile anhand der Zeilennummer automatisch an der logisch richtigen Position des Programms 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 eigentlich nur der Basic-Programm- Speicher versteht, so daß die LIST-Routine das ' Directory-Programm' listen kann. Deshalb gibt e) einige Bytes, die für uns wertlos sind und überlesen werden müssen. 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ß normalerweise 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 Linkbytes ü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önnen. Hieran anschließend folgen nun ein oder mehrere Spacezeichen, sowie der Filename und die Filekennung im Klartext. 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 ( Basic-) Zeile kennzeichnet. An ihrer Stelle müssen wir lediglich einen Zeilenvorschub ausgeben ( ein PRINT ohne Parameter) . 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 entsprechende 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 Bytewert 0 einen " illegal quantity error" verursacht. Das liegt daran, daß ein String, der nur den Bytewert 0 als Zeichen enthält, einem Leerstring entspricht. 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. voherige Teile dieses Kurses) . In Zeile 210 werden nun die Startadresse und die beiden Linkbytes der ersten Zeile überlesen.
Danach beginnt die Hauptschleife des Unterprogramms. In den Zeilen 220 und 230 lesen wir hier zunächst mit Hilfe unserer " Zeichen lesen"- Unterroutine, Lowund 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 bewußt ein Semikolon an, damit der folgende Text direkt hinter der Blockanzahl ausgegeben wird. Dies geschieht in den Zeilen 250 und 260 . Dort lesen wir jeweils 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 Hauptschleife 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 wollen 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 Floppybefehl an den Befehlskanal muß also lauten " S: TEST" . Hieraufhin beginnt die Floppy nun, das Inhaltsverzeichnis der eingelegten 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 lediglich 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 normalerweise im Directory nicht mehr angezeigt wird. An dieser Leerstelle wird das File einfach übersprungen. Im Prinzip sind aber noch alle seine Informationen auf der Diskette enthalten. Zumindest einmal solange, bis Sie wieder ein neues File auf die Diskette schreiben. Dann nämlich sucht sich die Floppy den ersten freien Directoryeintrag heraus, der in unserem Fall, der des Files " TEST" ist, und trägt dort das neue File ein. Desweiteren kann es dann auch passieren, daß die Datenblocks, die von " TEST" belegt wurden möglicherweise von denen des neuen Files überschrieben werden. 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 andere 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 Anzeigen. Hieraufhin muß vom Benutzer entschieden 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 Entsprechenden Code in den Fileeintrag zu schreiben und alle Blocks des Files zu verfolgen, die von ihm belegt wurden und sie abermals 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 verketteten 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 Vorund Nachteile.
Benutzen wir die erste Methode, so haben wir bei höherem Programmieraufwand eine weitaus höhere Arbeitsgeschwindigkeit ( da nur die Blocks eines Files herausgesucht werden müssen und nicht aller Files 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 arbeiten, die ebenfalls gesucht werden müssen. Das aber wiederum macht der Validate- 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 zeitraubender Datenaustausch zwischen Floppy und C64 entfällt. Da wir unser Programm in BASIC schreiben wollen, ist er bestimmt 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 Programm ja so erweitern, daß z. B. bei weniger als fünf Files automatisch der Validate-Befehl benutzt wird und im anderen Fall die " von Hand"- Routine.
Zunächst will ich Ihnen nun eine Unterroutine vorstellen, die uns das Inhaltsverzeichnis einliest und alle Informationen darüber in Variablenfeldern ablegt. Sie steht in dem Beispielprogramm " 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 Eintrag einem DEL-File entspricht. Ich habe die Routine jedoch so ausgelegt, daß Sie sie auch für andere Zwecke benutzen können, da sie so ziemlich alle Informationen des Directorys ausliest.
Vorher sind jedoch noch einige Anmerkungen zu der Routine zu machen. Vorab sei gesagt, daß in den Zeilen 600-620 dieselbe 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 Variablenfelder, die im Hauptprogramm mit Hilfe der DIM-Anweisung dimensioniert werden müssen. 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 beinhalten kann, werden alle diese Felder auf maximal 144 Elemente dimensioniert. Die Felder DT und DS werden benutzt um Track und Sektor der Folgeblocks des Directorys 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 ( hierauf 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 werden die Vorbereitungen zum Einlesen des Directorys getroffen, sowie der Diskettenname und die ID in die Variablen " dn$" und " id$" eingelesen. Diese Variablen können Sie im Hauptprogramm eben- falls weiterverwenden.
Nachdem also in Zeile 200 ein Informationstext ausgegeben wurde, öffnen wir in Zeile 210 den Befehlskanal und einen Pufferkanal. Ersterer erhält die Filenummer 1, letzterer die Filenummer 2 .
Beim Öffnen des Befehlskanals initialisieren wir die Diskette auch gleichzeitig. 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 Pufferzeiger 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 Laufvariable " 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 Directoryblock ein, dessen Track und Sektor ja noch in TR und SE stehen. Anschliessend 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 Fileeinträge stehen. In den Zeilen 310 und 320 werden nun schon einmal Trackund Sektornummer des Folgeblocks in TR und SE eingelesen.
Bitte Teil 2 des Floppy-Kurses laden !

Valid HTML 4.0 Transitional Valid CSS!