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
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 |