8086 Assembler (MS-DOS) vs Code::Blocks C:
Beispiel Filterprogramm TEE zur Dateibehandlung mit Handles

Dies für den Assembler ML 6.14 geschriebene Quellprogramm ist ein Beispielprogramm zur Dateibehandlung mit Handles. Es verwendet Handles für Lesen von Standardeingabe und zum Schreiben zur Standardausgabe. In eine zweiten Version des gleichen Programmes wird die Verwendung der Funktion 71h mit Unterfunktion 6ch zur Verarbeitung von Dateien mit langen Dateinamen demonstriert.

Die dritte Version zeigt ein vergleichbares Quellprogramm in der Programmiersprache C. Der Quellprogrammcode ist erheblicher kürzer als die beiden Assemblervarianten. Die Übersetzung des C-Proramms erfolgte mit Hilfe der Open-Source-IDE von Code::Blocks. IDE steht für Integrated Development Environment (Integrierte Entwicklungsumgebung). Diese Variante funktioniert auch unter Windows 10.

Verwendete Funktionen des Interrupts 21h:

  • 3c create a file
  • 3d open a file
  • 3e close a file
  • 3f read a file
  • 40 write a file
  • 42 get file size
  • 5b create new file
  • 716ch create / open file (supports long file names)

Es sei der Hinweis auf die hier nicht verwendete Funktion 6C des INT 21H hingewiesen: Sie fasst die Funktionen 3C, 3d und 5B zusammen.

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

Da die Verwendung der Handles zum Lesen von Standardeingabe und zum Schreiben zur Standardausgabe in veröffentlichten Programmbeispielen kaum vorkommt, wird vorher das spezielle Testprogramm KOPIE gezeigt.

KOPIE - das Programm für den Vorversuch

Das kleine Programm KOPIE kopiert von der Standardeingabe zur Standardausgabe. Die Standardeingabe wird über den Handle 0 angesprochen. Die Standardausgabe wird über den Handle 1 angesprochen.

Unter MS-DOS sind fünf Handles standardmäßig für Geräte vorbelegt:

  • Handle 0 ist das Standardeingabegerät CON. Es verweist normalerweise auf die Tastatur
  • Handle 1 ist das Standardausgabegerät CON. Es verweist normalerweise auf den Bildschirm.
  • Handle 2 ist das Standardgerät zur Fehlerausgabe CON. Es verweist normalerweise auf den Bildschirm.
  • Handle 3 ist verweist auf die serielle Standardschnittstelle (AUX).
  • Handle 4 verweist auf den Standarddruckeranschluss (PRN).

Um das Öffnen und Schließen von Tastatur und Bildschirm braucht sich das Programm nicht zu bekümmern.

Tastatur und Bildschirm lassen sich durch Dateien ersetzen. Dazu dienen die Umleitungssymbole
< für Eingabe (statt Tastatur aus Datei )
> für Ausgabe in eine neue Datei (statt Bildschirm in Datei). Ist die Datei bereits vorhanden, so wird sie vorher gelöscht.
>> für Ausgabe zur Erweiterung einer bereits bestehenden Datei. Falls die Datei nicht vorhanden war, wird sie neu angelegt.


Nach Eingabe der Befehlszeile
kopie <hallo1.txt >hallo2.txt

wird die Datei HALLO1.TXT in die Datei HALLO2.TXT kopiert.

Das Quellprogramm ist überraschend einfach. Am Anfang des Quellprogrammtextes sind einige Anregungen für Versuche aufgeführt.

.MODEL TINY
;======================================
;Zeigt, wie einfach sich ein Kopierprogramm mittels Handles
;programmieren laesst
;Beim Eintippen von Text das Programm mit ctrl C anfordern!
;Vorher die letzte Eingabezeile mit der Enter-Taste abschliessen!
;---
; Zum Testen nacheinander aufrufen mit
; kopie             Eingetippter Text sollte auf dem Bildschirem erscheinen
; kopie >hallo.txt  Eingetippter Text kopieren in die Datei hallo.txt
; kopie <hallo.txt >hallo1.txt   Die Datei hallo.txt soll in die Datei
;                                hallo1.txt kopiert werden
; kopie <hallo.txt >>hallo1.txt  Die Datei hallo.txt sollte an die Datei
;                                hallo1.txt angehängt werden
;======================================
;
FALSE   EQU    0
TRUE    EQU    NOT FALSE

dump$   equ    false           ;fuer mdump,  rdump
prompt$ equ    false           ;fuer PROMPT, INKJN
intasc$ equ    false           ;fuer INT2ASC, ASC2INT
string$ equ    false           ;fuer CMPSTR, LENSTR, INSTR, MOVSTR

.CODE
       ORG     100h

kopie: JMP     around
       include firm.mac

;Text, gleichzeitig Puffer
Text   DB      '0'
;
around:
       mov      bx,0                   ;Handle console (eingabe)
       mov      cx,1                   ;1 Zeichen lesen
       mov      dx,offset Text
       mov      ah,3fh                 ;lesen
       int      21h
       or       ah,al                  ;ax ist 0 wenn EOF
       jz       fertig

       mov      bx,1                   ;Handle console (ausgabe)
       mov      cx,1                   ;Länge des Textes
       mov      dx,offset Text
       mov      ah,40h                 ;schreiben
       int      21h
       jmp      around

fertig:
       MOV      AX,4C00h               ;EXIT
       INT      21h
       END      kopie


Von KOPIE nach TEE

Unter Unix (wie Linux) und bei der alternativen Kommandooberfläche 4DOS für MS-DOS bewirkt der Befehl „TEE” eine Kopie der Bildschirmausgabe eines Programmes in eine Datei. Voraussetzung ist, dass dies Programm seine Bildschirmausgaben über die Standardausgabe Handle 1 durchführt. Etliche der von Microsoft bei MS-DOS mitgelieferten Programme und Kommandos erfüllen diese Voraussetzung.
Beispielsweise zeigt dir | tee zwi.txt die Inhaltsanzeige des Verzeichnisses auf dem Bildschirm und erzeugt eine Kopie der Bildschirmausgabe in der Datei ZWI.TXT.

TEE lässt sich gut zur Dokumentation der mit HELP anzeigbaren Hilfstexte verwenden. Beispielsweise steht nach Eingabe von
help|tee help.txt
Das MS-DOS Kommandoverzeichnis in der Datei HELP.TXT.

Nach Eingabe von help cd|tee help_cd.txt
enthält HELP_CD.TXT den Hilfstext für das Kommando CD (Change Directory).

Bei VISTA in sieht die solcherart erzeugte Datei HELP_CD.txt so aus:

Wechselt das Verzeichnis oder zeigt dessen Namen an.

CHDIR [/D] [Laufwerk:][Pfad]
CHDIR [..]
CD [/D] [Laufwerk:][Pfad]
CD [..]

  ..   Gibt an, dass Sie in das übergeordnete Verzeichnis wechseln möchte.

Geben Sie "CD Laufwerk:" ein, um das aktuelle Verzeichnis auf dem angegebenen
Laufwerk anzuzeigen. Mit CD ohne Parameter wird das aktuelle Laufwerk und
Verzeichnis angezeigt.

Verwenden Sie die /D-Option, um zusätzlich zum Wechseln des Verzeichnisses
auch das aktuelle Laufwerk zu wechseln.

Wenn die Befehlserweiterungen aktiviert sind, wird CHDIR folgendermaßen
verändert:

Der angegebene Verzeichnisname wird so konvertiert, dass dieser bezüglich
Groß- und Kleinschreibung dem Namen auf dem Laufwerk entspricht. So wird durch
CD C:\TEMP der aktuelle Pfad auf das Verzeichnis C:\Temp festgelegt, wenn ein
Verzeichnis mit diesem Namen auf dem Laufwerk existiert.

Der CHDIR-Befehl behandelt Leerzeichen nicht als Begrenzungszeichen, so dass es
möglich ist, in ein Unterverzeichnis zu wechseln, dessen Name Leerzeichen
enthält, ohne diese mit Anführungszeichen einzuschließen. Beispiel:

    cd Eigene Dateien

ist dasselbe wie:

    cd "Eigene Dateien"

Wenn die Befehlserweiterungen nicht aktiviert sind, müssen die Anführungs-
zeichen angegeben werden.

Die Funktionen des ausführbaren Programmes TEE gehen aus dem Programmlisting bei der Hilfstextanzeige hervor. Die Hilfstextanzeige befindet sich beim Merkmal „helpanzeige” der Programmauflistung.

Das Programm stellt die Hilfsanzeige mit dem Aufruf TEE /? auf dem Bildschirm dar. Diese Ausgabe erfolgt nicht über ein Handle. Die Hilfszeige von TEE lässt sich somit nicht in eine Datei umleiten!

.MODEL TINY
comment #
======================================
Uebertraegt Daten von der Standardeingabe zur Standardausgabe. Zusaetzlich
wird eine Kopie der Daten in die angegebenen Zieldatei geschrieben.
Wenn der Schalter /A angegeben ist, wird die Zieldatei erweitert.
Ist kein Schalter /A angeben, wird die Zieldatei neu angelegt.
Ist bei Angabe des Schalters /A keine solche Zieldate vorhanden, wird
die Zieldatei neu angelegt.
Die Ausgabe in eine Zieldatei entfaellt, wenn keine Zieldatei
angegeben ist.
Ctrl Z (hexdezimal 1A) von der Standardeingabe bewirkt ein Programmende.
======================================
#
FALSE   EQU     0
TRUE    EQU     NOT FALSE

dump$   equ     true    ;fuer mdump,  rdump
prompt$ equ     false   ;fuer PROMPT, INKJN
intasc$ equ     false   ;fuer INT2ASC, ASC2INT
string$ equ     false   ;fuer CMPSTR, LENSTR, INSTR, MOVSTR

.CODE
        ORG     100h

_start: JMP     around
        include firm.mac

;---------------------
;datenbereich
;---------------------
zdatei  db      40h dup(32)
handle  dw      ?
text    DB      '0'     ;text, gleichzeitig Puffer
append  db      0       ;kennzeichen Append, Enthaelt A wenn der
                        ;Parameter /A bzw, /a eingetippt wurde.
                        ;Enthaelt E, wenn Dateiname ohnme /A bzw. /a
                        ;angegeben ist.
;---------------------
;Unterprogramme
;---------------------
;upro Zieldatei schliessen
;---------------------
end_file:
        fclose  handle
        jmpc    err6
        ret
;---------------------
; upro Zieldatei kreeiren und öffnen
; Funktion 3ch oder 5bh steht bereits vor Unterprogrammaufruf in ax
;---------------------
create_file:
        mov     dx,offset zdatei
        mov     cx,0h           ;normale Datei
        int21
        jc      create_file5

        mov     handle,ax
        ret

create_file5:
        cmp     ax,50h          ;Datei bereits existent ?
        jne     err2            ;nein, anderer Fehler

        fopen   zdatei,1        ;ja, dann normales oeffnen zum Schreiben
        jc      err2
        mov     handle,ax

        mov     ah,42h          ;und auf Dateiende positionieren
        xor     dx,dx
        xor     cx,cx
        mov     al,2
        mov     bx,handle
        int     dos
        jc      err5
        ret
;---------------------
;fehlermeldungen fuer dateibehandlung
;---------------------
ERR1:   prstr   'Quell'
        jmps    err1_2

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

ERR4:   prstr   'Schreibfehler!'
        jmp     ret1

ERR5:   prstr   'Positionierung auf Dateiende nicht erfolgreich!'
        jmp     ret1

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

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

;---------------------
;Hauptprogramm
;---------------------
;Verarbeiten der Eingabeparameter. Im PSP sind nur die Eingabeparameter
;enthalten, die nicht mit einem Pipe-Symbol (<>|) beginnen.
;-----
; 1. Schritt: ob /? als einziger Parameter eingetippt wurde. Dann
; erfolgt Anzeige des Hilstextes und sofortige Programmende
;-----
around:
       cmp     b cs:lparm,03h
       jne     para2
       cmp     b cs:lparm+2,"/"        ;/? bewirkt Hilfstextanzeige
       jne     para2
       cmp     b cs:lparm+3,"?"
       jne     para2

helpanzeige:
       call    prmsg
       dbl     "Dupliziert die Standardausgabe in eine benannte Datei."
       dbl     "Aufruf:  tee [zieldateiname [/A]]"
       dbl     "Bei Angabe von /A wird die Datei erweitert (append)."
       dbl     "Die Ausgabe in eine benannte Datei entfaellt, wenn kein"
       dbl     "Zieldateiname angegeben wurde."
       db      cr
       dbl     "Bei Tastatureingabe: Ctrl Z bewirkt Programmende."
       db      0
       jmp     fertig

;-----
; 2. Schritt: ist /a oder /A enthalten? Wenn ja, wird das Kennzeichen
; Append für Dateierweiterung gesetzt.
;-----
para2: cmp     b cs:lparm,00h
       jne     para3
       jmp     lesen           ;es wurden gar keine Parameter eingegeben

para3: mov     si,lparm        ;Vergleichsvorbereitung: Parameterlaenge
       xor     ch,ch           ;nach si
       mov     cl,[si]

para5: inc     si              ;Adresszeiger
       cmp     b [si],'/'      ;suchen Bruchstrich
       je      para6           ;Bruchstrich gefunden
       loop    para5
       jmp     get_name        ;kein Bruchstrich enthalten

para6: inc     si              ;a oder A nach Bruchstrich?
       mov     al,b [si]
       and     al,0dfh         ;Kleinschrift in Grossschrift
       cmp     al,"A"
       jne     get_name        ;es war nicht /a oder /A

       mov     append,al       ;Kennzeichen Append setzen
       dec     si              ;im Eingabestring des PSPs den /
       mov     b [si],cr       ;mit cr ueberschreiben
;-----
; 3. Schritt Aufbereiten des Dateinamens und Einspeichern des Namens
; in Bereich zdatei
; Der Fall Parameterlaenge=0 wurde bereits beim Label para2 behandelt.
;-----
get_name:
       mov     si,lparm        ;Parameterlaenge nach cx
       xor     ch,ch
       mov     cl,[si]

       getparm                 ;Parameteranfangsadresse nach si
       mov     di,offset zdatei

get_name6:
       mov     al,b [si]
       cmp     al,cr           ;Absuchen des Parameterbereichs auf cr
       jz      get_name7       ;Ende gefunden

       mov     b [di],al       ;1 Byte vom Dateinamen nach zdatei
       inc     di
       inc     si
       jmps    get_name6

get_name7:
       mov     b [di], 00h     ;Ende kennzeichnen

       mov     si, offset zdatei

;-----
;get_name8 wird durchlaufen, wenn ein Zieldateiname angegeben wurde
;-----
get_name8:
       cmp     append,"A"      ;war /A angegeben?
       mov     ah,5bh          ;fuer create new file
       je      get_name9       ;ja
       mov     append,"N"      ;append war nicht angegeben
       mov     ah,3ch          ;fuer create file ggf. loeschen einer
                                ;vorhanden Datei gleichen Namens
;-----
;Erzeugen der Zieldatei
;-----
get_name9:
       call    create_file

comment #
Bis zum Kommentarende steht eine nicht mehr benoetigte Testhilfe wegen
Problemen mit den Original-Tastaturtreiber bei VISTA's CMD.EXE

;Anlesen der Standardeingabe. Falls das erste Zeichen EOF ist, wird EOF ignoriert.
;
       mov     bx,0            ;Handle console (eingabe)
       mov     cx,1            ;1 Zeichen lesen
       mov     dx,offset text
       mov     ah,3fh          ;lesen Standardeingabe
       int     21h
       jc      mist
       or      ah,al           ;ax ist 0 wenn EOF
       jnz     mist3
       jmp     mist2
mist:  prstr   "CY beim Anlesen der Standardeingabe gesetzt"
       jmp     fertig
mist2: prstr   "CY nicht gesetzt, ax=0000"
       jmp     fertig

mist3: pusha
       rdump
       popa
       mdump   offset handle,4
       prstr   "CY nicht gesetzt, ax nicht 0000"
       jmp     lesen2
#

lesen:
       mov     bx,0            ;Handle console (eingabe)
       mov     cx,1            ;1 Zeichen lesen
       mov     dx,offset text
       mov     ah,3fh          ;lesen Standardeingabe
       int     21h
       or      ah,al           ;ax ist 0 wenn EOF
       jnz     lesen2
       jmp     fertig

lesen2:
       mov     al,text
       cmp     al,01ah         ;ctrl z bewirkt Programmende
       je      fertig

       mov     bx,1            ;Handle console (ausgabe)
       mov     cx,1            ;Länge des Textes
       mov     dx,offset Text
       mov     ah,40h          ;schreiben Standardausgabe
       int     21h
       cmp     append,0
       jz      lesen           ;wenn ohne Zieldatei

       fwrit   handle,text,1   ;schreiben in Zieldatei
       jnc     lesen

;      or      ax,3030h        ;wenn Schreibfehler
;      push    ax              ;alte Testhilfe. Zeigt den Inhalt von
;      mov     al,ah           ;AX auf dem Bildschirm an
;      call printchr
;      pop     ax
;      call printchr
       jmp     err4

fertig:
       cmp     append,0
       jz      fertig1
       call    end_file        ;Zieldatei schliessen (falls geoeffnet wurde)
fertig1:
       jmp     ret0
       END     _start


TEE mit Unterstützung für lange Dateinamen

Mit Windows 95 wurde die Möglichkeit von langen Dateinamen eingeführt. Der Interrupt 21h erhielt dabei eine neue Funktion 71h mit etlichen Unterfunktionen. Die nachfolgend gezeigte Version des Programms verwendet die Funktion 71h. Die geänderten Teile sind in blauer Schrift dargestellt. Bei der Standardein- und -ausgabe wird die Verwendbarkeit von langen Dateinamen durch die Laufzeitumgebung sichergestellt. Lediglich die beim Programmaufruf zusätzlich anzugebende weitere Ausgabedatei führt zu Änderungen im Programmtext.
.MODEL TINY
comment #
Schwachstelle:
Nach dem Kreeiren/Oeffnen der Datei wird die Rueckmeldung der
durchgeführten Aktion nicht geprüft

======================================
Uebertraegt Daten von der Standardeingabe zur Standardausgabe. Zusaetzlich
wird eine Kopie der Daten in die angegebenen Zieldatei geschrieben.
Wenn der Schalter /A angegeben ist, wird die Zieldatei erweitert.
Ist kein Schalter /A angeben, wird die Zieldatei neu angelegt.
Ist bei Angabe des Schalters /A keine solche Zieldate vorhanden, wird
die Zieldatei neu angelegt.
Die Ausgabe in eine Zieldatei entfaellt, wenn keine Zieldatei
angegeben ist.
Ctrl Z (hexdezimal 1A) von der Standardeingabe bewirkt ein Programmende.
======================================
#
FALSE   EQU     0
TRUE    EQU     NOT FALSE

dump$   equ     true    ;fuer mdump,  rdump
prompt$ equ     false   ;fuer PROMPT, INKJN
intasc$ equ     false   ;fuer INT2ASC, ASC2INT
string$ equ     false   ;fuer CMPSTR, LENSTR, INSTR, MOVSTR

.CODE
        ORG     100h

_start: JMP     around
        include firm.mac

;---------------------
;datenbereich
;---------------------
zdatei  db      80h dup(32)
handle  dw      ?
text    DB      '0'     ;text, gleichzeitig Puffer
append  db      0       ;kennzeichen Append, Enthaelt A wenn der
                        ;Parameter /A bzw, /a eingetippt wurde.
                        ;Enthaelt E, wenn Dateiname ohnme /A bzw. /a
                        ;angegeben ist.
;---------------------
;Unterprogramme
;---------------------
;upro Zieldatei schliessen
;---------------------
end_file:
        fclose  handle
        jmpc    err6
        ret
;---------------------
; upro Zieldatei kreeiren und öffnen
; Aktion steht bereits vor Unterprogrammaufruf in dx
;---------------------
create_file:
        mov      ax,716ch        ;Funktion  71
        mov      cx,0            ;kein attribut
        mov      bx,2001h        ;return error code, write only
        mov      si,offset zdatei
        int21
        jc       create_file5    ;zur Fehlerbearbeitung

        mov      handle,ax

        cmp      append,"A"      ;war /A angegeben?
        je       create_file6    ;dann Dateizeiger positionieren
        ret

create_file5:                    ;Fehlerbearbeitung
        cmp      ax,7100h
        je       err7100

        jmps     err2            ;anderer Fehler

create_file6:
;       pusha                   ;alter Testaufruf Registerdump
;       rdump
;       popa

        mov     ah,42h          ;auf Dateiende positionieren
        xor     dx,dx
        xor     cx,cx
        mov     al,2
        mov     bx,handle
        int     dos
        jc      err5                ;zur Fehlerbehandlung
        ret
;---------------------
;fehlermeldungen fuer dateibehandlung
;---------------------
ERR1:   prstr   'Quell'
        jmps    err1_2

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

ERR4:   prstr   'Schreibfehler!'
        jmp     ret1

ERR5:   prstr   'Positionierung auf Dateiende nicht erfolgreich!'
        jmp     ret1

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

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

err7100:
        prstr        'Lange Dateinamen werden nicht unterstuetzt'
        jmp        ret1
;---------------------
;Hauptprogramm
;---------------------
;Verarbeiten der Eingabeparameter. Im PSP sind nur die Eingabeparameter
;enthalten, die nicht mit einem Pipe-Symbol <>|) beginnen.
;-----
; 1. Schritt: ob /? als einiger Parameter eingetippt wurde. Dann
; erfolgt Anzeige des Hilstextes und sofortige Programmende
;-----
around:
       cmp     b cs:lparm,03h
       jne     para2
       cmp     b cs:lparm+2,"/"        ;/? bewirkt Hilfstextanzeige
       jne     para2
       cmp     b cs:lparm+3,"?"
       jne     para2

helpanzeige:
       call    prmsg
       dbl     "Dupliziert die Standardausgabe in eine benannte Datei."
       dbl     "Aufruf:  tee [zieldateiname [/A]]"
       dbl     "Bei Angabe von /A wird die Datei erweitert (append)."
       dbl     "Die Ausgabe in eine benannte Datei entfaellt, wenn kein"
       dbl     "Zieldateiname angegeben wurde."
       db      cr
       dbl     "Bei Tastatureingabe: Ctrl Z bewirkt Programmende."
       db      0
       jmp     fertig

;-----
; 2. Schritt: ist /a oder /A enthalten? Wenn ja, wird das Kennzeichen
; Append für Dateierweiterung gesetzt.
;-----
para2: cmp     b cs:lparm,00h
       jne     para3
       jmp     lesen           ;es wurden gar keine Parameter eingegeben

para3: mov     si,lparm        ;Vergleichsvorbereitung: Parameterlaenge
       xor     ch,ch           ;nach si
       mov     cl,[si]

para5: inc     si              ;adresszeiger
       cmp     b [si],'/'      ;suchen Bruchstrich
       je      para6           ;bruchstrich gefunden
       loop    para5
       jmp     get_name        ;kein Bruchstrich enthalten

para6: inc     si              ;a oder A nach Bruchstrich?
       mov     al,b [si]
       and     al,0dfh         ;Kleinschrift in Grossschrift
       cmp     al,"A"
       jne     get_name        ;es war nicht /a oder /A

       mov     append,al       ;Kennzeichen Append setzen
       dec     si              ;im Eingabestring des PSPs den /
       mov     b [si],cr       ;mit cr ueberschreiben
;-----
; 3. Schritt Aufbereiten des Dateinamens und Einspeichern des Namens
; im Bereich zdatei
; Der Fall Parameterlaenge=0 wurde bereits beim Label para2 behandelt.
;-----
get_name:
       mov     si,lparm        ;parameterlaenge nach cx
       xor     ch,ch
       mov     cl,[si]

       getparm                 ;parameteranfangsadresse nach si
       mov     di,offset zdatei

get_name6:
       mov     al,b [si]
       cmp     al,cr           ;absuchen des parameterbereichs auf cr
       jz      get_name7       ;ende gefunden

       mov     b [di],al       ;1 Byte vom Dateinamen nach zdatei
       inc     di
       inc     si
       jmps    get_name6

get_name7:
       mov     b [di],00h      ;ende kennzeichnen

       mov     si, offset zdatei

;-----
;get_name8 wird durchlaufen, wenn ein Zieldateiname angegeben wurde
;-----
get_name8:
       cmp     append,"A"      ;war /A angegeben?
       mov     dx,0011h        ;open file else create new file
       je      get_name9       ;ja
       mov     append,"N"      ;append war nicht angegeben
       mov     dx,0012h        ;create new file else truncate file

;-----
;Erzeugen der Zieldatei
;-----
get_name9:
       call    create_file

lesen:
       mov     bx,0            ;Handle console (eingabe)
       mov     cx,1            ;1 Zeichen lesen
       mov     dx,offset text
       mov     ah,3fh          ;lesen Standardeingabe
       int     21h
       or      ah,al           ;ax ist 0 wenn EOF
       jnz     lesen2
       jmp     fertig

lesen2:
       mov     al,text
       cmp     al,01ah         ;ctrl z bewirkt Programmende
       je      fertig

       mov     bx,1            ;Handle console (ausgabe)
       mov     cx,1            ;Länge des Textes
       mov     dx,offset Text
       mov     ah,40h          ;schreiben Standardausgabe
       int     21h
       cmp     append,0
       jz      lesen           ;wenn ohne Zieldatei

       fwrit   handle,text,1   ;schreiben in Zieldatei
       jnc     lesen
       jmp     err4

fertig:
       cmp     append,0
       jz      fertig1
       call    end_file        ;Zieldatei schliessen (falls geoeffnet wurde)
fertig1:
       jmp     ret0
       END     _start


TEE in CodeBlocks C

Nachfolgend der Quellprogrammtext und das Ablaufbeispiel einer Testsitzung:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

main(int argc, char *argv[]) {

    char datei[100] = { 0 };
    FILE *fp;
    int c, i, result;

    printf("%s%d","\nargc= ", argc);
    for (i = 1; i<argc; i++) {
        printf("%s%d%s%s","\nargv[", i,"]= ", argv[i]);
        }
/* strcmp liefert 0 bei gleich und 1 bei ungleich zurueck. Bei Bedingungen fuer
 if, while oder for  ist es es genau umgekehrt: unwahr ist hier 0, wahr ist
 "nicht 0".
 Eine Oder-Verknuepfung bei strcmp ergibt hier immer 1. Deshalb wird mit Und
 verknuepft. Dann ergibt  der richtige Parametereintrage /A bzw. /a eine 0, ein
 falscher Parameter ergibt ein 1. Die Negierung ergibt dann "nicht 0" fuer wahr.*/
    if  (argc==3) {
        result= ((strcmp(argv[1], "/a")) && (strcmp(argv[1], "/A")));
        if (!result) { fp = fopen(argv[2], "a");
            strcpy(datei, argv [2]);
            }
        }

    if  (argc == 2) {fp = fopen(argv[1], "w"); strcpy(datei,argv[1]);
        }

    if  (argc <= 1 || argc >=4) {
        printf("\nError");
        printf("\nDie Syintax is: tee [/A] dateiname");
        printf("\n                    (A)ppend (erweitern)");
        printf("\nStatt /A darf /a genommen werden");
		printf("\nBei Tastatureingabe: Eingabe beenden mit ctrl Z an erster Stelle"
        " einer neuen Zeile\n");
        exit (-1);
        }

    printf("%s%s%s","\nAusgabedatei ist ", datei,"\n");

    c=getchar();
    while(c != EOF){
        putchar(c);
        putc(c, fp);
        c=getchar();
        }

    fclose(fp);
    exit (0);
}

Ablaufbeispiel einer Testsitzung
Das Ablaufbeispiel lief unter der Kommandooberfläche TCC LE.

Zuerst wurde die Verzeichnisanzeige für das frisch compilierte Programm tee.c durchgeführt. Dann folgte ein Testlauf mit falscher Parameterangabe. Er hatte die Anzeige des Hilfstextes zur Folge. Die Ausgaben argc=... und argv[1]= text.txt sind Testhilfen.

Anschließend erfolgte testweise der Lauf des Programmes mit Texteingabe über die Tastatur. Dabei wird die Eingabe zweimal angezeigt — genau dies ist richtig! Außerdem wird die erzeugte Ausgabedatei mit dem Type-Kommando geprüft.

Da in TCC LE bereits ein Tee-Kommando enthalten ist, muss für den Testlauf tee.exe eingetippt werden.

02.02.2020  21:26           1.605  tee.c
04.02.2020  10:46          31.045  tee.exe
04.02.2020  10:46           1.982  tee.o
            34.643 Bytes in 3 Dateien und 0 Verzeichnisse    40.960 Bytes belegt
    66.733.400.064 Bytes frei

0:10:50:45 C:\PGM\dm857c\dm\bin>tee.exe

argc= 1
Error
Die Syintax is: tee [/A] dateiname
                    (A)ppend (erweitern)
Statt /A darf /a genommen werden
Bei Tastatureingabe: Eingabe beenden mit ctrl Z an erster Stelle einer neuen Zeile

0:10:50:52 C:\PGM\dm857c\dm\bin>tee.exe text.txt

argc= 2
argv[1]= text.txt
Ausgabedatei ist text.txt
Hier beginnt die versuchsweise Texteingabe per Tastatur
Hier beginnt die versuchsweise Texteingabe per Tastatur
Und was kommt dabei heraus?
Und was kommt dabei heraus?
^Z

0:10:52:26 C:\PGM\dm857c\dm\bin>type text.txt
Hier beginnt die versuchsweise Texteingabe per Tastatur
Und was kommt dabei heraus?

0:10:52:47 C:\PGM\dm857c\dm\bin>
Letztes Upload: 24.03.2023 um 11:35:12 • Impressum und Datenschutzerklärung