MASM32-SDK (Dateizugriffe bei Windows Konsolapplikationen):
Testerei mit input, StdIn, fwrite, fprint, exist, fcreate, fclose

Hier handelt es sich um zwei Versionen eine kleinen Übungsprogrammes. Das Programm liest von der Konsole Textzeilen ein und speichert jede Zeile in einer jeweils neu kreierten Ausgabedatei.

Der Name und ggf. der Pfad der Ausgabedatei kann per Aufrufparameter angegeben werden. Wird das Programm ohne Parameter gestartet, wird eine Defaultausgabedatei verwendet.

Damit die Ausgabedatei mit einem Texteditor wie z.B. Notepad.exe bearbeitet werden kann, sind die Zeilenwechsel mit CR LF markiert.

Beim Aufruf mit dem Parameter /? erfolgt die Anzeige einer Bedienungsanleitung.

Die beiden Versionen des Programms unterscheiden sich in der Verarbeitung des Zeilenendes und deren Folgen. Beachten Sie bitte den folgenden Hinweis.


Hinweis: Der Hinweis bezieht sich auf die nachfolgend gezeigte überarbeitete Übersetzung der Funktionsbeschreibung für die alternativen Konsoleingaben per input und StdIn.

Die Unterschiede in der leider nur vagen Originalbeschreibung beider Funktionen führten dazu, dass ich in Version 1 des Testprogramms statt sinngemäß beispielsweise

.code
    invoke  input "Bitte Eingabe > "
verwende:
data
    msg     db "Bitte Eingabe > ",0
.code
    invoke  StdOut,ADDR msg
    StdIncr buffer1,lpbuffer1

Input oder StdIn ?

input - Texteingabe von der Tastatur aus High Level Macro Help / Macro Categories / Console Mode Macros
Das Makro „input” nimmt Texteingaben von der Tastatur entgegen und zeigt dabei die Eingaben auf dem Bildschirm an.
Parameter:
Wahlweise Text zur Anzeige vor dem Eingabebereich
Rückgabewert: in EAX die Anfangsadresse des eingetippten Textes Betätigen der Eingabetaste

Die nachfolgend beschriebene Funktion StdIn fügt bei einen Wagenrücklauf (CR) und einen Zeilenvorschub (LF) und hinter den eingegeben Text hinzu. Das Makro „input” entfernt CR und LF wieder, so dass die Texteingabe ohne weitere Behandlung in numerische Werte (Zahlen) konvertiert werden kann. Die aktuelle Version ist auf eine Länge von 128 Zeichen beschränkt. In der US-englischen Originalbeschreibung steht hier 128 character limit. Da „character” genauso mehrdeutig ist wie „Zeichen”, ist unklar, ob 128 den Zeilenwechsel CR/LF und die nachfolgende Schlussnull beinhaltet.

StdIn - Texteingabe von der Tastatur aus MASM32-SDK Library Reference / Console Mode Functions
StdIn proc lpszBuffer:DWORD,bLen:DWORD

Die Funktion StdIn nimmt Texteingaben von der Tastatur entgegen und zeigt dabei die Eingaben auf dem Bildschirm an.
Hinweis: In der Originalbeschreibung steht leider nicht, dass StdIn den Eingabestring ab seinem Anfang nach einem Zeilenvorschub (CR) absucht und diesen durch eine 0 als Kennzeichen für Stringende ersetzt: StdIn schneidet den Eingabestring unmittelbar vor dem ersten Zeilenwechsel ab.
Parameter:
1. lpszBuffer ist die Adresse des Speicherpuffers in dem der eingetippte Text abgelegt werden soll
2. bLen gibt die (nutzbare) Länge des Speicherpuffers an
Rückgabewert: ohne Rückgabewert

Testlauf Version 1 (fwrite, Zeileneingabe mit privatem StdIncr statt StdIn)
Nacheinander wird aufgerufen:
  • Das Testprogramm mit Ausgabe in die Datei aaa.txt
  • Eingabe eines Textes. Hinter dem gewünschten Dateiende werden noch einige weitere Zeichen eingegeben. Diese werden nicht in die Datei geschrieben
  • Aufruf dir, um Informationen über die Ausgabedatei zu erlangen
  • Anzeige des Dateiinhalts in hexadezimaler Form
  • Aufruf des Testprogramms zur Anzeige der Bedienungsanleitung
C:\masm32\Uebung\Konsole>linein1 aaa.txt
Eingabe mehrere Zeilen. Eingabeende mit Ctrl Z ab der zweiten Eingabestelle einer Zeile
>Alle meine Entlein schwimmem auf dem See,
>Köpfchen in das Wasser, Beichen in die Höh'
>
>Das war es!^Zna noch länger?
Press any key to continue ...

C:\masm32\Uebung\Konsole>dir aaa.txt
 Datenträger in Laufwerk C: ist LW_C
 Volumeseriennummer: F26A-A8AA

 Verzeichnis von C:\masm32\Uebung\Konsole

30.01.2019  20:51               144 aaa.txt
               1 Datei(en),            144 Bytes
               0 Verzeichnis(se), 46.168.203.264 Bytes frei

C:\masm32\Uebung\Konsole>hd aaa.txt
00000000: 41 6C 6C 65 20 6D 65 69  6E 65 20 45 6E 74 6C 65  | Alle meine Entle
00000010: 69 6E 20 73 63 68 77 69  6D 6D 65 6D 20 61 75 66  | in schwimmem auf
00000020: 20 64 65 6D 20 53 65 65  2C 0D 0A 4B 94 70 66 63  |  dem See,..Köpfc
00000030: 68 65 6E 20 69 6E 20 64  61 73 20 57 61 73 73 65  | hen in das Wasse
00000040: 72 2C 20 42 65 69 63 68  65 6E 20 69 6E 20 64 69  | r, Beichen in di
00000050: 65 20 48 94 68 27 0D 0A  0D 0A 70 66 63 68 65 6E  | e Höh'....pfchen
00000060: 20 69 6E 20 64 61 73 20  57 61 73 73 65 72 2C 20  |  in das Wasser,
00000070: 42 65 69 63 68 65 6E 20  69 6E 20 64 69 65 20 48  | Beichen in die H

00000080: 94 68 27 0D 0A 44 61 73  20 77 61 72 20 65 73 21  | öh'..Das war es!
00000090:                                                   | ................

C:\masm32\Uebung\Konsole>linein1 /?
lineout Testprogramm Konsoleingabe mit Abspeicherung in Datei
Aufruf: [/?|dateiname]
Wenn kein Dateiname angegeben ist, erfolgt die Speicherung in c:/temp/versuch.txt
Das Programm nimmt mehrzeilige Texteingaben entgegen und speichert sie in
einer Datei

Press any key to continue ...
Quellprogramm Version 1 (fwrite, Zeileneingabe mit privatem StdIncr statt StdIn)
Eine Interpretation steht unterhalb des Quellprogrammtextes.
comment * ---------------------------
Teile der Dateizugriffe nach masm32/examples\exampl07/ppfileio.asm

                    Build as a CONSOLE mode application

Testprogramm fuer fprint, Zeileneingabe mit privatem StdIncr statt StdIn
    Es werden mehrere Zeilen uber die Konsole eingetippt und in die
    gewuenschte beim Programmaufruf angegebene Datei gespeichert

    Falls keine Datei angegeben wurde, erfolgt die Speicherung
    nach c:\temp\versuch.txt
 mymasm32rt.inc - siehe fredriks.de/8086asm/masm321.php?f=2#mymasm32rt
 ----------------------------------------------- *
debugFT  equ FALSE
include  c:\masm32\include\mymasm32rt.inc
Main     PROTO              ;erforderlich weil Main eine Prozedur ist
.LIST

; ------------
; Locales Makro
; ------------
; StdIncr ermoeglicht die Konsoleingabe ohne Abschneiden von CR LF am
; Ende der Eingabezeile.
; Es ist eine Umformung aus masm32/m32lib/stdin.asm
;
;StdIncr erfordert in Main PROC:
;    LOCAL hInput :DWORD
;    LOCAL bRead  :DWORD
; ------------

StdIncr MACRO buffer,lenbuffer
    invoke GetStdHandle,STD_INPUT_HANDLE
    mov hInput, eax

    invoke SetConsoleMode,hInput,ENABLE_LINE_INPUT or \
                                 ENABLE_ECHO_INPUT or \
                                 ENABLE_PROCESSED_INPUT

    invoke ReadFile,hInput,ADDR buffer,lenbuffer,ADDR bRead,NULL
    ENDM
; ------------

.data
lpos       dword    0    ;Stringlaenge im Low-byte, Position von ctrlZ im High-byte von cx
savech     db       0    ;sichert ob ctrlZ

buffer1    db       0				;spaeter: switch Teil / oder Datenpuffer
buffer1p1  db       511 dup(0)		;spaeter: Switch Teil ? oder Fortsetzung Datenpuffer
lpbuffer1  equ      $ - buffer1
buffer2    db       260 dup(0)      ;buffer2 fuer Dateiname
lpbuffer2  equ      $ - buffer2

;Defaultwerte
fname	db	'C:\temp\versuch.txt',0
lfname  equ $ - fname

hilfe db "lineout Testprogramm Konsoleingabe mit Abspeicherung in Datei",cr,lf
  db  "Aufruf: [/?|dateiname]",cr,lf
  db  "Wenn kein Dateiname angegeben ist, erfolgt die Speicherung in  c:/temp/versuch.txt",cr,lf
  db  "Das Programm nimmt mehrzeilige Texteingaben entgegen und speichert sie in",cr,lf
  db  "einer Datei",cr,lf
crlf  db  cr,lf,0         ;Zeilenwechsel  ;ergaenzt hilfe

msg1  db  "Eingabe mehrere Zeilen. Eingabeende mit Ctrl Z ab der "
      db  "zweiten Eingabestelle einer Zeile",cr,lf,0
msg2  db  62,0

 .code
start:
      invoke Main
      inkey
      invoke ExitProcess,eax

;-------------------------------
Main PROC
    LOCAL hFile :DWORD                  ;file handle
    LOCAL bwrt  :DWORD                  ;variable for bytes written
    LOCAL cloc  :DWORD                  ;current location variable
    LOCAL txt   :DWORD                  ;text handle
    LOCAL flen  :DWORD                  ;file length variable
    LOCAL hMem  :DWORD                  ;allocated memory handle

    LOCAL hInput :DWORD                 ;fuer die Umgehung von StdIn
    LOCAL bRead  :DWORD

    invoke  GetCL,1,ADDR buffer1        ;Parameter abfragen
    cmp     eax, TRUE
    je      @F
    invoke	MemCopy,ADDR fname,ADDR buffer2,lfname
    jmp	    param99                 ;kein Parameter angegeben

;1. Parameter: Switch oder Dateiname?
@@:
	mov	    byte ptr al,buffer1
	cmp     al,'/'
	jne     @F                      ;O.K., Dateiname in buffer1

	mov		byte ptr al,buffer1p1
	cmp		al,'?'
	jne		@F                      ;Dateiname
	call 	help                    ;/? in buffer1. Also Hilfstextanzege
	ret

@@:	mov		flen, len(ADDR buffer1)     ;Dateiname laut Parameter nach buffer2
    invoke	MemCopy,ADDR buffer1,ADDR buffer2,flen

param99:
   DumpMem offset lpos, 32, "lpos + buffer1"
   DumpMem offset buffer2, 32, "lpos + buffer2"

   .if rv(exist,ADDR buffer2) != 0      ;if file already exists
        test fdelete(ADDR buffer2), eax ;delete it
   .endif

; ----------------------------------
; create the  file
; ----------------------------------
    mov hFile, fcreate(ADDR buffer2)    ;create the file

    invoke StdOut,ADDR msg1             ;Anzeige Bedienungsanleitung

konsoleingabe:
	invoke StdOut,ADDR msg2			    ;Anzeige Prompt
	StdIncr	buffer1,lpbuffer1		    ;lesen Eingabezeile

  DumpMem offset lpos, 32, "pos + buffer1 nach Taste"

	mov	edi,offset buffer1

lenstr: xor	ecx,ecx                 ;laenge und ggf. position von ctrlZ des
;                                    ueber edi adressierten strings nach ecx

@@: mov     al,[edi]
    or      al,al
    jz      @F                      ;ende gefunden
    inc     cl                      ;Laenge +1
    inc     edi
    cmp     al,ctrlZ                ;Eingabeende angefordert?
    jne     @B

    dec     cl
    mov     ch,cl   	            ;Position von ctrlZ
    dec     edi
    xor     al,al
    mov     byte ptr [edi],al       ;Neues Stringende an Position von ctrlZ und fertig!

    DumpMem offset lpos, 32, "pos + buffer1 nach Taste lenstr"

@@: mov	    savech,ch               ;sichert ob ctrlZ
    xor     ch,ch
    mov     lpos,ecx                ;Stringlaenge nun in lpos

  DumpMem offset lpos, 32, "pos + buffer1 nach Taste lenstr"

    mov     bwrt, fwrite(hFile,ADDR buffer1,lpos)        ;write data to file

    mov    ah,savech
    or     ah,ah                    ;fertig, wenn ah <> 0
    jz     konsoleingabe

    fclose hFile                    ;Datei schliessen
    mov    eax,TRUE
    ret
Main ENDP

; -----
; Unterprogramm Hilfstext ausgeben
; -----
help PROC
    print   offset  hilfe
    mov     eax,99                  ;Errorlevel 99 und Schluss!
    ret
help ENDP

 end start


Interpretation Quellprogramm Version 1 (fwrite, Zeileneingabe mit privatem StdIncr statt StdIn)
Gleich am Anfang der Programmes wird in einem Kommentar auf masm32/examples\exampl07/ppfileio.asm hingewiesen. Einige der darin enthaltenen Kommentartexte sind ohne Übersetzung in das Quellprogramm eingeflossen.

DBGWIN_DEBUG_ON = 1: Diese und die folgende Zeile bewirken, dass die im weiteren Programmtext enthaltenen Speicherauszüge mittels Debuggingwerkzeug DumpMem assembliert oder ignoriert werden.

StdIncr MACRO buffer,lenbuffer: Dies ist die neue Definition des Makros zum Einlesen einer auf der Tastatur eingetippten Zeile und Speichern in den angegebenen Puffer (1.Parameter) mit Längenbegrenzung. Das Makro ist eine verkürzte Version von masm32\m32lib\stdin.asm. Anders als stdin.asm schneidet dies Makro nicht Zeilenende nicht ab. Das Zeilenende wird durch die beiden Bytes CR (Carriage return/Wagenrücklauf) und LF (Linefeed/Zeilenvorschub) gekennzeichnet.

Main PROC: Der Ablauf der Prozedur Main beginnt nach einer Vielzahl von Definition lokaler Variablen und Konstanten bei der Kommentarzeile 1. Parameter: Switch oder Dateiname? Bis zur Sprungmarke param99 erfolgt die Auswertung der beiden optionalen Programmaufrufparameter. Falls /? angegeben wurde, erfolgt die Ausgabe der Bedienungsanleitung und das Programm wird ohne weitere Aktion beendet. Wurde ein Dateiname beim Programmaufruf angegeben, wird er nach buffer2 übernommen. Wurde kein Dateiname angegeben, wird der im Feld fname definierte Defaultdateiname nach buffer2 übernommen.

Hinter param99 erfolgt

  • falls vorhanden die Löschung einer Datei gleichen Namens,
  • immer die Neuanlage einer solchen Datei und
  • immer die Anzeige der Bedienungsanleitung auf dem Bildschirm.
Die Eingabeschleife einschließlich der Ausgabe in die Datei spielt sich zwischen der Sprungmarke konsoleingabe und der Zeile jz konsoleingabe ab.

Innerhalb der Eingabeschleife wird die Länge der eingegebenen Zeile ins Datenfeld lpos eingestellt. Falls Dateiende anfordert wurde (ctrl Z), wird dessen Position in savech gesichert. Somit ist es möglich, durch die drei Programmzeilen

    mov    ah,savech
    or     ah,ah                    ;fertig, wenn ah <> 0
    jz     konsoleingabe
festzustellen, ob das Programm beendet werden soll.
Zum Quellprogramm Version 2 (fprint, Zeileneingabe mit StdIn)
Die Veränderungen im Vergleich zu Version 1 sind:
  • Das Makro StdIncr am Programmanfang kann entfallen
  • Die Zeileneingabe beim Merkmal konsoleingabe erfolgt jetzt über StdIn
  • Das Speichern der eingegeben Zeile in die Ausgabedatei erfolgt jetzt per fprint. Das Makro fprint erkennt das Zeilenende anhand der Schlussnull der auszugebenden Zeichenkette, so dass hier eine Längenangabe nicht zulässig ist.
comment * ---------------------------
Teile der Dateizugriffe nach masm32/examples\exampl07/ppfileio.asm

                    Build as a CONSOLE mode application

Testprogramm fuer fprint, Zeileneingabe mit StdIn
    Es werden mehrere Zeilen uber die Konsole eingetippt und in die
    gewuenschte beim Programmaufruf angegebene Datei gespeichert

    Falls keine Datei angegeben wurde, erfolgt die Speicherung
    	nach c:\temp\versuch.txt
 mymasm32rt.inc - siehe fredriks.de/8086asm/masm321.php?f=2#mymasm32rt
 ----------------------------------------------- *
debugFT  equ FALSE
include  c:\masm32\include\mymasm32rt.inc
Main     PROTO              ;erforderlich weil Main eine Prozedur ist
.LIST
.data
lpos       dword    0    ;Stringlaenge im Low-byte, Position von ctrlZ im High-byte von cx
savech     db       0    ;sichert ob ctrlZ

buffer1    db       0				;spaeter: switch Teil / oder Datenpuffer
buffer1p1  db       511 dup(0)		;spaeter: Switch Teil ? oder Fortsetzung Datenpuffer
lpbuffer1  equ      $ - buffer1
buffer2    db       260 dup(0)      ;buffer2 fuer Dateiname
lpbuffer2  equ      $ - buffer2

;Defaultwerte
fname	db	'C:\temp\versuch.txt',0
lfname  equ $ - fname

hilfe db "lineout Testprogramm Konsoleingabe mit Abspeicherung in Datei",cr,lf
  db  "Aufruf: [/?|dateiname]",cr,lf
  db  "Wenn kein Dateiname angegeben ist, erfolgt die Speicherung in c:/temp/versuch.txt",cr,lf
  db  "Das Programm nimmt mehrzeilige Texteingaben entgegen und speichert sie in",cr,lf
  db  "einer Datei",cr,lf
crlf  db  cr,lf,0         ;Zeilenwechsel  ;ergaenzt hilfe

msg1  db  "Eingabe mehrere Zeilen. Eingabeende mit Ctrl Z ab der "
      db  "zweiten Eingabestelle einer Zeile",cr,lf,0
msg2  db  62,0

 .code
start:
      invoke Main
      inkey
      invoke ExitProcess,eax

;-------------------------------
Main PROC
    LOCAL hFile :DWORD                  ;file handle
    LOCAL bwrt  :DWORD                  ;variable for bytes written
    LOCAL cloc  :DWORD                  ;current location variable
    LOCAL txt   :DWORD                  ;text handle
    LOCAL flen  :DWORD                  ;file length variable
    LOCAL hMem  :DWORD                  ;allocated memory handle

    LOCAL hInput :DWORD                 ;fuer die Umgehung von StdIn
    LOCAL bRead  :DWORD

    invoke  GetCL,1,ADDR buffer1        ;Parameter abfragen
    cmp     eax, TRUE
    je      @F
    invoke	MemCopy,ADDR fname,ADDR buffer2,lfname
    jmp	    param99                 ;kein Parameter angegeben

;1. Parameter: Switch oder Dateiname?
@@:
	mov	    byte ptr al,buffer1
	cmp     al,'/'
	jne     @F                      ;O.K., Dateiname in buffer1

	mov		byte ptr al,buffer1p1
	cmp		al,'?'
	jne		@F                      ;Dateiname
	call 	help                    ;/? in buffer1. Also Hilfstextanzege
	ret

@@:	mov		flen, len(ADDR buffer1)     ;Dateiname laut Parameter nach buffer2
    invoke	MemCopy,ADDR buffer1,ADDR buffer2,flen

param99:
   DumpMem offset lpos, 32, "lpos + buffer1"
   DumpMem offset buffer2, 32, "lpos + buffer2"

   .if rv(exist,ADDR buffer2) != 0       ;if file already exists
        test fdelete(ADDR buffer2), eax  ;delete it
   .endif

; ----------------------------------
; create the  file
; ----------------------------------
    mov hFile, fcreate(ADDR buffer2)    ;create the file

    invoke StdOut,ADDR msg1             ;Anzeige Bedienungsanleitung

konsoleingabe:
    invoke StdOut,ADDR msg2			    ;Anzeige Prompt
    invoke StdIn,ADDR buffer1,lpbuffer1 ;lesen Eingabezeile

  DumpMem offset lpos, 32, "pos + buffer1 nach Taste"

	mov	edi,offset buffer1

lenstr: xor ecx,ecx                 ;laenge und ggf. position von ctrlZ des
;                                    ueber edi adressierten strings nach ecx

@@: mov     al,[edi]
    or      al,al
    jz      @F                      ;ende gefunden
    inc     cl                      ;Laenge +1
    inc     edi
    cmp     al,ctrlZ                ;Eingabeende angefordert?
    jne     @B

    dec     cl
    mov     ch,cl   	            ;Position von ctrlZ
    dec     edi
    xor     al,al
    mov     byte ptr [edi],al       ;Neues Stringende an Position von ctrlZ und fertig!

    DumpMem offset lpos, 32, "pos + buffer1 nach Taste lenstr"

@@: mov	    savech,ch               ;sichert ob ctrlZ
    xor     ch,ch
    mov     lpos,ecx                ;Stringlaenge nun in lpos

  DumpMem offset lpos, 32, "pos + buffer1 nach Taste lenstr"

    fprint  hFile,offset buffer1    ;write line to file

    mov    ah,savech
    or     ah,ah                    ;fertig, wenn ah <> 0
    jz     konsoleingabe

    fclose hFile                    ;Datei schliessen
    mov    eax,TRUE
    ret
Main ENDP

; -----
; Unterprogramm Hilfstext ausgeben
; -----
help PROC
    print   offset  hilfe
    mov     eax,99                  ;Errorlevel 99 und Schluss!
    ret
help ENDP

 end start
Letztes Upload: 28.10.2022 um 13:45:25 • Impressum und Datenschutzerklärung