;
; SYSLIB Module Name:  SZFNAM
; Author:  Richard Conn
; SYSLIB Version Number:  2.2
; Module Version Number:  1.1
; Module Entry Points:
;	ZFNINIT		ZFNAME		ZDNAME		ZDNFIND
;	ZCPRQ2
; Module External References:
;	CAPS		FI3$CLOSE	FI3$OPEN	F3$GET
;	INITFCB		MOVEB		ZPFIND		BDOS
;
;*
;*  ZFNAME is a file name scanner.  Pointing to the first character
;*	of a file name specification of the form 'dir:filename.typ', where
;*	any part of this specification is optional, this routine fills in
;*	an FCB with zeros, properly initializes the FN and FT (File Name and
;*	File Type) fields if 'filename.typ' or any part thereof is present,
;*	and returns the value of disk and user if they are specified
;*	(or FFH if they are not).
;*  The directory indicator 'dir:', if specified, may be of one of two forms:
;*		DIRECT -- A named directory, of up to 8 chars in length
;*		d      -- A disk drive letter
;*		u      -- A user number
;*		du     -- A disk drive letter and a user number
;*	The named directory form is checked first, so if a directory named
;*		A or A10 exists, it matches, as opposed to Drive A or
;*		drive/user A/10.
;*	Examples:
;*		HELP:*.HLP
;*		A5:TEST.TXT
;*		C?:ABC.*
;*		PASCAL:*.COM
;*	NOTE:  It is the programmer's responsibility to have called and
;*		properly initialized the buffers in the ZCPRINIT routine
;*		in the SZCPR module
;*


;*
;*  EXTERNALS
;*
	EXT	BDOS	; BDOS UTILITY
	EXT	MOVEB	; COPY UTILITY
	EXT	INITFCB	; INIT FCB UTILITY
	EXT	CAPS	; CAPITALIZE ROUTINE
	EXT	ZPFIND	; FIND FILE ALONG PATH
	EXT	FI3$OPEN	; BYTE-ORIENTED FILE I/O
	EXT	FI3$CLOSE
	EXT	F3$GET


;*
;*  BASIC EQUATES
;*
MAXDISK	EQU	16	; MAX NUMBER OF DISKS
MAXUSER	EQU	31	; MAX USER NUMBER
MAXNAME	EQU	64	; MAX NUMBER OF NAMES IN DIR FILE
CPM	EQU	0	; CP/M ENTRY
BENTRY	EQU	CPM+5	; BDOS ENTRY
CR	EQU	0DH
LF	EQU	0AH


;*
;*  INIT MODULE
;*	IF THE USER WISHES TO CHANGE THE NAME OF THE DIRECTORY FILE TO LOOK
;*	FOR, HE CALLS THIS ROUTINE, WITH THE FCB PTR IN DE
;*
;*	IF THE USER WISHES TO CHANGE THE ADDRESS OF THE MEMORY-RESIDENT
;*	DISK NAMES BUFFER, HE CALLS THIS ROUTINE WITH THE ADDRESS IN HL
;*
;*	IF THE USER WISHES TO CHANGE THE NUMBER OF DIRECTORY NAMES PERMITTED
;*	IN THE DIRECTORY FILE, HE CALLS THIS ROUTINE, WITH THE NEW NAME
;*	COUNT IN C
;*
;*	THE SPECIFIC BUFFERED VALUES TO CHANGE ARE INDICATED BY THE A
;*	REGISTER AS FOLLOWS:
;*		BIT 7 -- SET NAME OF DIR FILE TO FCB PTED TO BY DE
;*		BIT 6 -- SET MAX NUMBER OF DIRECTORY NAMES PERMITTED
;*		BIT 5 -- SET ADDRESS OF MEMORY-RESIDENT BUFFER
;*
;*	IF THIS MODULE IS NOT CALLED, THE FOLLOWING DEFAULT VALUES ARE
;*	ASSUMED:
;*		NAME OF DIRECTORY NAMES FILE -- NAMES.DIR
;*		MAX NUMBER OF DIRECTORY NAMES -- 64
;*		NO MEMORY-RESIDENT NAMES BUFFER
;*
;*	NO REGS ARE AFFECTED
;*	ON INPUT, DE PTS TO NEW FCB
;*		  HL IS THE ADDRESS OF THE MEMORY-RESIDENT NAMES BUFFER
;*		  C IS THE MAX NUMBER OF DIRECTORY NAMES
;*		  A IS FLAG --
;*			BIT 7 SET (1) - LOAD DEFAULT FCB FROM DE
;*			BIT 6 SET (1) - LOAD NAME COUNT FROM C
;*
ZFNINIT::
	PUSH	H	; SAVE REGS
	PUSH	D
	PUSH	B
	PUSH	PSW
	MOV	B,A	; SAVE FLAG IN B
	ANI	20H	; LOOK AT BIT 5
	JZ	ZFNIN0	; SKIP ADDRESS LOAD IF BIT 5 = 0
	SHLD	NDADR	; SET ADDRESS FROM HL
ZFNIN0:
	MOV	A,B	; GET FLAG BYTE
	ANI	80H	; LOOK AT BIT 7
	JZ	ZFNIN1	; SKIP FCB LOAD IF BIT 7 = 0
	PUSH	B	; SAVE FLAG IN B
	XCHG		; HL PTS TO FCB
	LXI	D,FNFCB	; PT TO MY FCB
	MVI	B,12	; COPY 12 BYTES
	CALL	MOVEB	; COPY
	POP	B	; GET FLAG IN B
ZFNIN1:
	MOV	A,B	; GET FLAG
	ANI	40H	; LOOK AT BIT 6
	JZ	ZFNIN2	; SKIP NAMES LOAD IF BIT 6 = 0
	MOV	A,C	; GET COUNT
	STA	MAXN	; STORE IN BUFFER
ZFNIN2:
	POP	PSW	; RESTORE REGS
	POP	B
	POP	D
	POP	H
	RET


;*
;*  ZCPRQ2 -- RETURN POINTER TO BUFFER AREA IN 2ND ZCPR2 MODULE
;*	ON RETURN, HL PTS TO FIRST BYTE OF BUFFER AREA
;*
ZCPRQ2::
	LXI	H,MAXN	; 1ST BYTE
	RET

;
;  FCB USED BY ZFNAME
;
MAXN:
	DB	MAXNAME				; INIT TO MAXNAME
NDADR:
	DW	0				; INIT TO NO BUFFER
FNFCB:
	DB	0,'NAMES   DIR',0,0,0,0		; INIT TO NAMES.DIR
	DS	16
	DS	4

;*
;*  MAIN MODULE
;*	ON ENTRY, DE PTS TO FCB TO BE FILLED AND HL PTS TO FIRST BYTE OF
;*		TARGET STRING; FCB IS 36 BYTES LONG
;*	ON EXIT, B=DISK NUMBER (1 FOR A, ETC) AND C=USER NUMBER
;*		HL PTS TO TERMINATING CHAR
;*		A=0 AND Z SET IF ERROR IN DISK OR USER NUMBERS, A=0FFH AND NZ
;*			IF OK
;*
ZFNAME::
	PUSH	D	; SAVE DE
	PUSH	H	; SAVE HL
	XCHG		; SAVE PTR TO FCB
	SHLD	FCBPTR
	XCHG		; DE PTS TO FCB
	POP	H	; GET HL
	MVI	A,0FFH	; SET DEFAULT DISK AND USER
	STA	DISK
	STA	USER
;  FILL TARGET FCB WITH ZEROES
	MVI	B,36	; INIT FCB
	XRA	A	; A=0
FNINI:
	STAX	D	; STORE ZERO
	INX	D	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	FNINI
;  SCAN FOR COLON IN STRING
	PUSH	H	; SAVE PTR TO TARGET STRING
COLON:
	MOV	A,M	; SCAN FOR COLON OR SPACE
	CPI	':'	; COLON FOUND?
	JZ	COLON1
	CALL	DELCK	; DELIMITER FOUND?
	JZ	GETF1
	INX	H	; PT TO NEXT
	JMP	COLON	; CONTINUE IF NOT END OF LINE
;  WE HAVE FOUND A COLON, SO THERE IS A DIR: PREFIX
COLON1:
	POP	H	; GET PTR TO FIRST CHAR
	MVI	A,0FFH	; ALLOW DU: FORM
	CALL	ZDNFIND	; SCAN FOR DIRECTORY NAME; RETURN DISK IN DISK,
	JNZ	GETFILE		;   USER IN USER, NZ IF OK, HL PTS TO COLON
	XRA	A	; ERROR INDICATOR
	POP	D	; RESTORE DE
	RET

;  EXTRACT FILE NAME
GETF1:
	POP	H	; GET PTR TO BYTE
GETFILE:
	XCHG		; GET PTR TO FCB
	LHLD	FCBPTR
	XCHG		; HL PTS TO TARGET STRING, DE PTS TO FCB
	MOV	A,M	; PTING TO COLON?
	CPI	':'
	JNZ	GFILE1
	INX	H	; SKIP OVER COLON
GFILE1:
	CALL	DELCK	; GET NEXT CHAR AND CHECK FOR A DELIMITER
	JNZ	GFILE2	; PROCESS SINCE NOT A DELIMITER
	CPI	'.'	; WAS DELIMITER A '.'?
	JZ	GFILE2	; PROCESS SINCE FN MISSING
;  NO NAME SPECIFIED, SO MAKE IT WILD
GFQUES:
	INX	D	; FILL WITH '?'
	MVI	B,11	; 11 BYTES
	MVI	A,'?'
GFFILL:
	STAX	D	; PUT ?
	INX	D	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	GFFILL
;  EXIT ZFNAME
FNDONE:
	LDA	DISK	; GET DISK NUMBER
	CPI	0FFH	; CURRENT DISK?
	JZ	FNDN1
	INR	A	; ADD 1 SO IN THE RANGE FROM 1 TO 16
FNDN1:
	MOV	B,A	; ... IN B
	LDA	USER	; GET USER NUMBER
	MOV	C,A	; ... IN C
	POP	D	; RESTORE REGS
	MVI	A,0FFH	; NO ERROR
	ORA	A	; SET FLAGS
	RET
;  GET FILE NAME FIELDS
GFILE2:
	MVI	B,8	; AT MOST 8 BYTES FOR FN
	CALL	SCANF	; SCAN AND FILL
	MVI	B,3	; AT MOST 3 BYTES FOR FT
	MOV	A,M	; GET DELIMITER
	CPI	'.'	; FN ENDING IN '.'?
	JNZ	GFILE3
	INX	H	; PT TO CHAR AFTER '.'
	CALL	SCANF	; SCAN AND FILL
	JMP	FNDONE	; DONE ... RETURN ARGS
;  FT FIELD NOT GIVEN, SO <SP> FILL FT FIELD IN FCB
GFILE3:
	CALL	SCANF4	; FILL WITH <SP>
	JMP	FNDONE
;
;  SCANNER ROUTINE
;
SCANF:
	CALL	DELCK	; CHECK FOR DELIMITER
	JZ	SCANF4	; <SP> FILL IF FOUND
	INX	D	; PT TO NEXT BYTE IN FN
	CPI	'*'	; ? FILL?
	JNZ	SCANF1
	MVI	A,'?'	; PLACE '?'
	STAX	D
	JMP	SCANF2
SCANF1:
	STAX	D	; PLACE CHAR
	INX	H	; PT TO NEXT POSITION
SCANF2:
	DCR	B	; COUNT DOWN
	JNZ	SCANF	; CONTINUE LOOP
SCANF3:
	CALL	DELCK	; "B" CHARS OR MORE - SKIP TO DELIMITER
	RZ
	INX	H	; PT TO NEXT
	JMP	SCANF3
SCANF4:
	INX	D	; PT TO NEXT FN OR FT
	MVI	A,' '	; <SP> FILL
	STAX	D
	DCR	B	; COUNT DOWN
	JNZ	SCANF4
	RET

;*
;*  ZDNAME -- LOAD THE CONTENTS OF THE NAMES.DIR FILE INTO THE MEMORY
;*	BUFFER PTED TO BY HL
;*	ON ENTRY, HL PTS TO THE MEMORY BUFFER EXTENDING TO THE BASE OF
;*		THE BDOS
;*	ON EXIT, HL PTS TO THE FIRST ENTRY IN THE NAMES.DIR FILE, BC IS
;*		THE NUMBER OF VALID ENTRIES, A IS THE ERROR FLAG (A=0FFH
;*		AND NZ IF NO ERROR, A=0 AND Z IF ERROR)
;*			ERRORS MAY BE EITHER MEMORY OVERFLOW OR NAMES.DIR
;*			NOT FOUND
;*	EACH NAMES.DIR ENTRY IS 10 BYTES LONG, STRUCTURED AS FOLLOWS:
;*		BYTE 0: DISK NUMBER (A=0)
;*		BYTE 1: USER NUMBER
;*		BYTES 2-9: DIRECTORY NAME, 8 CHARS MAX, <SP> FILL AT END
;*
ZDNAME::
	PUSH	D	; SAVE UNCHANGED REG
	SHLD	DIRNAME	; SAVE PTR TO BUFFER
	SHLD	CURNAME	; SAVE PTR TO FIRST ENTRY
	LXI	D,FNFCB	; PT TO FCB WHICH CONTAINS DIR FILE NAME
	CALL	INITFCB	; INIT FCB
	MVI	B,0FFH	; SEARCH CURRENT USER
	CALL	ZPFIND	; LOOK FOR NAMES.DIR FILE
	JZ	DIRNERR	; FILE NOT FOUND ERROR
;
;  FOUND NAMES.DIR, SO LOAD IT
;
	CALL	PUTUD	; SAVE CURRENT USER/DISK
	CALL	LOGUD	; LOG IN NEW USER/DISK
	LXI	D,FNFCB	; PT TO FCB
	CALL	FI3$OPEN	; OPEN FOR INPUT
;
;  LOAD NAMES.DIR FILE
;
	MVI	C,0	; SET ENTRY COUNT
	LDA	MAXN	; GET MAX NUMBER OF NAMES
	MOV	B,A	; ... IN B
ZDNA1:
	LXI	H,ENTRY	; PT TO ENTRY BUFFER
	CALL	GETNAME	; GET NAME FROM DISK
	JNZ	ZDNA3	; DONE?
	LDA	ENTRY+2	; LOOK AT FIRST LETTER OF DIR NAME
	ORA	A	; NO ENTRY?
	JZ	ZDNA2
	LHLD	DIRNAME	; PT TO BUFFER ENTRY
	LXI	D,ENTRY	; PT TO NEW ENTRY
	INR	C	; INCREMENT ENTRY COUNTER
	PUSH	B	; SAVE COUNTERS
	XCHG		; HL PTS TO NEW ENTRY, DE PTS TO DEST
	MOV	A,M	; GET DISK NUMBER
	STAX	D	; STORE DISK NUMBER
	INX	H	; PT TO USER NUMBER
	INX	D
	MOV	A,M	; GET USER
	STAX	D	; PUT USER
	MVI	B,8	; AT MOST 8 MORE BYTES
ZDNA1A:
	INX	H	; PT TO NEXT BYTE
	INX	D
	MOV	A,M	; GET NEXT BYTE
	ORA	A	; END OF NAME?
	JZ	ZDNA1B	; <SP> FILL
	STAX	D	; PUT BYTE
	DCR	B	; COUNT DOWN
	JNZ	ZDNA1A
	INX	D	; PT TO FIRST BYTE OF NEXT ENTRY
	JMP	ZDNA1C
ZDNA1B:
	MVI	A,' '	; <SP> FILL
	STAX	D	; PLACE <SP>
	INX	D	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	ZDNA1B
ZDNA1C:
	POP	B	; RESTORE COUNTERS
	LHLD	BENTRY+1	; PT TO BDOS ADDRESS
	MOV	A,H	; CHECK FOR PAGE BEFORE BDOS
	DCR	A	; PAGE BEFORE
	CMP	D	; ARE WE THERE?
	JZ	DNSC2A	; ERROR IF SO, BUT RESTORE UD
	JC	DNSC2A
	XCHG		; HL PTS TO NEXT BUFFER POSITION
	SHLD	DIRNAME	; SAVE PTR
;
;  CONTINUE LOOPING
;
ZDNA2:
	DCR	B	; COUNT DOWN
	JNZ	ZDNA1
;
;  COMPLETION EXIT
;
ZDNA3:
	CALL	FI3$CLOSE	; CLOSE FILE
	CALL	GETUD	; RESTORE USER/DISK
	MVI	B,0	; SET HIGH-ORDER BYTE
	LHLD	CURNAME	; GET PTR TO FIRST ENTRY
	MVI	A,0FFH	; SET NO ERROR
	ORA	A	; SET FLAGS
	POP	D	; RESTORE DE
	RET

;*
;*  ZDNFIND -- SCAN FOR POSSIBLE DISK DIRECTORY NAME
;*	THIS ROUTINE EXAMINES THE DIR: PREFIX FOR EITHER A DIRECTORY NAME
;*		OR THE DU FORM
;*	ON ENTRY, HL PTS TO DIRECTORY NAME ENDING IN ANY VALID DELIMITER
;*		AND A=0 IF DU: FORM NOT ALLOWED (JUST DIR: FORM ALLOWED)
;*	RETURN DISK IN B, USER IN C, NZ IF OK, HL PTS TO COLON
;*	DE IS NOT AFFECTED
;*
ZDNFIND::
	PUSH	D	; SAVE DE
	SHLD	DIRNAME	; SAVE DIRECTORY NAME AWAY
	ORA	A	; DU: FORM ALLOWED?
	JNZ	SVDISK	; SCAN FOR DU: FORM FIRST
;
;  LOOK FOR DIR: FORM
;
NAME:
;
;  SCAN MEMORY-RESIDENT BUFFER IF ONE IS AVAILABLE
;
	LHLD	NDADR	; GET ADDRESS
	MOV	A,L	; CHECK FOR ZERO
	ORA	H
	JZ	NAME2
	INX	H	; PT TO ENTRY COUNT
	MOV	A,M	; GET ENTRY COUNT
	ORA	A	; CHECK FOR NO ENTRIES
	JZ	NAME2	; GOTO DISK IF NO ENTRIES IN MEMORY
	MOV	B,A	; ENTRY COUNT IN B
	INX	H	; PT TO FIRST ENTRY
	XCHG		; DE PTS TO FIRST ENTRY IN MEMORY
;
;  MAIN SCANNING LOOP FOR MEMORY-RESIDENT BUFFER
;
NAME0:
	LHLD	DIRNAME	; HL PTS TO DIR NAME
	PUSH	D	; SAVE PTR TO CURRENT MEMORY ENTRY
	MVI	C,8	; SCAN UP TO 8 BYTES
	INX	D	; SKIP DISK
	INX	D	; SKIP USER
NAME1:
	CALL	DELCK	; CHECK FOR DELIMITER IN DIR NAME
	JZ	NAME1B
	LDAX	D	; GET CHAR IN BUFFER
	CMP	M	; COMPARE AGAINST TARGET NAME
	JNZ	NAME1A
	INX	H	; PT TO NEXT
	INX	D
	DCR	C	; COUNT DOWN
	JNZ	NAME1
	JMP	NAME1C	; FOUND
NAME1A:
	POP	H	; GET PTR TO CURRENT BUFFER ENTRY
	LXI	D,10	; SKIP TO NEXT ENTRY
	DAD	D	; HL PTS TO NEXT ENTRY
	XCHG		; DE PTS TO NEXT ENTRY
	DCR	B	; COUNT DOWN
	JNZ	NAME0
	JMP	NAME2	; COMPLETE FAILURE -- DISK SCAN NOW
;
;  DELIM ENCOUNTERED ON TARGET NAME, SO CHECK FOR SPACE ON BUFFER ENTRY
;    FOR A MATCH
;
NAME1B:
	LDAX	D	; DELIM ENCOUNTERED, SO MUST BE <SP> TO MATCH
	CPI	' '	; CHECK FOR SPACE
	JNZ	NAME1A	; NOT SPACE, SO SKIP TO NEXT
;
;  ENTRY FOUND
;
NAME1C:
	POP	H	; GET PTR TO ENTRY
	JMP	DNSC3A	; EXTRACT DATA AND CONTINUE
;
;  LOOK FOR DIR NAME FILE
;
NAME2:
	LXI	D,FNFCB	; PT TO FCB WHICH CONTAINS DIR FILE NAME
	CALL	INITFCB	; INIT FCB
	MVI	B,0FFH	; SEARCH CURRENT USER
	CALL	ZPFIND	; LOOK FOR NAME FILE
	JZ	DIRNERR	; ERROR IF NOT FOUND
;
;  FOUND DIR NAME FILE, SO LOAD IT AND SCAN IT FOR TARGET NAME
;
	CALL	PUTUD	; SAVE CURRENT USER/DISK
	CALL	LOGUD	; LOG IN NEW USER/DISK
	LXI	D,FNFCB	; PT TO FCB
	CALL	FI3$OPEN	; OPEN FOR INPUT
;
;  LOAD DIR NAME FILE ENTRIES
;
	LDA	MAXN	; GET MAXIMUM NUMBER OF NAMES
	MOV	B,A	; ... IN B
DNSC1:
	LXI	H,ENTRY	; PT TO ENTRY BUFFER
	CALL	GETNAME	; GET NAME FROM DISK
	JNZ	DNSC2	; ERROR EXIT?
	CALL	SCANAME	; SCAN FOR DIR NAME
	JZ	DNSC3	; FOUND ENTRY, SO GET VALUES
	DCR	B	; COUNT DOWN
	JNZ	DNSC1
DNSC2:
	CALL	FI3$CLOSE	; CLOSE FILE
DNSC2A:
	CALL	GETUD	; RESTORE CURRENT USER/DISK
	JMP	DIRNERR	; ERROR SINCE NO ENTRY FOUND
;
;  DIR NAME FOUND, SO GET DISK AND USER INFORMATION
;
DNSC3:
	CALL	FI3$CLOSE	; CLOSE FILE
	CALL	GETUD	; RESTORE CURRENT USER/DISK
DNSC3A:
	MOV	A,M	; GET DISK (HL PTS TO CURRENT ENTRY)
	STA	DISK	; SAVE DISK
	INX	H	; PT TO USER
	MOV	A,M	; GET USER
	STA	USER	; SAVE USER
;
;  SKIP TO COLON AFTER DIR NAME
;
	LHLD	DIRNAME	; PT TO DIR NAME
DNSC4:
	CALL	DELCK	; SKIP TO DELIMITER
	JZ	DIRNX	; EXIT IF SO
	INX	H	; PT TO NEXT
	JMP	DNSC4
;
;  LOOK AT START OF DU: FORM
;	ON ENTRY, HL PTS TO FIRST CHAR OF DIRECTORY NAME
;
SVDISK:
	MOV	A,M	; GET DISK LETTER
	CALL	CAPS	; CAPITALIZE LETTER
	CPI	'A'	; DIGIT?
	JC	USERCK	; IF NO DIGIT, MUST BE USER OR COLON
	SUI	'A'	; CONVERT TO NUMBER
	CPI	MAXDISK	; LIMIT?
	JNC	NAME	; NAME IF OUT OF LIMIT
	STA	DISK	; SAVE FLAG
	INX	H	; PT TO NEXT CHAR
;
;  CHECK FOR USER
;
USERCK:
	MOV	A,M	; GET POSSIBLE USER NUMBER
	CPI	':'	; NO USER NUMBER
	JZ	DIRNX	; EXIT IF SO
	CPI	'?'	; ALL USER NUMBERS?
	JNZ	USERC1
	STA	USER	; SET VALUE
	INX	H	; PT TO AFTER
	MOV	A,M	; MUST BE COLON
	CPI	':'
	JZ	DIRNX	; EXIT
	JMP	DIRNERR	; FATAL ERROR IF NOT COLON AFTER ?
USERC1:
	XRA	A	; ZERO USER NUMBER
	MOV	B,A	; B=ACCUMULATOR FOR USER NUMBER
USRLOOP:
	MOV	A,M	; GET DIGIT
	INX	H	; PT TO NEXT
	CPI	':'	; DONE?
	JZ	USRDN
	SUI	'0'	; CONVERT TO BINARY
	JC	NAME	; NAME IF USER NUMBER ERROR
	CPI	10
	JNC	NAME
	MOV	C,A	; NEXT DIGIT IN C
	MOV	A,B	; OLD NUMBER IN A
	ADD	A	; *2
	ADD	A	; *4
	ADD	B	; *5
	ADD	A	; *10
	ADD	C	; *10+NEW DIGIT
	MOV	B,A	; RESULT IN B
	JMP	USRLOOP
USRDN:
	MOV	A,B	; GET NEW USER NUMBER
	CPI	MAXUSER+1	; WITHIN RANGE?
	JNC	NAME	; NAME IF OUT OF RANGE
	STA	USER	; SAVE IN FLAG
;
;  VALID EXIT -- FOUND IT, SO LOAD BC AND EXIT FLAG; ON ENTRY, HL PTS TO :
;
DIRNX:
	LDA	USER	; RETURN USER IN C, DISK IN B
	MOV	C,A
	LDA	DISK
	MOV	B,A
	INR	B	; DISK A = 1
	MVI	A,0FFH	; SET NO ERROR
	ORA	A	; SET FLAGS
	POP	D	; RESTORE DE
	RET
;
;  INVALID EXIT -- NOT FOUND OR ERROR
;	NO VALID RETURN PARAMETERS (BC, HL)
;
DIRNERR:
	XRA	A	; ERROR CODE
	POP	D	; RESTORE DE
	RET

;*
;*  BUFFERS
;*
FCBPTR:	DS	2	; PTR TO FCB
DISK:	DS	1	; DISK NUMBER
USER:	DS	1	; USER NUMBER
ENTRY:
	DS	11	; ENTRY FROM DISK FILE (DISK, USER, DIR NAME)
DIRNAME:
	DS	2	; PTR TO DIRECTORY NAME
CURNAME:
	DS	2	; PTR TO CURRENT LOCATED NAME

;
;  SCAN DIRECTORY ENTRY PTED TO BY HL FOR DIRECTORY NAME STARTING AT DIRNAME
;	RETURN WITH Z IF FOUND; DO NOT AFFECT BC
;
SCANAME:
	PUSH	B	; SAVE BC
	SHLD	CURNAME	; SET CURRENT NAME PTR
	INX	H	; SKIP DISK
	INX	H	; SKIP USER
	MVI	B,9	; UP TO 9 CHARS
	XCHG		; CURRENT PTR IN DE
	LHLD	DIRNAME	; PT TO TARGET NAME
SCANL:
	LDAX	D	; GET CHAR
	ORA	A	; END OF STRING?
	JZ	SCANL2
	MOV	C,A	; SAVE IN C
	MOV	A,M	; GET TARGET NAME CHAR
	CALL	CAPS	; CAPITALIZE IT
	CMP	C	; COMPARE
	JNZ	SCANL1	; ABORT IF NO MATCH
	CALL	DELCK	; END OF TARGET NAME?
	JZ	SCANL1	; ABORT IF SO
	INX	H	; PT TO NEXT
	INX	D
	DCR	B	; COUNT DOWN
	JNZ	SCANL
;  NOT FOUND RETURN
SCANL1:
	LHLD	CURNAME	; PT TO CURRENT ENTRY
	LXI	B,11	; SKIP 11 BYTES
	DAD	B	; PT TO NEXT ENTRY
	POP	B	; RESTORE BC
	MVI	A,0FFH	; NOT FOUND FLAG
	ORA	A	; SET FLAGS
	RET
;  FOUND RETURN
SCANL2:
	CALL	DELCK	; MUST PT TO DELIMITER IF MATCH
	JNZ	SCANL1	; ABORT IF NOT
	LHLD	CURNAME	; PT TO FOUND ENTRY
	POP	B	; RESTORE BC
	XRA	A	; FOUND
	RET	

;
;  GET NAME FROM FILE 3 INTO BUFFER PTED TO BY HL
;	DO NOT AFFECT BC OR HL; RET W/NZ IF ERROR
;
GETNAME:
	PUSH	B	; SAVE BC
	PUSH	H	; SAVE HL
	CALL	F3$GET	; GET DISK LETTER
	JNZ	GNERR	; ERROR?
	SUI	'A'	; CONVERT TO NUMBER
	MOV	M,A	; STORE IT
	INX	H	; PT TO NEXT
	MVI	B,10	; GET USER AND DIRECTORY NAME
GETN1:
	CALL	F3$GET	; GET BYTE
	JNZ	GNERR	; ERROR?
	MOV	M,A	; STORE IT
	INX	H	; PT TO NEXT
	DCR	B	; COUNT DOWN
	JNZ	GETN1
	XRA	A	; OK
GNERR:
	POP	H	; RESTORE HL
	POP	B	; RESTORE BC
	RET

;
;  CHECK CHAR PTED TO BY HL FOR A DELIMITER
;    RET WITH Z FLAG SET IF DELIMITER
;
DELCK:
	MOV	A,M	; GET CHAR
	CALL	CAPS	; CAPITALIZE
	ORA	A	; 0=DELIM
	RZ
	CPI	' '+1	; <SP>+1
	JC	DELCK1	; <SP> OR LESS
	CPI	'='
	RZ
	CPI	5FH	; UNDERSCORE
	RZ
	CPI	'.'
	RZ
	CPI	':'
	RZ
	CPI	';'
	RZ
	CPI	','
	RZ
	CPI	'<'
	RZ
	CPI	'>'
	RET
DELCK1:
	CMP	M	; COMPARE WITH SELF FOR OK
	RET

;
;  PUTUD -- SAVE CURRENT USER/DISK FOR LATER RESTORE
;	NO REGS AFFECTED
;
PUTUD:
	PUSH	B	; SAVE REGS
	PUSH	PSW
	PUSH	D
	PUSH	H
	MVI	C,25	; GET CURRENT DISK
	CALL	BDOS
	STA	CDISK	; SET CURRENT DISK
	MVI	E,0FFH	; GET USER
	MVI	C,32	; GET CURRENT USER
	CALL	BDOS
	STA	CUSER	; SET CURRENT USER
	POP	H	; RESTORE REGS
	POP	D
	POP	PSW
	POP	B
	RET

;
;  BUFFERS
;
CDISK:
	DS	1	; CURRENT DISK
CUSER:
	DS	1	; CURRENT USER

;
;  GETUD -- RESTORE USER/DISK FROM PREVIOUS PUTUD
;
GETUD:
	PUSH	H	; SAVE REGS
	PUSH	D
	PUSH	B
	PUSH	PSW
	LDA	CDISK	; SELECT DISK
	MOV	E,A
	MVI	C,14	; SELECT
	CALL	BDOS
	LDA	CUSER	; SELECT USER
	MOV	E,A
	MVI	C,32	; SELECT
	CALL	BDOS
DONE:
	POP	PSW	; GET REGS
	POP	B
	POP	D
	POP	H
	RET

;
;  LOGUD -- LOG IN USER/DISK, WHICH C=USER AND B=DISK
;
LOGUD:
	PUSH	H	; SAVE REGS
	PUSH	D
	PUSH	B
	PUSH	PSW
	MOV	E,C	; SELECT USER
	MVI	C,32
	CALL	BDOS
	MOV	E,B	; SELECT DISK
	MVI	C,14
	CALL	BDOS
	JMP	DONE


	END
