home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
lib4a86
/
doc
/
recordio.doc
< prev
next >
Wrap
Text File
|
1992-02-22
|
20KB
|
523 lines
─────────────────────────────────────────────────────────────────────────────
Dokumentation zur Datei: RECORDIO.INC
─────────────────────────────────────────────────────────────────────────────
RECORDIO.INC - Routinen zur gepufferten Bearbeitung von Record-Dateien
(für den Assembler A86)
(c) Bernd Schemmer 1992
Letzter Update: 22.02.1992
■ Beschreibung:
---------------
RECORDIO.INC stellt Routinen zur gepufferten Bearbeitung von
Record-Dateien (d.h. satzorientierten Dateien mit wahlfreien,
direkten Lese- und Schreibzugriffen) zur Verfügung. Die Routinen
können beliebig viele Dateien gleichzeitig und bis zu 250 Puffer
pro Datei verwalten. Die Puffer werden nach einer LRU-Strategie
verwaltet. LRU (= Last Reasently Used) bedeutet, daß, falls ein
Puffer überschrieben werden muß, immer der Puffer, der am
längsten nicht mehr genutzt wurde, überschrieben wird. Hierbei
wird nicht unterschieden, ob ein Puffer zum Lesen oder Schreiben
benutzt wurde.
Die Routinen berücksichtigen auch einen eventuell vorhandenen
Datei-Header vor den Sätzen in der Datei.
Jeder Puffer muß mindestens einen kompletten Satz (= Record)
aufnehmen können. Jeder Puffer wird nur soweit genutzt, daß genau
n Sätze rein passen, d.h. die Länge eines Puffers sollte
möglichst ein Vielfaches der Satzlänge sein. Zur Erhöhung der
Performance der Lese- und Schreibvorgänge sollte die Länge
eines Puffers und des Headers (falls vorhanden) auch ein
Vielfaches von 512 (= Sektorlänge) sein (muß aber nicht!).
Es ist auch möglich, die Verwendung der Puffer auf das Lesen
von Sätzen einzuschränken (d.h. die Puffer können auch im Modus
'Write Through' betrieben werden).
Für die Routinen gelten folgende Limits:
max. Dateigröße: 2.147.483.647
max. Headergröße: 2.147.483.647
max. Satzgröße: 65.535
min. Satzgröße: 2
max. Anzahl Sätze: 2.147.483.647
max. Anzahl Puffer: 250
max. Größe eines Puffers: 65.535
Folgende Bedingungen müssen ebenfalls eingehalten werden:
Größe eines Puffer >= Satzgröße
Dateitgröße + Headergröße <= 2.147.483.647
Falls der Header länger als 65.535 Byte ist, kann er mit dem
Routinen aus dieser Datei weder gelesen noch geschrieben werden.
■ Aufbau der Datei-Tabelle
Für jede Datei muß eine Tabelle mit folgendem Aufbau vom Programm
zur Verfügung gestellt werden:
Offset | Länge | Inhalt
-------+----------+-------------------------------------------
* 00h | 1 Wort | Handle der Datei
02h | 2 Wörter | Offset des letzten Satzes
* 06h | 2 Wörter | Länge des Headers der Datei
| | oder 0 falls die Datei keinen Header hat
* 0Ah | 1 Wort | Länge eines Satzes der Datei (Länge >= 2)
0Ch | 2 Wörter | Datei-Zeiger oder 0FFFFh:0FFFFh
* 10h | 1 Wort | Anzahl der Puffer (Anzahl >= 1)
* 12h | 1 Wort | Größe eines Puffers ( >= Länge eines Satzes)
| | Der Inhalt dieses Feldes wird vor der ersten
| | Benutzung auf ein Vielfaches der Satzlänge
| | abgerundet.
* 14h | 1 Byte | Flags, Aufbau: siehe unten
15h | 1 Byte | Indikator für eine leere Datei
DIREKT HINTER dieser Tabelle muß für jeden Puffer eine Tabelle mit
folgenden Aufbau deklariert werden:
Offset | Länge | Inhalt
-------+----------+-------------------------------------------
00h | 1 Byte | LRU-Inex
01h | 1 Byte | Flags des Puffers
* 02h | 2 Wörter | Zeiger auf den Puffer (Offset, Segment)
06h | 2 Wörter | Datei-Offset des ersten Satzes im Puffer
Die Puffer müssen alle gleich groß sein, sie können aber in
beliebigen Speicherbereichen angelegt werden. Der Speicher
für die Puffer muß von der aufrufenden Routine zur Verfügung
gestellt werden. Die Adressen der Puffer werden vor der ersten
Benutzung in das Format ssss:000o gebracht (d.h. normalisiert).
■ Aufbau des Flagbytes beim Offset 14h:
Bit | Bedeutung
--------+------------------------------------------------------------
0 | Writethrough-Bit, falls dieses Bit auf 1 steht, werden
| die Puffer nur zum Lesen benutzt und jeder veränderte
| Satz wird sofort in die Datei übertragen.
| Da das Schreiben in die Datei nur Pufferweise vorgenommen
| wird, sollte zur Verbesserung der Performance in diesem
| Fall jeder Puffer nur 1 bis 4 Sätze aufnehmen können.
|
1 | Ignore-LRU-Bit, falls dieses Bit auf 1 steht, werden
| die akt. Werte der Puffer für die LRU-Verwaltung NICHT
| mehr verändert. D.h. falls ein Puffer überschrieben
| werden muß, wird immer der gleiche Puffer benutzt
| und die anderen Puffer behalten ihren Inhalt.
| Dies ist z.B. sinnvoll, falls die Datei mit leeren
| Sätzen aufgefüllt werden soll.
|
2..7 | reserviert
ALLE mit einem Asterix (*) gekennzeichneten Felder in den Tabellen
müssen von der aufrufenden Routine VOR dem ersten Benutzen der
Tabelle durch die aufrufende Routine gefüllt werden.
Nach dem Eröffnen oder Erstellen einer Datei darf, außer dem Feld
mit dem Flags, kein Feld mehr verändert werden!
Hinweis:
Eine Änderung des WriteThrough-Bits bezieht sich nur auf
zukünftige Schreibvoränge. Es sollte daher nach oder vor dem
Setzen des WriteThrough-Bits die Routine 'FlushRecordFile'
zum Sichern der geänderten Puffer aufgerufen werden.
Das Feld für das Handle muß mit -1 initialisiert werden.
Alle Wörter, Doppelwörter und Adressen müssen im INTEL-Format
eingetragen werden.
Die Routinen benutzen das Register AX als Arbeitsregister und
verändern das Directionflag.
■ Variablen:
------------
RFOpenMode
Byte, diese Variable enthält den Modus, der zum Öffnen einer
Datei verwendet wird. Voreinstellung für den Modus ist 02h;
der Inhalt der Variable ist nur bei der Eröffnung einer
bestehenden Datei von Bedeutung. (Aufbau: siehe unten)
CreateRFileAttr
Wort, Attribute für eine neu zu erstellende Datei
(nur für die Routinen CREATE... von Bedeutung)
Voreinstellung für das Attribut ist 0, folgende Bits werden
ignoriert: Bit 3 (08h, Volume-Bit)
Bit 4 (10h, Directory-Bit)
und
Bit 6 und 7 (40h und 80h, reservierte Bits)
(Aufbau: siehe unten)
■ Routinen:
-----------
ResetRecordFile - Öffnet eine bestehende Record-Datei
CreateRecordFile - Erstellt eine Record-Datei
CreateNewRecordFile - Erstellt eine neue Record-Datei
CloseRecordFile - Schließt eine Record-Datei
FlushRecordFile - Schreibt alle veränderten Puffer einer
Record-Datei
WriteRecord - Schreibt einen Satz der Datei
ReadRecord - Liest einen Satz der Datei
TestRecord - Überprüft, ob ein Satz vorhanden ist
ReadRecordFileHeader - Liest den Header einer Record-Datei
WriteRecordFileHeader - Schreibt den Header einer Record-Datei
GetRecordFileSize - Ermittelt die Größe und die Anzahl der
Sätze einer Record-Datei
SetRecordFileSize - Vergrößert oder verkleinert eine
Record-Datei
und falls nötig (d.h. die .LIB-Dateien mit den entsprechenden
Routinen werden nicht benutzt):
MulLongInt - Multipliziert zwei LongInt-Werte
DivLongInt - Dividiert zwei LongInt-Werte
Make20BitValue - Rechnet eine 32-Bit-Adresse in eine
20-Bit-Zahl um
Make32BitAdress - Rechnet eine 20-Bit-Zahl in eine
32-Bit-Adresse um
■ Aufbau des Modus-Bytes für die Eröffnung einer bestehenden
Datei (= Variable RFOpenMode):
Bit | Bedeutung | Aufschlüsselung der Bits
-------+---------------+-------------------------------------------
0..3 | Zugriffscode | 0000 nur Lesen
| | 0001 nur Schreiben
| | 0010 Lesen + Schreiben
| |
4..6 | Sharing-Code | 000 Kompatibilitätsmodus
| | 001 ablehnender Schreib/Lese-Modus
| | 010 ablehnender Schreibmodus
| | 011 ablehnender Lesemodus
| | 100 nicht-ablehnender Modus
| |
7 | Inherit-Bit | 0 Zugriff für Unterprozesse erlaubt
| | 1 Zugriff für Unterprozesse verboten
RFOpenMode DB 002h ; Modus für die Eröffnung von Dateien
■ Aufbau des Attributes für die Erstellung einer neuen Datei
(= Variable CreateRFileAttr)
Bit | Bedeutung
-------+---------------
0 | Read-Only-Bit
1 | Hidden-Bit
2 | System-Bit
3 | Volume-Bit
4 | SubDir-Bit
5 | Archive-Bit
6 | reserviert
7 | reserviert
8..15 | reserviert
CreateRFileAttr DW 0h ; Attribut für neu zu erstellende Dateien
; EQUs für das Flag-Byte
; -----------------------------
RF_WriteThrough EQU 01h ; Write-Through-Bit einschalten
RF_IgnoreLRU EQU 02h ; Ingore-LRU-Bit einschalten
RF_DontWriteThrough EQU NOT RF_WriteThrough
RF_DontIgnoreLRU EQU NOT RF_IgnoreLRU
Fehlernummern der Routinen
--------------------------
Alle Fehlernummern der Routinen haben das Format 86xx, wobei xx die
Nummer des eigentlichen Fehlers ist. Neben diesen werden auch die
DOS-Fehlernummern im Format 00xx zurück geliefert.
Name Nummer Bedeutung
----------------------------------------------------------------------
000xxh ; DOS-Fehlernummer
RFileTableError EQU 08601h ; Die Datei-Tabelle ist fehlerhaft
RFileNotOpen EQU 08602h ; Die Datei ist geschlossen
RFileAlreadyOpen EQU 08603h ; Die Datei ist noch offen
RFileReadError EQU 08604h ; Lesefehler, unerwartetes Dateiende
RFileWriteError EQU 08605h ; Schreibfehler, Disk ist voll
RFileRecordError EQU 08606h ; Falsche Satznummer angegeben
; beim Lesen: Satz nicht vorhanden
; beim Verlängern: Datei kann nicht
; auf die angegebene Länge verlängert
; werden.
RFileLengthError EQU 08607h ; Die Länge der Datei stimmt nicht
; mit den Werten in der Datei-Tabelle
; überein.
RFileDeviceError EQU 08608h ; Die Verwaltung der Ein- und Ausgaben
; von Geräten ist über diese Routinen
; nicht möglich
RFileHeaderError EQU 08609h ; Der Datei-Header kann nur geschrieben
; oder gelesen werden, falls die Länge
; des Datei-Headers ungleich 0 und
; kleiner als 65.536 ist.
■ Hinweis: Da nicht alle Bezeichner aus dieser Datei dokumentiert
sind, sollten in eigenen Routinen keine Bezeichner mit
der Zeichenfolge 'RF_' verwendet werden.
----------------------------
ResetRecordFile
Funktion: Eröffnet eine bestehende Datei
Eingabe: DS:BX -> Datei-Tabelle
ES:DI -> Dateiname als String mit Längenzähler
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Die Datei muß mindestens den Header (falls in der Datei-
Tabelle angegeben) enthalten, die Größe der Datei muß
ein Vielfaches der Satzlänge plus der Länge des Datei-
headers sein.
Der Modus der Datei (Lesen, Schreiben oder Lesen und
Schreiben) wird durch die Variable RFOpenMode bestimmt.
Geräte können über diese Routine nicht eröffnet werden.
----------------------------
CreateRecordFile
Funktion: Erstellt eine neue Datei.
Eingabe: DS:BX -> Datei-Tabelle
ES:DI -> Dateiname als String mit Längenzähler
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Eine bestehende Datei wird überschrieben!
Die Attribute der Datei werden durch die Variable
CreateRFileAttr bestimmt.
Geräte können über diese Routine nicht erstellt werden.
----------------------------
CreateNewRecordFile
Funktion: Erstellt eine Datei
Eingabe: DS:BX -> Datei-Tabelle
ES:DI -> Dateiname als String mit Längenzähler
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Eine bestehende Datei führt zu einem Fehler!
Die Attribute der Datei werden durch die Variable
CreateRFileAttr bestimmt.
Geräte können über diese Routine nicht erstellt werden.
----------------------------
CloseRecordFile
Funktion: Schreibt alle Puffer mit veränderten Daten in die Datei
und schließt die Datei
Eingabe: DS:BX -> Datei-Tabele
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
FlushRecordFile
Funktion: Schreibt alle Puffer mit veränderten Daten in die Datei
Eingabe: DS:BX -> Datei-Tabelle
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Ab DOS-Version 3.30 werden auch die DOS-internen Puffer
über die Funktion 68h des Interrupts 21h geschrieben.
----------------------------
ReadRecord
Funktion: Liest einen Satz
Eingabe: DS:BX -> Datei-Tabelle
DX:AX = Nummer des Satzes (0..n)
ES:DI -> Puffer für den Satz
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Die Satzlänge wird der Datei-Tabelle entommen.
Es können nur schon existierende Sätze gelesen werden.
----------------------------
TestRecord
Funktion: Überprüft, ob ein Satz in der Datei vorhanden ist
Eingabe: DS:BX -> Datei-Tabelle
DX:AX = Nummer des Satzes (0..n)
Ausgabe: CF = 0 ->> okay
ZF = 0 ->> Satz vorhanden
ZF = 1 ->> Satz nicht vorhanden
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
WriteRecord
Funktion: Schreibt einen Satz
Eingabe: DS:BX -> Datei-Tabelle
DX:AX = Nummer des Satzes (0..n)
ES:DI -> zu schreibender Satz
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Die Satzlänge wird der Datei-Tabelle entommen.
Falls der Satz noch nicht existiert, wird die
Datei verlängert. Nach einer Verlängerung existieren
alle Sätze bis zum neuen Satz inclusive, wobei alle
Sätze zwischen den letzten Satz und dem neuen Satz
nur 'Datenmüll' enthalten.
----------------------------
GetRecordFileSize
Funktion: Ermittelt die Größe einer Datei und die Anzahl
der Sätze in der Datei
Eingabe: DS:BX -> Datei-Tabelle
Ausgabe: CF = 0 ->> okay
DX:AX = Größe der Datei (incl. Header)
CX:BX = Anzahl der Sätze
CF = 1 ->> Fehler
AX = Fehlernummer
----------------------------
SetRecordFileSize
Funktion: Setzt die Größe einer Datei
Eingabe: DS:BX -> Datei-Tabelle
DX:AX = Anzahl der Sätze für die Datei
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Bes.: Falls die Datei verkleinert wird, sind alle Sätze,
die hinter dem neuen letzten Satz liegen verloren!
Falls die Datei vergrößert wird, enthalten alle neuen
Sätze nur 'Datenmüll'.
Nach der Veränderung der Größe der Datei werden die
Inhalte aller Puffer mit gültigen veränderten Daten
in die Datei geschrieben.
----------------------------
ReadRecordFileHeader
Funktion: Liest den Header einer Datei
Eingabe: DS:BX -> Datei-Tabelle
ES:DI -> Puffer für den Header
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Hinweis: Die Länge des Headers wird aus der Datei-Tabelle entnommen,
für das Lesen des Headers wird kein Puffer benutzt.
Der Header kann nur gelesen werden falls gilt:
0 < HeaderLength <= 65.535
----------------------------
WriteRecordFileHeader
Funktion: Schreibt den Header einer Datei
Eingabe: DS:BX -> Datei-Tabelle
ES:DI -> Header für die Datei
Ausgabe: CF = 0 ->> okay
CF = 1 ->> Fehler
AX = Fehlernummer
Hinweis: Die Länge des Headers wird aus der Datei-Tabelle entnommen,
für das Schreiben des Headers wird kein Puffer benutzt.
Der Header kann nur geschrieben werden falls gilt:
0 < HeaderLength <= 65.535
----------------------------
MulLongInt
Funktion: Multipliziert zwei Longint-Werte
Eingabe: DX:AX = 1. Operand
CX:BX = 2. Operand
Ausgabe: DX:AX = (DX:AX * CX:BX) = Ergebnis
Keine Überprüfung auf Überlauf!
----------------------------
DivLongInt
Funktion: Dividiert zwei Longint-Werte
Eingabe: DX:AX = 1. Operand
CX:BX = 2. Operand
Ausgabe: CF = 0 ->> okay
DX:AX = (DX:AX DIV CX:BX) = Ergebnis
CX:BX = (DX:AX MOD CX:BX) = Rest
CF = 1 ->> Fehler
2. Operand ist 0
----------------------------
Make32BitAdress
Funktion: Konvertiert eine 20-Bit-Zahl in eine normalisierte
Adresse aus Segment und Offset
Eingabe: DX:AX = 20-Bit-Zahl (Aufbau: 000n:nnnn)
Ausgabe: DX:AX = 32-Bit-Adresse (Aufbau: ssss:000o)
----------------------------
Make20BitValue
Funktion: Konvertiert eine Adresse aus Segment und Offset in
eine 20-Bit-Zahl
Eingabe: DX:AX = Adresse (ssss:oooo)
Ausgabe: DX:AX = 20-Bit-Zahl (000n:nnnn)
Bes.: Die Adresse muß nicht normalisiert sein.