;FILE2/ASM
*TITLE	'FILE2 - MODEL II FILE SYSTEM - 1.0'
;
;	FILE2 IS THE RESIDENT MODEL II FILE SYSTEM.
;	RANDOM, SEQUENTIAL & VARIABLE LENGTH FILE
;	RECORDS ARE SUPPORTED.
;
;	THIS PACKAGE CONSISTS OF THE FOLLOWING ROUTINES:
;
;		$LOCATE - LOCATE CURRENT RECORD NUMBER
;		$READNX - GETS NEXT RECORD (SEQUENTIAL)
;		$DIRRD	- READS SPECIFIED RECORD (DIRECT)
;		$WRITNX - WRITES NEXT RECORD (SEQUENTIAL)
;		$DIRWR	- WRITES SPECIFIED RECORD (DIRECT)
;		$DIRRED - READ DIRECTORY FOR FILE
;		$DIRWRT - WRITE DIRECTORY FOR FILE
;		$CIOF	- INPUT NEXT BYTE (SEQUENTIAL)
;		$POSN	- POSITION TO DIRECT RECORD
;		$REWD	- REWIND FILE
;		$PEOF	- POSN TO END-OF-FILE
;		$BKSP	- BACKSPACE LOGICAL RECORD
;
IODISK	EQU	10H		;DISK I/O OPERATION
;
*EJECT
;	$LOCATE - LOCATE CURRENT RECORD
;
LOCATE	CALL	SAVER		;SAVE REG
	LD	D,(IX+07)	;D = NRN BYTE
	LD	B,(IX+08)	;B = MSB
	LD	H,(IX+09)	;L = NSB
	LD	L,(IX+10)	;BHLD = FILE LENGTH
	LD	A,(IX+15)	;GET LRL
	OR	A		;PHY REC?
	JR	Z,LOCRC2	;IF YES
;
LOCRC1	CALL	TDIVD		;MSB/LRL
	LD	C,H		;MSB RESULT
	LD	B,L		;NSB RESULT
	LD	H,A
	LD	L,D		;HL = LSB
	LD	A,(IX+15)	;LRL
	CALL	DDIVD		;LSB/LRL
	LD	H,B
	LD	B,C		;BHL = RESULT
;
LOCRC2	BIT	3,(IX+2)	;EXTENDED OPEN?
	POP	DE		;GET RET ADD
	EX	(SP),HL 	;HL => RESULT
	JR	Z,LOCRC3	;IF NOT
	LD	(HL),B		;SET MSB
	POP	BC		;GET LSB'S
	INC	HL		;HL => NSB
	LD	(HL),B		;SET NSB
	INC	HL		;HL => LSB
	LD	(HL),C		;SET LSB
	DEC	HL
	DEC	HL		;HL => DATA
	PUSH	HL		;SAVE => DATA
LOCRC3	PUSH	DE		;RET ADD
	RET
;
*EJECT
;	$POSN - POSITION TO RECORD
;
;	ENT	BC =>	RECORD NUMBER
;		IX =>	FCB
;
POSN	CALL	SAVER		;SAVE REG
POSN0	SET	6,(IX+1)	;RANDOM ACCESS
	LD	H,B
	LD	L,C		;HL = REC NUM
	LD	BC,00FFH	;BHL = REC NUM
	BIT	3,(IX+2)	;EXTENDED OPEN?
	JR	Z,POSN1 	;IF NOT
;
	LD	B,(HL)		;B = MSB
	INC	HL		;NEXT
	LD	A,(HL)		;A = NSB
	INC	HL		;NEXT
	LD	L,(HL)		;L = LSB
	LD	H,A		;BHL = REC NUM
	LD	C,B		;C = MSB
;
;	CHECK FOR SPECIAL EOF POSN
;
POSN1	LD	A,H		;MSB
	AND	L		;NSB
	AND	C		;LSB
	INC	A		;FFFFFF?
	JR	Z,PEOF1 	;POSN TO EOF
;
;	CALCULATE PHYSICAL RECORD
;
	BIT	7,(IX+1)	;BLOCKED?
	JR	Z,POSN4 	;IF NOT
	LD	A,(IX+15)	;LRL
	CALL	TMULT		;LRN * LRL
;
;	ACTUAL RECORD POSN HERE
;
;	ENT	BHL =	PHY RECORD
;		  A =	NRN BYTE
;
POSN2	LD	(IX+7),A	;NRN BYTE
	BIT	5,(IX+1)	;BUFFER = NRN?
	JR	NZ,POSN4	;IF NOT
	LD	A,B		;GET MSB
	CP	(IX+8)		;AT NRN?
	JR	NZ,POSN3	;IF NOT
	LD	A,H		;GET NSB
	CP	(IX+9)		;AT NRN?
	JR	NZ,POSN3	;IF NOT
	LD	A,L		;GET LSB
	CP	(IX+10) 	;AT NRN?
	JR	Z,POSN4 	;IF YES
;
POSN3	PUSH	BC		;SAVE NEW NRN
	PUSH	HL		;SAVE NEW NRN
	CALL	DBLOCK		;WRITE RESIDUAL DATA
	POP	HL		;GET NEW NRN
	POP	BC
	RET	NZ		;IF ERROR
	SET	5,(IX+1)	;BUFFER <> NRN
;
POSN4	LD	(IX+8),B	;NEW NRN MSB
	LD	(IX+9),H	;NEW NRN NSB
	LD	(IX+10),L	;NEW NRN LSB
	JP	CKEOF		;CHECK EOF
;
*EJECT
;	$REWD - POSN TO BEGINING
;
;	ENT	DE =>	FCB
;
REWD	CALL	SAVER		;SAVE REG
	LD	B,A
	LD	L,A
	LD	H,A		;BHL = NRN
	JR	POSN2		;POSN TO RECORD
;
;	$PEOF - POSN TO FILE END
;
;	ENT	DE =>	FCB
;
PEOF	CALL	SAVER		;SAVE REG
PEOF1	LD	A,(IX+11)	;A - ERN BYTE
	LD	B,(IX+12)
	LD	H,(IX+13)
	LD	L,(IX+14)	;BHL = ERN
	JR	POSN2		;POSN TO RECORD
;
;	$BKSP - BACKSPACE LOGICAL RECORD
;
;	ENT	DE =>	FCB
;
BKSP	CALL	SAVER		;SAVE REG
	LD	B,(IX+8)
	LD	H,(IX+9)
	LD	L,(IX+10)	;BHL = NRN
	BIT	7,(IX+1)	;BLK'D?
	JR	Z,BKSP1 	;IF NOT
	LD	A,(IX+15)	;LRL
	NEG			;-LRL
	ADD	A,(IX+7)	;NRN BYTE
	JR	C,POSN2 	;POSN TO RECORD
;
BKSP1	PUSH	AF		;SAVE BYTE
	LD	A,-1
	DEC	L		;BKSP REC
	CP	L		;CRY?
	JR	NZ,BKSP2	;IF NOT
	DEC	H		;BKSP REC
	CP	H		;CRY?
	JR	NZ,BKSP2	;IF NOT
	DEC	B		;BKSP REC
BKSP2	POP	AF		;GET BYTE
	JR	POSN2		;POSN!
;
*EJECT
;	$READNX - READ NEXT RECORD
;
;	ENT	DE =>	FCB
;
READNX	CALL	SAVER		;SAVE REGISTERS
	BIT	7,(IX+1)	;BLK'D?
	JP	Z,RDREC 	;IF NOT
	BIT	7,(IX+2)	;FIXED?
	JR	Z,READ1 	;IF YES
	LD	L,(IX+5)
	LD	H,(IX+6)	;HL => USER BUFFER
	PUSH	HL
	CALL	RDBYTE		;READ RECORD LENGTH
	POP	HL
	RET	NZ		;IF ERROR
	LD	(HL),A		;SET LRL
	INC	HL		;HL => DATA
	LD	B,A		;B = REC LENGTH
	DEC	B		;CORRECT
	JR	NZ,READ2	;HAVE DATA
	RET
;
;	$WRITNX - WRITE NEXT RECORD
;
;	ENT	DE =>	FCB
;
WRITNX	CALL	SAVER		;SAVE REGISTERS
	BIT	7,(IX+1)	;BLK'D?
	JP	Z,WRREC 	;IF NOT
	BIT	7,(IX+2)	;FIXED?
	JR	Z,WRITE1	;IF YES
	LD	L,(IX+5)
	LD	H,(IX+6)	;HL => USER BUFFER
	LD	B,(HL)		;GET LRL
	INC	HL		;HL => DATA
	DEC	B		;CORRECT
	JR	NZ,WRITE2	;HAVE DATA
	RET
;
*EJECT
;	$DIRRD - DIRECT RECORD READ
;
;	ENT	BC =>	RECORD NUMBER
;		DE =>	FCB
;
DIRRD	CALL	SAVER		;SAVE REG
	CALL	POSN0		;POSN TO RECRD
	RET	NZ		;IF ERROR
	BIT	7,(IX+1)	;BLK'D?
	JP	Z,RDREC 	;IF NOT
;
READ1	LD	B,(IX+15)	;LRL
	LD	L,(IX+5)
	LD	H,(IX+6)	;HL => USER BUFFER
;
READ2	PUSH	BC		;SAVE
	PUSH	HL
	CALL	RDBYTE		;READ BYTE
	POP	HL		;RESTORE
	POP	BC
	RET	NZ		;IF ERROR
	LD	(HL),A		;DATA => USER
	INC	HL		;NEXT
	DJNZ	READ2		;TIL DONE
	XOR	A		;NO ERRORS
	RET
;
;	$DIRWR - DIRECT RECORD WRITE
;
;	ENT	BC =>	RECORD NUMBER
;		DE =>	FCB
;
DIRWR	CALL	SAVER		;SAVE REG
	CALL	POSN0		;POSN TO RECRD
	JR	Z,$+9		;NO ERROR
	CP	28		;EOF?
	JR	Z,$+5		;ERROR OK
	CP	29		;PAST EOF?
	RET	NZ		;IF NOT
	BIT	7,(IX+1)	;BLK'D?
	JP	Z,WRREC 	;IF NOT
;
WRITE1	LD	B,(IX+15)	;LRL
	LD	L,(IX+5)
	LD	H,(IX+6)	;HL => USER BUFFER
;
WRITE2	LD	A,(HL)		;GET DATA
	INC	HL		;NEXT
	PUSH	BC		;SAVE
	PUSH	HL
	CALL	WRBYTE		;READ BYTE
	POP	HL		;RESTORE
	POP	BC
	RET	NZ		;IF ERROR
	DJNZ	WRITE2		;TIL DONE
	RET
;
*EJECT
;	$CIOF - FILE CHAR I/O DRIVER
;
CIOF	PUSH	IX
	POP	DE		;DE => DCB
	EX	AF,AF'          ;SAVE TYPE
	CALL	SAVER		;SAVE REGISTERS
	EX	AF,AF'          ;GET TYPE
	SET	7,(IX+1)	;BLK'D (BYTE I/O)
	BIT	0,A		;INPUT?
	LD	A,B		;GET DATA
	JR	Z,WRBYTE	;OUTPUT
	CALL	RDBYTE		;READ BYTE
	RET	NZ		;IF ERROR
	POP	HL		;GET RET ADD
	POP	BC		;GET DATA
	LD	B,A		;NEW DATA
	PUSH	BC		;SAVE DATA
	PUSH	HL		;RET ADD
	XOR	A		;NO ERROR
	RET
;
;	READ BYTE FROM FILE
;
RDBYTE	CALL	CKEOF		;CHECK END-OF-FILE
	RET	NZ		;IF ERROR
	BIT	5,(IX+1)	;BUFFER = NRN?
	CALL	NZ,RDSEC	;GET BUFF IF NOT
	RET	NZ		;I/O ERROR
	CALL	CALCBA		;GET BUFFER ADD
	LD	A,(DE)		;GET DATA
	LD	(DBYT1),A	;SAVE BYTE
	INC	(IX+7)		;NEXT NRN BYTE
	JR	NZ,RDBYT1	;IF WITHIN RECORD
	CALL	DBLOCK		;WRITE RESIDUAL
	RET	NZ		;IF ERROR
	CALL	INCREC		;NEXT RECORD
;
DBYT1	EQU	$+1
RDBYT1	LD	A,0		;SET DATA
	CP	A		;Z STATUS
	RET
;
;	WRITE BYTE TO FILE
;
WRBYTE	LD	(DBYT2),A	;SAVE DATA
	BIT	5,(IX+1)	;BUFFER = NRN?
	JR	Z,WRBYT2	;IF YES
	CALL	CKEOF		;CHECK END-OF-FILE
	JR	Z,WRBYT1	;IF NOT EOF
	RES	5,(IX+1)	;BUFFER = NRN
	LD	A,(IX+7)	;NRN BYTE
	OR	A		;EOF BYTE NEXT?
	JR	Z,WRBYT2	;IF YES
;
WRBYT1	CALL	RDSEC		;GET RECORD FOR UPDATE
	RET	NZ		;I/O ERROR
;
WRBYT2	CALL	CALCBA		;GET BUFFER ADD
DBYT2	EQU	$+1
	LD	A,0		;GET DATA
	LD	(DE),A		;WRITE DATA
	SET	4,(IX+1)	;BUFFER UPDATED
	INC	(IX+7)		;NEXT NRN BYTE
	JR	NZ,WRBYT3	;NOT END BUFF
	CALL	WRSEC		;WRITE SECTOR
	RET	NZ		;I/O ERROR
	CALL	INCREC		;INC REC
;
WRBYT3	CALL	STEOF		;SET OPTIONAL EOF
	XOR	A		;Z STAT
	RET
;
*EJECT
;	READ PHYSICAL RECORD FROM FILE
;
RDREC	CALL	CKEOF		;CHECK END-OF-FILE
	RET	NZ		;EOF ERROR
	CALL	RDSEC		;READ SECTOR
	RET	NZ		;I/O ERROR
	CALL	INCREC		;NEXT RECORD
	XOR	A		;NO ERROR
	RET
;
;	READ SECTOR FROM FILE
;
RDSEC	LD	A,(IX+1)	;GET FLAGS
	LD	HL,FLAGK1	;SYSTEM FLAGS
	BIT	1,(HL)		;FORCE READ?
	JR	NZ,RDSEC1	;IF YES
	AND	7		;ATTRIB
	CP	6		;READ?
	JR	C,RDSEC1	;IF NOT
	LD	A,36		;ILLEGAL ACCESS
	OR	A		;NZ STAT
	RET
;
RDSEC1	CALL	GETPDA		;GET DISK ADDRESS
	RET	NZ		;IF ERROR
	RES	5,(IX+1)	;BUFFER = NRN
	LD	L,(IX+3)
	LD	H,(IX+4)	;HL => BUFFER
	LD	A,3		;READ SECTOR
	RST	IODISK		;DO IT!
	RET
;
;	WRITE PHYSICAL RECORD TO FILE
;
WRREC	CALL	WRSEC		;WRITE SECTOR
	RET	NZ		;IF ERROR
	CALL	INCREC		;NEXT RECORD
	CALL	STEOF		;SET EOF
	XOR	A		;NO ERROR
	RET
;
;	WRITE SECTOR TO FILE
;
WRSEC	BIT	5,(IX+2)	;OPEN FOR READ?
	JR	NZ,WRSEC0	;IF YES
	LD	A,(IX+1)	;FLAGS
	AND	7		;ATTRIB
	CP	5		;WRITE?
	JR	C,WRSEC1	;OK
WRSEC0	LD	A,36		;ILLEGAL ACCESS
	OR	A		;NZ STATUS
	RET
;
WRSEC1	CALL	GETPDA		;GET DISK ADDRESS
	RET	NZ		;IF ERROR
	LD	L,(IX+3)
	LD	H,(IX+4)	;HL => BUFFER
	LD	A,5		;WRITE SECTOR
	RST	IODISK		;DO IT!
	RET	NZ		;IF ERROR
	LD	HL,FLAGK1	;SYSTEM FLAGS
	BIT	3,(HL)		;VERIFY?
	JR	Z,WRSEC2	;NO VERIFY
	LD	HL,BUFFER	;TEMP BUFFER
	LD	A,4		;VERIFY
	RST	IODISK		;DO IT!
	RET	NZ		;IF ERROR
WRSEC2	RES	4,(IX+1)	;BUFF UPDATED
	RET
;
;	WRITE ANY RESIDUAL DATA
;
DBLOCK	LD	A,(IX+1)	;FLAGS
	CPL
	AND	90H		;NEW BLK'D DATA?
	JR	Z,WRSEC 	;IF YES
	XOR	A		;NO ERROR
	RET
;
;	INCREMENT TO NEXT RECORD
;
INCREC	SET	5,(IX+1)	;BUFFER <> NRN
	INC	(IX+10) 	;NRN LSB
	RET	NZ
	INC	(IX+9)		;NRN NSB
	RET	NZ
	INC	(IX+8)		;NRN MSB
	RET
;
;	ROUTINE TO SET END-OF-FILE
;
STEOF	SET	3,(IX+1)	;FILE UPDATED!
	CALL	CKEOF		;CHECK EOF
	JR	NZ,STEOF1	;IF EOF
	BIT	6,(IX+1)	;RANDOM ACCESS
	RET	NZ		;IF YES
;
STEOF1	PUSH	IX
	POP	DE		;DE => FCB
	LD	HL,7		;NRN OFFSET
	ADD	HL,DE		;HL => NRN
	EX	DE,HL		;DE => NRN
	LD	HL,4		;OFFSET
	LD	B,H
	LD	C,L		;BC = COUNT
	ADD	HL,DE		;HL => ERN
	EX	DE,HL		;FOR MOVE
	LDIR			;NRN => ERN
	RET
;
;	CALCULATE BUFFER ADDRESS
;
CALCBA	LD	A,(IX+7)	;NRN BYTE
	LD	C,A		;C = BYTE
	ADD	A,(IX+3)	;LSB BUFFER
	LD	E,A		;E => LSB
	LD	A,(IX+4)	;MSB BUFFER
	ADC	A,0		;+ CRY
	LD	D,A		;DE => LOGICAL BUFFER
	RET
;
;	ROUTINE TO CHECK END-OF-FILE
;
;	ENT	IX =>	FCB
;
CKEOF	LD	A,(IX+8)	;MSB NRN
	CP	(IX+12) 	;NRN = ERN?
	JR	NZ,CKEOF2	;IF NOT
	LD	A,(IX+9)
	CP	(IX+13) 	;NRN = ERN?
	JR	NZ,CKEOF2	;IF NOT
	LD	A,(IX+10)
	CP	(IX+14) 	;NRN = ERN?
	JR	NZ,CKEOF2	;IF NOT
	LD	A,(IX+7)
	SUB	(IX+11) 	;NRN = ERN?
	JR	NZ,CKEOF2	;IF NOT
	OR	28		;EOF ERROR!
	RET
;
CKEOF2	LD	A,29		;PAST EOF!
	RET	NC		;IF ERROR
	XOR	A		;NO ERROR
	RET
;
*EJECT
;	SAVE REG & SET-UP FOR FCB ACTIVITY
;
;	ENT	DE =>	FCB
;
SAVER	LD	A,(DE)		;GET DCB TYPE
	RLCA			;OPEN?
	JR	NC,SAVER1	;IF NOT
;
SAVERN	POP	AF		;GET CALLER
	PUSH	HL
	PUSH	DE		;FCB TO STACK
	EX	(SP),IX 	;IX => FCB
	PUSH	IY		;SAVE REG (ORDER DEP)
	PUSH	DE
	PUSH	BC
;
	PUSH	HL		;SAVE
	LD	HL,SAVER2	;UNSTACKER
	EX	(SP),HL 	;RESTORE
	PUSH	AF		;CALLER
	XOR	A		;ZERO
	RET
;
SAVER1	POP	AF		;IGNORE CALLER
	LD	A,38		;NOT OPEN!
	OR	A		;NZ STATUS
	RET
;
;	RESTORE REGISTERS & CHECK EOF
;
SAVER2	POP	BC		;RESTORE REG
	POP	DE
	POP	IY
	JR	Z,SAVER4	;ALL OK
	CP	28		;EOF?
	JR	C,SAVER3	;IF NOT
	CP	30		;EOF?
	JR	NC,SAVER3
	LD	H,(IX+19)	;MSB EOF ADD
	INC	H
	DEC	H		;EOF 0?
	JR	Z,SAVER3	;SKIP
	LD	L,(IX+18)	;HL => EOFADD
	POP	IX		;RESTORE
	EX	(SP),HL 	;TO STACK
	RET
;
SAVER3	OR	A		;STATUS
;
SAVER4	POP	IX		;FINISH
	POP	HL
	RET
 