home *** CD-ROM | disk | FTP | other *** search
Text File | 1992-02-16 | 44.3 KB | 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
-
- ;
- ; ----------------------------
-
-