
;SWAPCOPY.ASM.....a single drive copy program.
;	November 1980 
;by	John M. Kodis, Buffalo, New York.
;	Used with permission of Mr. Kodis.
;
;modified by 	Jerry W. Haigwood, 4/21/84 for use
;		with the AMPRO Little Board (tm) CPU
;
;Revision history:
;
;Version 1.1	 8/07/84	Modified to work with 48tpi.com - rbl
;  	 1.2    10/17/84	Improved disk reset logic - rbl
;	 1.3    12/10/85        Modified to copy R/O files - RLH
;	 1.3A    1/08/86        Modified to copy R/O files and set
;                                the destination R/O attribute - RLH
;
;      **************************** NOTE ******************************
;      * Version 2.0 and later require AMPRO BIOS Version 2 and later *
;      ****************************************************************
;        2.0     1/28/86        Improved SWAPCOPY program - RLH
;	 2.1     1/29/86	Added trap for Version 1 BIOS - rbl
;        2.2     1/30/86        Added trap for valid floppy drives only - RLH
;
;
;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).

;self prompting for operator convience
;
;for use with AMPRO 8 bit machines ONLY
;
;developed using CP/M 2.0, but uses only those bdos calls
;which are supported under CP/M 1.4 except BDOS CALL 30 - SET FILE ATTRIBUTES
;
;	disk to disk file transfer program.
;
;	at the command level, the command:
;
;	SWAPCOPY <cr>
;
;	will copy the file filename.ext from the source diskette
;	to destination diskette, prompting as necessary to allow the
;	diskettes to be swapped if necessary.
;
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
;
NUMKEYS	EQU       14
CNTRLC	EQU	   3
ESC	EQU	  1BH
TAB	EQU	   9
NUL	EQU	   0
LF	EQU	  10
CR	EQU	  13
BELL	EQU	   7
SECSIZ	EQU	 128		;bytes per sector
;
	ORG	TPA
;
SWAPCOPY:
	LXI	SP,STACK	;set up local stack space

;
SETUP:	MVI	A,FALSE
	STA	DONE		;we're not done yet
	STA	ONE2GO		;nor do we have a file to go

;
	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
;
ASKUSR: LXI	D,MENU		;load the menu
	MVI	C,9		;print the menu
	CALL	BDOS

	call	cget
	call	dfdev		;print the floppy drive menu

	jm	wrong$bios	;can't use version 1 bios

	LXI	D,MENU2		;load the continuation menu
	MVI	C,9		;print the menu
	CALL	BDOS

	LXI	D,SOURINP	;POINT TO SOURCE MESSAGE
	CALL	RESPONSE
	STA	SOURDRV		;SAVE THE DRIVE LETTER
	dcr	a		;change input to real drive
	STA	SDISK		;source disk

	LXI	D,DESTINP	;POINT TO DESTINATION MESSAGE
	CALL	RESPONSE
	STA	DESTDRV		;SAVE THE DRIVE LETTER
	dcr	a		;change input to real drive
	STA	DDISK		;destination disk

	LXI	D,FNMSG		;DISPLAY FILENAME INPUT STRING
	MVI	C,PRINTF
	CALL	BDOS
	CALL	FNINP		;INPUT THE FILE NAME

ASKSR:	CALL	CRLF		;CR & LF THE CRT
	CALL	CRLF
	LXI	D,SOURMX
	CALL	PROMPT		;ask for the source disk
	CALL	RDRST		;reset disk unless source = "e"
	LDA	SDISK		;get the source disk
	MOV	E,A		;move it to e
	CALL	SELDSK		;select it
	CALL	FFNAME		;get the first matching file name
	CALL	ADJPNT
	CALL	FILFPB		;set rdma & wdma pointers, fill in file name
	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.
	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)
	CALL    WRRST		;reset disk unless dest = "e"
	LDA	DDISK
	MOV	E,A
	CALL	SELDSK

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,

;*************  V1.3A  *************
	PUSH	H
	PUSH	D
	PUSH	B
	PUSH	PSW

	LHLD	DFCB
	LXI	D,RENFCB
	LXI	B,32
	CALL	LDIR		;TRANSFER LOWERCASE FILENAME TO RENAME FCB

	LXI	H,RENFCB+9
	MOV	A,M
	ANI	20H		;CHECK FOR R/O FLAG
	JZ	NORO		;NO R/O FLAG

	MOV	A,M
	ANI	05FH		;SET UPPERCASE AND INSURE NO R/O FLAG
	MOV	M,A

	LXI	D,RENFCB	;RESET R/O VECTOR
	MVI	C,SETATRF
	CALL	BDOS
	CPI	4		;CHECK FOR ERRORS
	JNC	NORO

	LXI	D,RENFCB
	MVI	C,DELETEF
	CALL	BDOS

	LXI	D,DELRO		;DISPLAY DELETED MESSAGE
	MVI	C,PRINTF
	CALL	BDOS

NORO:	POP	PSW
	POP	B
	POP	D
	POP	H

;*************  V1.3A  *************

	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.


;********  V 1.3A  ********

	PUSH	H
	PUSH	D
	PUSH	B
	PUSH	PSW

	LHLD	DFCB
	LXI	D,RENFCB
	LXI	B,16
	CALL	LDIR		;SET UP RENAME SOURCE

	LHLD	DFCB
	LXI	B,16
	CALL	LDIR		;SET UP DESTINATION FCB

;****  V1.3A - 1/8/86 ****
	LDA	RENFCB+9	;CHECK FOR R/O SOURCE FILE
	ANI	20H		;MOVE THE POSSIBLE R/O FLAG INTO CARRY FLAG
	JZ	EQUALJP		;SKIP THE RENAME TO R/O FILE - IT WASN'T
;****  V1.3A - 1/8/86 ****

	LXI	H,RENFCB+25	;POINT TO RENAME DESTINATION TYPE CHAR 1
	MOV	A,M
	ANI	0DFH		;RESET TO UPPER CASE
	ORI	80H		;SET R/O FLAG
	MOV	M,A

	LXI	D,RENFCB
	MVI	C,RENAMEF
	CALL	BDOS
	CPI	4		;CHECK SUCCESS OF RENAME
	LXI	D,RENERR
	JNC	ABORT		;ERROR

EQUALJP:
	POP	PSW
	POP	B
	POP	D
	POP	H

;********  V 1.3A  ********

	LXI	D,CPYDMX
	CALL	PRINT		;print 'copied '
	LXI	H,RENFCB+16	;V1.3A was  LHLD	DFCB
	CALL	PFNAME		;print the file name
;
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
	CALL	RDRST		;reset disk unless source = "e"
	LDA	SDISK
	MOV	E,A
	CALL	SELDSK
	JMP	RDLOOP
;
WRONG$BIOS:
	LXI	D,BIOSMSG
	CALL	ABORT
;
FINI:	
	LXI 	D,NORMAL
	CALL	PRINT		;show copy complete
	LXI	D,SYSTMX
	CALL	PROMPT		;prompt for system disk
	RST	BOOT		;exit to CP/M
;
ABORT:	CALL	PRINT
	LXI	D,SYSTMX
	CALL 	PROMPT		;prompt for system disk
	RST	BOOT		;exit to CP/M
;
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
;
; *****************  V1.3A  ***************
	PUSH	H		;MAKE SURE I DON'T DESTROY ANYTHING
	PUSH	D
	PUSH	B
	PUSH	PSW

	LHLD	DFCB
	LXI	D,9		;SET INCREMENT TO FCB TYPE CHARACTER 1
	DAD	D
	MOV	A,M
	RLC			;CHECK FOR R/O BIT SET
	JNC	NORO2		;NOT A READ ONLY FILE

	MOV	A,M
	ANI	7FH		;RESET THE R/O BIT
	ORI	20H		;CHANGE LETTER TO LOWER CASE
	MOV	M,A		;AND PUT IN THE FCB NAME

NORO2:	POP	PSW		;MAKE SURE I DON'T DESTROY ANYTHING
	POP	B
	POP	D
	POP	H
; *****************  V1.3A  ****************
;
	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
;
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
RENAMEF	EQU	  23		;V1.3A  rename a file
DMAF	EQU	  26		;set dma address function #
SETATRF	EQU	  30		;set file attributes *** V2.2 CP/M ***
;
OPEN:	MVI	C,OPENF
	XCHG
	CALL	BDOS
	INR	A
	RNZ			;successful open of requested file
OPENNG:	LXI	D,CANTOP
	JMP	ABORT
;
CLOSE:	MVI	C,CLOSEF
	LHLD	DFCB
	XCHG
	CALL	BDOS
	LHLD	OPENED
	MVI	M,FALSE
	RET

;
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
	RET			;RETURNS WITH 'Z' FLAG INDICATING STATUS

;
WRITE:	LHLD	WDMA
	MOV	E,M
	INX	H
	MOV	D,M
	CALL	SETDMA
	MVI	C,WRITEF
	LHLD	DFCB
	XCHG
	CALL	BDOS
	ANA	A
	RZ
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
	RNZ
MAKENG:	LXI	D,WRPROT
	CALL	PRINT
	LXI	D,NODIR
	JMP	ABORT
;
SETDMA:	MVI	C,DMAF
	JMP	BDOS
;
WRRST:	;skip reset if destination drive is "e" because 48tpi.com
	;will crash if a 48tpi "e" disk is in a 96tpi "a" drive 
	LDA	DDISK		;check destination disk number
	CPI	4		;is it "e"?
	RZ			
	MVI	C,RESETF
	JMP	BDOS
;
RDRST:	;skip reset if source drive is "e" because 48tpi.com
	;will crash if a 48tpi "e" disk is in a 96tpi "a" drive 
	LDA	SDISK		;check destination disk number
	CPI	4		;is it "e"?
	RZ			
	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:
	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	ESC		
	JZ 	BOOT		;quit if ctrl-c or escape
	CPI	CR
	JNZ	BADCH		;explain the procedure
	call	crlf
	RET

SELDSK:	MVI	C,14		;select disk function
	CALL	BDOS
	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

;-----------------------------------------------------------------------
;
;	CCGET		GET SYSTEM BIOS JUMP TABLES
;
;	Brings the current BIOS Jump tables starting at WARM BOOT
;	to this local area for ease of utility access.
;
;	If this BIOS is Version 2.1 or greater, also brings in the
;	secondary Jump Table.
;
;	Exits with Z set if lower than 2.1 Bios level
; 
;---------------------------------------------------------------------

CGET:
	LHLD	1		;GET START OF BIOS CODE AREA
	LXI	D,BBOOT		;MOVE TO LOCAL STORAGE
	MVI	B,BLEN		;SET COUNT
	CALL	CGET0		;MOVE STRING
	MVI	A,0		;TEST FOR VERSION
	CALL	BGETT		;IF 0, THEN LESS TAHN 1.4
	STA	BVERS		;SAVE BIOS VERS
	INX	H		;SEE IF HL IS FFFF
	MOV	A,H
	ORA	L
	RZ			;IF SO, THEN OLD SYSTEM
	DCX	H		;FIX HL SINCE HAS THE TABLE ADDRESS
	LXI	D,BNXTTBL	;SAVE NEXT TABLE
	MVI	B,BSLEN
	CALL	CGET0
	MVI	A,0FFH		;SET NZ
	ORA	A
	RET			;TO ID THIS LEVEL

CGET0:
	MOV	A,M
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	CGET0
	RET

DFDEV:
	lda	bvers
	cpi	20
	rm

	LXI	D,D$FDEV$HDR	; Print header
	mvi	c,9
 	call	bdos

	mvi	a,0		; starting unit #
D$NEXT$FDEV:
	sta	unit
	call	bpaget		; Get address of unit id	
	MOV	A,M		; Get unit id
	CPI	01		; Floppy?
	JNZ	D$BUMP$PTR	; No -- go to the next device
	inx	h		; Get drive #
	mov	a,m		; .
	ani	03h		; mask out excess bits
	MOV	l,a		; update floppy device number
	mvi	h,0		; .
	dad	h		; x2
	xchg
	LXI	H,FNAMES	; .
	dad	d		; x2
	dad	d		; x4
	dad	d		; x6
	lxi	d,d$fname	;
	lxi	b,6		; 
	db	0edh,0b0h	; . (LDIR)

	lxi	h,valdrv	; point to the valid drive table
	mvi	d,00h		; prepare to index into storage table
	mov	e,a		; finish index value
	dad	d		; index hl to the table

	lda	unit		;
	adi	'A'		;
	sta	d$current	;
	mov	m,a		;put the ascii drive letter in the table

	LXI	D,D$FDEV$LIN	; and output the line
	mvi	c,9
	call	bdos

D$BUMP$PTR:
	lda	unit
	inr	a		; Bump to next unit
	cpi	16		; Done yet?
	jm	D$NEXT$FDEV	; No -- go do the next one

	ret


unit:	db	0

D$FDEV$HDR:	DB	cr,lf,lf,'FLOPPY DISK ASSIGNMENTS:',CR,LF
		DB	' CP/M drive   Floppy disk',CR,LF
		DB	'--------------------------',CR,LF,'$'

D$FDEV$LIN:
		DB	' '
D$CURRENT:	DB	'x  '
D$EDISK:	DB	'   '
D$EBLANK:	DB	'         '
D$FNAME:	DB	'        '
		DB	CR,LF,'$'
D$FDEV$HLEN	EQU	$-D$FDEV$LIN	; Line length

FNAMES:		DB	'First '
		DB	'Second'
		DB	'Third '
		DB	'Fourth'

VALDRV:	db	00h,00h,00h,00h,'E',00h,00h,00h		;valid drive table
	db	00h,00h,00h,00h,00h,00h,00h,00h		;null means no drive
			; 'E' is forced since it is the virtual drive


RESPONSE:
	MVI	C,9
	CALL	BDOS		;PRINT OUT THE PASSED MESSAGE

CONIN:	mvi	e,0ffh
	mvi	c,6
	call	bdos		;input the character
	ani	5fh		;insure upper case character
	ora	a		;anything there?
	jz	conin

	CPI	CNTRLC		;a ctrl-C?
	JZ 	BOOT		;get out if so...
	CPI	ESC		;an escape?
	JZ	BOOT		;ditto
;	CPI	'A'		;is it a valid drive letter?
;	JC	CONIN
;	CPI	'Q'		;is it in the valid range?	
;	JNC	CONIN
	lxi	h,valdrv	;point to the valid drive table
	lxi	b,16		;load the max number of loops
	db	0edh,0b1h	; Z80 CPIR instruction
	jnz	conin		;if no match - enter a new character

	PUSH	PSW		;save the character
	MOV	E,A
	mvi	c,6
	call	bdos		;output the character
	POP	PSW		;RETURN THE CHARACTER

	ret


FNINP:				;FILE NAME INPUT ROUTINE
	lxi	h,keybuff
	mvi	m,numkeys	;set max buffer size
	xra	a
	inx	h
	mov	m,a		;zero current key count

	mvi	c,linef
	lxi	d,keybuff
	call	bdos		;get the keyboard input

	lda	keybuff+1	;load the input count	
	ana	a
	lxi	d,kbuff0
	jz	abort		;exit if no file name input

	lxi	h,keybuff+1
	inr	m		;increment the number of inputs
	mov	e,m
	mvi	d,0
	dad	d
	mvi	m,cr		;append cr to the end of input

	lxi	h,fcb1		;point to the file control block
	xra	a		;clear the accumulator
	mov	m,a		;set to default drive

	lxi	h,fcb1+1	;WRITE SPACES TO FCB1  filename.ext
	lxi	d,fcb1+2
	mvi	m,' '
	mvi	b,10
	call	mldir

	lxi	h,keybuff+2	;point to the 1st input character
	lxi	d,fcb1+1	;point to destination in fcb1
	mvi	c,'.'		;load character to look for
	mvi	b,9		;load the max count before or at EXT

FNILP:	shld	kpoint		;save input pointer
	mov	a,m		;load the input character
	cpi	'*'		;check for '?' remainder of input line
	jz	fline		;if zero - finish the fcb line
	cmp	c		;check for end of file name
	jz	fniext		;jump to ext input
	cpi	cr
	jz	fndone		;if carriage return - leave remainder spaces
	call	valid		;set to upper case
	stax	d		;load character into destination fcb location
	inx	h
	inx	d
	dcr	b
	jnz	fnilp

FNIEXT:	lhld	kpoint		;restore the keyboard input pointer

	inx	h		;point to first non period

	mov	a,b		;check last counter
	cpi	0
	jnz	fnigo
	mov	a,m		;get the next character
	cpi	'.'		;it had better be the dot.
	lxi	d,kgoof
	jnz	abort		;you goofed - sorry, you can do it all again

FNIGO:	lxi	d,fcb1+9	;point to destination in fcb1
	mvi	c,'.'		;load character to look for
	mvi	b,3		;load the max count before or at EXT
FNIELP:	mov	a,m		;load the input character
	cpi	'*'		;check for '?' remainder of input line
	jz	fext		;if zero - finish the fcb line
	cmp	c		;check for end of file name
	jz	fniejp		;skip over fcb1 storage if '.'
	cpi	cr
	jz	fndone		;if carriage return - leave remainder spaces
	call	valid		;set to upper case
	stax	d		;load character into destination fcb location
	inx	d
	dcr	b
FNIEJP:	inx	h
	mov	a,b
	ana	a		;check for zero
	jnz	fnielp		;loop till done
FNDONE:	RET

;
FLINE:
	push	d
	pop	h
	dcr	b		;reduce one for counter
	call	allfile		;copy '?' into fcb1
	jp	fniext		;input the file extent

;
FEXT:	push	d
	pop	h
	dcr	b		;reduce one for counter
	call	allfile		;copy '?' into fcb1
	jp	fndone

;
FFCB:	push	d
	pop	h
	inr	b		;add both ext characters
	inr	b
	call	allfile
	jp	fndone

;
ALLFILE:	;enters - HL=source & bc=number to transfer
	mvi	a,'?'		;load character for fcb
	mov	m,a		;load 1st character

	push	h
	pop	d
	inx	d		;point to destination location
	mov	c,a
	mvi	c,0
	call	mldir		;load the remainder of file name with '?"

	call	zfcb		;zero out the remainder of the fcb
	ret

;
ZFCB:	lxi	h,fcb1+12	;zeros out the remainder of the fcb
	xra	a		;load character for fcb (zero)
	mov	m,a

	mvi	b,23
	lxi	d,fcb1+13
	call	mldir		;load the remainder of file name with '?"
	ret

;
MLDIR:	MOV	A,M		;same as Z80 LDIR except, this only uses B reg.
	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	MLDIR
	RET

;
VALID:	cpi	20h		;changes lower case characters to upper case
	jc	badinp		;abort if control character
	cpi	61h		;< 'a' ?
	jc	v1
	cpi	7bh		;< '{'
	jnc	v1
	ani	5fh		;create upper case character
V1:	ret


;
BADINP:
	lxi	d,kgoof
	jp	abort


;
;	console messages
;
SOURINP:
	DB	CR, LF, 'Enter Source Drive? (A thru P) $'
SOURMX:	DB	CR, LF, LF, 'Place SOURCE on '
SOURDRV:
	DB	'A:, then type <RETURN>  $'

DESTINP:
	DB	CR, LF, LF, 'Enter Destination Drive? (A thru P) $'
DESTMX:	DB	CR, LF, 'Place DESTINATION on '
DESTDRV:
	DB	'A:, then type <RETURN>  $'

SYSTMX:	DB	'Insert SYSTEM disk      ...then press <RETURN>$'
FNMSG:	DB	CR, LF, 'Enter FILENAME.EXT to copy  ... then type <RETURN>  $'
COPYMX:	DB	'Copy $'
CPYDMX:	DB	CR, LF, 'Copied $'
QMARK:	DB	'?  $'
EXPLAN:	DB	'Press <RETURN> to continue, '
        DB      'or <CTRL>C to quit.', CR, LF, '$'
NORMAL:	DB	CR, LF, LF, 'Copy complete.', CR, LF, '$'
KGOOF:	db	CR,LF,LF,'Invalid input, check entries and try again',LF,CR,'$'
KBUFF0:	DB	CR, LF, LF, 'No filename input, please try again', CR,LF,'$'
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, '$'
RENERR:	DB	CR, LF, 'Destination R/O error', CR, LF, '$'
DELRO:	DB	CR, LF, 'Destination R/O file deleted$'

BIOSMSG:  db	CR, LF, 'BIOS Version 2 or later required!', CR, LF, '$'

MENU:	
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	CR, LF, 'Single Drive Copy Utility for AMPRO Little' 
	DB	' Board and Series 100'
VERSION:
	DB	CR, LF, '                         Version 2.2'
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	'$'
MENU2:
	DB	CR, LF
	DB	        ' E              User defined'
	DB	CR, LF, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL, NUL
	DB	'$'

;
;	data areas
;

;
;------------------------------------------------------------------
;
;	REPLICATED BIOS JUMP TABLE FOR EASE OF USAGE.
;
;------------------------------------------------------------------
;
BBOOT	DS	3
BCSTS	DS	3
BCIN	DS	3
BCOUT	DS	3
BLST	DS	3
BPNCH	DS	3
BRDR	DS	3
BHOME	DS	3
BSEL	DS	3
BSTRK	DS	3
BSSEC	DS	3
BSDMA	DS	3
BSRD	DS	3
BSWRT	DS	3
BLSTS	DS	3
BSTRN	DS	3
BGETT	DS	3		;GET 2.1 JUMP TABLES
BGETE	DS	3
BIOINT	DS	3
BSCSI	DS	3

BLEN	EQU	$-BBOOT	;LENGTH TO GET
;
BNXTTBL:			;VERSION 2.1 > SECONDARY TABLE
BSWAP	DS	3
BSXBINT DS	3
BPHTBAC DS	3
BPAGET	DS	3
	DS	3
	DS	3
	DS	3
	DS	3
BSLEN	EQU	$-BNXTTBL


BVERS:	DB	0		;VERSION OF BIOS CODE



KPOINT:	DS	1
KEYBUFF:
	ds	NUMKEYS+2
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
RENFCB:	DS	32		;rename fcb buffer
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
FPBUSD:	DS	1		;current fpb has been used flag
ONE2GO:	DS	1		;there is a file to be transfered flag
SDISK:	DB	0		;source disk-default to A
DDISK:	DB	1		;destination disk-default to A
;
	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
