include stdlib.a
includelib stdlib.lib
cseg segment byte public 'CODE'
assume cs:cseg, ds:nothing, es:dseg, ss:sseg
; Note: The constants CR (0dh) and LF (0ah) appear within the
; stdlib.a include file.
tab equ 09h
MainPgm proc far
; Properly set up the segment registers:
mov ax, seg dseg
mov es, ax ;Leave DS pointing at PSP
;---------------------------------------------------------------
; First, parse the command line to get the filename:
mov es:GotName1, 0 ;Init flags that tell us if
mov es:GotName2, 0 ; we╒ve parsed the filenames
mov es:ConvertLC,0 ; and the ╥/U" switch.
; Okay, begin scanning and parsing the command line
mov si, 81h ;Pointer to command line
SkipDelimiters:
lodsb ;Get next character
call TestDelimiter
je SkipDelimiters
; Determine if this is a filename or the /U switch
cmp al, '/'
jnz MustBeFN
; See if it's "/U" here-
lodsb
and al, 5fh ;Convert "u" to "U"
cmp al, 'U'
jnz NotGoodSwitch
lodsb ;Make sure next char is
cmp al, cr ; a delimiter of some sort
jz GoodSwitch
call TestDelimiter
jne NotGoodSwitch
; Okay, it's "/U" here.
GoodSwitch: mov es:ConvertLC, 1 ;Convert LC to UC
dec si ;Back up in case it's CR
jmp SkipDelimiters ;Move on to next item.
; If a bad switch was found on the command line, print an error
; message and abort-
NotGoodSwitch:
print
byte cr,lf
byte 'Illegal switch, only "/U" is allowed!',cr,lf
byte 'Aborting program execution.',cr,lf,0
jmp PgmExit
; If it's not a switch, assume that it's a valid filename and
; handle it down here-
MustBeFN: cmp al, cr ;See if at end of cmd line
je EndOfCmdLn
; See if it's filename one, two, or if too many filenames have been
; specified-
cmp es:GotName1, 0
jz Is1stName
cmp es:GotName2, 0
jz Is2ndName
; More than two filenames have been entered, print an error message
; and abort.
print
byte cr,lf
byte 'Too many filenames specified.',cr,lf
byte 'Program aborting...',cr,lf,lf,0
jmp PgmExit
; Jump down here if this is the first filename to be processed-
Is1stName: lea di, FileName1
mov es:GotName1, 1
jmp ProcessName
Is2ndName: lea di, FileName2
mov es:GotName2, 1
ProcessName:
stosb ;Store away character in name
lodsb ;Get next char from cmd line
cmp al, cr
je NameIsDone
call TestDelimiter
jne ProcessName
NameIsDone: mov al, 0 ;Zero terminate filename
stosb
dec si ;Point back at previous char
jmp SkipDelimiters ;Try again.
; When the end of the command line is reached, come down here and
; see if both filenames were specified.
assume ds:dseg
EndOfCmdLn: mov ax, es ;Point DS at DSEG
mov ds, ax
; We're at the end of the filename, so zero-terminate it as
; required by DOS.
GotName: mov ax, es ;Point DS at DSEG
mov ds, ax
; See if the names were supplied on the command line.
; If not, prompt the user and read them from the keyboard
cmp GotName1, 0 ;Was filename #1 supplied?
jnz HasName1
mov al, '1' ;Filename #1
lea si, Filename1
call GetName ;Get filename #1
HasName1: cmp GotName2, 0 ;Was filename #2 supplied?
jnz HasName2
mov al, '2' ;If not, read it from kbd.
lea si, FileName2
call GetName
; Okay, we've got the filenames, now open the files and copy the
; source file to the destination file.
HasName2: mov ah, 3dh
mov al, 0 ;Open file for reading
lea dx, Filename1 ;File to open
int 21h
jnc GoodOpen1
print
byte 'Cannot open file, aborting program...',cr,lf,0
jmp PgmExit
; If the source file was opened successfully, save the file handle.
GoodOpen1: mov FileHandle1, ax ;Save file handle
; Open (CREATE, actually) the second file here.
mov ah, 3ch ;Create file
mov cx, 0 ;Standard attributes
lea dx, Filename2 ;File to open
int 21h
jnc GoodCreate
; Note: the following error code relies on the fact that DOS
; automatically closes any open source files when the program
; terminates.
print
byte cr,lf
byte 'Cannot create new file, aborting operation'
byte cr,lf,lf,0
jmp PgmExit
GoodCreate: mov FileHandle2, ax ;Save file handle
; Now process the files
CopyLoop: mov ah, 3Fh ;DOS read opcode
mov bx, FileHandle1 ;Read from file #1
mov cx, 512 ;Read 512 bytes
lea dx, buffer ;Buffer for storage
int 21h
jc BadRead
mov bp, ax ;Save # of bytes read
cmp ConvertLC,0 ;Conversion option active?
jz NoConversion
; Convert all LC in buffer to UC-
mov cx, 512
lea si, Buffer
mov di, si
ConvertLC2UC:
lodsb
cmp al, 'a'
jb NoConv
cmp al, 'z'
ja NoConv
and al, 5fh
NoConv: stosb
loop ConvertLC2UC
NoConversion:
mov ah, 40h ;DOS write opcode
mov bx, FileHandle2 ;Write to file #2
mov cx, bp ;Write however many bytes
lea dx, buffer ;Buffer for storage
int 21h
jc BadWrite
cmp ax, bp ;Did we write all of the
jnz jDiskFull ; bytes?
cmp bp, 512 ;Were there 512 bytes read?
jz CopyLoop
jmp AtEOF
jDiskFull: jmp DiskFull
; Various error messages:
BadRead: print
byte cr,lf
byte 'Error while reading source file, aborting '
byte 'operation.',cr,lf,0
jmp AtEOF
BadWrite: print
byte cr,lf
byte 'Error while writing destination file, aborting'
byte ' operation.',cr,lf,0
jmp AtEOF
DiskFull: print
byte cr,lf
byte 'Error, disk full. Aborting operation.',cr,lf,0
AtEOF: mov bx, FileHandle1 ;Close the first file
mov ah, 3Eh
int 21h
mov bx, FileHandle2 ;Close the second file
mov ah, 3Eh
int 21h
PgmExit: ExitPgm
MainPgm endp
TestDelimiter proc near
cmp al, ' '
je xit
cmp al, ','
je xit
cmp al, Tab
je xit
cmp al, ';'
je xit
cmp al, '='
xit: ret
TestDelimiter endp
; GetName- Reads a filename from the keyboard. On entry, AL
; contains the filename number and DI points at the buffer in ES
; where the zero-terminated filename must be stored.
GetName proc near
print
byte 'Enter filename #',0
putc
mov al, ':'
putc
gets
ret
GetName endp
cseg ends
dseg segment byte public 'data'
PSP word ?
Filename1 byte 128 dup (?) ;Source filename
Filename2 byte 128 dup (?) ;Destination filename
FileHandle1 word ?
FileHandle2 word ?
GotName1 byte ?
GotName2 byte ?
ConvertLC byte ?
Buffer byte 512 dup (?)
dseg ends
sseg segment byte stack 'stack'
stk word 0ffh dup (?)
sseg ends
zzzzzzseg segment para public 'zzzzzz'
LastBytes byte 16 dup (?)
zzzzzzseg ends
end MainPgm