;******************************************
;* *
;* SINGLE DRIVE FILECOPY V81.1 4 MAY 81 *
;* *
;* WILL COPY FILES UP TO 65535 RECORDS *
;* LONG (128 BYTES/REC) ONLY LIMITED BY *
;* THE CONSTRAINTS OF AVAILABLE MEMORY *
;* ALL CONSOLE AND DISK I/O *
;* THROUGH BDOS CALL AT LOC 5 *
;* *
;* REVISED BY SHELDON EICHENBAUM *
;* *
;* ORGINAL BY KEN BARBIER AS PUBLISHED IN *
;* MICROCOMPUTING SEPT. 1980 *
;* *
;******************************************
; CP/M BDOS ADDRESSES
RBOOT EQU 0 ;RE-BOOT CP/M
BDOS EQU 5 ;BDOS CALL ENTRY
FCB EQU 5CH ;DEFAULT FILE CONTROL BLOCK
INBUF EQU 80H ;DEFAULT DMA ADDRESS
;CP/M BDOS FUNCTIONS
READF EQU 1 ;READ CONSOLE INTO (A)
TYPEF EQU 2 ;READ CONSOLE FROM (E)
INIT EQU 13 ;INITIALIZE DISC IN DRIVE A:
OPEN EQU 15 ;OPEN FILE
CLOS EQU 16 ;CLOSE FILE
FIND EQU 17 ;FIND FILE IN DIRECTORY
DELE EQU 19 ;DELETE FILE
READ EQU 20 ;READ FILE
WRIT EQU 21 ;WRITE FILE
MAKE EQU 22 ;CREATE FILE DIRECTORY ENTRY
ORG 0100H ;TPA PROGRAM START ADDRESS
JMP START ;GOTO PROGRAM START
; CONSOLE I/O THROUGH BDOS CALL
CI PUSH H ;SAVE REGISTERS
PUSH D
PUSH B
MVI C,READF ;READ FUNCTION
CALL BDOS ;RETURN CHAR IN (A)
POP B ;RESTORE OTHER REGISTERS
POP D
POP H
RET
CO PUSH H
PUSH D
PUSH B
MOV E,A ;MOVE PRINT CHAR TO (E)
MVI C,TYPEF
CALL BDOS
POP B
POP D
POP H
RET
CCRLF MVI A,0DH ;CR LF TO CONSOLE
CALL CO
MVI A,0AH
JMP CO
MSGXP POP H ;OUTPUT MESSAGE AND RETURN
MSGX1 MOV A,M ;THROUGH INDEX (H,L)
CPI 0 ;TEXT TERMINATOR = 0
JZ MSGEX
CALL CO
INX H
JMP MSGX1
MSGEX INX H ;POINT TO TEXT + 1
PCHL ;AND RETURN THERE
; FILECOPY CONSOLE MESSAGE SUBROUTINE
RDMSG CALL CCRLF ;PROMPT FOR READ DISK
CALL MSGXP
DB 'READ DISK IN DRIVE, THEN CR'
DB 0
RDMS1 CALL CI ;GET RESPONSE
CPI 'X' ;ALLOW EXIT
JZ RBOOT ;BACK TO CP/M
CPI 0DH ;ACCEPT CR ONLY
JNZ RDMS1
CALL CCRLF ;ACKNOWLEDGE
RET ;AND RETURN
WRMSG CALL CCRLF ;PROMPT FOR WRITE DISK
CALL MSGXP
DB 'WRITE DISK IN DRIVE, THEN CR'
DB 0
WRMS1 CALL CI
CPI 'X'
JZ RBOOT
CPI 0DH
JNZ WRMS1
CALL CCRLF
RET
RDERR CALL CCRLF ;SHOW READ ERROR
CALL MSGXP
DB 'READ ERROR! ENTER X TO ABORT'
DB 0DH,0AH
DB ' CR TO IGNORE'
DB 0
RDER1 CALL CI ;ACCEPT CR OR X
CPI 'X'
JZ EXIT
CPI 0DH
RZ ;RETURN MEANS IGNORE
JMP RDER1
WRERR CALL CCRLF ;SHOW WRITE ERROR
CALL MSGXP
DB 'PERMANENT WRITE ERROR!'
DB 0
EXIT CALL MSGXP
DB 'BACK TO CP/M?'
DB 0
WRER1 CALL CI ;WAIT FOR CR X
CPI 0DH
JZ RBOOT
CPI 'X'
JZ RBOOT
JNZ WRER1 ;AS ONLY LEGAL RESPONSE
; BEGIN FILECOPY PROGRAM
START CALL CCRLF ;SIGN ON MESSAGE
CALL MSGXP
DB 'SINGLE DRIVE FILECOPY V81.1 4 MAY 81'
DB 0DH,0AH
DB 0
CALL RDMSG ;PROMPT FOR READ DISK
LXI D,FCB ;LOOK FOR FILE
MVI C,FIND ;BEFORE GOING AHEAD
CALL BDOS
CPI 255 ;DOES FILE EXITS?
JNZ RUN ;YES. READ IT
CALL CCRLF ;NO. GIVE UP
CALL MSGXP
DB 'FILE DOES NOT EXIST!'
DB 0
JMP EXIT ;REBOOT CP/M
RUN LXI H,FCB ;SET UP FCB'S FOR
LXI D,RFCB ;READ AND WRITE
MVI C,16
RUN1 MOV A,M
STAX D
INX H
INX D
DCR C
JNZ RUN1
LXI H,FCB
LXI D,WFCB
MVI C,16
RUN2 MOV A,M
STAX D
INX H
INX D
DCR C
JNZ RUN2
LXI H,BUFFR ;INITIALIZE POINTER
SHLD HSAVE ;INTO BUFFER
XRA A ;ZERO RECORD COUNTS
STA ASAVE
STA ASAVE+1
STA RFCBN
STA WFCBN
; READ THE FILE INTO RAM
RFILE LXI D,RFCB ;USE READ FCB
MVI C,OPEN ;AND OPEN THE FILE
CALL BDOS
CPI 255 ;ERROR?
JNZ RFIL1
CALL CCRLF
CALL MSGXP ;YES. SHOW IT
DB 'UNABLE TO OPEN FILE!'
DB 0
JMP EXIT ;AND ABORT
RFIL1 LXI D,RFCB ;READ A RECORD
MVI C,READ
CALL BDOS
CPI 0 ;GOOD READ?
JZ RFIL2 ;YES. STORE IT
CPI 1 ;OR END OF FILE?
JZ WFILE ;YES. WRITE IT
CALL RDERR ;NO. SHOW ERROR
RFIL2 LHLD HSAVE ;STORE THE RECORD
LXI D,INBUF
MVI C,80H
RFIL3 LDAX D
MOV M,A
INX H
INX D
DCR C
JNZ RFIL3
SHLD HSAVE ;AND NEXT ADDRESS
PUSH H
LHLD ASAVE
INX H
SHLD ASAVE
POP H
LDA 7 ;ANY MEMORY LEFT?
DCR A
CMP H
JNZ RFIL1 ;YES. KEEP READING
CALL CCRLF ;NO. ABORT
CALL MSGXP
DB 'FILE IS TOO BIG!'
DB 0
JMP EXIT
; WRITE THE FILE ONTO DISK
WFILE CALL WRMSG ;PROMPT FOR WRITE DISK
MVI C,INIT ;INITIALIZE DISK FOR WRITE
CALL BDOS
LXI D,WFCB ;SEE IF FILE EXITS
MVI C,FIND
CALL BDOS
CPI 255 ;WE CAN'T WRITE TWO
JZ WFIL1 ;NO. CONTINUE
CALL CCRLF ;YES. ERASE OR ABORT?
CALL MSGXP
DB 'FILE ALREADY EXITS. ENTER:X TO ABORT'
DB 0DH,0AH
DB ' CR TO ERASE IT'
DB 0
WAIT1 CALL CI
CPI 'X'
JZ RBOOT
CPI 0DH
JNZ WAIT1
LXI D,WFCB ;ERASE THE OLD FILE
MVI C,DELE
CALL BDOS
WFIL1 LXI D,WFCB ;OPEN FILE FOR WRITE
MVI C,MAKE
CALL BDOS
CPI 255 ;OPEN OK?
JNZ WFIL2 ;YES. CONTINUE
CALL CCRLF
CALL MSGXP ;SHOW UNABLE TO OPEN
DB 'OUT OF DIRECTORY SPACE!'
DB 0
JMP EXIT
WFIL2 LXI H,BUFFR ;INITIALIZE POINTER
SHLD HSAVE
WFIL3 LHLD HSAVE ;MOVE RECORD TO OUTPUT
LXI D,INBUF ;BUFFER (SAME AS INPUT)
MVI C,80H
WFIL4 MOV A,M
STAX D
INX H
INX D
DCR C
JNZ WFIL4
SHLD HSAVE ;SAVE NEXT ADDRESS
LXI D,WFCB ;WRITE THE RECORD
MVI C,WRIT
CALL BDOS
CPI 0
CNZ WRERR ;SHOW WRITE ERROR
LHLD ASAVE ;COUNT RECORD WRITTEN
DCX H
SHLD ASAVE
MOV A,H
ORA L
JNZ WFIL3 ;AND WRITE ANOTHER
LXI D,WFCB ;DONE. CLOSE THE FILE
MVI C,CLOS
CALL BDOS
CALL CCRLF
CALL MSGXP ;PROMPT FOR REBOOT
DB 'ALL DONE!'
DB 0
JMP EXIT ;AND WE ARE ALL DONE
; RAM BUFFERS
HSAVE DS 2 ;BUFFER ADDRESS STORE
ASAVE DS 2 ;RECORD COUNT
RFCB DS 33 ;READ FILE CONTROL BLOCK
WFCB DS 33 ;WRITE FILE CONTROL BLOCK
BUFFR DB 0 ;DATA BUFFER START
RFCBN EQU RFCB+32 ;RECORD COUNTS. READ
WFCBN EQU WFCB+32 ;AND WRITE
END