;
; DOS DIRECTORY ROUTINES
;
;	OPEN A DIRECTORY (FOR USER)
;
LSTDIR	LDY	#$80-11
SAVFNB	LDA	FNAME-$80+11,Y
	STA	(FMSBPT),Y
	INY
	BPL	SAVFNB
	JSR	SFDIR		;FIND A MATCH IN THE DIRECTORY
	BCS	ENDDIR		;IF NO MORE MATCHES, REPORT FREE SPACE
NXTDIR	JSR	FMTDIR		;ENTRY FOUND, FORMAT INTO A TEXT STRING
	LDA	CURFNO
	STA	FCBFNO,X	;SAVE THE FILE NUMBER OF THE ENTRY FOUND
GODONE	JMP	DONE		;AND RETURN
;
GOTEOD	DEC	DATBYT		;CONVERT EOL TO $9B (REAL EOL)
	STA	CURLEN,X	;AND FINISH UP
	BNE	GODONE
;
DIRRD	LDY	#$80-11
RSTFNB	LDA	(FMSBPT),Y	;FETCH BYTES OF PREVIOUSLY PARSED DIRECTORY ENT
	STA	FNAME-$80+11,Y
	INY
	BPL	RSTFNB
	LDA	CURLEN,X
	BMI	DIREOF		;EOF IF WE ALREADY REPORTED FREE SPACE
	TAY
	LDA	(FMSBPT),Y
	STA	DATBYT
	INC	CURLEN,X
	CMP	#$9C
	BEQ	GOTEOD
	CMP	#$9B		;IS THIS END OF LINE?
	BNE	GODONE		;IF NOT, CONTINUE FETCHING OLD BYTES
	LDA	FCBFNO,X
	CMP	CURFNO
	BNE	DMSTRD
	CPX	DIUNIT
	BEQ	DRDNRQ
DMSTRD	JSR	RRDIR		;IF SO, INSURE DIRECTORY BLOCK IS IN MEMORY
DRDNRQ	JSR	CSFDIR		;AND FIND THE NEXT ENTRY
	BCC	NXTDIR		;IF FOUND, LOOP BACK AND FORMAT IT
;
;  NO MORE ENTRIES, REPORT FREE SECTORS LAST
;
ENDDIR	JSR	RBITMP		;READ THE VTOC DATA
	LDY	#0
	STY	CURMAP		;FORCE A REREAD NEXT TIME
	LDA	MAPBUF+3
	LDX	MAPBUF+4	;AND STUFF THE BUFFER WITH NO. OF FREE SECTORS
	JSR	CVTDEC
	LDX	#-14
FSECL	LDA	FSECM+14-256,X	;FOLLOWED BY THE "FREE SECTORS" TEXT
	STA	(FMSBPT),Y
	INY
	INX
	BNE	FSECL
	BEQ	GODONE
;
DIREOF	JMP	RETEOF		;NO MORE LINES, RETURN EOF INDICATION
;
FSECM	DB	' FREE SECTORS',$9C
;
;  FORMAT A DIRECTORY ENTRY FOR BASIC, ETC.
;
FMTDIR	LDY	#' '
	LDX	DIRDSP
	LDA	DIRBUF,X
	PHA
	AND	#$20
	BEQ	D0E35
	LDY	#'*'	;IF SO, MARK AS LOCKED
D0E35	TYA
	LDY	#0
	STA	(FMSBPT),Y
	PLA
	LDY	#' '
	AND	#$10
	BEQ	NOTDIR
	LDY	#':'
NOTDIR	TYA
	LDY	#1
	STA	(FMSBPT),Y
CPYNAML	INY
	LDA	DIRBUF+5,X
	STA	(FMSBPT),Y
	INX
	CPY	#13
	BCC	CPYNAML
;
	LDA	#' '
	STA	(FMSBPT),Y
	LDY	DIRDSP
	LDA	DIRBUF+1,Y
	LDX	DIRBUF+2,Y
	LDY	#14	;SECTOR COUNT STARTS HERE
;
;  CONVERT A 16-BIT INTEGER TO A 4 OR 5 DIGIT NUMBER
;
CVTDEC	STX	TMP2
	STA	TMP1
	LDX	#HIGH[10000]
	LDA	#LOW[10000]
	JSR	MKDGT2
	CMP	#'0'
	BNE	SKIP5
	DEY
SKIP5	LDX	#HIGH[1000]
	LDA	#LOW[1000]
	JSR	MKDGT2
	LDA	#100		;FOR THE SHORT STUFF
	JSR	MAKDGT
	LDA	#10
	JSR	MAKDGT
	TXA
	ADC	#'0'+10
	STA	(FMSBPT),Y
	INY
	LDA	#$9B		;TERMINATE LINE
	STA	DATBYT
	STA	(FMSBPT),Y
	LDA	#0
	LDX	CURFCB
	STA	CURLEN,X
	RTS
;
;  CREATE A DIGIT AND STORE IT INTO THE DIRECTORY BUFFER
;
MAKDGT	LDX	#0		;IF SUBTRAHEND < 256, ZERO UPPER BYTE
MKDGT2	STX	DIRDSP
	STA	DIRSEC
	STY	DATBYT
	LDY	#'0'
	SEC
DGTLP2	LDA	TMP1
	SBC	DIRSEC
	TAX
	LDA	TMP2
	SBC	DIRDSP
	BCC	DGTXIT
	STA	TMP2
	STX	TMP1
	INY
	BCS	DGTLP2
;
DGTXIT	TYA
	LDY	DATBYT
	STA	(FMSBPT),Y
	INY
	RTS
;
;  PARSE A FILE NAME WITH WILD CARD CHARACTERS ('*' AND '?')
;
GETNM2	iny			;look for ">" in
	lda	(ICBALZ),y	;the start of
	cmp	#'>'		;the filename
	beq	GETNAM		;(for SpartaDOS compatibility)
	dey			;[Bob Puff]
	bne	GETNAM		;branch always
;
GETFNM	LDX	CURFCB
	LDY	#HIGH[361]
	LDA	#LOW[361]
	JSR	SETDIR
	INY
	LDA	(ICBALZ),Y
	INY
	CMP	#':'		;DEFAULT DIRECTORY?
	BNE	GETNM2		;IF NOT, CHECK FOR SPARTA ">"
	DEY
	STY	TMP1
	LDY	DEFAULT
	STY	ICDNOZ
	TYA
	STA	ICDNO,X
	JSR	SETUPD
	LDA	CDIREC
	LDY	CDIREC+1
	JSR	SETDIR
	LDY	TMP1
;
GETNAM	LDX	#-11
	INY
AFTSTR	LDA	(ICBALZ),Y
	CMP	#'*'
	BNE	TSTPER
	LDA	#'?'
	INY
QLOOP	STA	FNAME+11-256,X
	INX
	BPL	TOXITC		;END OF EXTENSION?
PERFND	CPX	#-3		;END OF FILE NAME?
	BNE	QLOOP		;NO MORE -?-S
	BEQ	AFTSTR
;
TSTPER	CMP	#'.'		;A PERIOD?
	BNE	TSTCHR		;IF NOT, CHECK FOR INDIVIDUAL CHARACTERS
	LDA	#' '		;IF SO, FILL WITH SPACES
	INY
	BNE	PERFND
;
TSTCHR	CMP	#'?'
	BCC	ENDCHR		;IF < '?', CHECK FOR DIGIT
	CMP	#'Z'+1		;ELSE, UPPER CASE LETTER, '?', OR '@'?
	BCC	GOTCHR
	CMP	#'_'
	BCC	ENDCHR		;IF CARET, BACKSL. OR BRACKETS
	CMP	#'z'+1		;LOWER CASE, ACCENT OR UNDERSCORE?
	BCC	GOTCHR
ENDCHR	CPX	#-11		;IF FIRST CHAR, ERROR
	BEQ	ERRCHR		;NO BYTES IN FILE NAME
	CMP	#'0'		;ELSE, A DIGIT?
	BCC	FILLNM		;IF NOT, THIS IS END OF NAME
	CMP	#':'
	BCS	FILLNM
;
GOTCHR	STA	FNAME+11-256,X
	INY
	INX
	BMI	AFTSTR
;
TOXITC	LDA	(ICBALZ),Y
TSTDIR	CMP	#':'		;LOOK FOR SUBDIRECTORY
	BEQ	MYDIR		;IF MYDOS SYNTAX
	CMP	#'>'		;OR SPARTA SYNTAX
	BNE	XITCHR		;IF FINISHED, RESTORE FCB PTR TO X AND EXIT
MYDIR	STY	TMP2
	JSR	SFDIR		;ELSE, FIND FILE
	BCS	FNER1		;NO SUCH FILE
	JSR	TONXDR
	BEQ	FNER1
	LDY	TMP2
	BNE	GETNAM
FNER1	LDA	#174	;IF NOT, RETURN ERROR 174
	DB	$2C	;BIT ABS (SKIP 2 BYTES)
;
ERRCHR	LDA	#165
	JMP	AEXIT
;
FILLNM	PHA
	LDA	#' '
FILLLP	STA	FNAME+11-256,X
	INX
	BMI	FILLLP
	PLA
	JMP	TSTDIR
;
;  RETURN WITH NON-ZERO FLAG IF FILE IS A DIRECTORY
;
TONXDR	LDA	#$10		;FILE FOUND, A DIRECTORY?
	JSR	GETFLAG
	BEQ	TONXIT		;IF NOT, SET ZERO FLAG
	LDA	DIRBUF+3,Y	;IF SO, MOVE POINTERS TO THE NEW LEVEL
	STA	DIRBAS,X
	LDA	DIRBUF+4,Y
	STA	DIRBAS+1,X
	LDA	#$10		;AND CLEAR THE ZERO FLAG
TONXIT	RTS
;
;  ENTER A NAME INTO THE DIRECTORY AT DIRBUF[DIRDSP]
;
ENTNAME	PHP
	LDX	#-11
	LDY	DIRDSP
NAMELP	LDA	FNAME+11-256,X	;LOAD THE MASK CHARACTER
	CMP	#'?'
	BNE	STORIT		;IF NOT '?', SAVE IT AS IT APPEARS
	PLP
	PHP
	BCC	NOSTOR		;IF CY CLEAR, LEAVE THE CHARACTERS UNCHANGED
	LDA	#' '		;IF CY SET, CONVERT '?'S TO SPACES
STORIT	STA	DIRBUF+5,Y
NOSTOR	INY
	INX
	BMI	NAMELP
	PLP
	LDY	DIRDSP
XITCHR	LDX	CURFCB
	RTS
;
SFDIR	JSR	WBITMP		;INSURE BIT MAP IS SAFE
	LDX	#255
	STX	HOLFN
	STX	CURFNO
	INX
	STX	DAUX2
	INX
	STX	DAUX1
	LDX	#READ
	STX	DCOMND
	JSR	SYSSET		;SET UP POINTERS FOR SYSTEM BUFFER I/O
;
	LDA	ICDNOZ
	CMP	RAMDKU
	BEQ	CSFDIR		;IF RAMDISK, FORGET DENSITY CHECK
	ldx	CURFCB		;IF A ROOT DIRECTORY ACCESS, READ BOOT SECTOR
	lda	DIRBAS,X	;IF IN A SUBDIRECTORY, ASSUME DENSITY IS OK
	cmp	#LOW[361]	;[Bob Puff]
	bne	CSFDIR
;;;	lda	DIRBAS+1,X	;Only occasionally will we get an extra read!
;;;	cmp	#HIGH[361]
;;;	bne	CSFDIR
;
	JSR	DSKINV		;ELSE, READ THE FIRST BOOT SECTOR
	BMI	ERRX
	JSR	INVUNIT		;UPDATE DRIVE CONFIGURATION
;
CSFDIR	INC	CURFNO		;READ NEXT 16-BYTE DIR. BLOCK
	LDA	CURFNO
	JSR	BSECDS		;CONVERT TO SECTOR AND DISPLACEMENT
XITCH1	BCS	XITCHR
	BNE	NOREAD		;IF DISP>0, PROCESS BLOCK
	JSR	RDIRBK		;IF DISP=0, READ SECTOR
;
NOREAD	LDY	DIRDSP
	LDA	DIRBUF,Y
	BEQ	FNDOLD		;ZERO IS END OF DIRECTORY (NO MORE ENTRIES)
	BMI	FNDOLD		;NEGATIVE IS EMPTY SLOT (MAY HAVE MORE ENTRIES)
;
;  HANDLE DOS 2.5 FILES
;
	and	#$DF		;preserve lock flag
	cmp	#3		;is this DOS 2.5 + file?
	bne	NOD25		;nope
	lda	#$41		;otherwise, kludge the
	eor	DIRBUF,Y	;flag to make $42
	sta	DIRBUF,Y	;and save lock.
;
NOD25	AND	#$01		;IGNORE ANY FILE THAT IS MARKED "OPEN"
	BNE	CSFDIR
	LDX	#-11
CPNXCH	LDA	FNAME+11-256,X
	CMP	#'?'
	BEQ	WCMTCH		;EVERYTHING MATCHES "?"
	CMP	DIRBUF+5,Y
	BNE	CSFDIR		;NO MATCH, LOOK AT THE NEXT DIRECTORY ENT
WCMTCH	INY
	INX
	BMI	CPNXCH
	CLC
	BCC	XITCHR		;ENTRY FOUND, RETURN WITH CY=0
;
FNDOLD	LDX	HOLFN
	BPL	KPOLD		;IF AN EMPTY SLOT IS ALREADY FOUND, DO NOTHING
	LDX	CURFNO
	STX	HOLFN		;ELSE SAVE THIS ONE, ITS THE FIRST!
KPOLD	TAX
	BMI	CSFDIR		;IF NOT END OF THE DIRECTORY, KEEP LOOKING
ERRX	SEC
	BCS	XITCH1		;ELSE, ENTRY NOT FOUND, RETURN WITH CY=1
;
; DOS I/O ROUTINES
;
;  DISK SECTOR I/O ROUTINES
;
WRDISK	SEC			;FMS DISK WRITE ENTRY
RWDISK	LDY	FMSBPT		;DATA SECTOR READ/WRITE ENTRY
	LDA	FMSBPT+1
	JSR	BUFSET
	LDA	CURSEC+1,X
	LDY	CURSEC,X
FMDKIO	PHP
	LDX	DUNIT
	CPX	RAMDKU
	BEQ	RDKIO1
	PLP
	pha			;ALLOW FOR DENSITY CHANGE IN FORMAT, ETC.
	lda	SECSIZ-1,X	;[Bob Puff]
	tax
	pla
	JMP	DKIO
;
RDKIO1	JMP	RDKIO		;ABSOLUTE DISK I/O ROUTINE WAS MOVED TO LOW RAM
;
EXTEND	JSR	ALLOC
	LDA	FCBOTC,X
	LSR	A
	BCC	REWRIT
	DEC	FCBOTC,X
	JSR	WTRICK
	JMP	WRTTST
;
REWRIT	LDY	LNKSEC+1,X
	LDA	LNKSEC,X
	JSR	SAVLNK
WRTTST	BMI	RTBADF
	INC	SECCNT,X
	BNE	TONXT
	INC	SECCNT+1,X
;
TONXT	LDA	LNKSEC,X	;MAKE NEXT SECTOR
	STA	CURSEC,X	;NEW CURRENT SEC.
	LDA	LNKSEC+1,X
	STA	CURSEC+1,X
	LDA	#0
	STA	LNKSEC,X	;ZERO LINK
	STA	LNKSEC+1,X
LENSET	STA	CURLEN,X	;ZERO CURRENT OFFSET
	LDA	DLINK		;GET THE LINK LOC.
	STA	MAXLEN,X	;MAKE IT MAX. LEN.
	CLC			;CLEAR CY FOR LATER READ
	RTS
;
RDNXTS	LDA	FCBFLG,X
	BEQ	CHASE
;
WRNXTS	LDA	FCBFLG,X
	BMI	EXTEND
	ASL	A
	BPL	RDNXTS
	ASL	A
	STA	FCBFLG,X
	JSR	WRDISK
	BPL	RDNXTS
;
RTBADF	JMP	HWERR		;RETURN HARDWARE ERROR CODE IF PRESENT
;
SAVLNK	PHA
	TYA
	LDY	DLINK
	STA	(FMSBPT),Y
	PLA
	INY
	STA	(FMSBPT),Y
	INY
	LDA	CURLEN,X
NOBIT	STA	(FMSBPT),Y
	LDY	FCBOTC,X
	BMI	LEN16		;16-BIT LENGTH?
	LDA	FCBFNO,X
	ASL	A
	ASL	A
	LDY	DLINK
	ORA	(FMSBPT),Y
	STA	(FMSBPT),Y
LEN16	JMP	WRDISK
;
WTRICK	LDA	LNKSEC,X
	STA	SAVSEC,X
	LDA	LNKSEC+1,X
	STA	SAVSEC+1,X
	STX	LSTIOCB
	LDA	CURSEC,X
	STA	LSTSEC
	LDA	CURSEC+1,X
	STA	LSTSEC+1
	JMP	WRDISK
;
INSTRT	JSR	INITYP
;
CHASE	LDA	LNKSEC,X
	ORA	LNKSEC+1,X
	BEQ	NOLINK
	JSR	TONXT		;SET CY=0, FUNC=READ
	JSR	RWDISK
	BMI	RTBADF		;CANNOT READ SO BAD FILE NUMBER(ERR=164)
	LDY	DLINK
	LDA	FCBOTC,X	;16-BIT LINK?
	ORA	#$7F
	BMI	LNGLNK
	LDA	(FMSBPT),Y
	LSR	A
	LSR	A
	CMP	FCBFNO,X
	BNE	XLINKED
	LDA	#$03
LNGLNK	AND	(FMSBPT),Y
	STA	LNKSEC+1,X
	INY
	LDA	(FMSBPT),Y
	STA	LNKSEC,X
	INY
	LDA	(FMSBPT),Y
	STA	MAXLEN,X
DRDXIT	CLC
	RTS
;
XLINKED	LDA	ICCOM,X
	CMP	#FMTCMD		;IS THIS A FORMAT?
	BNE	FNOERR
NOLINK	SEC
	RTS
;
;	READ OR WRITE A DIRECTORY BLOCK
;
RRDIR	LDA	FCBFNO,X
;
SDIRBK	STA	CURFNO
RDCFNO	LDA	CURFNO
	JSR	BSECDS
;
RDIRBK	JSR	WBITMP		;TAKE CONTROL OF SYSTEM BUFFER
	CLC
	DB	$A9		;LDA # (SKIPS 1 BYTE)
WDIRBK	SEC
RWDBK	PHP
	LDX	CURFCB		;PUT FCB NO. IN X
	STX	DIUNIT		;SAVE THE DIR. BUFFER IOCB
	JSR	SYSSET
	CLC
	LDA	DIRSEC
	ADC	DIRBAS,X
	TAY
	LDA	DIRBAS+1,X
	ADC	#0		;MULTIPLE DIRS. REQ. THIS [ChasM]
	PLP
SYSRW	JSR	FMDKIO
	BPL	DRDXIT
	LDA	#163		;BIT MAP R/W ERROR, RETURN SYSTEM ERR. CODE
	DB	$AE		;SKIP 2 BYTES
;
FNOERR	lda	#164
	sta	DSTATS
	jmp	HWERR		;FILE NUMBER MISMATCH
;
;	READ OR WRITE THE DISK VTOC (BIT MAP)
;
RBITMP	LDA	CURMAP
	CMP	ICDNOZ
	BEQ	MAPXIT		;SKIP READ IF WHAT WE WANT IS ALREADY THERE
	JSR	WBITMP		;ELSE, REAL I/O, SAVE CURRENT BUFFER CONTENTS
;
	LDA	#0
	TAY
ZMAP	STA	MAPBUF,Y	;ZERO ENTIRE 512
	STA	MAPBUF+256,Y	;BYTES OF MAP BUF.
	DEY
	BNE	ZMAP
	CLC
	JSR	RWBMAP		;THEN READ 128 OR 256 BYTES OF VTOC DATA
;
	LDY	#$FF
	STY	DIUNIT		;INDICATE MAP (NOT DIR) IS LOADED
	STY	MAP2		;INDICATE SECOND PAGE OF MAP IS UNLOADED
	INY
	STY	CHGMAP		;INDICATE MAP IS UNCHANGED
	INY
	STY	MAP2MOD
	STY	CURMP
;
MAPCLR	STA	CURMAP		;AND SAVE DRIVE NUMBER MAP APPLIES TO
MAPXIT	RTS
;
WBITMP	LDA	CHGMAP
	BEQ	MAPCLR		;IF MAP NOT CHANGED, SKIP WRITING IT
	STA	DUNIT
FMTMAP	LDA	#0
	STA	CHGMAP		;ELSE MARK IT UNUSED
	STA	CURMAP
	lda	DUNIT		;save drive # [Bob Puff]
	pha
	SEC
	JSR	RWBMAP
 	pla			;then restore it [Bob Puff]
	sta	DUNIT
;
WRNXTM	LDA	MAP2MOD
	BNE	NOMPI2		;IF THE PAGE BUFFER IS CLEAN, JUST EXIT
	LDA	#$FF		;ELSE, WRITE IT TO DISK
	PHA
	LDA	MAP2
	INC	MAP2MOD
	SEC
	BCS	MUSTWM
;
RDNXTM	CMP	MAP2		;READ A PAGE INTO THE SECOND PAGE BUFFER
	BEQ	NOMAPI		;IF IT IS ALREADY THERE, JUST EXIT
	PHA
	JSR	WRNXTM		;ELSE, WRITE THE CURRENT PAGE (IF NECESSARY)
	PLA			;AND READ THE NEW ONE
	PHA
	CLC			;BY FALLING INTO MUSTWM WITH CY=0
;
MUSTWM	PHA
	LDA	#HIGH[MAPBUF+256]
	LDY	#LOW[MAPBUF+256]
	JSR	BUFSET		;SET UP THE BUFFER POINTER FOR 2ND PAGE
	PLA			;  OF THE VTOC BUFFER
	JSR	MAPIOC		;ISSUE I/O REQUESTS
	PLA
	STA	MAP2		;UPDATE SECOND BUFFER ID BYTE
NOMAPI	RTS
;
RWBMAP	JSR	SYSSET		;SET UP BUFFER POINTERS FOR SYSTEM BUF I/O
	LDA	#0
MAPIOC	PHP
	pha 
	ldx	DUNIT		;NOTE: THE CURRENT I/O MAY NOT BE TO THE
	lda	SECSIZ-1,X	;FCB BEING ACCESSED!
	tax			;[Bob Puff]
	pla
	cpx	#2		;256 BYTE SECS?
	beq	MAPDDS
	ASL	A		;128, CHANGE PAGE NUMBER TO PAIR NUMBER
MAPDDS	EOR	#$FF
	SEC
	ADC	#LOW[360]
	TAY
	cpx	#2		;128 OR 256 BYTE SECTORS?
	beq	DDMAPX		;IF 128, READ 2 SECTORS TO FILL BUFFER
	LDA	#HIGH[360]
	PLP
	PHP
	JSR	SYSRW		;READ OR WRITE THE FIRST SECTOR
	LDA	MAPBUF
	CMP	#3		;IF DOS 2.0 DISK, READ ONE SECTOR
	BCC	XITMBF		;EVEN IN SINGLE DENSITY
	JSR	STEPBP
	DEY
DDMAPX	LDA	#HIGH[360]
	PLP
	PHP
	JSR	SYSRW		;READ OR WRITE THE SECOND (OR ONLY) SECTOR
XITMBF	PLP
NOMPI2	LDA	ICDNOZ
	STA	DUNIT		;RESTORE THE USER DRIVE NUMBER TO DUNIT,
	RTS			;SINCE I/O MAY HAVE BEEN TO ANOTHER DRIVE
;
SYSSET	LDA	#HIGH[MAPBUF]
	LDY	#LOW[MAPBUF]
	JMP	BUFSET
;
;  ROUTINE TO STEP TO THE NEXT DIRECTORY ENTRY (UNTIL WE RUN OUT)
;
BSECDS	LDY	#0
	STY	DIRDSP
	LSR	A
	ROR	DIRDSP
	LSR	A
	ROR	DIRDSP
	LSR	A
	ROR	DIRDSP		;(FILE NUMBER MOD 8) * 16 IS OFFSET IN SECTOR
	STA	DIRSEC		;FILE NUMBER/8 IS SECTOR OFFSET
;
	CMP	#8		;END OF DIRECTORY?
	DEY
	BCS	BSECXT
	ROR	DIRDSP
BSECXT	RTS
