home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
ftp.barnyard.co.uk
/
2015.02.ftp.barnyard.co.uk.tar
/
ftp.barnyard.co.uk
/
cpm
/
walnut-creek-CDROM
/
SIMTEL
/
CPMUG
/
CPMUG078.ARK
/
SWAPCOPY.ASM
< prev
next >
Wrap
Assembly Source File
|
1984-04-29
|
14KB
|
679 lines
;SWAPCOPY.ASM.....A single drive copy program.
; November 1980
;by John M. Kodis, Buffalo, New York.
;
;Allows files to be transfered from one diskette to
;another in a system with only a single drive.
;
;Allows ambiguous file specifications.
;Allows transfer of files larger than available memory,
;and transfer of multiple files in a single pass.
;
;Allows use of dissimiliar media (i.e., to copy
;programs from a single density master diskette
;to a double density working diskette).
;Further documentation in SWAPCOPY.DOC
;
;No Hardware dependencies
;
;Developed using CP/M 2.0, but uses only those bdos calls
;which are supported under CP/M 1.4.
;
;
; Disk to disk file transfer program.
;
; At the command level, the command:
;
; SWAPCOPY FILENAME.EXT <cr>
;
; will copy the file A:FILENAME.EXT from diskette
; to diskette, prompting as necessary to allow the
; diskette in drive A to be swapped.
;
boot equ 0 ;system reboot
bdos equ 5 ;bdos entry point
memtop equ 6 ;pointer to start of fbase
fcb1 equ 5ch ;first file name & source fcb
fcb2 equ 6ch ;second file name
tpa equ 100h ;beginning of tpa
;
false equ 0
true equ 255
;
cntrlc equ 3
tab equ 9
lf equ 10
cr equ 13
secsiz equ 128 ;bytes per sector
;
org tpa
;
swapcopy:
lxi sp,stack;set up local stack space
;
mvi a,false
sta done ;we're not done yet
sta one2go ;nor do we have a file to go
sta pflag
sta qflag
sta rflag ;set all options false
lda fcb2+1
call setops
lda fcb2+2
call setops
lda fcb2+3
call setops ;test for up to three options
;
lxi h,buf+eofo
mvi m,true ;set initial eof to true
;
lhld memtop
lxi d,-(secsiz+freeo+8)
dad d ;highest availiable dma buffer
shld buftop
;
lxi h,buf
shld fpbpnt ;free space starts at buf
;
mvi a,1
sta names ;initial next-names count
;
lxi d,sourmx
call prompt ;ask for the source disk
call ffname ;get the first matching file name
call adjpnt
call filfpb ;set rdma & wdma pointers, fill in file name
call query ;is the first file to be copied?
jnc nxtnam ;if not, try the next file
mvi a,true
sta one2go ;if so, set 'one to go' to true, then copy it
;
rdloop: lda fileof
ana a
jm wr ;start writing when the last file has been read
lhld rdma
call fulbuf
jc wr ; or when the buffer space has been exhausted
;
lhld eof
mov a,m
ana a
jz samfil ;if not end-of-file, we're on the same file.
;
call adjpnt ;Else, this is the start of a new file...
call filfpb ;adjust pointers & fill new fpb
xra a
lhld sfext
mov m,a ;source file extent := 0
lhld sfcr
mov m,a ;source file current record := 0
lhld dfext
mov m,a ;dest file extent := 0
lhld dfcr
mov m,a ;dest file current record := 0
lhld eof
mov m,a ;eof := false
lhld made
mov m,a ;made := false
lhld opened
mov m,a ;opened := false
lhld last
mov m,a ;last := false
mvi a,true
sta fpbusd ;mark current fpb as used
lhld sfcb
call open
;
samfil: call read
lhld eof
mov a,m
ana a
jz samnam ;read sectors until eof or buffer full
;
nxtnam: call ffname ;on eof, find the next name to be considered
lxi h,names
mov a,m
sta namcnt
nnloop: call fnname ;find next name...
lxi h,namcnt
dcr m
jnz nnloop ;as many times as necessary.
lxi h,names
inr m ;then bump the count for the next pass
;
lda fileof
ana a ;if all matching file names have been copied
jm wr ;(or passed over), start writing.
call query ;is the first file to be copied?
jnc nxtnam ;if not, try the next file
mvi a,true
sta one2go ;if so, set 'one to go' to true, then copy it
lda fpbusd
ana a ;if the current fpb is unused, use it
jz samnam
lhld rdma ;else set up the next fpb, and use it
mov a,m
inx h
mov h,m
mov l,a
shld fpbpnt ;next block starts just past rdma
jmp rdloop
;
samnam: lhld rdma
call bump ;rdma := rdma + secsiz
jmp rdloop
;
wr: lda one2go ;anything for the destination disk?
ana a
jz fini ;if not, we're done.
lxi h,buf
shld fpbpnt ;fpbpnt := buf
call adjpnt
lxi d,destmx
call prompt ;prompt(destmx)
;
wrnext: lhld made
mov a,m
ana a
jnz a$m ;if already made, don't make it again
;
mvi m,true ;if not made, set made := true
lhld opened
mvi m,true ;then set opened := true,
call make ;then make the file.
;
a$m: lhld opened
mov a,m
ana a
jnz a$op ;if already opened, don't open it again
mvi m,true
lhld dfcb
call open ;if not open, open it & set opened := true
;
a$op: lhld rdma
mov e,m
inx h
mov d,m ;de gets rdma
lhld wdma
mov a,e
cmp m ;compare least signifigant bytes
jnz nequal
inx h
mov a,d
cmp m
jz equal ;is wdma equal to rdma?
;
nequal: call write ;if not, write a sector
lhld wdma
call bump ;wdma := wdma + secsiz
jmp a$op
;
equal: call close ;when wdma = rdma, close the file
lhld eof
mov a,m
ana a ;done with file?
jz skprpt ;if not, don't report the transfer yet.
lda rflag
ana a ;is the 'Report' option set?
jz skprpt ;if not, don't report the file transfer.
;
lda pflag
ana a
cnz crlf ;if 'Print' is on, we need a new line
lxi d,cpydmx
call print ;print 'Copied '
lhld dfcb
call pfname ;print the file name
call crlf ;start a new line
;
skprpt: lhld wdma
call fulbuf ;if the whole buffer has been written,
jc wrexit ;try to read another some more in
;
lhld rdma ;else, set up to write the next file
mov e,m
inx h
mov d,m
xchg ;hl points to next fpb
shld fpbpnt ;set up the file param. block pointer
lhld last
mov a,m
sta done
ana a
jnz fini ;if the last file has been written, we're done
call adjpnt
jmp wrnext ;else adjust pointers, then write the next file
;
wrexit: lda done
ana a ;shall we exit or read more files?
jnz fini ;we're done, so exit
;
lxi b,freeo
lxi d,buf
lhld fpbpnt
call ldir ;move the last fpb to the start of the buffer
;
lxi h,buf
shld fpbpnt
call adjpnt
call filfpb ;set up the pointers at the start of the buffer
;
lxi d,sourmx
call prompt ;ask for the source disk
jmp rdloop
;
fini: lxi d,systmx
call prompt ;prompt for system disk
lxi d,normal
abort: call print
rst boot
;
namsiz equ 12 ;size of a disk file name (1+8+3)
fcbsiz equ 36 ;size of a file control block
sfcbo equ 0 ;offset to source fcb
sfexto equ 12 ;offset to source file extent
scro equ 32 ;offset to source file current record
dfcbo equ 36 ;offset to destination file control block
dfexto equ 48 ;offset to destination file extent
dcro equ 68 ;offset to destination file current record
rdmao equ 72 ;offset to read zone pointer
wdmao equ 74 ;offset to write zone pointer
madeo equ 76 ;offset to file-made flag
openo equ 77 ;offset to file-open flag
eofo equ 78 ;offset to end-of-file flag
lasto equ 79 ;offset to last-file flag
freeo equ 80 ;offset to start of freespace
;
adjpnt: lhld fpbpnt ;compute and save the...
lxi d,sfexto
dad d
shld sfext ; pointer to source file extent
lxi d,scro-sfexto
dad d
shld sfcr ; pointer to source file current record,
lxi d,dfcbo-scro
dad d
shld dfcb ; pointer to dest fcb,
lxi d,dfexto-dfcbo
dad d
shld dfext ; pointer to dest file extent,
lxi d,dcro-dfexto
dad d
shld dfcr ; pointer to dest file current record,
lxi d,rdmao-dcro
dad d
shld rdma ; pointer to read dma zone,
inx h
inx h
shld wdma ; pointer to write dma zone,
inx h
inx h
shld made ; pointer to file made flag,
inx h
shld opened ; pointer to file-open flag
inx h
shld eof ; pointer to end-of-file flag,
inx h
shld last ; pointer to the 'last-file' flag,
inx h
shld fspace ;and the pointer to the start of free space.
ret
;
filfpb: lhld fpbpnt
xchg
lhld fileof ;get offset into directory bufffer
mvi h,0
dad h
dad h
dad h
dad h
dad h ;multiply by 32
lxi b,dirbuf
dad b ;hl points to file name
lxi b,namsiz
push h
push b
call ldir ;move file name to source fcb
pop b
lhld dfcb
xchg
pop h
call ldir ;move file name to destination fcb
lhld fspace
xchg
lhld rdma
mov m,e
inx h
mov m,d ;point rdma to start of free space
inx h
mov m,e
inx h
mov m,d ;point wdma to start of free space
ret
;
bump: mvi a,secsiz
add m
mov m,a ;add sector size to l.s. byte of address
rnc
inx h
inr m ;if carry, increment m.s. byte of address
ret
;
fulbuf: mov e,m
inx h
mov d,m ;de gets address to be compared
lhld buftop
mov a,l
sub e
mov a,h
sbb d
ret ;return with carry set if @(de) > buftop
;
setops: cpi 'P'
jnz isitq
sta pflag ;set 'Print' flag
isitq: cpi 'Q'
jnz isitr
sta qflag ;set 'Query' flag
isitr: cpi 'R'
rnz
sta rflag ;set 'Report' flag
ret
;
query: lda qflag
ana a
stc
rz ;copy all files if not querying
lda pflag
ana a
cnz crlf ;if 'Printing', a new line is needed
lxi d,copymx
call print ;print 'Copy '
lda fileof
add a
add a
add a
add a
add a ;get 32 * file offset
lxi h,dirbuf
add l
mov l,a
adc h
sub l
mov h,a ;point hl to filename
call pfname ;print the filename
lxi d,qmark
call print ;print '?'
lxi h,askbuf
mvi m,127
xchg
mvi c,linef
call bdos ;get a response to the question
mvi e,lf
call co
lxi h,askbuf+1
mov a,m
ana a
rz ;if no response, return with carry clear.
skipbl: inx h
mov a,m
cpi ' '
jz skipbl
cpi tab
jz skipbl ;skip leading blanks and tabs
ani (not 20h) and 255
sui 'Y'
stc
rz ;if first non-blank is 'Y', copy the file
cmc
ret
;
pfname: mvi a,8
call pathl ;print 8 characters in the name,
mvi e,'.'
call co ;print a period,
mvi a,3 ;print the 3 characters in the extension.
;
pathl: inx h
mov e,m
call co ;print the character @+(hl)
dcr a
jnz pathl ;repeat (a) times
ret
;
; system interface routines
;
cif equ 1 ;console input function #
cof equ 2
printf equ 9 ;print buffer function #
linef equ 10 ;line input function #
cstsf equ 11 ;get console status function #
resetf equ 13 ;select & write enable drive A
openf equ 15 ;open file function #
closef equ 16 ;close file function #
sfff equ 17 ;search for first function #
sfnf equ 18 ;search for next function #
deletef equ 19 ;delete file function #
readf equ 20 ;sequential file read
writef equ 21 ;sequential file write
makef equ 22 ;create & open a new file
dmaf equ 26 ;set dma address function #
;
open: mvi c,openf
xchg
call bdos
inr a
jz openng
lda pflag
ana a
rz
mvi e,'O'
jmp co
openng: lxi d,cantop
jmp abort
;
close: mvi c,closef
lhld dfcb
xchg
call bdos
lhld opened
mvi m,false
lda pflag
ana a
rz
mvi e,'C'
jmp co
;
read: lhld rdma
mov e,m
inx h
mov d,m
call setdma
mvi c,readf
lhld fpbpnt
xchg
call bdos
lhld eof
mov m,a
ana a
rnz
lda pflag
ana a
rz
mvi e,'r'
jmp co
;
write: lhld wdma
mov e,m
inx h
mov d,m
call setdma
mvi c,writef
lhld dfcb
xchg
call bdos
ana a
jnz cantwr
lda pflag
ana a
rz
mvi e,'w'
jmp co
cantwr: lxi d,space
jmp abort
;
make: mvi c,deletef
lhld dfcb
xchg
call bdos
mvi c,makef
lhld dfcb
xchg
call bdos
inr a
jz makeng
lda pflag
ana a
rz
mvi e,'M'
jmp co
makeng: lxi d,wrprot
call print
lxi d,nodir
jmp abort
;
setdma: mvi c,dmaf
jmp bdos
;
reset: mvi c,resetf
jmp bdos
;
;
crlf: mvi e,cr
call co
mvi e,lf
co: push h
push psw
mvi c,cof
call bdos
pop psw
pop h
ret
;
print: mvi c,printf
jmp bdos
;
ffname: lxi d,dirbuf
call setdma
mvi c,sfff
lxi d,fcb1
call bdos
sta fileof
inr a
rnz
lxi d,nofile
jmp abort
;
fnname: lxi d,dirbuf
call setdma
mvi c,sfnf
lxi d,fcb1
call bdos
sta fileof
add a
sbb a ;a:=255 if fileof=255, else 0
lhld last
mov m,a
ret
;
prompt: lda pflag
ana a
push d
cnz crlf
pop d
call print
clear: mvi c,cstsf
call bdos
ana a
jz wait
mvi c,cif
call bdos ;if there's a char waiting, get it & ignore it.
jmp clear
wait: mvi c,cif
call bdos ;get the next char
cpi cntrlc
jz boot
cpi cr
jnz badch ;explain the procedure
call reset
ret
;
badch: lxi d,explan
jmp prompt
;
ldir: mov a,m
stax d
inx h
inx d
dcx b
mov a,c
ora b
jnz ldir
ret
;
; console messages
;
sourmx: db 'Insert SOURCE disk.', cr, lf, '$'
destmx: db 'Insert DESTINATION disk.', cr, lf, '$'
systmx: db 'Insert SYSTEM disk.', cr, lf, '$'
copymx: db 'Copy $'
cpydmx: db 'Copied $'
qmark: db '? $'
explan: db 'To continue, hit the ''RETURN'' key.', cr, lf
db 'To abort, hit control ''C''.', cr, lf, '$'
normal: db 'Copy complete.$'
nofile: db cr, lf, 'No source files', cr, lf, '$'
nodir: db cr, lf, 'Directory space exhausted', cr, lf, '$'
cantop: db cr, lf, 'Can''t reopen file.', cr, lf, '$'
space: db cr, lf, 'Data space exhausted', cr, lf, '$'
wrprot: db cr, lf, 'Write protected?', cr, lf, '$'
;
; data areas
;
sfcb: ds 0
fpbpnt: ds 2 ;pointer to start of the file param. block
sfext: ds 2 ;pointer to source file extent byte
sfcr: ds 2 ;pointer to source file current record byte
dfcb: ds 2 ;pointer to destination file control block
dfext: ds 2 ;pointer to dest file extent byte
dfcr: ds 2 ;pointer to dest file current record byte
buftop: ds 2 ;pointer to top of free memory
rdma: ds 2 ;pointer to next read dma zone
wdma: ds 2 ;pointer to next write dma zone
made: ds 2 ;pointer to file made flag
opened: ds 2 ;pointer to file open flag
eof: ds 2 ;pointer to end of file flag
last: ds 2 ;pointer to last file flag
fspace: ds 2 ;pointer to start of free buffer space
fileof: ds 1 ;file offset. index into dirbuf
done: ds 1 ;all files copied flag
names: ds 1 ;number of the next file to be copied
namcnt: ds 1 ;copy of 'names'. used as a counter
pflag: ds 1 ;'Print' option flag
qflag: ds 1 ;'Query' option flag
rflag: ds 1 ;'Report' option flag
fpbusd: ds 1 ;current fpb has been used flag
one2go: ds 1 ;there is a file to be transfered flag
;
ds 64 ;32 level stack
stack: ds 0
;
dirbuf: ds secsiz ;buffer for searching the directory
;
askbuf: ds 129 ;buffer for response to query
;
buf: ds 0 ;buffer starts here and extends to fbase
;
end swapcopy