|
Table of Content | |
| CHAPTER THIRTEEN: MS-DOS PC-BIOS AND FILE I/O (Part 11) |
| 13.4.10 - A
File I/O Example 13.5 - Sample Program |
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
|
Table of Content | |
Chapter Thirteen: MS-DOS
PC-BIOS and
File I/O (Part 11)
28 SEP 1996