lineout$ und writeline
lineout$ - Kopiere Textzeile von einem Anwenderbereich in einen Pufferspeicher aus MASM32 Library Reference / Macro Categories / Memory Line IO Macros /lineout$
mov spos, lineout$(source,buffer,spos,op_crlf)
Kopiert eine Textzeile aus einem Anwenderbereich in einen Pufferspeicher. Bietet die Möglichkeit, dabei CR LF am Zeilenende zu ergänzen.
Parameter:
1. source - der Anwenderbereich soll eine mit 0 abgeschlossene Zeichenkette enthalten
2. buffer- der Zielpufferspeicher, in den die Zeichenkette kopiert werden soll
3. spos - dies Variable enthält beim Aufruf die Position im Zielpufferspeicher, ab den der String zu kopieren ist. Der erste Eintrag in einem Zielpuffer beginnt auf Position 0
4. op_crlf gibt an, ob ein Zeilenwechsel aus CR und LF am Zeilenende hinzugefügt werden soll: 0=ja, 1=nein
Rückgabewert: Zurückgegeben wird die nächste freie Schreibposition im Zielpufferspeicher. Außerdem steht in ECX steht die Anzahl der zum Zielpufferspeicher geschriebene Bytes.
Hinweise: Der Zielpufferspeicher muss groß genug sein, um alle in ihn zu schreibende Bytes aufnehmen zu können.
Fast die gleiche Funktion wird unter MASM32 Library Reference / In Memory Text Read and Write / writeline angeboten. Dort ist als Aufrufmuster angegeben:
writeline proc source:DWORD,buffer:DWORD,spos:DWORD,flag:DWORD
Rückgabewerte:
EAX enthält den neuen Positionszeiger „spos”.
ECX enthält die die Anzahl der zum Zielpufferspeicher geschriebene Bytes.
Das Quellprogramm zu writeline steht unter masm32/m32lib/writeline.asm. Die Makrodefinition zu lineout$ ist in masm32/macros/macros.asm zu finden. Ihr Herz besteht aus diesem Aufruf invoke writeline,reparg(source),buffer,spos,op_crlf
In der Originalbeschreibung wird nicht deutlich geschrieben, dass die erste mögliche Einschreibposition in den Zielpufferspeicher den Wert Null hat.
Anbei ein rasch geschriebenes Testprogramm, mit dem sich diese Eigenschaft erforschen lässt:
|
Quellprogramm Version 3 (lineout$ und fprintc, Zeileneingabe mit StdIn)
Einige Hinweise zum Ablauf des Programmes stehen unterhalb des Quellprogrammtextes.
comment * ---------------------------
Teile der Dateizugriffe nach masm32/examples\exampl07/ppfileio.asm
Build as a CONSOLE mode application
Testprogramm fuer lineout$ und fprintc
Es werden mehrere Zeilen ueber 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
---------------------------------------- *
.486 ; create 32 bit code
.model flat, stdcall ; 32 bit memory model
option casemap :none ; case sensitive
.XLIST
include \masm32\include\windows.inc
include \masm32\macros\macros.asm
include \masm32\include\user32.inc
include \masm32\include\kernel32.inc
include \masm32\include\masm32.inc
include \masm32\include\msvcrt.inc
include \masm32\include\debug.inc ;fuer debug
includelib \masm32\lib\user32.lib
includelib \masm32\lib\kernel32.lib
includelib \masm32\lib\masm32.lib
includelib \masm32\lib\msvcrt.lib
includelib \masm32\lib\debug.lib ;fuer debug
.LIST
Main PROTO ;erforderlich weil Main eine Prozedur ist
DBGWIN_DEBUG_ON = 1 ;0 or 1. 1 if you want to include debug info into the program
DBGWIN_EXT_INFO = 1 ;0 or 1. 0 if you don't want to include extra debug info into the program
; Konstanten
; ------------------------------------------------
bel equ 7 ;Klingel
bs equ 8 ;Backspace
ht equ 9 ;Horizontaler Tabulator
lf equ 0ah ;Linefeed
vt equ 0bh ;Vertikaler Tabulator
ff equ 0ch ;Formfeed
cr equ 0dh ;Carriage Return
Ae equ 8eh ;A DOS-ASCII-codiert
Oe equ 99h ;O
Ue equ 9ah ;U
ae equ 84h ;a
oe equ 94h ;o
ue equ 81h ;u
sz equ 0e1h ;?
ctrlZ equ 1ah ;CTRL Z
.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 Eingabezeile
buffer1p1 db 260 dup(0)
lpbuffer1 equ $ - buffer1
;buffer 2 ist fuer das Testen der Programmlogik auf 64 Bytes verkuertzt. Für die echte Nutzung
;wird man buffer 2 erheblich groeßer ansetzen. Eine typische Groeße waere 4096 Bytes.
wpos dword 0
buffer2 db 64 dup(0) ;buffer2 fuer Dateiname / oder Zielpufferspeicher
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"
db " 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
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 + byte + buffer1"
DumpMem offset wpos, 32, "wlpos + 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
xor eax,eax
mov dword ptr wpos,eax ;Ausgabezwischenspeicher leer setzen
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 ;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!
@@: mov savech,ch ;sichert ob ctrlZ
xor ch,ch
mov lpos,ecx ;Stringlaenge nun in lpos
; fprint hFile,offset buffer1 ;write line to file
;--- ab hier gepuffertes Schreiben
mov eax, lpbuffer2 ;lpbuffer2 ist die Gesamtlänge des Zielpufferspcichers
sub eax,3 ;davon geht CR, LF und die 0 am Stringendes ab
sub eax,wpos ;noch frei
cmp eax,lpos
jg @F ;Sprung, wenn noch ausreichend Platz ist
fprintc hFile,offset buffer2 ;schreibt den belegten Teil des Zielpuffers in die Datei
xor eax,eax
mov dword ptr wpos,eax ;nun ist der Zielpuffer wieder ganz leer
@@: ;es kann in den Zwischenpuffer geschrieben werden!
mov wpos, lineout$(ADDR buffer1,ADDR buffer2,wpos,0)
DumpMem offset lpos, 32, "lpos + byte + buffer1"
DumpMem offset wpos, 80, "wpos + buffer2"
;---- bis hier gepuffertes Schreiben
mov ah,savech
or ah,ah ;fertig, wenn ah <> 0
jz konsoleingabe
xor eax,eax ;Eingabeende? Ist Zwischenpuffer leer?
cmp dword ptr wpos,eax
je @F ;er ist leer wenn wpos gleich 0
lea edi,buffer2 ;0 kennzeichnet Stringende
add edi,wpos
xor al,al
mov [edi],al
fprintc hFile,offset buffer2
@@:
fclose hFile ;Datei schliessen
mov eax,TRUE ;Errorlevel O.K.
ret
Main ENDP
; -----
; Unterprogramm Hilfstext ausgeben
; -----
help PROC
print offset hilfe
mov eax,99 ;Errorlevel 99 und Schluss!
ret
help ENDP
end start
|
Einige Hinweise zum Ablauf des Quellprogramms Version 3 (lineout$ und fprintc, Zeileneingabe mit StdIn)
lpos dword 0und
lpos dword 0: Mit dem Positionszeiger lpos wird die Position im Eingabepuffer verwaltet. Mit wpos wird die nächste Schreibposition im Zielpufferspeicher verwaltet.
buffer2 db 64 dup(0): Nur für den Test, ob die Zielpufferverwaltung richtig funktioniert, ist der Zielpufferspeicher klein angelegt. Wenn die Teste hier keinen Fehler gefunden haben, wird man den Zielpufferspeicher größer anlegen. Ich habe ihn später auf 4096 Bytes vergrößert: buffer2 db 4096 dup(0)
fprint hFile,offset buffer1 wurde durch das vorgestellte Semikolon zum Kommentar. Die Befehle zwischen den Kommmentarzeilen ;--- ab hier gepuffertes Schreiben und ;--- bis hier gepuffertes Schreiben ersetzen den auskommentierten Schreibbefehl. Das gepufferte Schreiben schreibt nur dann in den Puffer buffer2, wenn noch ausreichend Platz vorhanden ist. Dies wird durch den Vergleich cmp eax,lpos festgestellt. Wenn der freie Platz in buffer2 zu klein ist, wird der Inhalt von buffer2 mit fprintc hFile,offset buffer2 zur Ausgabedatei entsorgt. Dabei wird ein Zeilenwechsel ergänzt.
cmp dword ptr wpos,eax: nachdem die Eingabeverarbeitung ein ctrl Z gefunden hatte und demzufolge die eingetippten Daten bis unmittelbar vor ctrl Z in den Zielpufferspeicher buffer2 abgelegt hatte, ist das Programm fast fertig. Für den Fall, dass noch Daten aus dem Eingabepuffer buffer1 in die Datei geschrieben werden müssen, wird einmalig fprintc hFile,offset buffer1 durchgeführt. Vorher wurde noch im Eingabepuffer eine Schlussnull am Ende der auszugebenden Daten ergänzt.
|