8086 Assembler (MS-DOS):
Beispielprogramm ENTAB zur Dateibehandlung mit Handles

Dies für den Assembler ML 6.14 geschriebene Quellprogramm ist gedacht als Beispielprogramm zur Dateibehandlung mit Handles. Es verwendet den DOS-Interrupt INT 21 mit den Funktionen

  • 3c create a file
  • 3d open a file
  • 3e close a file
  • 3f read a file
  • 40 write a file
  • 41 delete a file
  • 42 get file size
  • 56 rename a file

Außerdem wird eine Makro- und Unterprogrammbibliothek namens firm.mac benutzt.

Die Funktionen des ausführbaren Programmes entab.com gehen aus dem Programmlisting beim Merkmal "get_name3" hervor. Das Merkmal befindet sich etwa bei der 40. Zeile der Programmauflistung. Es handelt sich um ein Hilfsprogramm zum Komprimieren und Expandieren von Textdateien. Die Textdateien lassen sich trotzdem mit Texteditoren weiter anzeigen und bearbeiten.

Dies ist ein Programm, dessen ausführbare Datei entab.com komprimiert werden kann. So schrumpft die Größe von entab.com bei Verwendung des Komprimierungprogrammes pklite.exe von 13149 auf 2660 Bytes.

.MODEL TINY
title   entab
        page    65,120

false   equ     0
true    equ     not false

dump$   equ     false   ;fuer mdump, rdump
prompt$ equ     true    ;fuer enter, inkjn
intasc$ equ     true    ;fuer int2asc, asc2int
string$ equ     true    ;fuer fill, cmpstr, lenstr, instrg, movstr, ucaseg, lcaseg

.CODE

        org     100h
_start: jmp     around

        include firm.mac
around:
        mov     si,lparm

;------------------------
;kommandozeile auswerten.
;wenn keine paramter angegeben sind, bedienungsanleitung anzeigen
;und parameter ueber tastatur anfordern.
;
;anschliessend parameter plausibilieren
;------------------------

get_name1:
        xor     cx,cx
        mov     cl,b [si]       ;laenge der kommandozeile
        jcxz    get_name3       ;eingabe auf kommandozeile anfordern wenn leer

        jmp     get_name5

get_name3:
      call    prmsg
 dbl
 dbl  "Dies Programm entfernt aus einer ASCII-Datei"
 dbl  "Spaces, indem es Tabulatoren fuer Stelle 8, 16, 24 ... einsetzt."
 dbl  "Wordstar Steuerzeichen 8Ah/8Dh werden in 0Ah/0Dh gewandelt."
 dbl  <"In Zeilen mit ' oder ",'"'," werden keine TABs eingesetzt.">
 dbl
 dbl  "-----------------"
 dbl  "Aufrufe:"
 dbl  "entab              Dateiname im Dialog eingeben"
 dbl  "entab dateiname    Dateiname nicht im Dialog eingeben"
 dbl  "entab dateiname c  entab mit Entfernen von CR * Die anderen Funktionen"
 dbl  "entab dateiname l  entab mit Entfernen von LF * ergaenzen CR-LF wieder"
 dbl  "entab dateiname u  umgekehrte Funktion zu entab Dateiname"
 dbl  "entab dateiname g  entab mit Wandlung in Grossschrift"
 dbl  "entab dateiname k  entab mit Wandlung in Kleinschrift"
 dbl  <"entab dateiname a  auch Zeilen mit ' oder ",'"'," werden komprimiert">
 dbl  "-----------------"
 db   0

get_name4:
        inkstr  'Dateiname [u|g|k|a|c|l]: ',40,lparm
        mov     si,lparm+1
        jmp     get_name1

get_name5:
        getparm         ;parameteranfangsadresse nach si
        push    si

        xor     cx,cx   ;laenge der parameterleiste nach cx
get_name6:
        cmp     b [si],cr
        jz      get_name7     ;ende gefunden
        inc     cx
        inc     si
        jmps    get_name6

get_name7:
        mov     b [si],0      ;ende kennzeichnen

        pop     si
        push    si            ;stringanfangsadresse
        call    ucaseg        ;wandeln in grossschrift
        pop     si
        push    si            ;stringanfangsadresse

get_name8:
        cmp     b [si],spc    ;suchen ob Space enthalten
        jz      get_name9             ;ja
        inc     si
        loop    get_name8

get_name9:
        cmp     b [si],spc    ;Space gefunden ?
        mov     b untab,'E'   ;kein Space, Parameter E unterstellen
        jne     get_name12

        mov     b [si],0            ;zwischenstring kennzeichnen
        inc     si
        mov     al, b [si]
        mov     b untab,al

get_name12:
        pop     si                  ;anfangsadresse parameter (dateiname)
        mov     di,offset q_datei
        call    movstr              ;dateiname (quelle) uebernehmen

        mov     di,offset q_datei + 1
        cmp     b [di],':'
        je      get_name13
        jmp     get_name15

get_name13:
        call    prmsg
 dbl     'Das Programm arbeitet mit RENAME. Deshalb ist die Angabe'
 dbl     'des Laufwerkes nicht zulaessig.'
 dbl     'Bitte ggf. auf das Verzeichnis setzen und entab erneut starten!'
 db        0
        jmp     get_name3

;---------------------
;plausibilierung des komprimierungsparamters
;---------------------
get_name15:
        mov     di, offset kompr      ;zugelassene komprimierunggsarten
        mov     si, offset untab
        call    instrg                ;zero flag gesetzt wenn nicht enthalten
        jnz     verarb
        prstr   "nur E, U, G, K, A, C, L oder kein Parameter zugelassen!"
        jmp     get_name3

;---------------------
;dateien eroeffnen
;---------------------
verarb:
        fopen   q_datei,0              ;nur lesen
        jmpc    err1

        mov     handle1,ax             ;dateihandle speichern

        fcrat   z_datei,0              ;create zieldatei (schreiben)
        jmpc    err2
        mov     handle2,ax

;---------------------
;quelldatei zeilenweise lesen und verarbeiten
;---------------------
lese:
        call    line_input     ;get a line

        mov     dx,lin_buf
        mov     cx,bx          ;zeilenlaenge nach cx

        mov     si,offset in_buf
        add     si,cx

        or      cl,ch         ;leerzeile?
        jz      lese3         ;ja

lesecut:                      ;trailing spaces entfernen
        dec     si
        cmp     b [si],spc
        jne     lesecut9
        loop    lesecut

lesecut9:
        inc     si
lese3:
        mov     b [si],0       ;stringende einsetzen

        push    cx             ;zeilenlaenge
        mov     si,offset in_buf

        pop     cx             ;zeilenlaenge
        or      cx,cx
        jz      lese5          ;keine ausgabe der zeile wenn leerzeile

;---------------------
;zeile verarbeiten, z.b. komprimieren und gross/kleinschriftwandlung
;       und zur zieldatei ausgeben. cr/lf wird getrennt ausgegeben
;---------------------
        push    cx
        mov     w lin_buf_bel,cx  ;tatsaechliche zeilenlaenge speichern
        call    verarbeite        ;verarbeitung der zeile

        pop     cx                ;zeilenlaenge
        jmps    lese7

lese5:
        cmp     eof_B_BUF,'Y'   ;war EOF?
        je      lese7           ;ja - keine ausgabe cr lf bei leerer letzter zeile
lese6:
        mov     al,b untab      ;lf nur ausgeben, wenn nicht L
        cmp     al,'L'          ;als Partameter angegeben
        jne       lese62

        fwrit   handle2,cr_buf,1      ;Ausgabe nur cr
        jmpc    err4
        jmps    lese7

lese62:
        cmp     al,'C'          ;cr nur ausgeben, wenn nicht C
        jne     lese65          ;als Parameter angegebn
        fwrit   handle2,cr_buf+1,1
        jmpc    err4
        jmps    lese7

lese65:
        fwrit   handle2,cr_buf,2      ;ausgabe cr lf
        jmpc    err4

lese7:
        cmp     eof_B_BUF,'Y'   ;war EOF?
        je      lese8
        jmp     lese
;---------------------
;wenn eof: dateigroessen anzeigen zum vergleich
;und dateien loeschen/renamen, dass die komprmierte / bearbeitete datei
;uebrig bleibt.
;---------------------
lese8:
        xor     dx,dx             ;Dateigroesse "vorher" anzeigen
        xor     cx,cx
        mov     al,2
        mov     bx,handle1
        int21   42h
        mov     di,offset cs:ziff1
        call    int2asc
        call    prmsg
        db      'Dateilaenge vorher  (Bytes):        '
ziff1   db      spc,cr,0

        xor     dx,dx             ;Dateigroesse "nachher" anzeigen
        xor     cx,cx
        mov     al,2
        mov     bx,handle2
        int21   42h
        mov     di,cs:offset ziff2
        call    int2asc
        call    prmsg
        db      'Dateilaenge nachher (Bytes):        '
ziff2   db      spc,cr,0

        call    end_file

;loeschen alte datei
        lea     dx,q_datei
        int21   41h
        jmpc    err7

;rename arbeitsdatei in alte datei
        lea     di,q_datei    ;neuer name
        push    ds
        pop     es
        lea     dx,z_datei
        int21   56h
        jmpc    err8

        jmp     ret0

;---------------------
;unterprogrammsammelsurium
;---------------------
;upro verarbeitung und ausgabe der zeile in in_buf, laenge wie cx
;---------------------
verarbeite:
        mov     al,b untab    ;zeile expandiert ausgeben
        cmp     al,'U'
        jne     verarb2
verarb1:
        mov     si,offset in_buf
        add     si,cx
        mov     b [si],cr             ;cr lf ergaenzen
        inc     si

        mov     b [si],lf
        inc     cx
        inc     cx
        fwrit   handle2,in_buf,cx
        jmpc    err4
        ret

verarb2:                        ;bei allen anderen formen zeile komprimieren
        cmp     al,'A'
        je      verarb11        ;bei a jede zeile komprimieren

         mov     si,offset in_buf
         push    cx

        mov     dh,'"'
        mov     dl,"'"
verarb4:
        mov     al,b [si]       ;bei nicht A nur zeilen komprimieren,
        cmp     al,dh           ;die nicht ' und " enthalten
        je      verarb6
        cmp     al,dl
        je      verarb6
        inc     si
        loop    verarb4
        jmps    verarb10        ;zum komprimieren

verarb6:
        pop     cx
        jmps    verarb1         ;satz aus in_buf heraus schreiben

verarb10:
        pop     cx
verarb11:
        call    entab           ;komprimieren hier...

        mov     si,offset out_buf
        mov     al,b untab
        cmp     al,'K'          ;Wandlung in Kleinschrift
        jne     verarb18

        call    lcaseg
        jmps    verarb20

verarb18:
        cmp     al,'G'          ;Wandlung in Grossschrift
        jne     verarb20

        call    ucaseg

verarb20:
        mov     cx,w lout_buf_bel
        mov     si,offset out_buf
        add     si,cx
        mov     al,b untab     ;cr nur ergaenzen, wenn nicht C
        cmp     al,'C'         ;als Parameter angegeben
        je      verarb21
        mov     b [si],cr      ;cr ergaenzen
        inc     si
        inc     cx
verarb21:                      ;lf nur ergaenzen, wenn nicht L
        cmp     al,'L'         ;als Parameter angegenem
        je      verarb22
        mov     b [si],lf
        inc     si
        inc     cx
verarb22:
        fwrit   handle2,out_buf,cx
        jmpc    err4
        ret

;------------------
;komprimieren durch tabulatoren
;------------------
entab:
        xor     cx,cx
entab10:
        add     cx,8
        mov     dx,8          ;teilstringlaenge
        mov     ax,w lin_buf_bel
        cmp     ax,cx
        jnb     entab20        ;sprung, wenn erhoehung der adresszeigers cx
        jz      entab20        ;noch ging

        sub     cx,8
        mov     dx,w lin_buf_bel
        sub     dx,cx         ;dx: rest der stringlaenge
        mov     cx,w lin_buf_bel

entab20:
        mov     si,offset in_buf
        add     si,cx
        push    cx
        mov     cx,dx         ;max dx-mal (8 oder teilstringlaenge)
        dec     si            ;rechter rand der teilkette
entab30:
        cmp     byte ptr [si],spc
        jne     entab40
        mov     byte ptr [si],9
        dec     si
        loop    entab30

entab40:
        pop     cx
        mov     ax,w lin_buf_bel
        cmp     ax,cx
        jnz     entab10

;kopieren quellstring nach zielstring
        mov     si,offset in_buf
        mov     di,offset out_buf
        xor     bx,bx
        mov     cx,w lin_buf_bel

entab50:
        mov     al,byte ptr [si]
        cmp     al,9
        je      entab60
entab55:
        mov     byte ptr [di],al
        inc     di
        inc     si
        inc     bx
        loop    entab50

entab99:
        mov     dx,di
        mov     di,offset out_buf
        sub     dx,di
        mov     w lout_buf_bel,dx
        ret

entab60:
        mov     ax,bx         ;position 7 des teilstrings?
        and     al,7
        cmp     al,7          ;dann wird der tab ein space
        jne     entab65
        mov     al,spc
        jmp     entab55

entab65:                      ;tab zum zielstring und vorlesen auf anfang
        mov     byte ptr[di],tab   ;naechster teilstring
        inc     di
        jmp     entab75
        jz      entab99       ;zur sicherheit
entab70:
        inc     si
        inc     bx
        mov     ax,bx
        and     al,7
        jz      entab50
entab75:
        loop    entab70
        jmp     entab99       ;zur sicherheit


;---------------------
;upro dateien schliessen
;---------------------
end_file:
        fclose  handle1
        jmpc    err5
        fclose  handle2
        jmpc    err6
        ret
;---------------------
;fehlermeldungen fuer dateibehandlung
;---------------------
ERR1:   prstr   'Quell'
        jmps      err1_2

ERR2:   prstr   'Ziel'
ERR1_2: prstr   'datei laesst sich nicht oeffnen'
        jmp      ret1

ERR3:   prstr   'Lesefehler!'
        jmp     ret1

ERR4:   prstr   'Schreibfehler!'
        jmp      ret1

ERR5:   prstr   'Quell'
        jmps     err5_6

ERR6:   prstr   'Ziel'
ERR5_6: prstr   'datei laesst sich nicht schliessen'
        jmp     ret1

ERR7:   prstr   'Quelldatei laesst sich nicht loeschen'
        jmp     ret1

err8:   call    prmsg
  dbl     'Rename der Arbeitsdatei in Quelldatei nicht moeglich.'
  dbl     'Die Arbeitsdatei heisst jetzt ENTAB.WRK'
  dbl     'Sie enthaelt die fertig bearbeiteten Daten.'
  db        0
        jmp     ret1

;---------------------
;upro lese eine zeile nach in_buf. dabei werden tabs aufgeloest
;---------------------
line_input:
        mov     cx,lin_buf
        xor     bx,bx         ;zeichenzaehler
        mov     si,offset in_buf
line_input1:
        pushreg <si,bx>
        call    getbyte               ;hole 1 byte
        popreg  <bx,si>
        cmp     eof_B_BUF,'N'   ;EOF?
        jne     line_input99    ;ja
        cmp     al,8dh                ;wordstar cr ?
        je      line_input9
        cmp     al,8ah                ;wordstar lf ?
        je      line_input9

line_input2:
        cmp     al,cr         ;cr?
        je      line_input99  ;ja
        cmp     al,lf         ;lf unter Umstaenden ueberlesen
        je      line_input8
        cmp     al,tab
        je      line_input5
        mov     b [si],al
        inc     bx
        inc     si
line_input3:
        mov     lezei,spc             ;merke space als letztes zeichen
        loop    line_input1

line_input4:
        prstr   'Abbruch- Zeile zu lang'
        call    end_file
        jmp     ret1

line_input5:                  ;tabulatoren aufloesen
        mov     b [si],spc
        inc     bx
        inc     si
        mov     ax,bx
        and     ax,7h         ;tabulatorposition erreicht ?
        jz      line_input3   ;ja
        loop    line_input5   ;nein
        jmps    line_input4   ;bei ueberlauf

line_input8:                  ;lf wurde gelesen
        cmp     lezei,cr      ;ueberlesen, wenn letztes zeichen cr war
        jne     line_input99  ;sonst wie cr behandeln

        mov     lezei,al
        jmps    line_input1

line_input9:
        and     al,7fh        ;wordstar cr/lf wird normales cr/lf
        jmps    line_input2

line_input99:
        mov     lezei,al      ;merke letztes zeichen
        ret
;---------------------
;upro lese 1 byte aus der quelldatei nach al
;---------------------

getbyte:
        mov     bx,anz_b_buf  ;noch was im puffer?
        or      bx,bx
        jz      getbyte10     ;nein

getbyte5:
        mov     bx,pos_b_buf  ;1 Byte aus Puffer abholen
        lea     si,b_buf
        mov     al,[si][bx]
        inc     bx
        mov     pos_b_buf,bx
        dec     anz_b_buf
        ret

getbyte10:
        cmp     eof_B_BUF,'Y'   ;war EOF?
        je      getbyte99       ;ja
        push    cx
        fread   handle1,b_buf,lb_buf
        pop     cx
        mov     anz_b_buf,ax    ;anzahl gelesener bytes
        jmpc    err3
        mov     pos_b_buf,0     ;position 0
        or      al,ah            ;eof?
        jnz     getbyte5        ;nein
        mov      eof_B_BUF,'Y'

getbyte99:
        mov      al,1ah         ;ja, dann eof melden
        ret

;---------------------
;datenbereiche
;---------------------
q_datei db     40 dup(32)
z_datei db     'ENTAB.WRK',0
handle1 dw     ?
handle2 dw     ?

untab   db     0                ;komprimerungsart
        db     0                ;0 kennzeichnet stringende komprimierungsart
kompr   db    'EU GKACL',0      ;zugelassene komprimierungsarten

cr_buf  db     cr,lf            ;zeilewechsel

pos_b_buf dw   0                ;pufferposition
anz_b_buf dw   0                ;bytes im puffer
eof_B_BUF db  'N'               ;kein EOF

lezei   db      0               ;letztes gelesenes zeichen

b_buf         db   1024*8 dup (0)
lb_buf        equ  $-b_buf

in_buf        db   1024 dup (0)
lin_buf       equ  $-in_buf
lin_buf_bel   dw   0             ;wie weit in_buf wirklich belegt ist

out_buf       db   1024 dup (0)
lout_buf      equ  $-in_buf
lout_buf_bel  dw   0             ;wie weit out_buf wirklich belegt ist

        end     _start
Letztes Upload: 24.03.2023 um 11:35:15 • Impressum und Datenschutzerklärung