home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Power-Programmierung
/
CD1.mdf
/
assemblr
/
library
/
lib4a86
/
demo
/
recordio.dem
< prev
next >
Wrap
Text File
|
1992-02-16
|
45KB
|
1,499 lines
; ----------------------------
; RECORDIO.DEM - Demoprogramm für die Routinen aus RECORDIO.LIB
; (für den A86)
;
; (c) Bernd Schemmer 1992
; Letzter Update: 15.02.1992
;
; Übersetzen:
; A86 RECORDIO.DEM DEMOS.INCIO.COM
;
; Hinweis: Die Environment-Variable 'A86' muß den Dateinamen 'MACROS.MAC'
; enthalten und die .LIB-Dateien müssen über die Datei A86.LIB
; erreichbar sein.
;
; ---------------------------
jmp start
; ----------------------------
; GetSTDInKey (Macro)
;
; Funktion: Liest eine Taste von der Standard-Eingabe,
; wandelt die Taste in Großbuchstaben um
; und schreibt CR und LF auf die Standard-Ausgabe
;
; Aufruf: GetSTDInKey {NoCRLF}
;
; Parameter:
; NoCRLF = Kein CR/LF nach dem Lesen der Taste ausgeben
;
; Ausgabe: AL = gedrückte Taste als Großbuchstabe
;
;
GetSTDInKey MACRO
mov ah,01 ; Taste lesen
int 021h
or al,al
jnz >m1
; Funktionstaste
mov ah,01
int 021h
xor al,al
m1:
and al,0DFh ; Tasten in Großbuchstaben konvertieren
##IF #NL EQ 0
call ShowCR_LF
##ENDIF
#EM
; ----------------------------
; Meldungen und Fehlermeldungen
logo db CR,LF
db 'RECORDIO.DEM - Demoprogramm für die Routinen aus RECORDIO.LIB' ,CR,LF
db '--------------------------------------------------------------' ,CR,LF
db CR,LF
db 'Das Demo erstellt zuerst die Record-Datei RECORDIO.BSP mit' ,CR,LF
db 'bis zu 100.000 Sätzen á 32 Byte (Dateilänge: ca. 3,2 Megabyte,' ,CR,LF
db 'nur falls sie noch nicht existiert bzw. ein falsches Format' ,CR,LF
db 'hat) und ermöglicht danach im Dialog das Lesen und Schreiben' ,CR,LF
db 'von Sätzen aus der Datei.' ,CR,LF
db 'Die Datei RECORDIO.BSP wird vom Programm NICHT gelöscht.' ,CR,LF
db 'Das Programm setzt temporär den Interrupt 21h um, damit' ,CR,LF
db 'wirkliche Zugriffe auf die Datei sichtbar werden.' ,CR,LF
db CR,LF,CR,LF
db 'Bitte eine Taste drücken (ESC = Programm-Abbruch) ...' ,CR,LF
db CR,LF
GETLENGTH logo
; ------------------
; Meldungen
MakeMsg BuildMsg, 'Erstelle die Datei ...'
MakeMsg MakeOkay, CR,LF,'Datei angelegt.'
MakeMsg ExistMsg, 'Datei existiert schon.'
MakeMsg CloseMsg, 'Schließe die Datei ... '
MakeMsg ReorgMsg, 'ReOrganisiere die Puffer für die Dialog-Bearbeitung ...'
MakeMsg OpenMsg, 'Öffne die Datei wieder ...'
MakeMsg1 UseMsg, 'Existierende Datei benutzen? (j/n) ==> '
; ------------------
; Variablen
; Puffer zum Lesen einer Eingabe von der
; Standard-Eingabe
LineBuffer db 16,0,20 dup 20h
; ------------------
; Satz für die Datei
; ------------------
DateiSatz dw 0,0 ; Satznummer im binären Format
DateiText1 db 10 dup (20h) ; Nummer des Satzes in Stringform
DateiText2 db '>'
db 16 dup ('_') ; beliebiger weiterer Text
db '<'
; Länge eines Satzes
SatzLaenge EQU ($ - Offset DateiSatz)
; ------------------
ExtraSeg dw 0 ; Segment des Speicherblocks für die Puffer
ExtraSegLength dw 0 ; Länge des Segments
; ------------------
; Name der Datei
DefString bspfile, 0, 'RECORDIO.BSP'
; ------------------
; Beispiel-Header für die Datei
FileHeader db CR,LF, 'RECORDIO.BSP - Record-Datei des Demo-Programms RECORDIO.DEM'
db CR,LF, ' aus der Sammlung Lib4A86'
db CR,LF,01Ah
FileHeader_LENGTH EQU $ - Offset FileHeader
; ------------------
RecordFileTablePtr dw 04000h ; Zeiger auf die Datei-Tabelle
; Aufbau der Datei-Tabelle
; ------------------------
; Die Felder, die initialisiert werden,
; sind mit einem Asterix (*) markiert
RecordFileTable STRUC
; Datei-Tabelle für die Record-Datei
; ----------------------------------
RecordFileHandle dw ? ; Handle (*)
RecordFileLastRec dw ?,? ; Offset des letzten Satzes
RecordFileHeaderL dw ?,? ; Länge des Headers (*)
RecordFileRecordL dw ? ; Länge eines Satzes (*)
RecordFileFPointer dw ?,?
RecordFileBufferC dw ? ; Anzahl Puffer (*)
RecordFileBufferL dw ? ; Länge eines Puffers (*)
RecordFileFlags db ? ; Flags (*)
RecordFileEmpty db ? ; Indikator für eine leere Datei
; ------------------
; Aufbau des ersten Puffer-Records
; --------------------------------
_1BufferRecordU1 dw ? ; 1. Puffer-Record ...
_1BufferRecordOfs dw ? ; (*)
_1BufferRecordSeg dw ? ; (*)
_1BufferRecordU2 dw ?,?
; ------------------
; Länge eines Puffer-Records
BufferRecordLength EQU $ - Offset _1BufferRecordU1
ENDS
; ----------------------------
start:
call ShowLogoAndAsk ; Logo ausgeben, Speicherblock verkleinern
; und Taste lesen
; ----------------------------
; Speicher für die Puffer anfordern
call GetMemForBuffer
if c jmp ErrorEnde1
; ----------------------------
; Dateitabelle anlegen
call InitFileTable
; ------------------
; Interrupt 21h umsetzen
call SetNewInt21h
; ------------------
; Datei eröffnen (falls möglich)
mov di,offset BspFile
; ES:DI -> Name der Datei
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call ResetRecordFile
jc ErstelleDatei ; Datei existiert nicht oder hat ein falsches
; Format
; Datei existiert und hat das richtige Format
Write_String ExistMsg
call ShowFileData ; Daten der Datei ausgeben
call CheckRECORDIOError
if c jmp ErrorEnde1
Write_String UseMsg
mov ah,01
int 021h
call ShowCR_LF
and al,0DFh
cmp al,'N'
if ne jmp BenutzeDatei ; existierende Datei benutzen
mov bx,RecordFileTablePtr
call CloseRecordFile
call CheckRECORDIOError
if c jmp ErrorEnde1
; ----------------------------
ErstelleDatei:
Write_String BuildMsg
mov di,offset BspFile
; ES:DI -> Name der Datei
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
; Datei existiert nocht nicht oder hat ein
; falsches Format ->> Datei neu aufbauen oder
; erstellen
call CreateRecordFile
call CheckRECORDIOError
if c jmp ErrorEnde1
; ------------------
call ShowFileData ; Daten der Datei ausgeben
call CheckRECORDIOError
if c jmp ErrorEnde1
call ShowBufferData ; Daten der Puffer ausgeben
; ----------------------------
; Header der Datei schreiben
mov di,offset FileHeader
; ES:DI -> File-Header
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call WriteRecordFileHeader
call CheckRECORDIOError
if c jmp ErrorEnde1
; ----------------------------
; Datei (sequentiell) füllen
call FillFile
call CheckRECORDIOError
if c jmp ErrorEnde1
Write_String MakeOkay
; ------------------
BenutzeDatei:
call ShowFileData ; Daten der Datei ausgeben
call CheckRECORDIOError
if c jmp ErrorEnde1
call ShowBufferData ; Daten der Puffer ausgeben
; ----------------------------
Write_String CloseMsg
; Datei schliessen
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call CloseRecordFile
call CheckRECORDIOError
if c jmp ErrorEnde1
; ----------------------------
Write_String ReOrgMsg
; Puffer umorganisieren
call ReOrgBuffer
; ----------------------------
Write_String OpenMsg
; Datei wieder eröffnen
mov di,offset BspFile
; ES:DI -> Name der Datei
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call ResetRecordFile
call CheckRECORDIOError
if c jmp ErrorEnde1
call ShowFileData ; Daten der Datei ausgeben
call CheckRECORDIOError
if c jmp ErrorEnde1
call ShowBufferData ; Daten der Puffer ausgeben
; ----------------------------
; Datei im Dialog bearbeiten
call DialogMenue
call CheckRECORDIOError
if c jmp ErrorEnde1
; ----------------------------
mov al,0
jmp SHORT Ende
; ----------------------------
; Fehlerausgang
; DX = Offset einer Fehlermeldung
; CX = Länge der Fehlermeldung
ErrorEnde1:
call ShowCR_LF
call OutputMsg ; Fehlermeldung ausgeben
call ShowCR_LF
; ----------------------------
ErrorEnde:
mov al,0FFh
; ------------------
Ende:
push ax ; Datei schliessen
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call CloseRecordFile
pop ax
EndProcess
; ----------------------------
; InitFileTable
;
; Funktion: Initialisiert die Datei-Tabelle für das
; Anlegen der Datei
;
InitFileTable:
; Die Dateitabelle wird hinter dem Code
; des Demos angelegt.
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
; Felder der Datei-Tabelle initialisieren
mov RecordFileHandle[bx],0FFFFh
mov RecordFileHeaderL[bx],FileHeader_LENGTH
mov RecordFileHeaderL[bx+2],0
mov RecordFileRecordL[bx],SatzLaenge
mov RecordFileFlags[bx],0
; beim Anlegen arbeiten wir nur mit
; einem großen Puffer
mov w RecordFileBufferC[bx],1
mov ax,ExtraSegLength
mov w RecordFileBufferL[bx],ax
; Puffer-Record füllen
mov ax,ExtraSeg
mov w _1BufferRecordOfs[bx],0
mov w _1BufferRecordSeg[bx],ax
ret
; ----------------------------
; FillFile
;
; Funktion: Füllt die Datei sequentiell
;
; Ausgabe: CF = 0 ->> okay
; CF = 1 ->> Fehler
; AX = Fehlernummer
;
FillFileMsg0 db 'Dateierstellung wird fortgesetzt ...'
db CR,LF
FillFileMsg db 'Sie können die Erstellung der Datei jederzeit'
db ' durch einen Tastendruck beenden'
db CR,LF
GetLength FillFileMsg
GetLength FillFileMsg0
MakeMsg1 FillFileAsk, CR,LF,'Datei-Erstellung beenden (j/n)? ==> '
MakeMsg1 LaufzeitA, 'Schreibe Satz Nummer 0000000000',CR
L_MaxSatzLow EQU [BP-2] ; lokale Variablen
L_MaxSatzHigh EQU [BP-4]
FillFile:
push bp
mov bp,sp
mov cx,005F5h
mov bx,0E100h ; CX:BX = 100.000 = max. Anzahl Sätze für die Datei
push bx
push cx ; lokale Variablen einrichten
Write_String FillFileMsg
xor dx,dx
xor ax,ax ; DX:AX = Satzzähler
; ------------------
FillFileLoop:
mov DateiSatz,ax ; akt. Satznummer sichern
mov DateiSatz+2,dx
; ------------------
mov ah,01h ; Testen, ob eine Taste gedrückt wurde
int 016h
jz >l1 ; keine Taste gedrückt
; ------------------
; Taste gedrückt, fragen ob die Dateierstellung
; beendet werden soll
Write_String FillFileAsk
mov ah,00h
int 016h ; gedrückte Taste ignorieren
mov ah,00h ; Taste lesen
int 016h
and al,0DFh
cmp al,'J'
if e jmp FillFileEnd ; Dateierstellung beenden
; ------------------
; Dateierstellung fortsetzen
Write_String FillFileMsg0
; ------------------
l1:
; Satz füllen
mov ax,DateiSatz
mov dx,DateiSatz+2 ; DX:AX = Satznummer für den nächsten Satz
; Zähler im String-Format eintragen
mov di,offset DateiText1
call KonvertDXAXToDezstring
; und Satz schreiben
mov di,offset DateiSatz
; ES:DI -> zu schreibender Satz
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
push ax,dx ; Satznummer sichern
call WriteRecord
if c jmp FillFileEnd ; CF = 1 ->> Fehler!
; ------------------
; Laufzeit-Anzeige ausgeben
mov si,offset LaufZeitA+30
l00: ; Zähler in der Meldung erhöhen
mov al,b[si]
inc al
cmp al,'9'
jbe >l1
mov al,'0'
mov b[si],al
dec si
jmp l00
l1:
mov b[si],al
mov si,Offset LaufZeitA
cld
l01:
lodsb
int 029h
cmp al,CR
jne l01
; ------------------
pop dx,ax ; DX:AX = Satznummer
inc ax
adc dx,0 ; Zähler erhöhen
cmp dx,L_MaxSatzHigh ; auf Schleifenende testen
jne >l1
cmp ax,L_MaxSatzLow
je FillFileEnd
l1:
jmp FillFileLoop
l8:
FillFileEnd:
mov sp,bp
pop bp
ret
; ----------------------------
; ReOrgBuffer
;
; Funktion: Reorganisiert die Puffer für die Dateibearbeitung im Dialog
; Für die Bearbeitung der Datei im Dialog ist es sinnvoller,
; mit mehreren kleinen Puffern zu arbeiten.
;
ReOrgBuffer:
mov ax,ExtraSegLength
; mal schauen wieviel Puffer wir anlegen
; können
push ax ; AX = Länge des Speicherblocks für die Puffer
xor dx,dx
mov cx,SatzLaenge*16 ; 16 Sätze/Puffer
; 16 * 32 = 512 (Länge eines Sektors)
div cx
mov bx,ax ; BX = Anzahl Sätze für die im Puffer Platz ist
mov ax,sp
sub ax,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
sub ax,10000xD ; AX = Freier Platz für Puffer-Records in
; diesen Segment
xor dx,dx
mov cx,10xD ; CX = Länge eines Puffer-Records
div cx ; AX = Anzahl Puffer-Records für die wir Platz
; haben
cmp ax,bx ;
if b mov bx,ax ; BX = Anzahl möglicher Puffer
cmp bx,250xD
if a mov bx,250xD ; max. sind nur 250 Puffer möglich
pop ax
xor dx,dx ; DX:AX = Länge des Speicherblocks für die Puffer
div bx ; BX = Anzahl Puffer
; AX = Größe eines Puffers
mov cx,bx ; CX = Anzahl Puffer
; Dateitabelle korrigieren
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
; Puffer-Anzahl korrigieren
mov RecordFileBufferC[bx],cx
; Puffer-Größe korrigieren
mov RecordFileBufferL[bx],ax
; Puffer-Records korrigieren
xor dx,dx ; DX = Offset des ersten Puffers
mov si,ExtraSeg ; SI = Segment aller Puffer
add bx,offset _1BufferRecordOfs[bx]
; BX = Offset-Feld des ersten Puffer-Records
l00:
mov [bx],dx ; Offset des Puffers eintragen
mov [bx+2],si ; Segment des Puffers eintragen
add dx,ax ; DX = Offset des nächsten Puffers
add bx,BufferRecordLength
; BX = Offset-Feld des nächsten Puffer-Records
loop l00
ret
; ----------------------------
; DialogMenue
;
; Funktion: Bearbeiten der Datei im Dialog
;
; Ausgabe: CF = 0 ->> okay
; CF = 1 ->> Fehler
; AX = Fehlernummer
;
DiagMsg db CR,LF
db ' -------------------------------- Dialog-Menue --------------------------------'
db CR,LF
db ' X = Ende, S = Statistik anzeigen, F = Puffer schreiben, D = Dateigröße ändern'
db CR,LF
db ' W = Write-Through ein/aus, N = nächster Satz, V = vorheriger Satz'
db CR,LF
db ' 0 ..n = Datensatz'
db CR,LF
db 'Hinweis: Wirkliche Zugriffe auf die Datei werden hier angezeigt.'
db CR,LF
db ' ┌────────────┴──────────────────────────┐'
db CR,LF
db ' ==> '
GetLength DiagMsg
DiagMsg1 db CR,LF, ' ------------------------------------------------------------------------------'
db CR,LF
GetLength DiagMsg1
MakeMsg DiagErr, 'Fehlerhafte Datensatz-Nummer eingegeben!'
MakeMsg1 NrMsg, 'Nummer des Datensatzes (0..n) ==> '
MakeMsg1 NewMsg, 'Datensatz nicht vorhanden, neu anlegen (j/n)? ==> '
MakeMsg1 Update, CR,LF,'Datensatz ändern (j/n)? ==> '
MakeMsg1 Update1, 'Neuen Inhalt2 für den Datensatz eingeben (max. 16 Zeichen) ',CR,LF,'==> '
MakeMsg Update2, 'Datensatz geändert bzw. neu angelegt.'
MakeMsg FlushMsg, 'Puffer geschrieben.'
MakeMsg WTOnMsg, 'Write-Through eingeschaltet.'
MakeMsg WTOffMsg, 'Write-Through ausgeschaltet.'
MakeMsg LengthMsg1, 'Dateigröße korrigiert (falls kein Fehlermeldung angezeigt wurde).'
LengthMsg db ' ---- Ändern der Dateigröße ---- '
db CR,LF
db 'Anzahl Sätze für die Datei eingeben (CR = keine Änderung)'
db CR,LF
db '==> '
GetLength LengthMsg
; ------------------
SatzNummer dw 0,0 ; Satznummer des akt. Satzes
; ------------------
DialogMenue:
; ------------------
Write_String DiagMsg ; Eingabe-Aufforderung ausgeben
; ------------------
GetSTDInKey NoCRLF ; Taste lesen
push ax
Write_String DiagMsg1
pop ax
; ------------------
cmp al,'D'
jne >l1
; D : Dateigröße ändern
l00:
Write_String LengthMsg
mov dx,offset LineBuffer
mov ah,0Ah
int 021h ; Anzahl Sätze für die Datei lesen
call ShowCR_LF
cmp LineBuffer+1,0
if e jmp DialogMenue
call GetNumber ; Anzahl Sätze ermitteln
jnc >l01
; ------------------
; Fehlerhafte Anzahl angegeben!
Write_String DiagErr
jmp l00
l01:
mov bx,RecordFileTablePtr
call SetRecordFileSize
jnc >k2
push ax
call CheckRECORDIOError
pop ax
jc DiagEnde1
k2:
Write_String LengthMsg1
call ShowFileData ; und neue Daten der Datei ausgeben
jmp DialogMenue
; ------------------
l1:
cmp al,'N'
jne >l1
; N : nächster Datensatz
mov ax,SatzNummer
mov dx,SatzNummer+2
inc ax
adc dx,0
jmp DatenSatzAnzeigen
; ------------------
l1:
cmp al,'V'
jne >l1
; V : vorheriger Datensatz
mov ax,SatzNummer
mov dx,SatzNummer+2
push ax
or ax,dx
pop ax
jz >l01 ; kein vorheriger vorhanden
dec ax
sbb dx,0
l01:
jmp DatenSatzAnzeigen
; ------------------
l1:
cmp al,'S'
jne >l1
; S : globale Daten ausgeben
call ShowFileData
pushf
call ShowBufferData
popf
jnc >k1
push ax
call CheckRECORDIOError
pop ax
jc DiagEnde1
k1:
jmp DialogMenue
DiagEnde1:
jmp DiagEnde ; Fehler!
; ------------------
l1:
cmp al,'F'
jne >l1
; F : Puffer schreiben
mov bx,RecordFileTablePtr
call FlushRecordFile
jnc >k1
push ax
call CheckRECORDIOError
pop ax
jc DiagEnde1
k1:
mov dx,offset FlushMsg
mov cx,FlushMsg_LENGTH
DialogMenue1:
call OutputMsg ; Meldung ausgeben
jmp DialogMenue
; ------------------
l1:
cmp al,'W'
jne >l1
; W : WriteThrough umschalten
mov bx,RecordFileTablePtr
xor RecordFileFlags[bx],RF_WriteThrough
mov dx,offset WTOnMsg
test RecordFileFlags[bx],RF_WriteThrough
if z mov dx,offset WTOffMsg
mov cx,WTOnMsg_Length
jmp DialogMenue1
; ------------------
l1:
cmp al,'X'
jne NummerEingegeben
; X : Ende
jmp DiagEnde
; ------------------
; sonst: Datensatz-Nummer
NummerEingegeben:
Write_String NrMsg
mov dx,offset LineBuffer
mov ah,0Ah
int 021h ; Nummer für den Datensatz lesen
call ShowCR_LF
cmp LineBuffer+1,0
if e jmp DialogMenue
call GetNumber ; Nummer des Satzes ermitteln
jnc DatenSatzAnzeigen
; ------------------
; Fehlerhafte Nummer angegeben!
Write_String DiagErr
jmp DialogMenue
; ------------------
DatenSatzAnzeigen:
; DX:AX = Nummer des Datensatzes
mov SatzNummer,ax ; Satznummer sichern
mov SatzNummer+2,dx
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call TestRecord ; Testen, ob der Satz existiert
jnc >l1
jmp DiagEnde
l1:
jnz >l1 ; Satz existiert
; ------------------
; Datensatz existiert nicht
Write_String NewMsg ; Fragen, ob der Datensatz angelegt werden soll
GetSTDInKey ; Taste lesen
cmp al,'J'
if ne jmp DialogMenue ; Satz soll nicht angelegt werden
; ------------------
; Datensatz anlegen
; Datei evtl. mit leeren Sätzen auffüllen
call InsertEmptyRecords
if c jmp DiagEnde
jmp >l2 ; und neuen Satz anlegen
; ------------------
l1:
; Satz lesen
mov di,offset DateiSatz
; ES:DI -> Puffer für den Satz
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call ReadRecord
jnc >k1
push ax
call CheckRECORDIOError
pop ax
if c jmp DiagEnde
k1:
call ShowDatenSatz ; Satz anzeigen
; ------------------
; Fragen, ob der Satz geändert werden soll
Write_String Update
GetSTDInKey ; Taste lesen
cmp al,'J'
if ne jmp DialogMenue ; Satz soll nicht geändert werden
; ------------------
l2:
; Satz soll geändert werden
Write_String update1
; neuen Inhalt für den Satz lesen
mov dx,offset LineBuffer
mov ah,0Ah
int 021h
; neuen Inhalt in den Satz übertragen
mov si,offset LineBuffer+2
mov di,offset DateiText2+1
mov cl,LineBuffer+1
xor ch,ch
push cx
rep movsb
pop ax
mov cx,16 ; Mit Blanks auffüllen
sub cx,ax
mov al,' '
rep stosb
; und Satz schreiben
mov ax,SatzNummer
mov dx,SatzNummer+2
mov di,offset DateiSatz
push di
mov w[di],ax
mov w[di+2],dx
mov di,offset DateiText1
call KonvertDXAXToDezString
pop di
; ES:DI -> zu schreibender Satz
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call WriteRecord
jnc >k1
push ax
call CheckRECORDIOError
pop ax
if c jmp DiagEnde
k1:
Write_String Update2
jmp DialogMenue
; ------------------
DiagEnde:
ret
; ----------------------------
; InsertEmptyRecords
;
; Funktion: Schreibt leere Sätze zwischen den letzten belegten
; Satz und den neuen Satz
;
; Ausgabe: CF = 0 ->> okay
; CF = 1 ->> Fehler
; AX = Fehlernummer
;
; Bes.: Während des Auffüllens wird das Ignore-LRU-Bit
; gesetzt, damit immer nur ein Puffer überschrieben
; wird und die Inhalt der anderen Puffer erhalten
; bleiben.
;
; Leerer Satz für die Datei
; ------------------
LeererSatz dw 0,0 ; Satznummer im binären Format
LeererText1 db 10 dup (20h) ; Nummer des Satzes in Stringform
LeererText2 db '?'
db 16 dup ('-') ; beliebiger weiterer Text
db '?'
MakeMsg1 InsertMsg, 'Fülle die Datei mit leeren Datensätzen auf ... '
MakeMsg InsertMsg1, CR,LF,'__________ leere Datensätze geschrieben.',CR,LF
EmptyRecords dw 0,0 ; Anzahl der leeren Sätze
InsertEmptyRecords:
Write_String InsertMsg
mov EmptyRecords,0 ; Zähler für die leeren Sätze auf 0 setzen
mov EmptyRecords+2,0
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
; Ignore LRU-Bit setzen
or RecordFileFlags[bx],RF_IgnoreLRU
; Anzahl Sätze in der Datei ermitteln
call GetRecordFileSize
jc >l8
; CX:BX = Anzahl Sätze in der Datei
mov ax,bx
mov dx,cx ; DX:AX = Anzahl Sätze in der Datei
; = Nummer des nächsten Satzes
l00:
mov bx,SatzNummer
mov cx,SatzNummer+2 ; CX:BX = Nummer des neuen Satzes
cmp dx,cx ; neuen Satz erreicht?
jb >l1
ja >l9
cmp ax,bx
jae >l9 ; ja, fertig
l1:
; nein, leeren Satz schreiben
mov LeererSatz,ax
mov LeererSatz+2,dx
mov di,offset LeererText1
call KonvertDXAXToDezString
mov di,offset LeererSatz
; ES:DI -> zu schreibender Satz
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call WriteRecord
jnc >k1
push ax
call CheckRECORDIOError
pop ax
jc >l8
k1:
push ax ; Laufzeit-Anzeige ausgeben
mov al,'.'
int 029h
pop ax
inc EmptyRecords ; Anzahl der leeren Sätze erhöhen
adc EmptyRecords+2,0
inc ax
adc dx,0 ; Satzzähler erhöhen
jmp l00
l9:
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
; Ignore LRU-Bit löschen
and RecordFileFlags[bx], RF_DontIgnoreLRU
; Anzahl der geschriebenen leeren Sätze ausgeben
mov di,offset InsertMsg1+2
mov ax,EmptyRecords
mov dx,EmptyRecords+2
call KonvertDXAXToDezString
Write_String InsertMsg1
clc
l8:
ret
; ----------------------------
; GetNumber
;
; Funktion: Ermittelt die eingegebene Satznummer
;
; Ausgabe: CF = 0 ->> okay
; DX:AX = Satznummer
; CF = 1 ->> Fehler
;
GetNumber:
mov si,offset LineBuffer+2
mov cl,LineBuffer+1
xor ch,ch ; CX = Anzahl Stellen
xor dx,dx
xor ax,ax ; Satznummer initialisieren
xor bh,bh
l00:
mov bl,[si]
inc si ; BL = akt. Zeichen
cmp bl,'.' ; Punkte überlesen
je >l01
sub bl,'0'
cmp bl,9
ja >L8 ; Fehler!
push bx,cx
mov bx,10xD ; alter_Wert = Alter_Wert * 10xD
mov cx,0
call MulLongInt
pop cx,bx
add ax,bx ; und neue Ziffer auf den Wert aufaddieren
adc dx,0
l01:
loop l00
clc
ret
l8:
stc
ret
; ----------------------------
; ShowDatenSatz
;
; Funktion: Ausgabe des Inhaltes des akt. Datensatzes
;
SatzMsg db 'Inhalt des Datensatzes: '
db 'Interner Satzzähler: '
SatzMsg1 db '________h, Inhalt: '
db CR,LF
db ' Inhalt1: '
GetLength SatzMSG
SatzMsg2 db CR,LF
db ' Inhalt2: '
GetLength SatzMsg2
ShowDatensatz:
mov di,offset SatzMsg1
mov ax,DateiSatz+2
call Konvert_AX_To_Hexstring
mov ax,DateiSatz
call Konvert_AX_To_Hexstring
Write_String SatzMsg
mov dx,offset DateiText1
mov cx,10xD
call OutPutMsg
Write_String SatzMsg2
mov dx,offset DateiText2
mov cx,18xD
call OutPutMsg
call ShowCR_LF
ret
; ----------------------------
; ShowFileData
;
; Funktion: Ausgabe der globalen Daten der Datei
;
; Ausgabe: CF = 0 ->> okay
; CF = 1 ->> Fehler
; AX = Fehlernummer
;
GlobalData db '-Dateistatus- Die Datei belegt '
m1 db '__________ Byte Speicher ',CR,LF
db ' und besteht aus '
m2 db '__________ Sätzen',CR,LF
GETLENGTH GlobalData
ShowFileData:
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
call GetRecordFileSize
jc ret
mov di,offset m1
call KonvertDXAXToDezString
mov dx,cx
mov ax,bx
mov di,offset m2
call KonvertDXAXToDezString
Write_String GLobalData
clc
ret
; ----------------------------
; ShowBufferData
;
; Funktion: Ausgabe der Anzahl und Größe der Puffer
;
BufferMsg db '-Pufferstatus- Benutze '
m1 db '_____ Puffer á '
m2 db '_____ Byte'
db CR,LF
db ' (-> '
m3 db '_____ Sätze/Puffer)'
db CR,LF
GetLength BufferMsg
BufMsg1 db ' Write-Through ist eingeschaltet.'
db CR,LF
GetLength BufMsg1
BufMsg2 db ' Write-Through ist ausgeschaltet.'
db CR,LF
GetLength BufMsg2
ShowBufferData:
mov bx,RecordFileTablePtr
; DS:BX -> Datei-Tabelle
mov di,offset m1
mov ax,RecordFileBufferC[bx]
; AX = Anzahl der Puffer
call Konvert_AX_To_Dezstring
mov di,offset m2
mov ax,RecordFileBufferL[bx]
; AX = Länge eines Puffers
push ax
call Konvert_AX_To_Dezstring
pop ax
mov cx,RecordFileRecordL[bx]
; CX = Länge eines Satzes
xor dx,dx
div cx ; AX = Anzahl Sätze pro Puffer
mov di,offset m3
call Konvert_AX_To_Dezstring
Write_String BufferMsg
mov dx,offset BufMsg1
test RecordFileFlags[bx],RF_WriteThrough
if z mov dx,offset BufMsg2
mov cx,BufMsg1_LENGTH
call OutputMsg
ret
; ----------------------------
; CheckRECORDIOError
;
; Funktion: Ermitteln der zu einer Fehlernummer der Routinen
; gehörenden Fehlermeldung
;
; Eingabe: AX = Fehlernummer der Routine
; CF = CF der Routine
;
; Ausgabe: CF = 0 ->> kein Fehler
; kein Register verändert
; CF = 1 ->> Fehler
; DX = Offset der Fehlermeldung
; CX = Länge der Fehlermeldung
; AX unverändert
;
;
MakeMsg1 ErrorAsk, CR,LF, 'Programm abbrechen? ==> '
; Fehlermeldungen
; ---------------
; Die Fehlermeldunge, die nicht mit einem '*' beginnen, führen NICHT
; zum Programm-Ende
;
ErrorMsg1 db '*** Fehler: Datei-Tabelle ist fehlerhaft'
ErrorMsg2 db '*** Fehler: Datei ist geschlossen'
ErrorMsg3 db '*** Fehler: Datei ist noch offen'
ErrorMsg4 db '+++ Fehler: Lesefehler, unerwartetes Dateiende'
ErrorMsg5 db '+++ Fehler: Schreibfehler, Disk ist voll'
ErrorMsg6 db '+++ Fehler: Falsche Satznummer angegeben'
ErrorMsg7 db '*** Fehler: Die Datei hat eine falsche Länge'
ErrorMsg8 db '*** Fehler: Geräte können mit diesen Routinen nicht verwaltet werden!'
ErrorMsg9 db '*** Fehler: Falsche Länge für den Header angegeben'
ErrorMsgA db '*** Zuwenig freier Speicher'
ErrorMsgU db '*** Unbekannte Fehlernummer: ____h!'
ErrorMsgL db 0 ; Dummy-Eintrag
; Offset für die Ausgabe der Fehlernummer bei
; unbekannten Fehlercodes
ErrorNrMsg EQU (Offset ErrorMsgU + 29)
; Tabelle der Fehlernummern und Fehlermeldungen
; ---------------------------------------------
; Fehlernummern Offset der Fehlermeldung
; -----------------------------------------------
ErrorTable dw RFileTableError , Offset ErrorMsg1
dw RFileNotOpen , Offset ErrorMsg2
dw RFileAlreadyOpen , Offset ErrorMsg3
dw RFileReadError , Offset ErrorMsg4
dw RFileWriteError , Offset ErrorMsg5
dw RFileRecordError , Offset ErrorMsg6
dw RFileLengthError , Offset ErrorMsg7
dw RFileDeviceError , Offset ErrorMsg8
dw RFileHeaderError , Offset ErrorMsg9
dw 08h , Offset ErrorMsgA
; Eintrag für unbekannte Fehlernummern
UnknownErr dw 0 , Offset ErrorMsgU
; Eintrag für die Ermittlung der Länge
; der letzten Fehlermeldung
dw 0 , Offset ErrorMsgL
CheckRECORDIOError:
jnc ret ; CF = 0 ->> kein Fehler aufgetreten
push si,ds,ax ; CF = 1 ->> Fehler aufgetreten,
; Offset der Fehlermeldung ermitteln
mov ds,cs ; DS = CS
mov si,offset ErrorTable
; DS:SI -> Fehlertabelle
mov UnknownErr,ax ; Eintrag für unbekannte Fehlernummern
; korrigieren
push ax,di,es
mov es,cs
mov di,ErrorNrMsg
call Konvert_AX_To_Hexstring
pop es,di,ax
mov dx,ax ; Fehlernummer nach DX
l0:
lodsw
cmp ax,dx
lodsw
jne l0
mov dx,ax ; DX = Offset der Fehlermeldung
mov cx,[si+2] ; CX = Offset der nächsten Fehlermeldung
sub cx,dx ; CX = Länge der Fehlermeldung
mov si,dx
cmp b[si],'*'
stc
je >l1 ; Programm-Abbruch
call OutputMsg ; Nur Fehlermeldung ausgeben, kein Programm-Abbruch
mov dx,offset ErrorAsk
mov cx,ErrorAsk_LENGTH
call OutputMsg
GetSTDInKey
cmp al,'J'
stc
je >l1
clc
l1:
pop ax,ds,si
ret
; ----------------------------
; KonvertDXAXToDezstring
;
; Funktion: Konvertiert (vorzeichenlos) DX:AX zu einem Dezimal-String bei ES:DI
;
; Eingabe: DX:AX = zu konvertierender Wert
;
; Ausgabe: Dezstring bei ES:DI
;
k1 db 0
k0:
call DivLongInt
cmp al,0
jne >k01
cmp k1,al
jne >k01
mov al,' '
jmp >k02
k01:
add al,'0'
mov k1,al
k02:
stosb
mov dx,cx ; Rest nach DX:AX
mov ax,bx
ret
KonvertDXAXToDezstring:
push ax,bx,cx,dx
mov k1,0
mov cx,03B9Ah
mov bx,0CA00h ; CX:BX = 1.000.000.000
call K0
mov cx, 05F5h
mov bx,0e100h ; CX:BX = 100.000.000
call K0
mov cx, 0098h
mov bx,09680h ; CX:BX = 10.000.000
call K0
mov cx, 0Fh
mov bx,04240h ; CX:BX = 1.000.000
call K0
mov cx, 01h
mov bx,086A0h ; CX:BX = 100.000
call K0
mov cx, 0h
mov bx,02710h ; CX:BX = 10.000
call K0
mov cx, 0h
mov bx,003E8h ; CX:BX = 1.000
call K0
mov cx, 0h
mov bx,00064h ; CX:BX = 100
call K0
mov cx, 0h
mov bx,0000Ah ; CX:BX = 10
call K0
mov al,bl
add al,'0'
stosb
pop dx,cx,bx,ax
ret
; ----------------------------
; GetMemForBuffer
;
; Funktion: Allociert den Speicher für die Puffer
;
; Ausgabe: CF = 0 ->> Okay
; CF = 1 ->> Fehler
; AX = Fehlernummer
;
GetMemForBuffer:
mov bx,1000h ; 1 Segment möchten wir ...
mov ah,048h
int 021h
jnc >l1
; 1 Segment kriegen wir nicht, nehmen wir
mov ah,048h ; also was wir kriegen können
int 021h
jc >l0 ; immer noch Fehler
cmp ax,512 ; 512 Byte sollten es aber schon sein
ja >l1
stc ; 512 Byte gibt's auch nicht, also Ende
mov ax,08h ; 08h = Zu wenig Speicher
l0:
ret
l1:
mov ExtraSeg,ax
shl bx,1
shl bx,1
shl bx,1
shl bx,1
or bx,bx
if z dec bx
mov ExtraSegLength,bx
clc
ret
; ----------------------------
; SetNewInt21h
;
; Funktion: Speichern des alten Interrupt 21h und umsetzen des
; Interrupt 21h auf unsere Routine
;
SetNewInt21h:
mov ax,03521h
int 021h
mov OldInt21h,bx
mov OldInt21h+2,es
push cs
pop es
mov dx,offset NewInt21h
mov ax,02521h
int 021h
ret
; ----------------------------
; NewInt21h
;
; Funktion: Neuer Interrupt-Handler für den Interrupt 21h
; Gibt vor dem Ausführen der Funktionen 40h und 3Fh
; mit dem Handle der Record-Datei eine Meldung aus
; und setzt vor dem Ausführen der Funktion 00h oder
; 4Ch den Interrupt 21h zurück.
;
; Der Handler wird während der Dateibearbeitung
; eingebunden, so daß erkennbar ist, wann die
; Pufferverwaltung wirklich auf die Datei zugreifen muß.
;
Int21ReadMsg db CR,LF
db ' ┌───────────────────────────────────────┐ '
db CR,LF
db ' │ ---- Lese aus der Datei ... ----- │ '
db CR,LF
db ' └───────────────────────────────────────┘ '
db CR,LF
GetLength Int21ReadMsg
Int21WriteMsg db CR,LF
db ' ┌───────────────────────────────────────┐ '
db CR,LF
db ' │ ---- Schreibe in die Datei ... ----- │ '
db CR,LF
db ' └───────────────────────────────────────┘ '
db CR,LF
GetLength Int21WriteMsg
Int21SizeMsg db CR,LF
db ' ┌───────────────────────────────────────┐ '
db CR,LF
db ' │ ---- Ändere die Dateigröße ... ----- │ '
db CR,LF
db ' └───────────────────────────────────────┘ '
db CR,LF
GetLength Int21SizeMsg
Int21Msg_LENGTH EQU Int21SizeMsg_LENGTH
OldInt21h dw ?,? ; Adresse der alten Routine
NewInt21h:
pushf
cmp ah,040h
je Func40_3f
cmp ah,03Fh
je Func40_3f
cmp ah,04Ch
je Func00_4c
cmp ah,00h
je Func00_4c
Int21Through: ; Weiter zur alten Routine
popf
jmp dword ptr cs:OldInt21h
Func00_4c:
push ax,bx,cx,dx ; Funktion 00h und 4Ch: Zuerst den
; Interrupt 21h zurücksetzen
push ds
lds dx,cs:OldInt21h
mov ax,02521h
int 021h
pop ds
pop dx,cx,bx,ax
jmp Int21Through
Func40_3f: ; Funktion 40h und 3Fh: Ausgabe einer
; Meldung falls in die Record-Datei
; geschrieben wird bzw. aus ihr gelesen
; wird
push si ; angegebenes Handle testen
mov si,cs:RecordFileTablePtr
cmp bx,cs:[si]
pop si
jne Int21Through
; Handle stimmt
push ds
push ax,bx,cx,dx
mov ds,cs
mov dx,offset Int21ReadMsg
cmp ah,03Fh
je >l1 ; Lesen aus der Datei
mov dx,offset Int21SizeMsg
jcxz >l1 ; Dateigröße wird verändert
; Schreiben in die Datei
mov dx,offset Int21WriteMsg
l1:
mov cx,Int21Msg_LENGTH
mov ah,040h
mov bx,StdOut
int 021h ; Meldung ausgeben
pop dx,cx,bx,ax
pop ds
jmp Int21Through ; und weiter zur alten Routine
;
; ----------------------------