; FLOPPY DISK COPY PROGRAM
; COPYRIGHT 1982, G. YOUNG, INC. 
; UPDATED 10/9/82
* 
* TO EXECUTE, ENTER THE PROGRAM NAME FOLLOWED BY THE FILE MASK:
*       A>FLOPCOPY *.COM
*
* THE PRIMARY PURPOSE OF THIS PROGRAM IS TO COPY A FLOPPY DISK ON  
* SYSTEMS THAT HAVE ONLY ONE FLOPPY DISK AND A HARD DISK.  THIS IS DONE
* BY READING THE DIRECTORY ON THE FLOPPY AND CREATING A LIST OF FILES TO
* TO BE COPIED, THEN COPY ALL THE FILES TO THE HARD DISK. A BLANK  
* DISK IS THEN INSERTED AND THE FILES ARE COPIED TO THE BLANK FLOPPY
* AND DELETED OFF THE HARD DISK.  THIS PROCEDURE IS USED INSTEAD OF
* THE "SINGLE.COM" PROGRAM BECAUSE THERE IS MORE THAN 1 FILE SO "SINGLE"
* CANNOT BE USED WITHOUT MODIFICATIONS AND EVEN THEN MANY, MANY DISKETTE 
* MOUNTS WOULD HAVE TO BE DONE.  THIS WAY, ONLY 1 DISKETTE MOUNT NEEDS
* TO BE DONE FOR EACH DISK THAT IS COPIED.
* 8/26/82...IF DISKETTE IS FULL, ASK FOR ANOTHER, DO NOT ABORT
* THIS ALLOWS COPYING DOUBLE DENSITY DISKS ON TO MULTIPLE SINGLE DENSITY DISKS
* 10/9/82 ASK FOR SOURCE/DESTINATION/HARD DISK DRIVE # AND NOT HARD CODED

* WRITTEN BY GARY YOUNG, BOX 3218, NO. HOLLYWOOD, CA 91609

	TITLE	'*** FLOPPY DISK COPY PROGRAM ***'
BDOS	EQU	5
RECSIZE EQU	12
BOOT	EQU	0
	ORG	100H
	JMP	START
	DB	'COPYRIGHT 1982, G. YOUNG, INC.'
START	LXI	SP,STACK+80
	LDA	5DH		;SEE IF A MASK WAS ENTERED
	CPI	20H		;BUFFER WILL BE BLANK IF NOT
	JZ	NOMASK
	MVI	C,0DH		;DISK RESET
	CALL	BDOS
	LXI	H,RAM		;SET UP TABLE ADDRESS
	SHLD	TABADDR
	LXI	H,0000H
	SHLD	TABCNT
	XRA	A		;THE TABLE REFERS TO THE REMAINING AREA
	STA	ABORT		;OF RAM TO HOLD AS MANY DIRECTORY ENTRIES
	STA	EOF		;AS POSSIBLE
	LXI	D,SIGNON	;PRINT SIGNON MESSAGE
	CALL	OUTPUT
	LXI	D,SRCFLPMSG	;GET SOURCE DRIVE
	CALL	QUESTION
	ORA	A
	JZ	QUEST2
	LDA	INREC
	STA	SRCFLP
QUEST2 LXI	D,DESTFLPMSG
	CALL	QUESTION
	ORA	A
	JZ	QUEST3
	LDA	INREC
	STA	SRCFLP
QUEST3	LXI	D,HDMSG
	CALL	QUESTION
	ORA	A
	JZ	QUEST4
	LDA	INREC
	STA	HDTEMP
QUEST4	LDA	HDTEMP
	ANI	0FH
	STA	HDTEMP
	LDA	SRCFLP
	ANI	0FH
	STA	SRCFLP
	LDA	DESTFLP
	ANI	0FH
	STA	DESTFLP
	CALL	EXTRACT		;GET DIRECTORY ENTRIES
	LDA	ABORT		;SEE IF TOO MANY ENTRIES FOR MEMORY SIZE
	ORA	A		;SHOULD BE ZERO TO BE OK
	JZ	NOMORE
	LXI	D,TABFULL	;REPORT WILL NOT BE COMPLETE
	CALL	OUTPUT		;MEMORY FULL ERROR
NOMORE	CALL	SORT
	CALL	KILLDUPS	;REMOVE ENTRIES FROM MULTIPLE EXTENTS
      	LDA	SRCFLP  	;FLOPPY IS THE SOURCE DRIVE
	STA	SRCE
	LDA	HDTEMP    	;HARD DISK IS THE DESTINATION
	STA	DEST
	CALL	CPYFILE	
AGAIN	LXI	D,MNTBLANK
	CALL	QUESTION
	MVI	C,0DH
	CALL	BDOS
	LDA	HDTEMP
	STA	SRCE
	LDA	DESTFLP 
	STA	DEST
	CALL	CPYFILE
MSG3	LXI	D,ANOTHER
	CALL	QUESTION
	ORA	A
	JZ	WIPEOUT
	LDA	INREC
	CPI	'N'
	JZ	WIPEOUT
	CPI	'Y'
	JNZ	MSG3
	JMP	AGAIN
WIPEOUT	CALL	ERASE
	JMP	BOOT		;RESET AND RETURN TO CPM
NOMASK	LXI	D,ERRNOMSK
	CALL	OUTPUT
	JMP	BOOT
*
* THE EXTRACT ROUTINE SCANS THE DIRECTORY ON THE FLOPPY DISK 
* AND CREATES A LIST OF FILES TO BE COPIED.  AFTERS SORTING,
* DUPLICATE ENTRIES RESULTING FROM MULTIPLE EXTENT ENTRIES WILL 
* BE REMOVED.
*
* THE DUMMYFCB SETS UP A SKELETON TO READ ALL FILES ON THE DIRECTORY
* TO BE MODIFIED BY THE SKELATON SETUP IN THE CALL (EX: FLOPCOPY *.ASC).
*
DUMMYFCB	DB	0,'????????????',0,0,0,0,0,0,0,0,0
		DB	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0
EXTRACT	EQU	$
	LXI	D,DUMMYFCB	;COPY THE MASK SET UP BY CCP
	LXI	H,5CH		;OVER THE DUMMY FCB TO LIMIT WHAT IS COPIED
	MVI	B,12
	CALL	MOVE
	LDA	SRCFLP  	;FORCE THE DRIVE TO BE FLOPPY DRIVE
	STA	DUMMYFCB
	ORI	40H
	STA	RDISK
	LXI	D,DISKBUF	;SET A DMA ADDRESS FOR DIRECTORY ENTRIES
	MVI	C,1AH
	CALL	BDOS		;SET DMA
	LXI	D,DUMMYFCB	;GET FIRST DIRECTORY ENTRY
	MVI	C,11H
	CALL	BDOS		;GET DIRECTORY
	INR	A
	RZ
	JMP	GETFCB		;EXTRACT DATA FROM FCB
NEXTFCB	LXI	D,DUMMYFCB	;GET NEXT ENTRY AFTER THE FIRST
	MVI	C,12H
	CALL	BDOS
	INR	A
	RZ
GETFCB	LXI	D,32		;EACH ENTRY IS 32 BYTES LONG
	LXI	H,DISKBUF	;DIRECTORY RECORD IS IN DISKBUF
	CPI	1		;FIRST ENTRY IN RECORD???
	JZ	FORMREC		;YES
	DAD	D		;ADD 32 TO ADDRESS IN RECORD
	CPI	2		;SECOND ENTRY IN RECORD???
	JZ	FORMREC
	DAD	D		;ADD 64 TO ADDRESS OF RECORD
	CPI	3		;THIRD ENTRY IN RECORD???
	JZ	FORMREC
	DAD	D		;ADD 96 TO ADDRESS OF RECORD
FORMREC	INX	H		;PASS DRIVE BYTE
	LXI	D,RFILE		;MOVE FILE NAME
	MVI	B,8		;MOVE 8 CHARACTERS
	CALL	MOVE
	LXI	D,8		;POSITION PAST NAME TO TYPE
	DAD	D
	LXI	D,RTYPE		;MOVE TYPE
	MVI	B,3		;MOVE 3 CHARACTERS
	CALL	MOVE
	INX	H		;POSITION TO THE EXTENT NUMBER
	INX	H
	INX	H
	LXI	H,RTYPE		;STRIP OFF THE HIGH BIT SET BY
	MVI	B,11		;THE VERSION PROGRAM
STRIP	MOV	A,M
	ANI	07FH
	MOV	M,A
	INX	H
	DCR	B
	JNZ	STRIP
	LXI	H,RTYPE		;SKIP OVER JUNK DISK ENTRIES
	MVI	B,11		;CONTAINING NONPRINTING CHARACTERS
NONPRNT MOV	A,M
	CPI	20H		;ANY CHAR LESS THAN A BLANK
	JC	NEXTFCB		;GO TO NEXT ONE IF SO
	INX	H
	DCR	B
	JNZ	NONPRNT
FIRSTEXT	EQU	$	;GOT THE FIRST EXTENT
	LHLD	TABADDR		;GET MEMORY TABLE ADDRESS
	LXI	D,RTYPE		;GET MEMORY RECORD ADDRESS
	XCHG			;RTYPE (HL) TO TABADDR (DE)
	MVI	B,RECSIZE	;MOVE RECSIZE BYTES
	CALL	MOVE
	LHLD	TABADDR		;INCREMENT FOR NEXT ENTRY
	LXI	D,RECSIZE		;RECSIZE BYTES IN RECORD
	DAD	D
	SHLD	TABADDR		;SAVE NEW ADDRESS
	MVI	M,1AH		;SET AN END-OF-TABLE INDICATOR
	LHLD	TABCNT		;GET RECORD COUNT
	INX	H
	SHLD	TABCNT		;INCREMENT RECORD COUNT
	LHLD	TABADDR		;SEE IF NEW ADDRESS IS GREATER
	XCHG			;THAN THE TOP OF TPA-128
	LHLD	BDOS+1		;HL=TOP...DE=TABLE+RECSIZE
	LXI	B,-128
	DAD	B		;SUBTRACT 128 FROM TOP
	CALL	COMPREG		;COMPARE REGISTER VALUES
	JNC	NEXTFCB		;THERE IS ROOM FOR MORE
	MVI	A,1		;NO MORE ROOM...ABORT NOW
	STA	ABORT
	RET

* COPY THE FILE FROM ONE DISK TO ANOTHER
* THIS CODE WAS TAKEN FROM BACKUP.ASM SO HDFCB REFERS TO THE SOURCE DISK
* AND FPFCB REFERS TO THE DESTINATION DISK REGARDLESS OF FLOPPY OR HARD.

CPYFILE	EQU	$
	LHLD	ADDR2		;GET THE CURRENT END OF TABLE
	INX	H		;PLUS ONE FOR THE START OF THE
	SHLD	ADDR3		;READ/WRITE BUFFER
	LXI	H,RAM		;SET THE ADDRESS OF THE FIRST ENTRY
	SHLD	ADDR1
	JMP	PASSMOVE
NEXTFILE	EQU	$
	LHLD	ADDR1
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR1
PASSMOVE LHLD	ADDR1
	MOV	A,M
	CPI	1AH
	RZ
FORMFCB	LXI	D,HDFCB		;CLEAR THE FCB
	MVI	B,36
	XRA	A
ZEROFCB	STAX	D
	INX	D
	DCR	B
	JNZ	ZEROFCB
	LHLD	ADDR1		;GET ADDRESS OF TABLE ENTRY
	LXI	D,HDTYPE	;MOVE IN THE TYPE
	MVI	B,3
	CALL	MOVE
	INX	H
	INX	H		;POSITION TO NAME
	INX	H
	LXI	D,HDFILE	;MOVE THE FILE NAME
	MVI	B,8
	CALL	MOVE
	LXI	D,8
	DAD	D		;POSITION TO DISK ID, A:, B: ETC
	LDA	SRCE
	STA	HDFCB
	LXI	D,FPFCB		;COPY THE HDFCB TO THE FLOPPY FCB
	LXI	H,HDFCB
	MVI	B,36
	CALL	MOVE
	LDA	DEST
	STA	FPFCB
	LHLD	ADDR1
	CALL	FORMAT
	LXI	D,PRNTREC
	CALL	OUTPUT
	LXI	D,HDFCB		;OPEN THE SOURCE FILE DRIVE
	MVI	C,0FH
	CALL	BDOS		
	INR	A
	JZ	NOTFOUND
	LXI	D,FPFCB		;SEE IF THE FILE IS ON THE DESTINATION DRV
	MVI	C,0FH
	CALL	BDOS		;DUMMY OPEN
	INR	A
	JZ	MAKEIT		;NOT THERE...MAKE IT
	LHLD	ADDR1		;SET THE DRIVE BYTE (#12) TO '*' TO MARK 
	LXI	D,RECSIZE-1	;THE FILE AS ALREADY BEING THERE SO THAT
	DAD	D		;THE ERASE ROUTINE WILL NOT ERASE IT
	MVI	A,'*'		;LATER WHEN REMOVING FILES
	MOV	M,A
HUH2	LXI	D,ALRDYEXT	;FILE ALREADY EXISTS ON DESTINATION.  ASK IF
	CALL	QUESTION	;YOU WANT TO COPY THE NEW SOURCE OVER THE
	CPI	1		;EXISTING COPY
	JNZ	HUH2
	LDA	INREC
	CPI	'Y'
	JZ	ERAIT		;ERASE IT
	CPI	'N'		;NO, USE THE COPY ALREADY ON THE DESTINATION
	JZ	NEXTFILE
	JMP	HUH2
ERAIT	EQU	$
 	LXI	D,FPFCB		;DELETE THE FILE ON FLOPPY IF IT
	MVI	C,13H		;EXISTS
	CALL	BDOS
MAKEIT	EQU	$
	LXI	D,FPFCB		;CREATE THE FILE ON FLOPPY 
	MVI	C,16H
	CALL	BDOS		;MAKE FILE
	INR	A
	JZ	DISKFULL
COPYLOOP	CALL	LOADBUFF	;LOAD MEMORY WITH FILE
	CALL	WRITEBUF		;WRITE MEMORY FILE
	LDA	EOF
	CPI	1
	JZ	ENDOFFILE
	CPI	2
	JZ	DISKFULL
	JMP	COPYLOOP
ENDOFFILE	LXI	D,FPFCB		;CLOSE FLOPPY FILE
	MVI	C,10H
	CALL	BDOS			;CLOSE
	JMP	NEXTFILE
DISKFULL	LXI	D,FPFCB
	MVI	C,13H		;DELETE FILE ON FLOPPY
	CALL	BDOS
	LXI	D,DSKFULL	;PRINT DISK FULL MESSAGE
	CALL	QUESTION
	MVI	C,0DH		;RESET DISKS
	CALL	BDOS
	JMP	FORMFCB
NOTFOUND LHLD	ADDR1
	CALL	FORMAT
	LXI	D,NFMSG
	CALL	OUTPUT
	LXI	D,PRNTREC
	CALL	OUTPUT
	RET

ERASE 	EQU	$
HUH	LXI	D,ERAMSG	;ASK IF YOU WANT THEM ERASED
	CALL	QUESTION
	ORA	A
	JZ	ERAALL
	LDA	INREC
	CPI	'Y'
	JZ	ERAALL
	CPI	'N'
	RZ
	JMP	HUH
ERAALL	EQU	$
	LXI	H,RAM		;SET THE ADDRESS OF THE FIRST ENTRY
	SHLD	ADDR1
	JMP	PASSMOVEX
ERANEXT EQU	$
	LHLD	ADDR1
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR1
PASSMOVEX LHLD	ADDR1
	MOV	A,M
	CPI	1AH
	RZ
	LXI	D,RECSIZE-1	;SEE IF THE DRIVE INDICATOR IS SET TO '*' 
	DAD	D		;MEANING THE FILE WAS ALREADY ON THE HARD DISK
	MOV	A,M		;SO IT WILL NOT BE DELETED
	CPI	'*'
	JZ	ERANEXT		;YES, IT WAS THERE, SO DO NOT ERASE IT
FORMFCBX	LXI	D,HDFCB		;CLEAR THE FCB
	MVI	B,36
	XRA	A
ZEROFCBX	STAX	D
	INX	D
	DCR	B
	JNZ	ZEROFCBX
	LHLD	ADDR1
	LXI	D,HDTYPE	;MOVE IN THE TYPE
	MVI	B,3
	CALL	MOVE
	INX	H
	INX	H		;POSITION TO NAME
	INX	H
	LXI	D,HDFILE	;MOVE THE FILE NAME
	MVI	B,8
	CALL	MOVE
	LXI	D,8
	DAD	D		;POSITION TO DISK ID, A:, B: ETC
	LDA	HDTEMP   
	STA	HDFCB
	LHLD	ADDR1
	CALL	FORMAT
	LXI	D,PRNTREC
	CALL	OUTPUT
	LXI	D,HDFCB		;DELETE THE FILE ON FLOPPY IF IT
	MVI	C,13H		;EXISTS
	CALL	BDOS
	JMP	ERANEXT

* THE FOLLOWING ROUTINE IS A BUBBLE SORT.  IN PSEUDOBASIC
* IS WOULD BE DONE AS FOLLOWS:
*SORT	ADDR1=BOTTOM(RAM)-RECSIZE (RECSIZE IS COUNT OF BYTES IN ONE RECORD)
*	MAX1=0
*LOOP1	MAX1=MAX1+1
*	ADDR1=ADDR1+RECSIZE	(FIRST TIME THIS WOULD BE THE BOTTOM)
*	IF MAX1>TABCNT-1 THEN GO TO SORTED
*	ADDR2=ADDR1
*	MAX2=MAX1
*LOOP2	MAX2=MAX2+1
*	ADDR2=ADDR2+RECSIZE
*	IF MAX2>TABCNT THEN GO TO LOOP1
*	IF TABLE(ADDR1)<TABLE(ADDR2) THEN GO TO LOOP2
*	TEMP=TABLE(ADDR1)
*	TABLE(ADDR1)=TABLE(ADDR2)
*	TABLE(ADDR2)=TEMP
*	GO TO LOOP2
*SORTED	RETURN
*
*NOW THAT THIS LOGIC IS INTUITIVELY OBVIOUS, HERE'S THE NOT SO
*OBVIOUS CODE:

SORT	
	LXI	H,0000		;INITIALIZE COUNT
	SHLD	MAX1		;SINCE IT WILL DECREMENT FIRST
	LXI	D,-RECSIZE	;SUBTRACT RECSIZE FROM THE BEGINNING
	LXI	H,RAM		;OF THE TABLE SINCE IT WILL ADD
	DAD	D		;RECSIZE TO IT FIRST
	SHLD	ADDR1
LOOP1	LHLD	ADDR1		;GET THE CURRENT ADDRESS
	LXI	D,RECSIZE		;INCREMENT IT BY RECSIZE
	DAD	D		;PAST THE NEXT ENTRY
	SHLD	ADDR1
	LHLD	MAX1		;SEE IF THE COUNT HAS REACHED THE LIMIT
	INX	H		;INCREMENT THE COUNTER
	SHLD	MAX1
	XCHG			;MOVE TO DE TO COMPARE TO LIMIT
	LHLD	TABCNT
	DCX	H		; IS MAX1 > TABCNT - 1 ???
	CALL	COMPREG		;COMPARE DE (CURRENT COUNT) TO HL (TABCNT-1)
	JC	SORTED		;FINISHED WHEN MAX1 > TABCNT-1
	LHLD	ADDR1		;SETUP FOR THE INNER LOOP
	SHLD	ADDR2
	LHLD	MAX1
	SHLD	MAX2
LOOP2	LHLD	ADDR2		;START WITH ONE ENTRY GREATER THEN
	LXI	D,RECSIZE		;THE OUTER LOOP AND INCREMENT
	DAD	D		;BY RECSIZE EACH TIME PAST THE NEXT RECORD
	SHLD	ADDR2		;POINTER TO THE CURRENT RECORD
	LHLD	MAX2		;LIKEWISE SEE IF THE COUNTER FOR THE
	INX	H
	SHLD	MAX2
	XCHG
	LHLD	TABCNT
	CALL	COMPREG
	JC	LOOP1		;WHEN FINISHED, INCREMENT OUTER LOOP
	LHLD	ADDR2
	XCHG			;ADDR2 NOW IN DE
	LHLD	ADDR1
	CALL	COMPARE		;COMPARE STRINGS POINTED TO BY DE/HL
	JNC	LOOP2		;TABLE(HL) < TABLE (DE)
* EXCHANGE THE TWO ENTRIES VIA A TEMPORARY RECORD
	LXI	D,TEMP
	LHLD	ADDR1
	MVI	B,RECSIZE
	CALL	MOVE		;TEMP=TABLE(ADDR1)
	XCHG			;ADDR1=DESTINATION
	LHLD	ADDR2		;ADDR2=SOURCE
	CALL	MOVE		;TABLE(ADDR1)=TABLE(ADDR2)
	XCHG			;ADDR2 = DESTINATION
	LXI	H,TEMP
	CALL	MOVE		;TABLE(ADDR2)=TEMP
	JMP	LOOP2
SORTED	RET			;FINISHED SORTING


 
KILLDUPS EQU	$	;KILL DUPLICATE ENTRIES FROM MULTIPLE EXTENTS
	LXI	H,RAM
	SHLD	ADDR1			;SET THE START OF THE TABLE
NEXTEQUAL	LHLD	ADDR1		;CHECK EACH ENTRY AGAINST THE NEXT
	LXI	D,RECSIZE
	DAD	D
	SHLD	ADDR2
NEXTCHK	MOV	A,M			;CHECK FOR END OF TABLE
	CPI	1AH
	RZ
	XCHG
	LHLD	ADDR1			;COMPARE ADDR1 WITH ADDR2
	MVI	B,RECSIZE
	CALL	COMPARE
	JNZ	SAVELAST
	PUSH	H			;SAVE CURRENT POSITION
	LHLD	ADDR2			;SET UP FOR MOVING LIST
	SHLD	ADDR1			;DOWN ONE ENTRY
	LXI	D,RECSIZE
	DAD	D			;MOVE THIRD ENTRY TO THE SECOND
	SHLD	ADDR2
	CALL	MOVELIST
	LHLD	TABCNT
	DCX	H
	SHLD	TABCNT
	POP	H			;RESTORE CURRENT POSITION
	SHLD	ADDR1			;NOW COMPARE 1ST & 3RD
	JMP	NEXTEQUAL
SAVELAST	LHLD	ADDR2		;MAKE NEW ONE THE CURRENT ONE
	SHLD	ADDR1
	JMP	NEXTEQUAL		;COMPARE

MOVELIST	LHLD	ADDR2		;MOVE THE TABLE FROM ADDR2 DOWN
	XCHG				;TO ADDR1 THEREBY ELIMINATING
	LHLD	ADDR1			;UNWANTED ENTRIES
MOVENEXT	LDAX	D		;AND MAKING MORE ROOM FOR THE
	MOV	M,A
	CPI	1AH
	RZ
	INX	H
	INX	D
	JMP	MOVENEXT
 

* ASSORTED ROUTINES


LOADBUFF	EQU	$	;THIS ROUTINE LOADS AS MUCH OF
	LXI	H,0000		;MEMORY WITH THE FILE AS POSSIBLE
	SHLD	MAX1
	LHLD	ADDR3		;NEW TOP OF TABLE +2
	SHLD	TEMP
	XRA	A
	STA	EOF		;CLEAR EOF FLAG
LOADNEXT	LHLD	TEMP
	XCHG			;SET DMA ADDRESS
	MVI	C,1AH
	CALL	BDOS
	LXI	D,HDFCB		;READ HARD DISK
	MVI	C,14H
	CALL	BDOS
	ORA	A
	JNZ	HDEOF		;EOF?
	LHLD	MAX1
	INX	H		;INCREMENT RECORD COUNT
	SHLD	MAX1
	LHLD	TEMP		;SEE IF NEXT RECORD WOULD EXCEED THE
	LXI	D,128		;TPA AREA
	DAD	D
	SHLD	TEMP
	DAD	D		;WILL THE NEXT RECORD OVERWRITE BDOS?
	XCHG
	LHLD	BDOS+1		;FIND THE TOP OF MEMORY
	CALL	COMPREG		;COMPARE REGISTERS
	RC			;RETURN IF MEMORY ALREADY FULL
	JMP	LOADNEXT	;GET ANOTHER RECORD
HDEOF	MVI	A,1		;SET FILE EOF
	STA	EOF
	RET

WRITEBUF	EQU	$	;WRITE FROM THE MEMORY BUFFER
	LHLD	ADDR3
	SHLD	TEMP
	LHLD	MAX1		;ALLOW FOR FILES THAT HAVE NO 
	LXI	D,0000		;RECORDS SUCH AS RESTART
	CALL	COMPREG
	RZ
WRITENEXT	LHLD	TEMP
	XCHG			;SET DMA ADDRESS
	MVI	C,1AH
	CALL	BDOS
	LXI	D,FPFCB
	MVI	C,15H		;WRITE SEQUENTIAL
	CALL	BDOS
	ORA	A
	JNZ	FPFULL		;FLOPPY DISK FULL
	LHLD	MAX1		;DECREASE RECORD COUNT
	DCX	H
	SHLD	MAX1
	LXI	D,0000		;CHECK FOR NO MORE TO WRITE
	CALL	COMPREG
	RZ
	LHLD	TEMP
	LXI	D,128		;INCREMENT WRITE ADDRESS
	DAD	D
	SHLD	TEMP
	JMP	WRITENEXT
FPFULL	MVI	A,2		;FULL DISKETTE
	STA	EOF
	RET

FORMAT	LXI	D,PRNTYPE	;FORMAT THE ENTRY FROM THE TABLE
	MVI	B,3		;FORMAT TO THE PRINT FORMAT
	CALL	MOVE		;THE TABLE ADDRESS IS ASSUMMED TO BE
	LXI	D,3		;IN HL. FIRST MOVE THE TYPE
	DAD	D		;NOW POSITION TO THE FILE NAME
	LXI	D,PRNFILE	;MOVE THE FILE NAME
	MVI	B,8
	CALL	MOVE
	LXI	D,8		;POSITION TO THE DISK ID
	DAD	D
	LDA	SRCE
	ORI	40H
	STA	PRNTREC
	MVI	A,':'
	STA	PRNTREC+1
	MVI	A,'.'
	STA	PRNTYPE-1
	RET

COMPREG	MOV	A,H		;COMPARE HL TO DE
	CMP	D
	RNZ
	MOV	A,L
	CMP	E
	RET

OUTPUT	PUSH	D		;PUT OUT A CRLF
	LXI	D,CRLF
	MVI	C,09
	CALL	BDOS
	POP	D		;NOW PUT OUT THE MESSAGE
OUT1	MVI	C,09
	JMP	BDOS


QUESTION	CALL	OUTPUT	;PUT OUT THE QUESTION
	LXI	D,INBUF
	MVI	C,0AH		;INPUT THE REPLY
	CALL	BDOS
	LDA	INCNT		;SEE IF ANYTHING WAS ENTERED
	RET
 
MOVE	PUSH	H		;MOVE DATA POINTED TO IN HL
	PUSH	D		;TO THE AREA POINTED TO IN DE
	PUSH	B		;BY THE BYTE COUNT IN B
MOVE1	MOV	A,M
	ANI	7FH		;RESET THE HIGH ORDER BIT BECAUSE IT
				;MAY HAVE BEEN TURNED ON FOR THE TYPE
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MOVE1
	POP	B		;RESTORE THE TOTAL ENVIRONMENT
	POP	D
	POP	H
	RET

COMPARE	PUSH	H		;COMPARE THE STRINGS POINTED TO IN HL
	PUSH	D		;TO THE STRING POINTED TO IN DE
	PUSH	B		;FOR A LENGTH OF B CHARACTERS
COMP1	LDAX	D		; JC IF HL > DE
	CMP	M		; JZ IF HL = DE
	JNZ	COMP2		;JNC IF HL < DE
	INX	H
	INX	D
	DCR	B
	JNZ	COMP1
COMP2	POP	B
	POP	D
	POP	H
	RET


SIGNON	DB	'FLOPPY DISK COPY PROGRAM '
	DB	'10/9/82$'
ERRNOMSK DB	'ERROR...NO FILE MASK IN COMMAND'
	DB	CR,LF,'COMMAND MUST BE IN THE FORMAT "FLOPCOPY *.*"'
	DB	CR,LF,'$'
TABFULL	DB	'MEMORY FULL...REPORT NOT COMPLETE$'
NFMSG	DB	'FILE NOT FOUND...ABORTING$'
DMNTMSG	DB	'DISMOUNT DISKETTE AND ENTER RETURN$'
ERAMSG	DB	'ERASE COPIES ON THE HARD DISK (Y/N)? $' 
MNTBLANK DB	'MOUNT A FORMATTED BLANK DISKETTE AND ENTER RETURN$'
ANOTHER DB	'WANT TO COPY THE SAME FILES ON TO ANOTHER DISKETTE (Y/N)? $'
ALRDYEXT DB	'FILE ALREADY EXISTS ON DESTINATION DISK.'
	DB	'  ENTER Y TO COPY OVER IT: $'
DSKFULL DB	'DISKETTE FULL...MOUNT ANOTHER DISK$'
PRNTREC	DS	1
	DB	':'
PRNFILE	DS	8
	DB	'.'
PRNTYPE	DS	3
	DB	'    $'
CRLFLFLF	DB	0DH,0AH,0AH,0AH,'$'
CRLF	DB	0DH,0AH,'$'
BIGMSG	DB	0DH,0AH,'FILE TOO LARGE TO FIT ON ONE DISKETTE '
	DB	'SO NOT BACKED UP **** $'
SRCFLPMSG DB	'SOURCE FLOPPY DRIVE (DEFAULT='
SRCFLP	DB	'D) $'
DESTFLPMSG DB	'DESTINATION FLOPPY DRIVE (DEFAULT='
DESTFLP	DB	'D) $'
HDMSG	DB	'HARD DISK DRIVE USED AS BUFFER (DEFAULT='
HDTEMP	DB	'A) $'
HDFCB	DS	1
HDFILE	DS	8
HDTYPE	DS	3
	DS	24
FPFCB	DS	36
SRCE	DS	1
DEST	DS	1
INBUF	DB	30
INCNT	DS	1
INREC	DS	30
STACK	DS	80
EOF	DS	1
ABORT	DS	1
LINECNT	DS	1
LASTTYPE DS     3
LASTFILE DS	8
TABADDR	DS	2
TABCNT	DS	2
SELFLAG	DS	1
TOOBIG	DS	1
ADDR1	DS	2
ADDR2	DS	2
ADDR3	DS	2
MAX1	DS	2
MAX2	DS	2
RTYPE	DS	3
RFILE	DS	8
RDISK	DS	3
	DB	'$'
TEMP	DS	RECSIZE
DISKBUF	DS	128
COMPSIZE DS	1
CR	EQU	0DH
LF	EQU	0AH
RAM	EQU	$
	END	100H
