; RCOPY.MAC ; Vers equ 11 ; version number SubVers equ ' ' ; modification level ; ; Copies a list of files between two directories. Source and destination ; directories and the list of files are internally configured. Under ; ZDDOS and ZSDOS file date stamps are preserved. For ZCPR3 only. ; ; USAGE: ; ; RCOPY {{/}option} ; ; OPTION: ; ; Q Toggles quiet mode. Quiet mode is set by the ZCPR3 quiet ; flag or by a configuration byte (non-zero defaults to ; quiet mode). Option Q toggles the current mode. ; ; For more information, see accompanying documentation file. ; ; Version 1.1 -- September 22, 1990 -- Gene Pizzetta ; Modified quiet mode display to print dots on screen so you know ; it's doing something. ; ; Version 1.0 -- September 16, 1990 -- Gene Pizzetta ; Initial release. ; ; Gene Pizzetta ; 481 Revere Street ; Revere, MA 02151 ; ; Newton Centre Z-Node: (617) 965-7259 ; GEnie: E.PIZZETTA ; Voice: (617) 284-0891 ; ; Developed with SLRMAC and SLRNK+: ; slrmac rcopy/m ; slrnkp rcopy/n,/v,/a:100,/j,rcopy,zslib/s,vlib/s,z3lib/s,syslib/s,/e ; ; System addresses . . . ; CpmFcb equ 5Ch CpmDma equ 80h ; ; ASCII characters . . . ; BEL equ 07h ; bell LF equ 0Ah ; linefeed CR equ 0Dh ; carriage return ; ; The following output buffer size is in sectors (records) of 128 bytes. ; It may may be set to any number of sectors up to a maximum of 256 (32K). ; BufSiz equ 256 ; output buffer in sectors ; MACLIB Z80 ; extended Intel mnemonics ; ; Following routines are from ZSLIB, VLIB, Z3LIB, and SYSLIB ; ext f$open,f$mopen,f$delete,f$close,f$read,f$write,initfcb ext setdma,codend,crlf,logud,epstr,pfn3,cout,pafdc ext z3vinit,stndout,stndend,getquiet,gzmtop,prtname ext puter2,zsyschk ext getstp,setstp ; public pstr ; jmp Start ; db 'Z3ENV' db 1 Z3EAdr: dw 0FE00h ; address of environment descriptor ; ; Configuration . . . ; db 0,0 db 'RCOPY' ; filename for ZCNFG CFG file db Vers/10+'0',Vers mod 10+'0',' ' QtFlag: db 0 ; ..non-zero defaults to quiet mode InUsr: db 0 ; source user InDrv: db 0 ; source drive OutUsr: db 0 ; destination user OutDrv: db 0 ; destination drive FilLst: rept 20 ; space for 20 filenames db ' ' endm db 0 ; end of file list ; ; Messages . . . ; MsgUse: db 'RCOPY Version ' db Vers/10+'0','.',Vers mod 10+'0',SubVers,CR,LF db 'Copies list of files from ',0 MsgUs1: db ' to ',0 MsgUs2: db CR,LF db 'Usage:',CR,LF,' ',0 MsgUs3: db ' {{/}option}',CR,LF db 'Option:',CR,LF db ' Q toggle quiet mode ',0 MsgUon: db 'on',0 MsgUof: db 'off',0 MsgCpy: db ' Copying from ',0 MsgTo: db ' to ',0 MsgDot: db ' ..',0 MsgFnf: db BEL,' File not found.',0 MsgWEr: db BEL,' Disk full!',0 MsgCEr: db BEL,' Close error.',0 MsgAmb: db BEL,' Ambiguous filename.',0 MsgDir: db BEL,' No directory space.',0 MsgBdO: db BEL,' Invalid option.',0 MsgDup: db BEL,' Source and destination are the same.',0 MsgDne: db ' Done.',0 ; Start: lhld Z3EAdr ; set up environment call zsyschk ; is this a Z-system? rnz ; (nope) call z3vinit sspd OldStk ; save old stack pointer call gzmtop ; get top of memory sphl ; ..and set up new stack ; call codend ; set buffer address shld WkBuf lxi h,FilLst ; initialize file list pointer shld LstPtr call getquiet ; is ZCPR quiet flag set? jrnz SetZQt ; (yes) lda QtFlag ; no, get quiet config byte SetZQt: sta OpQFlg ; ..and store in Q option flag call GetOpt ; get options lda InDrv ; check for duplicate directory mov b,a lda OutDrv cmp b jrnz DUOkay ; (okay they're different) lda InUsr ; the same, so check users mov b,a lda OutUsr cmp b jrnz DUOkay mvi a,16 ; set error code lxi h,MsgDup ; duplicate file specs jmp ErExit ; DUOkay: lxi h,MsgCpy call epstr call PrtIDU ; print input DU lxi h,MsgTo call epstr call PrtODU ; print output DU lda OpQFlg ; quiet option? ora a cnz crlf ; (yes, send new line) ; Major re-entry point Main: lxi d,InpFcb+1 ; point to input FCB lhld LstPtr ; ..and to next file mov a,m ora a ; null means no more files jrz Finish lxi b,11 ldir shld LstPtr ; lxi h,InpFcb+1 ; make outfile name same as infile mov a,m cpi ' ' ; is there a filename? jrz Main ; (no, so skip it) lxi d,OutFcb+1 lxi b,11 ldir lda OpQFlg ; quiet option? ora a jrnz NoPrt1 ; (yes, don't print anything) lxi d,InpFcb+1 call PrtFn NoPrt1: lxi h,MsgDot call epstr ; lxi h,InpFcb+1 ; ambiguous filename? lxi b,11 mvi a,'?' ccir jrnz Main2 ; (nope) lda OpQFlg ; quiet mode? ora a jrz NoPrt2 ; (no, don't print filename) lxi d,InpFcb+1 call PrtFn NoPrt2: lxi h,MsgAmb ; it's ambiguous call epstr lda OpQFlg ora a cnz crlf jmp Main ; get next file ; Main2: call OpnInp ; open input file jrnz Main call OpnOut ; open output file call RdLoop ; read and write files call ClsInp ; close input file call ClsOut ; close output file jrnz Main ; (error closing file) call DatStp ; get date stamp, if any lda OpQFlg ; quiet option? ora a jnz Main ; (yes) lxi h,MsgDne call epstr jmp Main ; ..and loop for next file ; Finish: xra a ; reset error flag ErExit: ora a cnz epstr ; print message Exit: call puter2 ; set error code lspd OldStk ; restore old stack pointer ret ; ..and return to CCP ; ; Subroutines . . . ; ; OpnInp -- open input file ; OpnInp: xra a ; initialize sector count sta SecCnt lhld WkBuf ; initialize buffer pointer shld BufPtr lxi d,InpFcb call initfcb call InDU ; set drive/user for input call f$open rz ; (all okay) lda OpQFlg ; quiet mode? ora a jrz OpnIn2 ; (no, don't print filename) lxi d,InpFcb+1 call PrtFn OpnIn2: lxi h,MsgFnf ; open error call epstr lda OpQFlg ora a cnz crlf xra a ; return non-zero for inr a ret ; ..next file ; ; OpnOut -- open output file ; OpnOut: lxi d,OutFcb call initfcb ; initialize FCB call OutDU call f$delete ; yes, delete it call f$mopen rz ; (okay) mvi a,11 ; set error flag lxi h,MsgDir ; open error jmp ErExit ; WrtErr: mvi a,11 ; set error flag lxi h,MsgWEr ; we have an output write error jmp ErExit ; ; ClsInp -- close input file ; ClsInp: call InDU ; close input file lxi d,InpFcb call f$close ret ; ; ClsOut -- closes output file ; ClsOut: call OutDU ; close output file lxi d,OutFcb call f$close rz ; (okay) lda OpQFlg ; quiet mode? ora a jrz ClsOu2 ; (no, don't print filename) lxi d,InpFcb+2 call PrtFn ClsOu2: lxi h,MsgCEr ; close error call epstr lda OpQFlg ora a cnz crlf xra a ; return non-zero inr a ret ; ; PrtFn -- Prints drive/user and filename on console ; PrtFn: call crlf mvi a,' ' call cout call cout call stndout call pfn3 ; print filename call stndend ret ; ; OutDU -- sets default drive and user for output file ; OutDU: lda OutUsr mov c,a lda OutDrv mov b,a call logud ret ; ; PrtODU -- print target drive and user ; PrtODU: lda OutDrv adi 'A' call cout lda OutUsr call pafdc mvi a,':' call cout ret ; ; InDU -- sets default drive and user for input file ; InDU: lda InUsr mov c,a lda InDrv mov b,a call logud ret ; ; PrtIDU -- print source drive and user ; PrtIDU: lda InDrv adi 'A' call cout lda InUsr call pafdc mvi a,':' call cout ret ; ; RdLoop -- Reads and writes file sectors. Assumes file has been ; successfully opened. ; RdLoop: lhld BufPtr RdLp1: call RdSec ; read a sector jrnz RdEnd ; (end of file) lda SecCnt ; get sector count inr a ; increment it sta SecCnt ; store it cpi BufSiz-1 ; end of buffer? jrz RdLp2 ; (yes, we need to write it) lhld BufPtr ; get current sector pointer lxi d,128 ; ..add 128 to it dad d shld BufPtr ; ..and store it jr RdLp1 ; RdLp2: call WrtLp ; write buffer to disk jnz WrtErr lhld WkBuf ; reset buffer pointer shld BufPtr xra a ; reset sector counter sta SecCnt jr RdLp1 ; RdEnd: call WrtLp ; write rest of file jnz WrtErr ret ; RdSec: call setdma ; set DMA address call InDU ; set DU lxi d,InpFcb call f$read ; read more file ret ; ; WrtLp -- write output buffer to disk ; WrtLp: lda SecCnt ; get buffer sector count mov b,a ; put it in B lhld WkBuf ; point to beginning of buffer WrtLp2: xra a ; check sector count cmp b rz ; (we're through) push b ; save sector count push h ; save DMA address call WrtSec ; write the sector pop h ; recover DMA address pop b ; get back sector count rnz ; (write error) dcr b ; decrement sector count lxi d,128 ; increment DMA address dad d jr WrtLp2 ; WrtSec: call setdma ; set DMA address call OutDu ; set drive and user lxi d,OutFcb ; ..and write sector call f$write ret ; ; GetOpt -- checks for user supplied options and sets option flags. ; GetOpt: lxi h,CpmFcb+1 ; point to command tail mov a,m ; anything there? cpi ' ' rz ; (no) cpi '/' ; slash? jrnz GetOp1 ; (nope, check option) inx h ; get next character mov a,m cpi '/' ; a second slash? jrz Usage ; (yes, give instructions) GetOp1: cpi 'Q' ; quiet option? jrz OptQ ; (yes) mvi a,19 ; set invalid option error lxi h,MsgBdO jmp ErExit ; ; Option setting routines ; Usage: lxi h,MsgUse call epstr call PrtIDU ; print input DU lxi h,MsgUs1 call epstr call PrtODU ; print output DU lxi h,MsgUs2 call epstr call prtname lxi h,MsgUs3 call epstr lda OpQFlg ; check quiet mode ora a jrz Usage2 ; (off) lxi h,MsgUof call epstr jmp Finish ; Usage2: lxi h,MsgUon call epstr jmp Finish ; OptQ: lda OpQFlg ; get Q flag rar ; get low bit into carry sbb a ; set all 8 bits according to carry cma ; flip sta OpQFlg ; store it ret ; ; DatStp -- Get create stamp from original file, if available, and ; transfer it to new file. ; DatStp: call InDU ; setup for input file lxi d,InpFcb lxi h,CpmDma ; point to DMA buffer call getstp ; get ZSDOS file stamp rnz ; (error) call OutDU ; setup for output file lxi d,OutFcb ; setup for file stamping lxi h,CpmDma call setstp ; set file stamp ret ; ; PSTR -- forces ZSYSCHK to use EPSTR ; pstr: jmp epstr ; ; Uninitialized storage . . . ; DSEG ; InpFcb: ds 36 ; input file fcb OutFcb: ds 36 ; output file fcb OpQFlg: ds 1 ; current quiet mode flag BufPtr: ds 2 ; buffer pointer LstPtr: ds 2 ; file list pointer SecCnt: ds 1 ; FPutC sector counter OldStk: ds 2 ; old stack pointer WkBuf: ds 2 ; i/o buffer address ; end