Inhaltsverzeichnis

3 Tips und Tricks

Im Gegensatz zu Kapitel 2 stehen in diesem Kapitel die Besonderheiten des C-128 im Vordergrund. Dabei sollen nicht alle POKE-, PEEK- und SYS-Befehle, die seit Jahren verschiedene Zeitschriften zum C-64 und C-128 füllen, einfach in Pascal formuliert werden, sondern nur exemplarisch der Zugriff auf Routinen in Maschinensprache gezeigt werden. Im ersten Abschnitt wird außerdem noch ausführlich auf die Verwaltung von Files eingegangen, da das Betriebssystem des C-128 Eigenschaften besitzt, die über die rein sequentielle Datenspeicherung hinausgehen.

3.1 Files im C-128-Modus

Haben Sie bereits in BASIC mit Dateien gearbeitet, so werden Sie bei der Verwendung der OPEN- und CLOSE-Routinen von Pascal 2.0 sicher auf keinerlei Probleme stoßen. Sollten Sie jedoch erst durch Abschnitt 2.16 Interesse an Files gewonnen haben, so sind sicherlich einige Hinweise zur Verwaltung von Dateien beim C-128 angebracht. Aber auch der fortgeschrittene Programmierer findet am Ende dieses Abschnittes einige interessante Hinweise zu Relativ- dateien, die nicht durch den im report definierten Sprachumfang erfaßt werden.

Zunächst muß die grundsätzliche Arbeitsteilung beim file handling auf Commodore-Computern erläutert werden. Bei Homecomputern dieser Firma (VC-20, C-64, C-128) befindet sich im ROM neben dem BASIC-Interpreter ein Betriebssystemkern, der die Kommunikation des Computers mit allen Peripheriegeräten (Bildschirm, Tastatur, Floppy, Drucker...) organisiert. Als normaler Anwender haben Sie über die Sprache BASIC nur einen indirekten Zugang zu den Betriebssystemroutinen. Ein übersetztes Pascalprogramm verwendet zur Ausführung von Fileoperationen ebenfalls Teile des im ROM gespeicherten Betriebssystems. Jedoch ist das Betriebssystem des C-128 im folgenden Sinne erweiterbar: Viele der anschließbaren Peripheriegeräte sind (wie z.B. die Floppy) intelligent. D.h. sie besitzen eigene Programme, um die vom Computer kommenden Daten und Befehle selbständig zu verarbeiten.

Um so unterschiedliche Geräte wie die Tastatur, eine Floppy oder einen Plotter einheitlich behandeln zu können, bietet das Betriebssystem das Konzept der logischen Dateien: Nur beim Öffnen eines Files müssen Sie angeben, welches physikalische Medium Sie wie ansprechen möchten. Anschließend können Sie auf alle geöffneten Dateien einheitlich lesend und schreibend zugreifen. Die Datenein- und ausgabe beenden Sie mit einem CLOSE-Befehl.

Eine logische Datei wird in Pascal 2.0 durch eine Filevariable repräsentiert. Mit den Prozeduren PUT, WRITE und WRITELN können Sie an Ausgabefiles Daten senden. Diese Datenausgabe erfolgt zeichenweise. Ebenfalls Byte für Byte erfolgt die Dateneingabe mit GET, READ und READLN. Welche Struktur die übertragenen Daten haben (z.B. Texte oder Files mit Recordkomponenten) wird in Pascal durch die Deklaration der Filevariablen festgelegt. Jedoch muß diese Struktur auch korrekt von dem Peripheriegerät akzeptiert werden. Daher ist es sehr wichtig, daß Sie bei den OPEN-Befehlen in Pascalprogrammen korrekte Parameter wählen, um die Ein- und Ausgabegeräte richtig zu adressieren. Diese Parameter werden in diesem Abschnitt insbesondere für die Diskettenstation (Floppy) in Beispielen besprochen.

Sie können bis zu 10 Files gleichzeitig bearbeiten. Für jede Datei muß ein eigener OPEN-Befehl durchgeführt werden, der sozusagen die Filevariable beim Betriebssystem anmeldet. Die Geräteadresse ist eine ganze Zahl zwischen 0 und 15, die das Peripheriegerät bestimmt, auf dem die logische Datei physikalisch gespeichert werden soll:

0 Tastatur (nur als Eingabegerät)
1 Kassettenrecorder (Ein- und Ausgabegerät)
2 RS-232-Schnittstelle (Ein- und Ausgabegerät)
3 Bildschirm (nur als Ausgabegerät)
4 Drucker oder Plotter an der seriellen Schnittstelle
8 Floppy an der seriellen Schnittstelle
>8 weitere Geräte an der seriellen Schnittstelle

Viele Geräte können unter der gleichen Geräteadresse mehrere Sekundäradressen besitzen. Diese Adresse im Bereich zwischen 0 und 255 ist stark von dem verwendeten Gerätetyp abhängig. In diesem Kapitel soll nur die Diskettenstation besprochen werden. Dort gelten folgende Konventionen über die Sekundäradresse:
0,1 sind reservierte Sekundäradressen, die zum Laden und Speichern von Programmen mit LOAD und SAVE verwendet werden.
15/td> ist die Sekundäradresse des sogenannten Kommandokanals der Floppy
2 bis 14/td> sind Sekundäradressen, die Sie in Pascalprogrammen zur Speicherung sequentieller Dateien verwenden können.

Haben Sie bei einer Floppy gleichzeitig mehrere Files geöffnet, so müssen diese verschiedene Sekundäradressen besitzen, damit das Betriebssystem die Dateien bei Schreib- und Leseoperationen von- einander unterscheiden kann.

Schließlich müssen Sie bei einem OPEN-Befehl für Diskettendateien immer einen Filenamen (max. 16 Zeichen lang) nennen. Durch ein Suffix legen Sie dabei gleichzeitig den Modus fest, in dem Sie die Datei bearbeiten möchten. Besitzen Sie ein Doppellaufwerk, so können Sie im Filenamen auch die Laufwerksnummer (»0:« oder »1:«) für das File spezifizieren.

Beispiele:

VAR FILE1,FILE2: TEXT;
    FILE3      : FILE OF INTEGER;
    FILE4: FILE OF RECORD
              A: INTEGER;
              B: STRING[30]
           END;
OPEN(FILE1, 8, 3, '1:DATEN,SEQ,READ');
OPEN(FILE2, 8, 4, '0:TEST,SEQ,WRITE');
OPEN(FILE3, 8, 5, '0:INTEGER,USR,APPEND');
OPEN(FILE4, 8, 6, '@0:RECORDS,PRG,WRITE');

Die Laufwerksbezeichnung »1:« ist natürlich nur dann sinnvoll, falls Sie ein Doppellaufwerk besitzen. Stellen Sie dem Filenamen das Zeichen CHR(64) (»@«) voran, so wird am Ende der Ausgabe auf das File eine eventuell zuvor existierende Version des Files gelöscht. Jedoch wird der Platz, den die alte Version auf der Diskette belegte, nicht freigegeben. Deshalb kann beim Schreiben nicht die gesamte Speicherkapazität der Diskette genutzt werden. Man löscht daher besser die alte Version des Files vor dem Eröffnen einer neuen Datei (s. Abschnit 3.3 Routine SCRATCH).

Hinter der Laufwerksbezeichnung folgt der eigentliche Filename, unter dem die Datei im Inhaltsverzeichnis der Diskette aufgeführt wird. Er darf keine Sonderzeichen und kein Komma enthalten.

Nach einem Komma wird der Typ der Datei spezifiziert. Normale Pascal-Dateien, die nur sequentiell lesend und schreibend bearbeitet werden, erhalten sinnvollerweise die Typen SEQ (sequential) oder USR (user defined). Den Typ PRG (program file) können Sie bei Bedarf ebenfalls verwenden, jedoch können solche Files im Inhaltsverzeichnis nicht mehr eindeutig identifiziert werden. Der Typ REL (relative) wird später in diesem Kapitel separat behandelt.

Getrennt durch ein weiteres Komma folgt schließlich der Modus, in dem das File bearbeitet werden soll. Sollen von einer Datei Daten (mit GET, READ, READLN) gelesen werden, so muß der Modus READ ge- wählt werden. Zum Schreiben einer neuen Datei wird der Modus WRITE gewählt. Somit lassen sich die Operationen RESET und REWRITE des report mit OPEN-Befehlen ersetzen. Eine Besonderheit stellt der Modus APPEND dar. Bei Ausgabeoperationen auf ein in diesem Modus eröffnetes File werden die Daten an ein bereits auf der Diskette existierendes File dieses Namens angehängt.

Wie bereits erwähnt sollten Sie beim Lesen einer Datei darauf achten, daß die Deklaration der Filevariablen, mit denen die Daten geschrieben und gelesen werden, übereinstimmen. Da alle Daten für das Betriebssystem aus unstrukturierten Bytefolgen bestehen, existiert keine Möglichkeit, auch innerhalb von Files Typüberprüfungen durchzuführen.

Mit den folgenden Prozeduren können Sie das Programm KUNDENLISTE erweitern, so daß die Daten beim Programmende auf Diskette gespeichert werden, um bei einem nachfolgenden Programmstart gelesen zu werden.

CONST FILENAME = '0:KLIST';
TYPE KUNDENDATEI = FILE OF KUNDE;

PROCEDURE WRITEFILE;
(* Diese Prozedur wird am Ende des Hauptprogrammes aufge- *)
(* rufen, um den Inhalt der Kundenliste alphabetisch sor- *)
(* tiert auf Diskette zu speichern.                       *)
  VAR KFILE: KUNDENDATEI;
      K    : KUNDENZEIGER;
BEGIN
  OPEN(KFILE, 8, 3, '@' + FILENAME + ',SEQ,WRITE');
  K:= KOPF^.NAECHSTER; (* leeren Anfangsrecord ignoriern  *)
  WHILE K<>ENDE DO (* bis zum leeren Enderecord:    *)
    BEGIN
      KFILE^:= K^; PUT(KFILE);
    END;
  CLOSE(KFILE);
END; (* WRITEFILE *)

PROCEDURE READFILE;
(* Diese Prozedur wird anstelle der Zuweisung             *)
(* KOPF^.NAECHSTER:= ENDE aufgerufen, um die Kundenliste  *)
(* von Diskette zu lesen.                                 *)
  VAR KFILE: KUNDENDATEI;
      K,K1 : KUNDENZEIGER;
BEGIN
  OPEN(KFILE, 8, 3, FILENAME + ',SEQ,READ');
  GET(KFILE); K1:= KOPF;
  WHILE NOT EOF(KFILE) DO
    BEGIN
      NEW(K); K^:= KFILE^;
      K1^.NAECHSTER:= K; K1:= K;
      GET(KFILE);
    END;
  CLOSE(KFILE); K1^.NAECHSTER:= ENDE;
END; (* READFILE *)

Bild 103: Erweiterung des Programmes KUNDENLISTE

Bei Ein- und Ausgaben auf Files wie in Bild 103 sollte man zumindest nach dem Aufruf der Prozeduren OPEN und CLOSE prüfen, ob Verarbeitungsfehler bei der Floppy aufgetreten sind (Diskette war nicht eingelegt oder schreibgeschützt). Dazu können Sie die Routine DSTATUS aus Abschnitt 3.3 verwenden, die den Kommandokanal der Floppy abfragt.

Ein etwas spezielleres Beispiel (Bild 104) geht auf die besonderen Eigenschaften der Floppy ein. In BASIC ist es möglich, das Directory der Diskette mit dem Befehl

LOAD"$0",8

im Format eines BASIC-Programmes zu laden. Mit der Prozedur READALL werden die Namen und Typen aller Files auf der Diskette gelesen und in einer Tabelle (T) gespeichert. Durch wiederholte Aufrufe dieser Prozedur kann der Inhalt mehrerer Disketten gesammelt werden. Anschließend werden die Filenamen mit der Prozedur QUICK alphabetisch sortiert. Zur Druckerausgabe der sortierten Tabelle T wird die Prozedur AUSGABE verwendet.

Bild 104: Directory lesen

Besonders beachten sollten Sie die Funktion BYTE: Da das Inhalts- verzeichnis von einer Datei mit dem Typ TEXT

VAR INF: TEXT;

gelesen wird, wandelt das Pascal-Laufzeitsystem alle Zeilenende- zeichen (CHR(13), carriage return) in Leerzeichen (CHR(20)) um. In diesem Fall ist EOLN(INF)=TRUE. Um nun beliebige Bytes aus dem Bereich 0..255 zu lesen, wird in der Funktion BYTE eine Umwandlung des gelesenen Zeichens in eine INTEGER-Zahl vorgenommen.

Die Floppy besitzt ein eigenes Betriebssystem, das die Verwaltung der Daten in Blöcken auf der Floppy vornimmt und unter anderem auch das Inhaltsverzeichnis selbständig verwaltet. Dieses Betriebssystem kennt einen weiteren Filetyp, der bei OPEN-Befehlen gewählt werden kann. Es handelt sich hierbei um Relativdateien. Während die übrigen Dateien (Typ PRG, SEQ und USR) nur sequentiell lesend oder schreibend bearbeitet werden können, sind auf Relativdateien auch indizierte Zugriffe (wie bei einem Array) möglich.

Voraussetzung für solche indexsequentiellen Dateien ist, daß jedes Element des Files die gleiche Länge in Bytes besitzt. Dies ist jedoch in der Sprache Pascal automatisch durch die Deklaration

VAR DATEI = FILE OF Komponententyp

gesichert. Sinnvollerweise verwendet man Relativdateien für Files, bei denen der Komponententyp ein zusammengesetzter Typ (z.B. Record) ist. Die Komponenten besitzen innerhalb des Files eine eindeutige Recordnummer. Nachdem eine Relativdatei angelegt wurde, können die Komponenten in beliebiger Reihenfolge durch die Angabe ihrer Recordnummer indiziert geschrieben und gelesen werden. Die erste Komponente im File besitzt die Recordnummer 1.

Andererseits können Relativdateien auch sequentiell Komponente für Komponente in der Reihenfolge der Recordnummern (1,2,3 ...) bearbeitet werden. Dies wird erreicht, indem der Zeiger auf die aktuell bearbeitete Komponente bei jeder Lese- und Schreiboperation auf die Folgekomponente im File gesetzt wird.

Bild 105: Relativdateien in Pascal 2.0

Das Programm in Bild 105 zeigt ein vollständiges Programm zur Ver- waltung von Buchtiteln in einer Relativdatei. Natürlich ist dieses Programm noch weit davon entfernt, eine sinnvolle Anwendung für Relativdateien zu zeigen, vielmehr sollen nur die generellen Operationen mit Relativdateien anschaulich illustriert werden.

Jedes Buch wird durch einen Record des Typs BUCH in der Relativdatei REL beschrieben. Jeder Record wird innerhalb des Files durch eine ganzzahlige Recordnummer größer als Null identifiziert. Der Benutzer des Programmes muß also für die Bücher eindeutige Recordnummern vergeben. Der Typ BUCH speichert folgende Felder

Titel 30 Zeichen
Autor 30 Zeichen
Signatur ganze Zahl (dies ist nicht die Recordnummer!)
MARKE 1 Zeichen

Das Feld MARKE hat eine rein technische Bedeutung: Das Betriebssystem der Floppy speichert normalerweise nur Texte (in Pascal wären dies ARRAYS OF CHAR) in einer relativen Datei. Diese Texte werden grundsätzlich mit dem Zeichen carriage return (CHR(13)) beendet. Fehlt dieses Zeichen am Ende eines Records, so ignoriert das Betriebssystem unter Umständen die letzten binären Nullen innerhalb des Records. Daher wird vor allen Schreiboperationen auf das File REL das Feld MARKE mit dem Wert CHR(13) belegt.

Neben der eigentlichen Relativdatei

REL: FILE OF BUCH;

existiert der sogenannte Kommandokanal der Floppy (Sekundäradresse 15):

DSK: TEXT;

Über ihn werden Kommandos vom Computer an die Floppy in Form von Zeichenfolgen gesendet. Außerdem kann man von diesem Kommandokanal auch Informationen über die Ausführung von Fileoperationen erhalten (s. Prozedur DSTATUS). Im Programm BOOKS werden folgende Befehle verwendet:

I0
'S' + NAME
'P' + CHR(SECOND) + CHR(INDEX AND 255) + CHR(HBYTE(INDEX))+ CHR(1)

Der erste Befehl (initialize) initialisiert die Diskette im Laufwerk 0 der Floppy. Dadurch werden eventuell noch geöffnete Floppy-Kanäle geschlossen. Der zweite Befehl (scratch) löscht die Datei mit dem Filenamen NAME. Besonders wichtig für die Arbeit mit Relativdateien ist der dritte Befehl. Mit ihm ist es möglich, in dem File mit der Sekundäradresse SECOND den Schreib- und Lesezeiger auf das Element mit der Recordnummer INDEX zu setzen. Während der gesamten Programmausführung bleibt die Datei DSK geöffnet. Grundsätzlich sollte sie als letztes File in einem Programm geschlossen werden.

Beim ersten Aufruf des Programms existiert noch keine Relativdatei. Sie wird erst in der Prozedur INITREL explizit angelegt. Zunächst wird der Dateiname für den OPEN-Befehl gebildet:

DNAME:= NAME + ',L' + CHR(SIZEOF(BUCH));

Bei dem nachfolgenden OPEN-Befehl

OPEN(REL, DEVICE, SECOND, DNAME)

wird deshalb eine relative Datei mit einer Satzlänge erzeugt, die exakt der Größe eines Records vom Typ BUCH in Bytes entspricht. DEVICE ist wie üblich die Geräteadresse der Floppy (8). Die Sekundäradresse (SECOND = 3) ermöglicht es, über den Kommandokanal beim Befehl »P« gezielt diese Relativdatei zu spezifizieren.

Bei einer Relativdatei wird normalerweise erst dann Speicherplatz auf der Diskette für ein Record des Files reserviert, falls versucht wird, hinter dem Fileende zu schreiben. Durch die Prozeduraufrufe

SEEK(50); PUT(REL)

würde der 50. Record der Datei REL gespeichert werden. Da dieser Record noch nicht existiert, würden auf der Floppy die Records mit den Indizes 1, 2, ... 49 mit zufälligen Werten belegt werden. Da diese Operation recht zeitaufwendig ist, und eventuell nicht mehr genügend Speicherplatz auf der Diskette vorhanden sein könnte, wird stattdessen in der Prozedur INITREL folgende Schleife verwen- det:

SEEK(1); FOR:= 1 TO DEFAULTSIZE DO PUT(REL);

Da zuvor der Record REL^ mit definierten Daten vorbelegt wurde, sind damit die ersten 50 Records korrekt initialisiert. Erst wenn durch spätere Schreiboperationen die Filegröße über DEFAULTSIZE Bücher anwächst, wird auf der Floppy zusätzlicher Speicherplatz reserviert.

Um eine bereits existierende Relativdatei zu benutzten, ist es nicht erforderlich, die Satzlänge erneut anzugeben, stattdessen wählt man beim OPEN-Befehl den Typ REL

OPEN(REL, DEVICE, SECOND, NAME + ',REL')

In vielen Implementationen der Sprache Pascal existiert der Befehl SEEK, der einen wahlfreien Zugriff (random access) auf die Elemente eines Files ermöglicht. In Anlehnung an diesen Standard wurde der Name der Prozedur SEEK gewählt. Da die Verwaltung von Relativdateien ausschließlich Aufgabe des Betriebssystems der Floppy ist, genügt es, einen Positionierbefehl über den Kommandokanal der Floppy zu senden:

'P' + CHR(SECOND) + CHR(INDEX AND 255) + CHR(HBYTE(INDEX)) + CHR(1)

Dieser Befehl beginnt mit dem Zeichen »P«, dem die Sekundäradresse der Relativadresse (codiert als ein Zeichen) folgt. Anschließend wird die gewünschte Position in Form von zwei Bytes übergeben. Zusätzlich besteht die Möglichkeit, innerhalb eines Records den Lesezeiger auf ein einzelnes Byte zu setzen. In der Sprache Pascal gibt es hierfür keine sinnvolle Anwendung, so daß die Position 1 (CHR(1)) gewählt wird. Nach dem Befehl »P« kann über den Kommando- kanal das Ergebnis der Operation abgefragt werden:

00, OK, 00, 00
50, RECORD NOT PRESENT, 00, 00

Bewegen Sie den Filezeiger hinter den momentan letzten Satz des Files, so erhalten Sie die Warnmeldung 50. Lesezugriffe (GET(REL)) auf nicht existente Records führen zu undefinierten Werten der Puffervariable REL^, während bei Schreibzugriffen das File bis zur gewählten Komponente erweitert wird (was einige Sekunden dauern kann).

Es ist extrem wichtig, daß eine eröffnete Relativdatei am Ende der Bearbeitung korrekt mit CLOSE geschlossen wird, damit alle Daten auch physikalisch auf Diskette gespeichert werden und nicht in Pufferspeichern verloren gehen.

Leider exisitiern einige Fehler im Betriebssystem aller Floppys für Commodore-Homecomputer. Daher kann es teilweise zu Schwierigkeiten beim Erweitern und sequentiellen Lesen von Relativdatein kommen (näheres findet man in Computerzeitschriften). Halten Sie sich jedoch an das Verarbeitungsschema von Bild 105, so können Sie Ihre Daten sicher in Relativdateien speichern.

Besonders interessant ist die Möglichkeit der Sprache Pascal, im Speicher des Computers dynamische Datenstrukturen (z.B. ausgeglichene Bäume) zu bilden, die eine schnelle Suche nach Schlüsseln (z.B. TITEL) ermöglichen. Mit jedem Schlüssel muß dann nur noch die Recordnummer gespeichert werden, unter der in einer relativen Datei auf Diskette die eigentliche Informationen zu diesem Schlüssel gespeichert sind. Somit läßt sich die hohe Speicher- kapazität der Floppy mit der Geschwindigkeit der Sprache Pascal koppeln.

Inhaltsverzeichnis