[Chapter Thirteen][Previous]
[Art of Assembly][Randall
Hyde]
Art of Assembly: Chapter Thirteen
- 13.4.10 - A File I/O Example
- 13.5 - Sample Program
13.4.10 A File I/O Example
The following piece of code puts everything together from the last several
sections. This is a short program which adds line numbers to a text file.
This program expects two command line parameters: an input file and an output
file. It copies the input file to the output file while appending line numbers
to the beginning of each line in the output file. This code demonstrates
the use of argc
, argv
, the Standard Library file
I/O routines, and I/O redirection.
; FILEIO
;
; This program copies the input file to the output file and adds line
; numbers while it is copying the file.
include stdlib.a
includelib stdlib.lib
dseg segment para public 'data'
ArgCnt word 0
LineNumber word 0
DOSErrorCode word 0
InFile dword ? ;Ptr to Input file name.
OutFile dword ? ;Ptr to Output file name.
InputLine byte 1024 dup (0) ;Input/Output data buffer.
OutputFile FileVar {}
InputFile FileVar {}
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
; ReadLn- Reads a line of text from the input file and stores the
; data into the InputLine buffer:
ReadLn proc
push ds
push es
push di
push si
push ax
mov si, dseg
mov ds, si
mov si, offset InputLine
lesi InputFile
GetLnLp:
fgetc
jc RdLnDone ;If some bizzarre error.
cmp ah, 0 ;Check for EOF.
je RdLnDone ;Note:carry is set.
mov ds:[si], al
inc si
cmp al, lf ;At EOLN?
jne GetLnLp
dec si ;Back up before LF.
cmp byte ptr ds:[si-1], cr ;CR before LF?
jne RdLnDone
dec si ;If so, skip it too.
RdLnDone: mov byte ptr ds:[si], 0 ;Zero terminate.
pop ax
pop si
pop di
pop es
pop ds
ret
ReadLn endp
; MyOutput- Writes the single character in AL to the output file.
MyOutput proc far
push es
push di
lesi OutputFile
fputc
pop di
pop es
ret
MyOutput endp
; The main program which does all the work:
Main proc
mov ax, dseg
mov ds, ax
mov es, ax
; Must call the memory manager initialization routine if you use
; any routine which calls malloc! ARGV is a good example of a
; routine calls malloc.
meminit
; We expect this program to be called as follows:
; fileio file1, file2
; anything else is an error.
argc
cmp cx, 2 ;Must have two parameters.
je Got2Parms
BadParms: print
byte "Usage: FILEIO infile, outfile",cr,lf,0
jmp Quit
; Okay, we've got two parameters, hopefully they're valid filenames.
; Get copies of the filenames and store away the pointers to them.
Got2Parms: mov ax, 1 ;Get the input filename
argv
mov word ptr InFile, di
mov word ptr InFile+2, es
mov ax, 2 ;Get the output filename
argv
mov word ptr OutFile, di
mov word ptr OutFile+2, es
; Output the filenames to the standard output device
printf
byte "Input file: %^s\n"
byte "Output file: %^s\n",0
dword InFile, OutFile
; Open the input file:
lesi InputFile
mov dx, word ptr InFile+2
mov si, word ptr InFile
mov ax, 0
fopen
jnc GoodOpen
mov DOSErrorCode, ax
printf
byte "Could not open input file, DOS: %d\n",0
dword DOSErrorCode
jmp Quit
; Create a new file for output:
GoodOpen: lesi OutputFile
mov dx, word ptr OutFile+2
mov si, word ptr OutFile
fcreate
jnc GoodCreate
mov DOSErrorCode, AX
printf
byte "Could not open output file, DOS: %d\n",0
dword DOSErrorCode
jmp Quit
; Okay, save the output hook and redirect the output.
GoodCreate: PushOutAdrs
lesi MyOutput
SetOutAdrs
WhlNotEOF: inc LineNumber
; Okay, read the input line from the user:
call ReadLn
jc BadInput
; Okay, redirect the output to our output file and write the last line
; read prefixed with a line number:
printf
byte "%4d: %s\n",0
dword LineNumber, InputLine
jmp WhlNotEOF
BadInput: push ax ;Save error code.
PopOutAdrs ;Restore output hook.
pop ax ;Retrieve error code.
test ax, ax ;EOF error? (AX = 0)
jz CloseFiles
mov DOSErrorCode, ax
printf
byte "Input error, DOS: %d\n",0
dword LineNumber
; Okay, close the files and quit:
CloseFiles: lesi OutputFile
fclose
lesi InputFile
fclose
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk db 1024 dup ("stack ")
sseg ends
;zzzzzzseg is required by the standard library routines.
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
13.5 Sample Program
If you want to use the Standard Library's output routines (putc, print,
printf, etc.) to output data to a file, you can do so by manually redirecting
the output before and after each call to these routines. Unfortunately,
this can be a lot of work if you mix interactive I/O with file I/O. The
following program presents several macros that simplify this task for you.
; FileMacs.asm
;
; This program presents a set of macros that make file I/O with the
; Standard Library even easier to do.
;
; The main program writes a multiplication table to the file "MyFile.txt".
.xlist
include stdlib.a
includelib stdlib.lib
.list
dseg segment para public 'data'
CurOutput dword ?
Filename byte "MyFile.txt",0
i word ?
j word ?
TheFile filevar {}
dseg ends
cseg segment para public 'code'
assume cs:cseg, ds:dseg
; For-Next macros from Chapter Eight.
; See Chapter Eight for details on how this works.
ForLp macro LCV, Start, Stop
local ForLoop
ifndef $$For&LCV&
$$For&LCV& = 0
else
$$For&LCV& = $$For&LCV& + 1
endif
mov ax, Start
mov LCV, ax
ForLoop textequ @catstr($$For&LCV&, %$$For&LCV&)
&ForLoop&:
mov ax, LCV
cmp ax, Stop
jg @catstr($$Next&LCV&, %$$For&LCV&)
endm
Next macro LCV
local NextLbl
inc LCV
jmp @catstr($$For&LCV&, %$$For&LCV&)
NextLbl textequ @catstr($$Next&LCV&, %$$For&LCV&)
&NextLbl&:
endm
; File I/O macros:
;
;
; SetPtr sets up the CurOutput pointer variable. This macro is called
; by the other macros, it's not something you would normally call directly.
; Its whole purpose in life is to shorten the other macros and save a little
; typing.
SetPtr macro fvar
push es
push di
mov di, offset fvar
mov word ptr CurOutput, di
mov di, seg fvar
mov word ptr CurOutput+2, di
PushOutAdrs
lesi FileOutput
SetOutAdrs
pop di
pop es
endm
;
;
;
; fprint- Prints a string to the display.
;
; Usage:
; fprint filevar,"String or bytes to print"
;
; Note: you can supply optional byte or string data after the string above by
; enclosing the data in angle brackets, e.g.,
;
; fprint filevar,<"string to print",cr,lf>
;
; Do *NOT* put a zero terminating byte at the end of the string, the fprint macro
; will do that for you automatically.
fprint macro fvar:req, string:req
SetPtr fvar
print
byte string
byte 0
PopOutAdrs
endm
; fprintf- Prints a formatted string to the display.
; fprintff- Like fprintf, but handles floats as well as other items.
;
; Usage:
; fprintf filevar,"format string", optional data values
; fprintff filevar,"format string", optional data values
; Examples:
;
; fprintf FileVariable,"i=%d, j=%d\n", i, j
; fprintff FileVariable,"f=%8.2f, i=%d\n", f, i
;
; Note: if you want to specify a list of strings and bytes for the format string,
; just surround the items with an angle bracket, e.g.,
;
; fprintf FileVariable, <"i=%d, j=%d",cr,lf>, i, j
;
;
fprintf macro fvar:req, FmtStr:req, Operands:vararg
setptr fvar
printf
byte FmtStr
byte 0
for ThisVal, <Operands>
dword ThisVal
endm
PopOutAdrs
endm
fprintff macro fvar:req, FmtStr:req, Operands:vararg
setptr fvar
printff
byte FmtStr
byte 0
for ThisVal, <Operands>
dword ThisVal
endm
PopOutAdrs
endm
; F- This is a generic macro that converts stand-alone (no code stream parameters)
; stdlib functions into file output routines. Use it with putc, puts, puti,
; putu, putl, putisize, putusize, putlsize, putcr, etc.
;
; Usage:
;
; F StdLibFunction, FileVariable
;
; Examples:
;
; mov al, 'A'
; F putc, TheFile
; mov ax, I
; mov cx, 4
; F putisize, TheFile
F macro func:req, fvar:req
setptr fvar
func
PopOutAdrs
endm
; WriteLn- Quick macro to handle the putcr operation (since this code calls putcr
; so often).
WriteLn macro fvar:req
F putcr, fvar
endm
; FileOutput- Writes the single character in AL to an output file.
; The macros above redirect the standard output to this routine
; to print data to a file.
FileOutput proc far
push es
push di
push ds
mov di, dseg
mov ds, di
les di, CurOutput
fputc
pop ds
pop di
pop es
ret
FileOutput endp
; A simple main program that tests the code above.
; This program writes a multiplication table to the file "MyFile.txt"
Main proc
mov ax, dseg
mov ds, ax
mov es, ax
meminit
; Rewrite(TheFile, FileName);
ldxi FileName
lesi TheFile
fcreate
; writeln(TheFile);
; writeln(TheFile,' ');
; for i := 0 to 5 do write(TheFile,'|',i:4,' ');
; writeln(TheFile);
WriteLn TheFile
fprint TheFile," "
forlp i,0,5
fprintf TheFile, "|%4d ", i
next i
WriteLn TheFile
; for j := -5 to 5 do begin
;
; write(TheFile,'----');
; for i := 0 to 5 do write(TheFile, '+-----');
; writeln(TheFile);
;
; write(j:3, ' |');
; for i := 0 to 5 do write(i*j:4, ' |);
; writeln(TheFile);
;
; end;
forlp j,-5,5
fprint TheFile,"----"
forlp i,0,5
fprintf TheFile,"+-----"
next i
fprint TheFile,<"+",cr,lf>
fprintf TheFile, "%3d |", j
forlp i,0,5
mov ax, i
imul j
mov cx, 4
F putisize, TheFile
fprint TheFile, " |"
next i
Writeln TheFile
next j
WriteLn TheFile
; Close(TheFile);
lesi TheFile
fclose
Quit: ExitPgm ;DOS macro to quit program.
Main endp
cseg ends
sseg segment para stack 'stack'
stk db 1024 dup ("stack ")
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes db 16 dup (?)
zzzzzzseg ends
end Main
- 13.4.10 - A File I/O Example
- 13.5 - Sample Program
Art of Assembly: Chapter Thirteen - 28 SEP 1996
[Chapter Thirteen][Previous]
[Art of Assembly][Randall
Hyde]