;
; SAVEKEY -- Commodore 128 -- Version 2.0
;
; Saves key definitions to a disk file.
;
;	Usage:	SAVEKEY {{d:}<fn>}
;
; The file will have a .KEY filetype.  If a filename is not given
; in the command line, it will be requested.  If a drive is not
; given, the current drive is assumed.
;
;	Eugene L. Pizzetta
;	481 Revere Street
;	Revere, MA  02151
;	(617) 284-0891
;
; Assemble with MAC and load with HEXCOM.  Z80.LIB required.
;
;
Bdos	equ	0005h		; Bdos entry
WBoot	equ	00h		; warm boot
CR	equ	0Dh		; carriage return
DBuff	equ	0080h		; default buffer
DskBuf	equ	01000h		; disk dma address (Bank 1)
Fcb	equ	05Ch		; default file control block
FcbDr	equ	Fcb		; drive
FcbEx	equ	Fcb+0Ch		; extent
FcbName	equ	Fcb+1		; filename
FcbType	equ	Fcb+9		; filetype
KeyBuf	equ	01000h		; key table address (Bank 0)
LF	equ	0Ah		; linefeed
MvSize	equ	080h		; bytes to move (128 maximum interbank)
TPA	equ	0100h		; program load address
;
; Bdos service functions
;
ConIn	equ	1
PrStr	equ	9
GetStr	equ	10
FOpen	equ	15
FClose	equ	16
FDelete	equ	19
FWrite	equ	21
FCreate	equ	22
SetDma	equ	26
FMulti	equ	44
ParseFn	equ	152
;
; Bios services (jump table)
;
BiosMv	equ	0F04Bh		; block move
BiosXmv	equ	0F057h		; set source and destination banks
;
;
; Macros
;
	MACLIB	Z80
;
BLKMOVE	MACRO	FROM,TO,LENGTH
	lxi	H,FROM
	lxi	D,TO
	lxi	B,LENGTH
	db	0EDh,0B0h	; Z80 LDIR
	ENDM
;
;
	org	TPA
	jmp	MAIN
;
MSG1:	db	CR,LF,'SAVEKEY    Commodore 128    v 2.0$'
MSG2:	db	CR,LF,LF,'Save key definitions to file: $'
MSG3:	db	CR,LF,LF,'File exists.  Overwrite?  (Y/N): $'
MSG4:	db	CR,LF,LF,'DONE$'
;
DFCB:	db	0,'        '
KTYPE:	db	'KEY'
BLANK:	db	'              '
;
PFCB:	dw	DBuff+2
	dw	Fcb
;
COUNT:	db	0
;
MAIN:	lxi	d,MSG1		; print sign-on
	call	PRINT
;
	lxi	d,KeyBuf	; starting source address
	lxi	h,DskBuf	; starting target address
	mvi	a,0		; set count to 0
AGAIN:	sta	COUNT		; store count
	call	BNKSET		; set for interbank move
	call	BNKMOV		; then move it
	lda	COUNT		; get count
	inr	a		; increment it
	cpi	8		; eight times yet?
	JRNZ	AGAIN		; if not, go again
;
	lda	Fcb+1		; check for command tail
	cpi	'A'
	JRNC	ISFILE		; tail found
	lxi	d,MSG2		; if not, print message
	call	PRINT
	BLKMOVE	DFCB,FCB,36	; clear FCB
	BLKMOVE	BLANK,DBuff+2,14
	mvi	a,14
	sta	DBuff
	lxi	d,DBuff
	call	GETS
	call	PARSE		; parse it, and
	lxi	h,FcbName	; make sure it's uppercase
	mvi	b,08
	call	UPCASE
;
ISFILE	BLKMOVE	KTYPE,FcbType,3	; type: .KEY
	call	OPEN
	inr	a		; does file exist
	JRZ	MKFILE		; if not, make it
	lxi	d,MSG3		; if so, ask: Overwrite?
	call 	PRINT
	call	GETC
	cpi	'Y'		; if yes, erase it
	JRZ	DELETE
	jmp	EXIT		; if not, abort
;
DELETE:	mvi	c,FDelete	; delete file
	lxi	d,Fcb
	call	Bdos
;
MKFILE:	call	MAKEF		; create file
	call	OPEN		; and open it
;
WRFILE:	mvi	c,SetDma	; set DMA for disk write
	lxi	d,DskBuf
	call	Bdos
	mvi	c,FMulti	; set multi-sector write
	lxi	d,0008h
	call	Bdos
	call	WRITE
	call	CLOSE
;
	lxi	d,MSG4		; say goodbye
	call	PRINT
EXIT:	jmp	WBoot		; return to CCP
;
;
BNKSET:	mvi	c,0		; source bank in C
	mvi	b,1		; destination bank in B
	call	BiosXmv		; set for interbank move
 	ret
;
BNKMOV:	lxi	b,MvSize	; bytes to move in BC
	call	BiosMv		; call for interbank move
	ret
;
CLOSE:	mvi	c,FClose	; close file
	lxi	d,Fcb
	call	Bdos
	ret
;
GETC:	mvi	c,ConIn		; get character from console
	call	Bdos
	cpi	03		; ^C ?
	JRZ	EXIT		; if so, abort
	ani	05Fh		; to uppercase
	ret
;
GETS:	mvi	c,GetStr	; get string to address
	call	Bdos		; pointed to in DE
	ret
;
MAKEF:	mvi	a,0		; extent=0
	sta	FcbEx
	lxi	d,Fcb
	mvi	c,FCreate	; create file
	call	Bdos
	ret
;
OPEN:	lxi	d,Fcb		; open file
	mvi	c,FOpen
	call	Bdos
	ret
;
PARSE:	lxi	d,PFCB		; parse string in DBUFF
	mvi	c,ParseFn	; to FCB filespec
	call	Bdos
	ret
;
PRINT:	mvi	c,PrStr		; print string, pointed to
	call	Bdos		; by DE, at console
	ret
;
UPCASE:	mov	a,m		; make uppercase
	ani	05Fh
	inx	h
	DJNZ	UPCASE
	ret
;
WRITE:	mvi	c,FWrite	; write buffer to file
	lxi	d,Fcb
	call	Bdos
	ret
;
	end
