; TXF.MAC
; contains a C-callable function: 

;	int txf(fname)
;	char *fname;

; which transmits the file(s) given by the (possibly ambiguous) file name
; fname over the console to be received by RX.
; It returns a non-zero value (TRUE) if all files were successfully
; transmitted, and zero (FALSE) if no file could be opened or an
; error occurred during file transfer.

; See GFN.MAC for how ambiguous file names are treated.

; Parameter passing complies with ECO-C conventions (see pp.63
; of the ECO-C manual).

; For transfer protocol, see comments in RX.MAC.

; 05 Feb 1988	A.Herrmann

BDOS	EQU	5
DMAADR	EQU	080H
DMASIZ	EQU	128

WBOOT	EQU	0

CONSTA	EQU	6		;console status port
CONDAT	EQU	4		;console data port

TEMPTY	EQU	2		;transmit buffer empty bit
RAVAIL	EQU	0		;receive char available bit

ACK	EQU	0FH		;ACK char

TRUE	EQU	1
FALSE	EQU	0


	.Z80

	INCLUDE B:FNCENT.LIB	;macro for parameter handling

TXF::
	FNCENT 2		;2 bytes for input parameter	
	LD HL,2+4		;get input parameter
	ADD HL,SP
	LD E,(HL)
	INC HL
	LD D,(HL)		;DE = pointer to name string
	XOR A			;A=0: search for first match
	CALL TXFILE
	JP NC,TXFNXT

ERREXT:
	LD HL,FALSE		;return FALSE if error on first match
	JP $RTNI##		; or on attempt to open file 

TXFNXT:
	LD A,0FFH		;A<>0: search for next match
	CALL TXFILE
	JP NC,TXFNXT

	XOR A			;Signal end of transmission
	CALL SENDCH

	LD HL,TRUE
	JP $RTNI##		;return upon successful completion

;--------------------------------------------------------------------------

TXFMSG:	DB 0DH,0AH,0AH
	DB 'Transmitting '
	DB '$'

TXFILE:
	LD HL,FCB
	CALL GNF		;if no error, HL = pointer to directory entry
	RET C			; else ready

	CALL BLDNAM		;convert directory entry into file name string
				;returns with HL -> file name string
				; terminated with '$'
				;Sets up FCB
	PUSH HL
	LD DE,TXFMSG
	LD C,9
	CALL BDOS
	POP DE
	LD C,9
	CALL BDOS		;show file name

	LD E,' '
	LD C,6
	CALL BDOS		;append a blank

	LD DE,FCB
	LD C,15
	CALL BDOS		;open file with FCB
	CP 0FFH
	JP Z,ERREXT

	CALL TXNAME
	CALL TXSIZE
	CALL TXDATA

	LD DE,FCB
	LD C,16
	CALL BDOS		;close file

	CALL WAITAK

	LD DE,ACKMSG
	LD C,9
	CALL BDOS

	RET

ACKMSG:	DB ' acknowledged'
	DB '$'


TXNAME:				;transmit the file name
	LD HL,FCB
	INC HL			;WITHOUT the disk number
	LD B,8
	CALL TXSTR
	PUSH HL
	LD A,'.'
	CALL SENDCH
	POP HL
	LD B,3
	CALL TXSTR
	XOR A
	CALL SENDCH
	CALL WAITAK		;wait for ACK
	RET

TXSTR:				;transmit B chars
	LD A,(HL)		;starting at HL
	INC HL			;skipping the Blanks
	CP ' '
	JR Z,TXSTR1
	PUSH HL
	PUSH BC
	CALL SENDCH
	POP BC
	POP HL
TXSTR1:	DJNZ TXSTR
	RET


TXSIZE:				;transmit the number of 128-byte records
	LD DE,FCB
	PUSH DE
	LD C,35
	CALL BDOS		;get file size
	POP DE
	LD HL,33		;random rec size in FCB
	ADD HL,DE
	LD A,(HL)
	PUSH HL
	CALL SENDCH		;low byte
	POP HL
	INC HL
	LD A,(HL)
	CALL SENDCH		;high byte
	CALL WAITAK
	RET


TXDATA:				;transmit file data
	LD DE,DMAADR
	LD C,26
	CALL BDOS		;set DMA address

TXDAT1:	LD DE,FCB
	LD C,20
	CALL BDOS		;read next sequential record
	OR A
	JP NZ,TXDONE

	LD HL,DMAADR
	LD B,DMASIZ
TXDAT2:	LD A,(HL)
	INC HL
	PUSH HL
	PUSH BC
	CALL SENDCH
	POP BC
	POP HL
	DJNZ TXDAT2
	CALL WAITAK
	JP TXDAT1
TXDONE:	RET

	
SENDCH:				;send char in A via console port
	PUSH AF
SENDC1:	IN A,(CONSTA)
	BIT TEMPTY,A
	JR NZ,SENDC2		;Wait until transmit buffer empty
	CALL CHKKEY		; or abort upon Ctrl/C from keyboard
	JR SENDC1
SENDC2:	POP AF
	OUT (CONDAT),A
	RET

WAITAK::			;wait for ACK from console port
	IN A,(CONSTA)
	BIT RAVAIL,A
	JR NZ,WAITA1		;Wait until character available
	CALL CHKKEY		; or abort upon Ctrl/C from keyboard
	JR WAITAK
WAITA1:	IN A,(CONDAT)
	CP ACK
	RET NZ			;Return if not ACK
	PUSH AF
	LD E,'.'
	LD C,6
	CALL BDOS		;Display '.' on screen
	POP AF
	RET			;Return with char in A, 
				;Z=1 iff ACK rec'd

CHKKEY:				;check if Ctrl/C from keyboard
	LD C,6
	LD E,0FFH
	CALL BDOS
	CP 03
	JP Z,WBOOT		;Warmboot
	RET

;-----------------------------------------------------------------
; BLDNAM
; converts a directory entry into a file name string

BLDNAM::			;HL -> directory entry
	LD DE,NAMSTR		;DE -> target string
	LD A,(HL)
	INC HL
	OR A
	JP Z,BLDFN		;0 = default drive

	ADD A,040H		;non-default drive
	LD (DE),A
	INC DE
	LD A,':'
	LD (DE),A
	INC DE

BLDFN:
	LD C,8			;copy file name (max. 8 chars)
	CALL CPYSTR

	LD A,'.'		;append file extension
	LD (DE),A
	INC DE

	LD C,3			;copy extension (max. 3 chars)
	CALL CPYSTR

	LD A,'$'		;terminate string with '$'
	LD (DE),A

	LD HL,NAMSTR		;return HL -> file name string
	RET

CPYSTR:
	LD A,(HL)		;copy at most C chars from HL to DE
	INC HL
	CP ' '			;but skip the blanks
	JP Z,CPYNXT
	LD (DE),A
	INC DE
CPYNXT:	DEC C
	JP NZ,CPYSTR
	RET

NAMSTR:	DEFS 14
	DEFB 0


; Local file control block

FCB:	DS 36


; GNF
; returns an FCB setup with either the first file matched by an
; ambiguous file name, or (if specified by entry parameter) the
; next file name.

; Note: This subroutine is context sensitive. You must not have
;	more than one ambiguous file name sequence in process at
;	any given time.

; Warning: This subroutine changes the DMA address inside the BDOS.

; Entry parameters:
;	DE -> Possibly ambiguous file name (00-byte terminated)
;	      (only needed for FIRST request)
;	HL -> File control block
;	A=0:  Return FIRST file name that matches
;	A<>0: Return NEXT file name that matches

; Exit parameters:
;	Carry set:	A=0FFH:  no file name matches
;			A<>0FFH: error in input file name
;	Carry clear:	FCB setup with next name
;			HL -> directory entry returned by
;			      Search First/Next

; Calling sequence:
;	LD	DE,filename
;	LD	HL,fcb
;	LD	A,0	(for first, or LD A,1 for next)
;	CALL	GNF

; Follows the pure Z80-code. For more comments see A.J.-L.'s
; "The Programmer's CP/M Handbook", pp.104.


B$FSEARCH	EQU	17
B$NSEARCH	EQU	18
B$SETDMA	EQU	26
BDOS		EQU	 5

GNFDMA		EQU	080H
GNFSVL		EQU	13
GNFFCL		EQU	36

GNFSV:		DS GNFSVL

GNF::
	PUSH HL
	PUSH DE
	PUSH AF

	LD DE,GNFDMA
	LD C,B$SETDMA
	CALL BDOS
	POP AF
	POP HL
	POP DE
	PUSH DE

	OR A
	JP NZ,GNFN
	CALL BF
	POP HL
	RET C
	PUSH HL

	LD DE,GNFSV
	LD C,GNFSVL
	CALL MOVE
	POP DE
	PUSH DE

	LD C,B$FSEARCH
	CALL BDOS
	POP HL
	CP 0FFH
	JP Z,GNFEX
	JP GNFC

GNFN:
	CALL GNFZF
	POP DE
	PUSH DE
	LD C,B$FSEARCH
	CALL BDOS
	POP DE
	PUSH DE
	LD HL,GNFSV

	LD C,GNFSVL
	CALL MOVE

	LD C,B$NSEARCH
	CALL BDOS
	POP HL
	CP 0FFH
	JP Z,GNFEX

GNFC:
	PUSH HL
	ADD A,A
	ADD A,A
	ADD A,A
	ADD A,A
	ADD A,A
	LD HL,GNFDMA
	LD E,A

	LD D,0
	ADD HL,DE

	POP DE
	PUSH HL
	PUSH DE
	LD C,GNFSVL
	CALL MOVE
	LD A,(GNFSV)
	POP DE
	LD (DE),A

	POP HL		;discard directory entry address
	PUSH DE		; but resave FCB address

	CALL GNFZF
	POP HL		;return FCB address
	XOR A
	RET

GNFEX:
	SCF
	RET


GNFZF:
	LD HL,GNFSVL
	ADD HL,DE
	LD D,H
	LD E,L
	INC DE
	LD (HL),0
	LD C,GNFFCL-GNFSVL-1

MOVE:
	LD B,0
	LDIR
	RET

BF:
	INC HL
	LD A,(HL)
	DEC HL
	CP ':'
	JP NZ,BF$ND
	LD A,(HL)
	AND 00011111B
	INC HL
	INC HL
	JP BF$SD

BF$ND:
	XOR A
BF$SD:
	LD (DE),A
	INC DE
	LD C,8
	CALL BF$GT

	CP '.'
	JP NZ,BF$NT
	INC HL

BF$NT:
	LD C,3
	CALL BF$GT

	LD B,0
	LD C,24
	CALL BF$FT
	RET

BF$GT:
	LD A,(HL)
	OR A
	JP Z,BF$SFT
	CP '*'
	JP Z,BF$QFT
	CP '.'

	JP Z,BF$SFT
	LD (DE),A

	INC DE
	INC HL
	DEC C
	JP NZ,BF$GT

BF$SKIP:
	LD A,(HL)
	OR A
	RET Z
	CP '.'
	RET Z
	INC HL
	JP BF$SKIP

BF$SFT:
	LD B,' '
	JP BF$FT

BF$QFT:
	LD B,'?'
	CALL BF$FT
	JP BF$SKIP

BF$FT:
	PUSH AF
	LD A,B

BF$FTL:
	LD (DE),A
	INC DE
	DEC C
	JP NZ, BF$FTL
	POP AF
	RET

	END
