; GFN.MAC
; contains two C-callable functions: 

;	char *getffn(name)		/* get first file name */
;	char *name;
; and
;	char *getnfn()			/* get next file name */

; getffn returns a pointer to a string containing the first filename 
; that matches the possibly ambiguous filename name, 
; or NULL if no match was found.

; getnfn returns a pointer to the next filename that matches after
; a previous call to getffn, or NULL if no more match was found.

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

; Both functions call subroutine GNF described on pp.104 in 
; "The Programmer's CP/M Handbook" by Andy Johnson-Laird.

; 27 Oct 1987	A.Herrmann
; 06 Feb 1988	made FCB public for file transmission by TX1.MAC

	.Z80

	INCLUDE B:FNCENT.LIB	;macro for parameter handling

GETFFN::
	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
	LD A,0			;A=0: search for first match
	JP GET

GETNFN::
	FNCENT 0		;no input parameter
	LD A,0FFH		;A<>0: search for next match

GET:	LD HL,FCB
	CALL GNF		;if no error, HL = pointer to directory entry
	JP C,ERREXT		;error?

	CALL BLDNAM		;convert directory entry into file name string
				;returns with HL -> file name string
	JP $RTNI##		;return this pointer as function value

ERREXT:	LD HL,0			;return NULL if error
	JP $RTNI##


; 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

	XOR A			;terminate string with 00-byte
	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, made public for TX1.MAC

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
