	TITLE  '(SB80DOS) - SB/80 DOS Module'

MEMSZ	EQU	64		!=;
BIOSSZ	EQU	01C00H		!=; tarbell bios sz = 3 1/2 k
VERS	EQU	0DH		!=;
;****************************************************************
;*
;* module name = dos.asm
;* descriptive name = sb/80 o/s disk operating system module
;* copyright = (c) 1981, lifeboat associates, inc.
;* author = lee rautenberg, dma
;*	    mark l. rollins, lifeboat associates
;* date written =
;*
;* change activity =
;*   01/18/82 mlr ny:  cleanup srch algorithm; fix bug in compute filesz fn
;*   12/16/81 mlr ny:  make get/set fcb compatibility single fn
;*			call;
;*			- add the ld pgm code
;*   12/09/81 mlr ny:  make one single fn call for bios vctrs;
;*			- remove 3f handling in ext byte
;*			- take out cp/m attr's, other cleanup
;*			- comment the listing for maintainability
;*   11/19/81 mlr ny:  fix extent handling for large files
;*   11/17/81 mlr ny:  fix srcnx3 (srchnx subrout) to not
;*			mask out hi bit on extent byte(s)
;*   11/09/81 mlr ny:  setup for full 1000h for cli;
;*			- put in vers # string
;*   08/10/81 mlr ny:  setup for tarbell dd controller;
;*			- setup cp/m compabitility handling
;*			- expand tabs for lstout
;*
;*   release = R0.D
;*   date = 18/jan/82
;*
;* environment =
;*   processor = mac (dig.rsrch)
;*
;****************************************************************
;
;
	PAGE
;****************************************************************
;*								*
;*		    SYSTEM DEFINITION EQUATES			*
;*								*
;****************************************************************

DOSSIZ	EQU	1400H		!=;
CLISIZ	EQU	1000H		!=;

TOFMEM	EQU	MEMSZ*1024	!=;
BIOS	EQU	TOFMEM-BIOSSZ	!=;
DOS	EQU	BIOS-DOSSIZ	!=; DOS ORG
CLI	EQU	DOS-CLISIZ	!=;

BIAS	EQU	DOS+DOSSIZ+3	; ADDRESS OF WBOOT ENTRY RELATIVE TO 0000


;****************************************************************
;*								*
;*		    MISCELLAENOUS EQUATES			*
;*								*
;****************************************************************

FALSE	EQU	0
TRUE	EQU	NOT FALSE
EDIT	EQU	003
VERNUM	EQU	80H		; DMA.DOS VERSION NUMBER IN BCD
CPMVER	EQU	22H		; COMPATIBLE CP/M VERSION
SBCVER	EQU	(40H*256)+CPMVER ; SB80 FLAG/CPM VERSION
;
SSIZE	EQU	39		; 39 LEVEL STACK
;
ERDIRF	EQU	2		; ERROR, DIRECTORY FULL
ERNCLS	EQU	3		; ERROR, CANT CLOSE EXTENT
ERSKUE	EQU	4		; ERROR, READ/WRITE UNWRITTEN DATA

	PAGE

;****************************************************************
;*								*
;*		    START OF DOS				*
;*								*
;****************************************************************

	ORG	DOS


	DB	'(c)DMA' 	; its in ram now
	JMP	ENTRY
FTBLAD: DW	FUNTBL		; place to give extrn ref to fn tbl addr
VRSTRNG:
	IF	(VERS/16) > 9
	DB	(VERS/16) + 37H
	ELSE
	DB	(VERS/16) + 30H
	ENDIF

	IF	(VERS MOD 16) > 9
	DB	(VERS MOD 16) + 37H
	ELSE
	DB	(VERS MOD 16) + 30H
	ENDIF

ENTRY:
	XCHG
	SHLD	ARG		; save regular input parm
	XCHG			;   & put back in <de>
	SHLD	ARG2		; save input parm2 (for biosfnc)
	LXI	H,FUNC		; INFORMATION ADDRESS AND FUNCTION STORED
	MOV	M,C
	LXI	H,0		; SAVE USER'S STACK
	DAD	SP		; 
	SHLD	ENTSP		; USE THE MONITOR'S STACK
	LXI	SP,LSTACK	; SET TO LOCAL STACK
	CALL	EXEC		; GOTO THE COMMAND BRANCH AREA
;
; THIS IS WHERE WE COME BACK TO AFTER THE FN CALL
;
	LHLD	ENTSP		; GET THE USERS STACK BACK
	SPHL			; 
	LHLD	RETCOD		; GET RETURN STUFF
	MOV	A,L		; FOR PL/M
	MOV	B,H
	RET

	PAGE
;****************************************************************
;*								*
;*	EXEC	EXECUTE DOS FUNCTION				*
;*								*
;****************************************************************

EXEC:
	CALL	EINIT		; INITIALIZE FOR FUNCTION EXECUTION
	LDA	FUNC		; GET FN #
	CALL	CHK18		; CHECK FOR SRCHNXT (DOS FN 18)
	CALL	TSTCHK		; TEST FOR REQUIRED DISK CHECKIN
	CC	DCHKIN		; CHECK IN FCB DISK IF NECESSARY
	LXI	D,EXCLNP	; SAVE RETURN ADDR ON STACK
	PUSH	D
	LDA	FUNC		; GET FN # AGAIN
	ORA	A		; CHECK BIT 7
	JM	SEXEC		; EXECUTE A SUPER FUNCTION


REXEC:
	CPI	NUMFUN		; TEST FOR LEGAL FUNCTION
	JNC	NULL		;
	LXI	H,FUNTBL	; BASE OF FN BRANCH ADDRS
	JMP	DISPATCH	; DO IT


SEXEC:
	ANI	7FH		; MASK HI ORDER BIT
	CPI	SNUMFUN		;   & TEST FOR LEGAL FUNCTION
	JNC	NULL		; NO, ILLEGAL
	LXI	H,SFUNTBL	; BASE OF SUPER FN BRANCH ADDRS
	JMP	DISPATCH	; DO IT	


;****************************************************************
;*								*
;*	EXCLNP	RETURN HERE FROM DOS FN HANDLING; DO CLEANUP	*
;*								*
;****************************************************************

EXCLNP:
	XRA	A
	STA	FUNC		; ZERO FOR THE BKPRINT
	LDA	DSKIN		; GET DISK AS INPUT 
	ORA	A
	RZ	 	     	; NO CHANGE
	LHLD	ARG		; FIRST BYTE POINTED TO IS DISK NAME
	MOV	M,A
	LDA	DSKTMP		; GET BACK LOGGED DISK NUMBER
	MOV	E,A		; PUT IN E FOR DCHKNW
	JMP	DCHKNW		; SELECT THE LOGGED DRIVE AGAIN

	PAGE
;****************************************************************
;*								*
;*	DISPATCH	DISPATCH FUNCTION			*
;*								*
;*	ENTRY:		<A>  CONTAINS FUNCTION NUMBER		*
;*			<HL> POINTS TO FUNCTION TABLE		*
;*								*
;****************************************************************

DISPATCH:
	ADD	A		; 2 BYTE TABLE ENTRIES
	CALL	ADDVAL		; GET OFFSET INTO TABLE
	MOV	E,M		; <HL> NOW PTS TO DOS FN ADDR,
	INX	H		; PUT THE ADDR IN <DE>
	MOV	D,M
DISPD:
	LHLD	ARG		; GET ENTRY PARMS
	XCHG			; PUT IN <DE>, BRANCH ADDR IN <HL>
	MOV	B,D		; FOR PRINT BUFFER COMMAND
	MOV	C,E	
	PCHL


;****************************************************************
;*								*
;*	NULL	DO NULL ROUTINE					*
;*								*
;****************************************************************

NULL:
	LXI	D,NOOP		; DUMMY ROUTINE FOR INVALID OR NONEXISTENT
	JMP	DISPD		;   FUNCTION CALLS


;****************************************************************
;*								*
;*	EINIT	INITIALIZE ENTRY PARAMETERS			*
;*								*
;****************************************************************

EINIT:
	LXI	H,0		; INITIALIZE
	SHLD	RETCOD		; RETURN CODE PARAMETERS
	XRA	A		; 
	STA	DSKIN		; 
	RET

	PAGE
;****************************************************************
;*								*
;*	CHK18	CHECK FOR DOS FUNCTION 18			*
;*								*
;****************************************************************

CHK18:	CPI	18		; SPECIAL FOR DUMMIES USING SEARCH NEXT AND NOT
				; KEEPING D-E POINTING TO PROPER FCB
	RNZ
	LHLD	SRCHO		; GET WHAT THEY REALLY WANT AS FCB
	SHLD	ARG
	XCHG
	RET


;****************************************************************
;*								*
;*	TSTCHK	TEST TO SEE IF THIS DOS FUNCTION REQUIRES	*
;*		FCB CHECKIN ROUTINE				*
;*								*
;****************************************************************

TSTCHK:	MOV	B,A		; COPY FUNCTION NUMBER TO B
	RRC			; DIVIDE BY 8
	RRC
	RRC
	ANI	1FH		; TURN OFF HI 3 BITS
;
	LXI	H,DSKFUN 	; FETCH DISK FUNCTION TABLE
	CALL	ADDVAL		; GET PTR TO APPROPRIATE BYTE
	MOV	A,B		; GET FUNCTION CODE BACK
	ANI	7		; GET RELATIVE POSITION WITHIN BIT MAP BYTE
	MOV	B,A		; BACK TO B
	MOV	A,M		; GET BIT MAP BYTE TO A
TSTCK1:	DCR	B		; FIND APPROPRIATE BIT
	JM	TSTCK2
	RLC
	JMP	TSTCK1
TSTCK2:	RAL
	RET

	PAGE
;****************************************************************
;*								*
;*		    DOS FUNCTION TABLE				*
;*								*
;****************************************************************

FUNTBL:
	DW	BOOT		; -0-  COLD BOOT
	DW	GT1CHR 		; -1-  GET AND ECHO CHARACTER
	DW	OUTCHR		; -2-  OUTPUT TO CONSOLE
	DW	READIN		; -3-  READER INPUT
	DW	PUNOUT		; -4-  PUNCH OUTPUT
	DW	LIST		; -5-  LIST CHARACTER
	DW	DIRIO 		; -6-  DIRECT CONSOLE INPUT/OUTPUT
	DW	IOSTAT		; -7-  DEVICE STATUS CHECK
	DW	CHIOST		; -8-  CHANGE IO STATUS
	DW	PRINT		; -9-  PRINT BUFFER ON CONSOLE
	DW	READBF		; -10- READ BUFFER FROM CONSOLE
	DW	FNCRDY		; -11- CONSOLE CHARACTER READY CHECK
	DW	FNVERS		; -12- VERSION NUMBER
	DW	RSTSYS		; -13- RESET DISK SYSTEM, LOG IN DISK 0
	DW	DCHKNW		; -14- LOG IN NEW DISK
	DW	FNOPEN		; -15- OPEN A FILE
	DW	FNCLOS		; -16- CLOSE A FILE
	DW	FNSRC		; -17- SEARCH FOR DIRECTORY ENTRY
	DW	FNSRNX		; -18- GET NEXT DIRECTORY ENTRY
	DW	FNDELT 		; -19- DELETE FILE
	DW	FNREAD		; -20- READ FROM FILE
	DW	FNWRIT		; -21- WRITE TO FILE
	DW	FNCREA		; -22- CREATE FILE ENTRY
	DW	FNRENA		; -23- RENAME A FILE
	DW	FNLOGV		; -24- GET LOGIN VECTOR
	DW	FNCURD		; -25- RETURN CURRENT DISK
	DW	FNSDMA		; -26- SET DMA ADDRESS
	DW	FNALOC		; -27- RETURN ADDR OF DISK ALLOCATION MAP
	DW	SETRO		; -28- WRITE PROTECT DISK
	DW	FNRODV		; -29- RETURN READ ONLY DISK VECTOR
	DW	FNSETA		; -30- SET ATTRIBUTES (DMADOS 59)
	DW	FNDPB 		; -31- GET ADDR OF DISK PARAMETER BLOCK
	DW	FNUSER		; -32- GET/SET USER NUMBER
	DW	FNRNRD		; -33- RANDOM RECORD READ
	DW	FNRNWR		; -34- RANDOM RECORD WRITE
	DW	FNSIZE		; -35- COMPUTE FILE SIZE
	DW	FNRNST		; -36- SET RANDOM RECORD
	DW	RSTDRV		; -37- RESET DRVS SPEC'D IN DRV VCTR
	DW	NOOP		; -38- (NOT USED)
	DW	NOOP		; -39- (NOT USED)
	DW	ZROFIL		; -40- RNDM WRT W/ZERO FILL
NUMFUN	EQU	($-FUNTBL)/2	; NUMBER OF DOS FUNCTIONS

	PAGE
;****************************************************************
;*								*
;*		    DOS SUPER FUNCTION TABLE			*
;*								*
;****************************************************************

SFUNTBL:			; SB/80 DMAD
	DW	QUEPRN		; -128-  48  SET A PRINT FILE IN THE QUEUE
	DW	UNQPRN		; -129-  49  RESET A QUEUED FILENAME
	DW	KILPRN		; -130-  50  KILL ALL QUEUED PRINT FILES
	DW	SUSPRN		; -131-  51  SUSPEND THE PRINT OPERATION
	DW	RESPRN		; -132-  52  RESTORE THE PRINT OPERATION
	DW	GTBPRS		; -133-  53  GET THE PRINT STATUS FLAG
	DW	STBPRS		; -134-  54  SET THE PRINT STATUS FLAG
	DW	QUEVEC		; -135-  55  GET THE QUEUE VECTOR (BASE)
	DW	INIBPR		; -136-  56  INITIALIZE THE BACKGND PRINT TASK
	DW	LDCLI		; -137-  57  INIT DOS AND READ SYSTEM.CLI FILE
	DW	FNGDMA		; -138-  60  GET CURRENT DMA ADDRESS
	DW	STCMPT		; -139-      GET/SET FCB COMPABITILITY
	DW	BIOSFNC		; -140-      FN CALL FOR BIOS JMP VCTR
	DW	STCLIF		; -141-      SET USER PROVIDED CLI FILENAME
	DW	STLDAD		; -142-      SET LOAD ADDR (DEF 100h)
	DW	STEXAD		; -143-      SET EXECUTION ADDR (DEF 100h)
	DW	LDPGM		; -144-      LD A PGM AT CURRENT LD ADDR

SNUMFUN	EQU	($-SFUNTBL)/2	; NUMBER OF DOS SUPER FUNCTIONS


DSKFUN:				;MAP OF FUNCTIONS REQUIRING FCB DISK CHECKIN
				;-FNS-
	DB	00000000B	; 0- 7
	DB	00000001B	; 8-15	I.E., SERVICE #15,
	DB	11111111B	;16-23		#16 - #23,
	DB	00000010B	;24-31		#30,
	DB	01111000B	;32-39		#31 - #35,
	DB	00000000B	;40-47
	DB	00000000B	;48-55
	DB	00000000B	;56-63
	DB	00000000B	;64-71
	DB	00000000B	;72-79
	DB	00000000B	;80-87
	DB	00000000B	;88-95
	DB	00000000B	;96-103
	DB	00000000B	;104-111
	DB	00000000B	;112-119
	DB	00000000B	;120-127
	DB	00000000B	;128-135
	DB	00000000B	;136-143
	DB	10000000B	;144-151	#144
	DB	00000000B	;152-159

	PAGE
;****************************************************************
;*								*
;*			BIOS EQUATES				*
;*								*
;****************************************************************

BOOT	EQU	BIAS+0
CONRDY	EQU	BIAS+3
CONIN 	EQU	BIAS+6
CONOUT	EQU	BIAS+9
LIST  	EQU	BIAS+12
PUNOUT	EQU	BIAS+15
READIN	EQU	BIAS+18
HOME  	EQU	BIAS+21
SELDSK	EQU	BIAS+24
SETTRK	EQU	BIAS+27
SELSEC	EQU	BIAS+30
SETDMA	EQU	BIAS+33
READ  	EQU	BIAS+36
WRITE 	EQU	BIAS+39
PRTRDY	EQU	BIAS+42
SECTRAN	EQU	BIAS+45

	PAGE
;****************************************************************
;*								*
;*		      CONTROL CHARACTER EQUATES			*
;*								*
;****************************************************************

CTLC	EQU	03H	;CONTROL C
CTLE	EQU	05H	;PHYSICAL END OF LINE
CTLH	EQU	08H	;BACKSPACE
CTLP	EQU	10H	;PRINTER TOGGLE
CTLQ	EQU	11H	;START AFTER CTL-S (XON)
CTLR	EQU	12H	;RETYPE LINE
CTLS	EQU	13H	;STOP/START SCREEN (XOFF)
CTLU	EQU	15H	;REDO NEW INPUT LINE
CTLX	EQU	18H	;REDO INPUT LINE
CTLZ	EQU	1AH	;END OF FILE
;
RUBOUT	EQU	7FH	;MAXIMUM ASCII CHARACTER
BS	EQU	08H	;BACKSPACE
TAB	EQU	09H	;TAB CHAR
LF	EQU	0AH	;LINE FEED
CR	EQU	0DH	;CARRIAGE RETURN
CTL	EQU	5EH	;UP ARROW

	PAGE
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
;*****************************************************************
;**								**
;**		DISK MONITOR SUPPORT ROUTINES			**
;**								**
;*****************************************************************
;>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>



;****************************************************************
;*								*
;*	NOOP	DUMMY FUNCTION CALL				*
;*								*
;****************************************************************

NOOP:
	RET

;****************************************************************
;*								*
;*	GT1CHR		DOS # 1					*
;*		GET CONSOLE CHARACTER	WITH ECHO		*
;*								*
;****************************************************************

GT1CHR:
	CALL	CONECH		; GET AND ECHO CHAR
	STA	RETCOD		; SAVE RESULT
	RET


;****************************************************************
;*								*
;*	IOSTAT		DOS # 7					*
;*		DEVICE STATUS CHECK				*
;*								*
;****************************************************************

IOSTAT:
	LHLD	IOBYTE
	SHLD	RETCOD
	RET

	PAGE
;****************************************************************
;*								*
;*	CHIOST		DOS # 8					*
;*		MODIFY I/O BYTE 				*
;*								*
;****************************************************************

CHIOST:
	MOV	A,E
	STA	IOBYTE
	RET


;****************************************************************
;*								*
;*	FNCRDY		DOS # 11				*
;*		CHECK CONSOLE STATUS				*	
;*								*
;****************************************************************

FNCRDY:
	CALL	CONBRK		; CHECK FOR CHARACTER READY
	STA	RETCOD		; SAVE RETURN CODE
	RET			; 


;****************************************************************
;*								*
;*	FNVERS		DOS # 12				*
;*		RETURN VERSION NUMBER				*
;*								*
;****************************************************************

FNVERS:
	LXI	H,SBCVER	; GET SB80 INDICATOR TO <H>, CP/M VERS
	SHLD	RETCOD		;   WE ARE COMPATIBLE W/ TO <L>
	RET

	PAGE
;****************************************************************
;*								*
;*	RSTSYS		DOS # 13				*
;*		RESET DISK SYSTEM				*
;*								*
;****************************************************************

RSTSYS:
	XRA	A		;
	STA	LOGDSK		; ZERO OUT CURRENT LOGGED-IN DISK NUMBER
	STA	LOGGED		; ALSO CLEAR THE LOGGED-IN DISK MAP
	STA	LOGGED+1
	STA	LISTCP		; RESET LST TOGGLE
RSSYS1:
	CALL	RSTDMA
	LXI	H,TPA
	SHLD	LDADDR		; RESET LD & EXECUTION ADDRS TO BASE OF TPA
	SHLD	EXADDR
	JMP	SELECT		; AND SELECT THE NEW LOGGED IN DISK

RSTDMA:
	LXI	H,DBUFF		; GET DEFAULT DIRECTORY DMA ADDRESS
	SHLD	DMAADR		; SAVE IN DEFAULT DATA DMA ADDRESS SAVE AREA
	CALL	DATDMA		; SET THE DMA IN UIOI
	RET

	PAGE
;****************************************************************
;*								*
;*	FNOPEN		DOS # 15				*
;*		OPEN FILE					*
;*								*
;****************************************************************

FNOPEN:
	XRA	A		; SWEEP, SWEEP (HOUSECLEANING)
	STA	RETCOD
				;
	CALL	SETUSR		; SET USER NUMBER
OPEN:	MVI	C,SEXTLN	; SRCH LENGTH (INCLUDES EXTENT)
	CALL	SEARCH
	LDA	RETCOD
	INR	A		; RETCODE = -1 IF FILE NOT FND
	RZ
	LHLD	ARG		; LOCATION OF FCB
	LXI	D,SNAMLN	
	DAD	D		; START POS TO COPY TO
	XCHG
	LDA	DIRDSP		; GET DISP INTO DIR BUFFER
	ADI	SNAMLN		; ADD FNM TO POINT TO FIRST BYTE AFTER NAME
	CALL	GETBF		; START POINT TO COPY FROM BUFFER
	MVI	B,FCBLEN-SNAMLN	; MOVE EVERYTHING AFTER NAME, INCLUDING EXT
	CALL	MOVE
	RET

	PAGE
;****************************************************************
;*								*
;*	FNCLOS		DOS # 16				*
;*		CLOSE FILE					*
;*								*
;****************************************************************

FNCLOS:
	CALL	SETUSR		; SET USER NUMBER IN FCB
CLOSE:	XRA	A
	STA	RETCOD
	CALL	CHKRO		; RO DISK?
	ORA	A
	RNZ
	MVI	C,SEXTLN	; SRCH LEN INCLUDES EXT
	CALL	SEARCH
	LDA	RETCOD
	INR	A
	RZ
	CALL	FILPRT
	RNZ			; IF FILE PROTECTED, NO MESSAGE-DONT UPDATE
	XCHG			; <DE> NOW PTS TO DCB (DIR BUF) ATTR BYTE
	CALL	GTFCBAT		; GET ADDR(FCB ATTR BYTE) INTO <HL>
	LDAX	D		; PUT DCB ATTR BYTE INTO <A>
	MOV	M,A		;   & STORE IN FCB
	JMP	CPYFCB		; TEST FOR WHETHER TO PERFORM PHYSICAL
				;   CLOSE IS IN CPYFCB
	PAGE
;****************************************************************
;*								*
;*	FNSRC		DOS # 17				*
;*		FILE SEARCH					*	
;*								*
;****************************************************************

FNSRC:
	LHLD	ARG		; GET ADDRESSED FCB
	SHLD	SRCHO		;   & SAVE IN SRCH FROM OUTSIDE VARIABLE
	LXI	D,FCBEX		; THEN GET THE EXT BYTE (ADD THE
	DAD	D		;   OFFSET TO THE FCB ADDR IN <HL>),
	MOV	A,M		; PUT IT IN <A>, & TEST FOR A <?>...
	CPI	'?'		;   IF EXT BYT IS NOT A <?>,
	JNZ	SRCH1		;     SRCH LEN INCLUDES EXTENT,
	MVI	C,SNAMLN	;   ELSE, SRCH LEN EXCLUDES EXTENT
	JMP	SRCH2
SRCH1:
	MVI	C,SEXTLN	; LENGTH TO SRCH FOR (INCLUDES EXTENT)
SRCH2:
	MOV	A,C		; PUT LENGTH IN <A>
	STA	SRCHLO		;   & SAVE AS LAST LENGTH SEARCHED, OUTSIDE
	CALL	SEARCH		; DO SEARCH
	JMP	FNSRC2		; SET SRCFLG AND DIRNMO

SEARCH:
	MOV	A,C		; GET LENGTH AND SAVE IN SRCHL
	STA	SRCHL
	LHLD	ARG		; GET ADDRESSED FCB ARGUMENT
	SHLD	SRCH		; SAVE FOR SEARCH NEXT
	LDA	CPMFLG		; TEST FOR CPM COMPATIBILITY
	ORA	A		;   FLAG IS: (Z=CPM,NZ=SB80) COMPATIBILITY
	JNZ	SRCH3		; IF Z, DON'T NEED TO BE CPM COMPATIBLE
				; ELSE, ZERO OUT S1 BYTE IN FCB
	LXI	D,FCBS1		;   GET OFFSET OF S1 BYTE
	DAD	D		;   <HL> NOW PTING TO S1 BYTE
	MOV	M,A		;   STORE A ZERO IN S1 BYTE
SRCH3:
	LXI	H,0FFFFH	; SET UP DIRECTORY NUMBER IN PREPARATION
	SHLD	DIRNUM		; FOR SEARCH NEXT LOOP
	CALL	HOMEHD		; HOME HEAD AND INIT SOME PARAMETERS
	JMP	SRCHNX		; SKIP NEXT COUPLE OF INSTR

	PAGE
;****************************************************************
;*								*
;*	FNSRNX		DOS # 18				*
;*		SEARCH FOR NEXT DIRECTORY ELEMENT.		*
;*		ASSUMES PREVIOUS CALL TO SEARCH TO GET SRCHL	*
;*								*
;****************************************************************


FNSRNX:
	LHLD	SRCHO		; GET SEARCH ARG FROM LAST OUTSIDE SEARCHNEXT
	SHLD	SRCH		; SAVE HERE
	LDA	SRCHLO		; LAST SEARCH LENGTH
	STA	SRCHL		; SAVE HERE
	LHLD	DIRNMO		; LAST DIR NUMBER
	SHLD	DIRNUM		; SAVE THERE
	MOV	A,H		; GET HIGH BYTE (=FFH IF AT END)
	STA	RETCOD		; IN CASE WE MUST LEAVE
	INR	A		; TEST FOR ZERO
	RZ			; RETURN IF ALREADY DONE
	LDA	SRCFLG		; GET OUTSID SRNX FLAG
	ORA	A		; SET FLAG
	JNZ	FNSRC1		; JUMP IF LAST WAS EXTERNAL SEARCH
	CALL	SEEKDR		; SEEK DIRECTORY RECORD
	CALL	RDDISK		; READ DISK
FNSRC1:
	CALL	SRCHNX		; DO SEARCH NEXT
FNSRC2:
	MVI	A,1		; PREPARE TO SET FLAG
	STA	SRCFLG		; SET FLAG TO SAY OUTSIDE SRCH NEXT MADE
	LHLD	DIRNUM		; GET DIRECTORY NUMBER FOUND
	SHLD	DIRNMO		; SAVE DIRECTORY NUMBER THIS CALL
;
	LHLD	DMAADR		; GET USER DMA ADDR,
	XCHG			;   & PUT IN <DE>
	LHLD	DIRBUF		; GET ADDR OF DIR BUFFER
	MVI	B,128		; NUMBER OF BYTES TO MOVE
	JMP	MOVE		; MOVE DIR BUFFER TO USER DMA
;
;	SEARCH FOR NEXT MATCH
;
SRCHNX:
	XRA	A		; PREPARE TO SET SRCFLG
	STA	SRCFLG		; TO INDICATE A SEARCH NEXT HAS OCCURRED
	LHLD	SRCH		; FCB AREA TO CHECK
	SHLD	ARG		; SAVE IN CASE SOMETHING FUNNY HAPPENED
	XCHG
SRCNX0:
	PUSH	D		; SAVE INFO FCB ADDRESS FOR LATER
	MVI	C,FALSE		; SET FOR TEST ONLY IN CHKSUM SUBROUT
	CALL	RDDIR		; GET NEXT DIRECTORY ENTRY
	POP	D		; RESTORE FCB ADDRESS
	LHLD	DIRNUM		; GET DIRECTORY ENTRY NUMBER
	MOV	A,H		; PUT HIGH BYTE IN <A> (WILL BE FF IF AT END)
	STA	RETCOD		; SAVE IN CASE WE ARE DONE
	INR	A		; TEST FOR FF
	RZ			; RETURN IF SO, AT END
	MOV	A,L		; GET LOW BYTE
	ANI	3		; GET LOW TWO BITS AS DIRECTORY CODE
	STA	RETCOD		; THIS BECOMES RETURN CODE IF SUCCESSFUL SEARCH
	LDA	DIRDSP		; GET DISPLACEMENT INTO BUFF OF NEXT DIR ENTRY
	CALL	GETBF		; CHECKING FOR TWO EMPTY VALUES TO FINISH
	CPI	EMP
	JNZ	SRCNX1
	LDAX	D		; GET CHAR FROM MATCHING BUFFER
	CMP	M		; SEE IF WE ARE LOOKING FOR AN EMPTY DIR
	RZ			; RETURN IF SO
	MVI	A,EMP		; RESTORE TESTING E5
	INX	H
	CMP	M
	JNZ	SRCHNX		; TRY ANOTHER ONE, JUST AN EMPTY ENTRY
	MVI	A,255
	STA	DIRNUM		; SET DCNT AS IF DIRECTORY FULLY SEARCHED
	STA	DIRNUM+1	;  BOTH BYTES TO BE SET
	STA	RETCOD
	RET
SRCNX1:
	LDA	SRCHL		; RETRIEVE SEARCH LENGTH
	MOV	C,A		; <C> IS LENGTH COUNTER (COUNTING DOWN)
	LDA	DIRDSP		; BASE DSP OF DIR ENTRY
	CALL	GETBF		; PT <HL> TO START OF DIRECTORY TO TEST
	MVI	B,11		; FILENAME + FILETYP (<B> USED TO COUNT #
				;   OF CHARS MATCHED, TO TST IF BYT IS EXT)
SRCNX2:	
	MOV	A,B		; GET COUNT OF CHARS MATCHED (COUNTING DOWN)
	ORA	A
	LDAX	D		;   (GET FCB CHAR TO MATCH 1ST)
	JM	SRCNX2A		;   IF <B> IS MINUS, THIS IS EXT BYTE,
				;     (DON'T TURN OFF HI BIT)
	XRA	M		;   ELSE, IGNORE HI BIT IN BOTH FCB & DCB
	ANI	7FH
	JMP	SRCNX2B
SRCNX2A:
	CMP	M		; COMPARE FCB CHAR TO DCB BUF CHAR
SRCNX2B:
	JZ	SRCNX3  	; JUMP IF MATCH
	LDAX	D		; ELSE, GET FCB CHAR AGAIN,
	CPI	'?'		;   & TRY WILDCARD MATCH;
	JNZ	SRCHNX		;   NOT WILDCARD EITHER, TRY NEXT ENTRY
	MOV	A,B		;   ELSE, GET COUNT OF CHARS MATCHED
	ORA	A		;   IF <B> IS MINUS, THIS IS EXT BYTE,
	JM	SRCHNX		;     WILDCARD MATCH WAS NOT VALID
SRCNX3:
	DCR	B		; COUNT DOWN # OF CHARS MATCHED
	INX	D		; BUMP FCB PTR,
	INX	H		;   & DCB PTR
	DCR	C		; DCR LENGTH COUNTER
	JNZ	SRCNX2		; LOOP TIL 0

	PAGE
SRNX3A:
	LDA	USRN		; CURRENT USER NUMBER
	ANI	UMK		; MASK OUT ATTRIBUTES
	RZ			; USER ZERO SEES ALL!!
	MOV	B,A		; SAVE IN <B>
	CALL	GTDCBAT		; GET DCB ATTR BYTE
	MOV	C,A		;   & SAVE IN <C>
	ANI	SYS		; TEST FOR SYSTEM FILE
	JNZ	SRCNX4
	MOV	A,C		; GET ATTR BYTE BACK FROM <C>
	ANI	UMK		; MASK OUT ATTRIBUTE BITS
	CMP	B		; SAME USER?
	JNZ	SRCHNX  	; JUMP IF NO MATCH
SRCNX4:
	JMP	SETUSR		; RETURN THRU SETUSR (PUT USER # IN
	    			;   ADDRESSED FCB)
	PAGE
;****************************************************************
;*								*
;*	FNDELT		DOS # 19				*
;*		DELETE FILE					*
;*								*
;****************************************************************

FNDELT:
	CALL	SETUSR		; SET FCB TO INDICATE LOGGED IN USER
DELETE:
	CALL	CHKWRT		; DSK WRITE PROTECTED? (doesn't ret if so)
	MVI	C,SNAMLN	; SRCH LEN EXCLUDES EXTENT
	CALL	SEARCH
	LDA	RETCOD		; GET RETCODE FROM SEARCH
	STA	SAVRC		;   & SAVE IT
DELET1:
	LDA	RETCOD		; GET RETCODE FROM SEARCH (# OF POSITION IN
	CPI	0FFH		;   DIR IF FOUND, 0FFH IF NOT FOUND)
	JNZ	DELT1A		; JMP IF FOUND TO SAVE LATEST GOOD RETCODE
	LDA	SAVRC
	STA	RETCOD
	RET
DELT1A:	STA	SAVRC
	CALL	TSTUSR		; TEST FOR VALID USER (OWNER OR 0)
	JZ	DELT1B		;   GOOD USER, JMP TO CONTINUE
	CALL	ERRUSR		;   ELSE, DSPLY MSG,
	JMP	DELET3		;     & LOOK FOR NEXT MATCH
DELT1B:
	CALL	FILPRT		; TEST FOR FILE WRITE PROTECTED
	JZ	DELET2		;   OK, IF NOT WRITE PROTECTED
	CALL	ERWPRT		;   ELSE, DSPLY MSG,
	JMP	DELET3		;     & LOOK FOR NEXT MATCH
DELET2:
	MVI	C,FALSE 	; LOW ORDER BIT OF C USED TO SET ALLOCATION BIS
				; CORRESPONDING TO FCB DISK MAP AREA
	CALL	MAPALL		; DEALLOCATE BLOCKS FROM DELETED FCB
	LDA	DIRDSP		; CURRENT BUFFER RELATIVE POINTER
	CALL	GETBF		; TO SET <HL> TO ACTIVE FCB BYTE
	MVI	M,EMP		; CLEAR ENTRY
	CALL	WRDIR		; WRITE BACK DIRECTORY ENTRY
DELET3:
	CALL	SRCHNX		; LOOK FOR ANOTHER MATCH
	JMP	DELET1

	PAGE
;****************************************************************
;*								*
;*	FNREAD		DOS # 20				*
;*		READ DISK					*
;*								*
;****************************************************************

FNREAD:
	XRA	A		; SWEEP, SWEEP (HOUSECLEANING)
	STA	RETCOD
	STA	RAFLAG		; CLEAR RANDOM READ FLAG
DSKRD:
	LXI	H,RDFLAG	; READ FLAG S.B. TRUE
	MVI	M,1
	CALL	GTCNTS		; GET REC CT & NEXT REC IND. FROM ADDRESSED FCB
	LXI	H,RECCNT	; POINT TO RECORD COUNT IN THIS EXT
	CMP	M
	JC	DSKRD1		; JUMP IF RECORD IS IN THIS EXTENT
	LXI	H,RETCOD
	MVI	M,1		; SET RETURN ERROR CODE TO ONE OUT OF RANGE
	MOV	H,A		; SAVE COUNT IN H
	LDA	RAFLAG		; RANDOM READ ?
	ORA	A
	RNZ			; RET IF SO, DO NOT TRY ANOTHER EXTENT
	MOV	A,H		; GET COUNT BACK TO A
	CPI	128		; COMPARE TO MAX RECORD COUNT/EXTENT
	CZ	OPEXT		; OPEN NEXT EXTENT IF THIS ONE FULL
	XRA	A
	STA	RELREC		; RESET RELATIVE RECORD NUMBER
	LDA	RETCOD		; GET RETURN FROM EXTENT OPEN(0 IF ALL OK)
	ORA	A
	RNZ			; NO GOOD
DSKRD1:
	CALL	FNDBLK		; GET BLOCK NUMBER CORRES TO REL REC INTO H/L
	MOV	A,L		; BLOCK NUMBER IS ALWAYS TWO BYTES LONG
	ORA	H
	JNZ	DSKRD2
	INR	A		; NO GOOD, CANT READ UNWRITTEN STUFF,SET
	STA	RETCOD		; RETURN ERROR CODE TO ONE
	RET
DSKRD2:
	CALL	FNDREC		; COMPUTE RECORD ASSUMING THAT AFTER THE OS
				; TRACKS, EACH SECTOR IS CONSECUTIVELY
				; NUMBERED
	CALL	SEEK		; COMPUTE PHYSICAL TRACK AND SEND HEAD THERE
	CALL	DATDMA		; SET DATA DMA ADDRESS
	CALL	RDDISK		; READ DISK
	LDA	RAFLAG		; RANDOM READ ?
	ORA	A
	RNZ			; RETURN IF SO, DO NOT ADVANCE RELREC
	JMP	PTCNTS		; RESTORE RELREC AND RECCNT TO FCB

	PAGE
;****************************************************************
;*								*
;*	FNWRIT		DOS # 21				*
;*		WRITE TO DISK					*
;*								*
;****************************************************************

FNWRIT:
	XRA	A
	STA	RAFLAG		; CLEAR RANDOM R/W FLAG
DSKWR:	LXI	H,RDFLAG	; READ FLAG S.B. FALSE
	MVI	M,FALSE
	CALL	CHKWRT		; WRITE PROTECTED (DOESN'T COME BACK IF IT IS)
	CALL	GTFCBAT		; GET ADDRESSED FCB ATTR BYTE INTO <A>
	ANI	PMK		; GET WRITE PROTECT BIT
	JNZ	ERWPRT		; ERROR IF WRITE PROTECTED
	CALL	GTCNTS		; SET RELREC AND RECCNT
	ORA	A		; COMPARE RELREC TO MAX OF 128
	JP	DSKWR1  	; JUMP IF NOT END OF FILE
	MVI	A,1		; WHOOPS, EXCEEDED MAX; IF OK, NEXT EXT SHOULD
	STA	RETCOD		;   BE OPEN, JUST RETURN BAD EXTENSION ERROR
	RET

DSKWR1:
	CALL	FNDBLK		; GET BLOCK NUMBER FOR THIS WRITE
	MOV	A,L		; GET ONE BYTE BLK NUMBER IN A
	ORA	H
	JNZ	DSKWR4		; JUMP IF BLOCK ALREADY ASSIGNED
	LXI	B,0		; WILL BE USED AS CLOSEST TO NEW BLK IF NEEDED
	MVI	A,FCBMP		; DISP TO DISK MAP IN FCB
	STA	LTEMP		; SAVE THERE TEMPORARILY
	LDA	RELREC		; GET RELATIVE RECORD AGAIN
	CALL	GTBLKN		; GET POS OF BLOCK IN DISK MAP
	ORA	A		; SET FLAGS--ZERO WILL BE ON IF 1ST BLK IN EXT
	JZ	DSKWR2		; JUMP IF THAT WAS THE CASE
	ADI	FCBMP		; COMPUTE DISP TO ACTUAL BLOCK NUMBER W/I EXT
	STA	LTEMP		; SAVE THERE
	MOV	E,A		; AND HERE
	LDA	TWOFLG		; GET FLAG INDICATING TWO-BYTE BLOCK # IF ON
	ORA	A
	LHLD	ARG		; GET BASE OF FCB ADDR
	MOV	A,E		; PUT DISP BACK TO A
	JNZ	DSKW11		; JUMP IF TWO BYTE BLOCK NUMBER
	DCR	A		; POINT TO PREVIOUS BLOCK NUMBER
	CALL	ADDVAL		; COMPUTE ITS ADDR
	MOV	C,M		; GET PREVIOUS BLOCK NUMBER TO C
	JMP	DSKWR2		; CONTINUE
DSKW11:
	DCR	A		; BACK UP TWO BYTES TO GET ADDR OF PREVIOUS ONE
	DCR	A
	CALL	ADDVAL		; COMPUTE ADDR OF PREVIOUS BLOCK NUMBER
	MOV	C,M		; GET LOW BYTE
	INX	H
	MOV	B,M		; GET HIGH BYTE
;
;	FIND A BLOCK AVAILABLE ON DISK CLOSEST TO THE
;	BLOCK IN REGISTER BC.
;
DSKWR2:	
	MVI	A,ODSM		; OFFSET TO NUMBER OF BLOCKS PARAMETER
	CALL	GTDPBA		; GET FROM DISK PARAMETER BLOCK
	INX	H		; BUMP EXTENT # (NO TEST FOR <?>'s)
	SHLD	MXBLK		; SAVE THERE
	MOV	D,B		; BC GOES UP, DE GOES DOWN
	MOV	E,C
	MOV	A,C
	ORA	B		; SET FLAGS
	JNZ	GTBLK1		; CHECK IF ZER0=>MUST INC B SO THAT
	INX	B		; THE ROUTINE DOES NOT PREMATURELY END
GTBLK1:
	PUSH	D		; SAVE DOWN BLOCK NUMBER
	CALL	TRYUP		; HIGHER BLOCK AVAILABLE?
	POP	D		; RESTORE DOWN BLOCK NUMBER
	ORA	A		; SET FLAGS
	JNZ	DSKWR3		; JUMP IF BLOCK AVAILABLE
	CALL	TRYDWN		; LOWER BLOCK AVAILABLE?
	ORA	A		; SET FLAGS
	JNZ	DSKWR3		; JUMP IF BLOCK AVAILABLE
	MOV	A,B
	ORA	C		; BC AND DE  WILL BE ZERO IF LIMITS REACHED
	ORA	D
	ORA	E
	JNZ	GTBLK1		; KEEP GOING IF AT LEAST ONE OF THEM IS NOT 0
	MVI	A,2		; ERROR, DISK FULL
	STA	RETCOD
	RET			; DONE, SORRY--NO WRITE
TRYUP:
	MOV	A,B
	ORA	C		; LIMIT REACHED ALREADY?
	RZ			; RETURN IF SO
	INX	B
	LHLD	MXBLK		; GET MAXIMUM BLOCK NUMBER
	CALL	COMPBC		; COMPARE TO BC
	JNZ	TRYUP1		; NOT YET, JUMP
	XRA	A		; SET UP RETURN REGISTER
	MOV	B,A		; FOR NEXT PASS TO CANCEL A 'TRYUP'
	MOV	C,A		; CLEAR BOTH BYTES
	RET
TRYUP1:
	CALL	GTABIT		; GET ALLOCATION BIT
	ANI	1		; MASK OFF UNNEEDED BITS
	MVI	A,FALSE
	RNZ			; RETURN IF ALLOCATED
	MVI	A,1		; FOUND A BLOCK
	RET
TRYDWN:
	MOV	A,E
	ORA	D		; LIMIT ALREADY REACHED?
	RZ
	DCX	D		; SET FOR NEXT LOWER BLOCK
	PUSH	D		; SAVE NEXT TEST BLOCK NUMBER
	PUSH	B		; SAVE BLOCK COUNTERS
	MOV	B,D		; PUT BLOCK NUMBER IN BC FOR GTABIT ROUTINE
	MOV	C,E
	CALL	GTABIT
	POP	B		; RESTORE COUNTERS
	POP	D		; RESTORE NEXT BLOCK NUMBER
	ANI	1		; MASK OFF UNNEEDED BITS
	MVI	A,FALSE		; SET FOR NG
	RNZ			; RETURN IF ALLOCATED
	MVI	A,1		; SIGNAL BLOCK FOUND
	MOV	B,D		; PUT BLOCK NUMBER IN BC
	MOV	C,E
	RET
DSKWR3:
	MVI	A,OBLM		; OFFSET FOR BLOCK MASK
	CALL	GTDPBB		; GET BLM
	MOV	H,A		; SAVE IN H
	LDA	RELREC		; GET NX RECORD TO R/W
	ANA	H		; MASK ALL BUT REL W/I BLOCK
	MVI	A,0		; SET A TO 0 IN CASE NOT FIRST W/I NEW BLOCK
	JNZ	DSKW30		; JUMP IF NOT FIRST W/I NEW BLOCK
	MVI	A,2		; CP/M UNALLOCATED BLOCK FLAG
DSKW30:
	STA	UNAFLG
	MOV	H,B		; 
	MOV	L,C		; SET UP H-L TO CONTAIN RECORD NUMBER
	PUSH	H		; SAVE FOR LATER WRITE
	LHLD	ARG		; GET ADDRESS OF FCB
	LDA	LTEMP 		; POINT TO DISPLACEMENT INTO DISK MAP
	CALL	ADDVAL		; CALC ADDR WHERE NEW BLOCK IS TO BE STORED
	MOV	M,C		; STORE NEW BLOCK NUMBER THERE
	LDA	TWOFLG		; TWO BYTE BLK NUMBER FLAG
	ORA	A
	JZ	DSKW31		; JUMP IF OFF
	INX	H		; POINT TO NEXT BYTE
	MOV	M,B		; STORE HIGH BYTE OF TWO BYTE BLOCK NUMBER
DSKW31:	MVI	E,1		; SET LOW BIT OF E FOR SETTING BIT  TO BLOCK BC
	CALL	STABIT		; MARK BLOCK AS ALLOCATED
	POP	H		; RESTORE BLOCK NUMBER FOR DISK WRITE
	CALL	TSTZRO		; TEST FOR WRT W/ZRO FILL; ZERO BLK IF ON
DSKWR4:
	LDA	RETCOD		; CHECK THAT ALL HAS BEEN WELL
	ORA	A
	RNZ
	CALL	FNDREC		; GET LOGICAL RECORD
	CALL	SEEK		; SET DISK TO THIS SPOT
	CALL	DATDMA		; PREPARE BY SETTING WRITE BUFFER ADDRESS
	CALL	WRDISK		; WRITE OUT SECTOR
	LDA	RELREC		; GET RELATIVE RECORD, SEE IF TIME TO BUMP CT
	LXI	H,RECCNT
	CMP	M		; HERES THE TEST
	JC	DSKWR5		; JUMP IF RECORD WRITTEN L THAN END OF CUR EXT
	INR	A		; BUMP RELATIVE RECORD AS STORED IN A SO
	MOV	M,A		; CAN SAVE THE NEW RECORD COUNT 
DSKWR5:
	LDA	RAFLAG		; RANDOM WRITE ?
	ORA	A
	JNZ	DSKWR6		; JUMP IF SO
	LDA	RELREC		; GET BACK VIRTUAL RCD #
	CPI	127		; COMPARE AGAINST THE MAX REL RECORD IN AN EXT
	JNZ	PTCNTS		; IF NOT SAME, PUT NEW COUNTS BACK IN FCB
	CALL	PTCNTS		; PUT NEW COUNTS BACK ANYWAY
	CALL	OPEXT		; BUT THIS TIME, CLOSE THE EXT, OPEN THE NEXT
	LDA	RETCOD		; GET RETURN CODE FOR THAT ROUTINE
	ORA	A
	JNZ	PTCNTS		; ALLOW RELREC TO BE THIS HIGH AND PT COUNT
	DCR	A		; SET RELRECORD TO FF SO IT WILL BE BUMPED TO 0
	STA	RELREC		; SAVE RELATIVE RECORD
       	JMP	PTCNTS		; PUT COUNTS
;
;	RANDOM WRITE, END OF PROCESSING
;
DSKWR6:
	LXI	H,RELREC	; POINT TO REL REC
	DCR	M		; BACK UP ONE SO PTCNTS DOESN'T ADVANCE IT
	JMP	PTCNTS

	PAGE
;****************************************************************
;*								*
;*	TSTZRO	-- TEST FOR ZEROFG TO BE ON; IF SO, ZERO OUT	*
;*		   CURRET FILE BLK				*
;*	   ENTRY	W/FCB SET UP FOR CURRENT WRITE		*
;*								*
;****************************************************************

TSTZRO:
	LDA	ZEROFG
	ORA	A
	RZ			; RET IF NOT ON
;
	PUSH D! PUSH B! PUSH H
	LHLD	DIRBUF
	CALL	ZROBUF		; CLEAR DIRBUF TO ZEROS
	POP  H! POP B
	PUSH B! PUSH H
;
	CALL	FNDREC		; GET LOGICAL RCD # (INTO <HL>)
	PUSH	H		;   & SAVE
	MVI	A,OBLM		; GET BLK MASK
	CALL	GTDPBB
	INR	A		; BUMP 1 TO USE AS COUNTER
	MOV	B,A		; PUT IN B AS COUNTER
	DCR	A		; RESTORE,
	CMA			;   & COMPLEMENT AS A MASK
	POP	H		; GET RCD # BACK,
	ANA	L		;   MASK TO 1ST SCTR IN BLK
	MOV	L,A		;   & PUT BACK IN <L>
;
ZROBK1:
	PUSH B! PUSH D! PUSH H
	CALL	SEEK
	CALL	DIRDMA		; USE ZEROED OUT DIRBUF FOR WRITES
	CALL	WRDISK
	POP  H! POP  D! POP  B
	INX	H
	DCR	B
	JNZ	ZROBK1		; LOOP BLKMSK+1 TIMES
;
	POP  H! POP  B! POP  D
	RET

	PAGE
;****************************************************************
;*								*
;*	FNCREA		DOS # 22				*
;*		CREATE A NEW FILE AND OPEN IT;			*
;*		(ATTR BYTE GETS CLEARED & THEN USER SET; I.E.,	*
;*		 FILE CREATED W/USER BUT W/NO ATTR's)		*
;*								*
;****************************************************************

FNCREA:
MAKE:
	CALL	CHKWRT		; DSK WRITE PROTECTED? (doesn't ret if so)
	LHLD	ARG		; FCB ADDRESS
	PUSH	H		; SAVE FCB ADDRESS
	LXI	H,EMPTY		; ADDRESS OF AN E5H BYTE
	SHLD	ARG		; SET SEARCH ROUTINE TO LOOK FOR FCB W/E5 
	MVI	C,1		; LEN PARM FOR SEARCH
	CALL	SEARCH
	LDA	RETCOD		; GET POSITION IN DIRECTORY
	INR	A
	POP	H		; RESTORE FCB ADDRESS
	RZ			; RETURN IF NO DIRECTORY ENTRY AVAILABLE
	SHLD	ARG		; RESTORE ACTUAL DESIRED FCB ADDRESS
	CALL	GTFCBAT		; PT <HL> TO FCB ATTR BYTE
	MVI	B,FCBLEN-FCBAT	; COUNT OF BYTES IN FCB TO ZERO OUT
	XRA	A
MAKE1:
	MOV	M,A
	INX	H
	DCR	B		; DONE?
	JNZ	MAKE1		;   NO, LOOP
;
	CALL	SETUSR		;   YES, SET LOGGED USER NUMBER IN FCB,
	JMP	CPYFCB		;     & WRITE IT

	PAGE
;****************************************************************
;*								*
;*	FNRENA		DOS # 23				*
;*		RENAME FILE.					*
;*								*
;****************************************************************

FNRENA:
	CALL	SETUSR		; SET USER NUMBER IN FCB
RENAME:
	CALL	CHKWRT		; WRITE PROTECTED?
	MVI	C,SNAMLN	; SRCH LEN EXCLUDES EXT
	CALL	SEARCH		; FIND A MATCH
	LDA	RETCOD		; SAVE RETCOD FROM SEARCH
	STA	SAVRC
RENAM1:
	LDA	RETCOD		; (SEARCH RETURNS # OF POSITION IN DIR
	CPI	0FFH		;   IF FOUND, 0FFH IF NOT FOUND)
	JNZ	RENM1A
	LDA	SAVRC
	STA	RETCOD
	RET
RENM1A:
	STA	SAVRC		; SAVE LATEST SUCCESSFUL RETCOD
	CALL	TSTUSR		; TEST FOR VALID USER (OWNER OR 0)
	JZ	RENM1B		;   GOOD USER, JMP TO CONTINUE
	CALL	ERRUSR		;   ELSE, DSPLY MSG,
	JMP	RENAM4		;     & LOOK FOR NEXT MATCH
RENM1B:
	CALL	FILPRT		;   ELSE, CHECK FILE WRITE PROTECTION
	JZ	RENM1C		;     OK, IF NOT PROTECTED
	CALL	ERWPRT		;     ELSE, DSPLY MSG,
	JMP	RENAM4		;       & LOOK FOR NEXT MATCH
RENM1C:
	MVI	A,FCBMP
	LHLD	ARG		; BASE OF CURRENT FCB
	CALL	ADDVAL		; COMPUTE ADDR OF SECOND FILE NAME
	XCHG			; INTO DE
	LDA	DIRDSP		; GET DISPLACEMENT INTO DIRECTORY BUFFER
	CALL	GETBF		; GET ADDRESS OF START OF FCB IN DIR DMA AREA
	MVI	B,SNAMLN-1	; NUMBER OF BYTES TO MOVE
	INX	D		; DO NOT CHANGE DRIVE/TYPE SPECIFIER OF 0
	INX	H
;
;	MOVE NEW FCB EXCEPT ? MARKS
;
RENAM2:
	LDAX	D		; GET CHAR
	CPI	'?'		; QUESTION MARK ?
	JZ	RENAM3		; SKIP IF SO
	MOV	M,A		; PUT INTO NEW FCB
RENAM3:
	INX	D
	INX	H
	DCR	B		; COUNT DOWN
	JNZ	RENAM2		; JUMP IF MORE TO DO
	CALL	SEEKDR		; SET DISK TO DIRECTORY TRACK/SECTOR
	CALL	WRDIR		; REWRITE NEW DIRECTORY ENTRY
RENAM4:
	CALL	SRCHNX		; LOOK FOR ANOTHER MATCH
	JMP	RENAM1

	PAGE
;****************************************************************
;*								*
;*	FNLOGV		DOS # 24				*
;*		RETURN LOGIN VECTOR				*
;*								*
;****************************************************************

FNLOGV:
	LHLD	LOGGED		;GET DISKS LOGGED-ON VECTOR
	SHLD	RETCOD
	RET


;****************************************************************
;*								*
;*	FNCURD		DOS # 25				*
;*		RETURN LOGGED IN DISK				*
;*								*
;****************************************************************

FNCURD:
	LDA	LOGDSK		; GET LOGGED ON DISK
	STA	RETCOD
	RET


;****************************************************************
;*								*
;*	FNSDMA		DOS # 26				*
;*		SET RECORD DMA ADDRESS				*
;*								*
;****************************************************************

FNSDMA:	XCHG    		; GET ARGUMENT, NEW DMA ADDRESS, INTO H/L
	SHLD	DMAADR
	JMP	DATDMA		; SET DMA--BUG COMPLIMENTS OF DIGITAL RESEARCH


;****************************************************************
;*								*
;*	FNGDMA		DOS # 138	(DMADOS # 60)		*
;*		GET DMA ADDRESS					*
;*								*
;****************************************************************

FNGDMA:
	LHLD	DMAADR		;GET CURRENT DMA ADDRESS
	SHLD	RETCOD		;SAVE AS RETURN RESULT
	RET

	PAGE
;****************************************************************
;*								*
;*	FNALOC		DOS # 27				*
;*		GET ADDRESS OF DISK ALLOCATION MAP		*
;*								*
;****************************************************************

FNALOC:
	MVI	A,OALVEC	; OFFSET OF MAP ADDRESS
	CALL	GTDPH		; FETCH FROM DISK PARAMETER HEADER
	SHLD	RETCOD		; AND GO HOME
	RET


;****************************************************************
;*								*
;*	FNRODV		DOS # 29				*
;*		GET READ ONLY VECTOR				*	
;*								*
;****************************************************************

FNRODV:
	LHLD	RODSK
	SHLD	RETCOD
	RET


;****************************************************************
;*								*
;*	FNDPB		DOS # 31				*
;*		GET ADDRES OF DISK PARAMETER BLOCK		*
;*								*
;****************************************************************

FNDPB:
	LHLD	CURDPB		;IS STASHED AWAY HERE - HOW CONVENIENT!
	SHLD	RETCOD
	RET

	PAGE
;****************************************************************
;*								*
;*	FNUSER		DOS # 32				*
;*		GET/SET USER NUMBER				*	
;*								*
;****************************************************************

FNUSER:
	MOV	A,E		; GET OR SET?
	INR	A
	JNZ	FNSTUS
	LDA	USRN		; FETCH IT FROM OUR HIDING PLACE
	STA	RETCOD
	RET
FNSTUS:				; SET IT
	MOV	A,E		; GET THAT BYTE TO A
	ANI	0FH		; ONLY ALLOW 16 USERS
	STA	USRN
	RET


;****************************************************************
;*								*
;*	FNRNRD		DOS # 33				*
;*		RANDOM RECORD READ				*
;*								*
;****************************************************************

FNRNRD:
	MVI	A,1
	STA	RDFLAG		; SET READ FLAG
	CALL	RNDSET		; SETUP PROPER EXTENT, ETC.
	JMP	DSKRD		; DO FILE READ


;****************************************************************
;*								*
;*	FNRNWR		DOS # 34				*
;*		RANDOM RECORD WRITE				*	
;*								*
;****************************************************************

FNRNWR:	XRA	A
	STA	RDFLAG		; CLEAR READ FLAG
	CALL	RNDSET		; SET UP PROPER EXTENT, ETC.
	JMP	DSKWR		; PERFORM FILE WRITE

	PAGE
;****************************************************************
;*								*
;*	RNDSET	Routine to prepare a random rd/wrt operation;	*
;*		- It will close the prv random ext if the new	*
;*		  one referenced is different;			*
;*		- Extent & nxt rcd counter will be set up for	*
;*		  the new rd/wrt;				*
;*		- If the ext is not available, a rd will abort,	*
;*		  while a wrt will attempt to open the new ext	*
;*		  (using OPEXT).				*
;*								*
;****************************************************************

RNDSET:
	MVI	A,1
	STA	RAFLAG		; SET RANDOM R/W FLAG ON
	XRA	A
	STA	RETCOD		; CLEAR HIM
	LHLD	ARG		; FCB ADDR
	LXI	D,FCBEX		; DISP TO EXTENT BYTE (LOW)
	DAD	D
	MOV	E,M		; GET LOW (EXTENT)
	INX	H
	MOV	D,M		; GET HIGH (EXTENT)
	CALL	CMPRND		; COMPUTE RANDOM EXTENT AND NEXT RECORD
	LHLD	RNDEXT		; GET RANDOM EXTENT
	CALL	COMPDE		; SEE IF SAME AS OLD EXTENT
	CNZ	OPEXT		; CLOSE CURRENT EXTENT, OPEN NEXT ONE
	LHLD	ARG		; GET FCB ADDRESS AGAIN
	LXI	D,FCBNS		; DISP TO NXT RCD
	DAD	D
	LDA	RNDNXR		; GET COMPUTED NXT RCD
	MOV	M,A		; PLACE IN FCB
	LDA	RETCOD		; GET RET CODE FROM OPEXT (OR ZERO IF NOT USED)
	ORA	A
	RZ			; RETURN IF OK
	INR	A		; CHECK FOR 0FFH ==>EXT NOT CLOSE OK
	POP	H		; FIX STACK
	RNZ			; RETURN IF ANY OTHER ERROR
	MVI	A,ERNCLS	; NOT CLOSE ERROR
	STA	RETCOD
	RET

	PAGE
;****************************************************************
;*								*
;*	FNSIZE		DOS # 35				*
;*		COMPUTE FILE SIZE				*	
;*								*
;****************************************************************

FNSIZE:
				; ADDRESSED FCB IS IN <DE>
	CALL	SETUSR		; SET USER CODE IN FCB
	MVI	C,SNAMLN	; SRCH LEN EXCLUDES EXT
	CALL	SEARCH		; DO FIRST SEARCH
	LDA	RETCOD		; ERROR ?
	INR	A
	RZ			; RETURN IF SO
	LXI	H,0
	SHLD	RNDEXT		; SET INITIAL LARGEST EXT TO 0
;
;	LOOP LOOKING FOR HIGHEST EXTENT #
;
FNSIZ1:
	LDA	DIRDSP		; GET DISP INTO DIRECTORY BUFFER
	CALL	GETBF		; <HL> NOW PTS TO FIRST BYTE OF FOUND ENTRY
	PUSH	H		; SAVE ON STACK
	LXI	D,FCBEX		; DISP TO LOW(EXT)
	DAD	D
	MOV	A,M		; GET LOW(EXT)
	INX	H
	MOV	H,M		; GET HIGH(EXT)
	MOV	L,A
	XCHG			; NEW EXT FOUND TO <DE>
	LHLD	RNDEXT		; GET PREVIOUS HIGHEST ONE FOUND,
	CALL	COMPDE		;   & SEE IF NEW ONE SMALLER
	POP	H		; GET BACK FCB BASE OF FOUND ENTRY
	JC	FNSIZ3		; JUMP IF SO, TO SRCH FOR NEXT ENTRY
	XCHG			; NEW HIGHEST EXT TO <HL>, FCB TO <DE>,
	SHLD	RNDEXT		;   & SAVE NEW HIGHEST EXT
	LXI	H,FCBRC		; DISP TO RCD COUNT
	DAD	D
	MOV	A,M		; GET NEXT RCD
	JP	FNSIZ2		; JUMP IF IT WAS NOT 80H
	XRA	A		; ELSE, MAKE IT 0 (AS IF NO RCDS IN FILE)
FNSIZ2:
	STA	RNDNXR		; SAVE THERE
FNSIZ3:
	CALL	SRCHNX		; CONTINUE WITH NEXT SEARCH
	LDA	RETCOD		; GET RETURN CODE
	INR	A		; DONE ?
	JNZ	FNSIZ1		; JUMP IF NOT TO CONTINUE LOOP
;
;	HIGHEST EXTENT/RECORD IN RNDEXT AND RNDNXR. USE THEM TO COMPUTE RAN RCD
;
	LHLD	RNDEXT		; GET RANDOM EXTENT TO USE,
	LDA	RNDNXR		;   GET FCB NEXT RCD #,
	MOV	B,A		;     & SAVE IN <B>;
	JMP	FNRNSAE		; THEN, JUMP TO SET RANDOM RCD ALT ENTRY

	PAGE
;****************************************************************
;*								*
;*	FNRNST		DOS # 36				*
;*		SET RANDOM RECORD				*	
;*	ENTRY:	W/ADDRESSED FCB IN <DE>				*
;*								*
;****************************************************************

FNRNST:
				; ADDRESSED FCB IS IN <DE>
	LXI	H,FCBNS		; DISP TO NEXT RCD,
	DAD	D
	MOV	B,M		;   SAVE IN <B>
	LXI	H,FCBEX		; PT TO LOW(EXT),
	DAD	D
	MOV	E,M		;   PUT LOW(EXT) INTO <E>,
	INX	H
	MOV	D,M		;   & HIGH(EXT) INTO <D>
	XCHG			; <H> NOW HAS HIGH(EXT), <L> HAS LOW(EXT)
;
FNRNSAE:
	MOV	A,L		; GET LOW(EXT)
	RAR			; PUT LOW BIT TO Cy
	MOV	A,B		; GET NEXT RCD (FIRST SEVEN BITS)
	RAL			; GET BIT 0 OF LOW(EXT) INTO BIT 0
	RRC			; FORM R0
	STA	RNDEXT		;  SAVE AT RNDEXT
	MOV	B,L		; GET LOW(EXT) AGAIN,
	MOV	A,H		;   & THEN HIGH(EXT)
	RAR			; GET LOW BIT TO Cy
	MOV	A,B		; GET BACK LOW(EXT)
	RAR			; BIT 0 OF HIGH(EXT) TO BIT 7 OF r1
	STA	RNDEXT+1	;  SAVE AT RNDEXT+1
	MOV	A,H		; GET HIGH(EXT) AGAIN
	ORA	A		; CLEAR Cy
	RAR			; FORM R2, MAX IS 7F (HIGH 7 BITS ROTATED)
;
	LHLD	ARG		; GET BACK ADDRESSED FCB
	LXI	D,FCBRR2	; DISP TO RR2 BYTE IN FCB
	DAD	D		; COMPUTE PTR TO R2,
	MOV	M,A		;   & STORE R2
	XCHG
	LHLD	RNDEXT		; GET BACK R1/R0 INTO <HL>
	XCHG
	DCX	H		; POINT TO R1 BYTE IN FCB,
	MOV	M,D		;   STORE R1,
	DCX	H
	MOV	M,E		;   & R0
	RET

	PAGE
;****************************************************************
;*								*
;*	RSTDRV		DOS # 37				*
;*		RESET DRIVE(S) SPECIFIED IN DRIVE VECTOR	*
;*								*
;****************************************************************

RSTDRV:
	LHLD	ARG	; GET DRV VECTOR,...
	MOV	A,H	; ...& SET UP MASK OF DRVS TO RESET
	CMA
	MOV	H,A
	MOV	A,L
	CMA
	MOV	L,A
	XCHG		; PUT IN DE
	LHLD	LOGGED	; GET CUR LOGGED IN DRVS
	CALL	ANDEHL	; LOGICALLY AND W/MASK IN DE OF DRVS TO RESET
	SHLD	LOGGED
	CALL	RSSYS1
	XRA	A	; CLEAR A FOR COMPATIBILITY W/MPM (AS PER CPM SPEC)
	STA	RETCOD
	RET


;****************************************************************
;*								*
;*	ZROFIL		DOS # 40				*
;*		WRITE RANDOM SECTOR, W/ZERO FILL IF BLOCK	*
;*		CONTAINING SECTOR WAS UNALLOCATED		*
;*								*
;****************************************************************

ZROFIL:
	MVI	A,1
	STA	ZEROFG		; TURN ZEROFG ON
	CALL	FNRNWR		; PERFORM RANDOM FILE WRITE
	XRA	A
	STA	ZEROFG		; TURN ZEROFG OFF
	RET

	PAGE
;****************************************************************
;*								*
;*	FNSETA		DOS # 30	(DMADOS # 59)		*
;*		SET FILE ATTRIBUTES				*	
;*								*
;****************************************************************

FNSETA:
	CALL	SETUSR		; SET USER BITS IN FILE ATTRIBUTE BYTE
	CALL	CHKWRT		; CHECK DISK FOR WRITE PROTECTION
	MVI	C,SNAMLN	; SRCH LEN EXCLUDES EXT
	CALL	SEARCH
	LDA	RETCOD		; GET RETCODE FROM 1ST SRCH 
	STA	SAVRC		;   & SAVE IT
STATR1:
	LDA	RETCOD		; GET RETCODE FROM SRCH (# OF POSITION IN
	CPI	0FFH		;   DIR IF FOUND, 0FFH (-1) IF NOT FOUND)
	JNZ	STATR2		; JMP IF FOUND TO SAVE LATEST GOOD RETCODE
	LDA	SAVRC
	STA	RETCOD		; ELSE EXIT W/1ST RETCODE OR LATEST GOOD
	RET			;   RETCODE
STATR2:
	STA	SAVRC
	CALL	TSTUSR		; TEST FOR VALID USER (OWNER OR 0)
	JZ	STATR3		;   GOOD USER, JMP TO CONTINUE
	CALL	ERRUSR		;   ELSE, DSPLY MSG,
	JMP	STATR4		;     & LOOK FOR NEXT MATCH
STATR3:
	CALL	GTFCBAT		; GET FCB ATTR BYTE (PRESERVES USER IN <D>)
	ANI	NOT UMK		; ONLY THE ATTRIBUTES GET CHANGED
	ORA	D		; 'OR' TOGETHER FCB ATTR W/DCB USER #
	STAX	B		;   & STORE BACK IN DCB
	CALL	WRDIR  		; WRITE OUT NEW DIRECTORY ENTRY
STATR4:
	CALL	SRCHNX		; LOOK FOR ANOTHER MATCH
	JMP	STATR1


TSTUSR:				; (MUST RET DCB ADDR OF ATTR BYTE IN <BC>)
	CALL	GTDCBAT		; GET DCB ATTR BYTE
	ANI	UMK		; MASK ALL BUT USER BITS
	MOV	B,H		; SAVE PTR TO ATTR BYTE IN <BC>,
	MOV	C,L		;   (FOR FNSETA)
	MOV	D,A		; SAVE DCB USER NUMBER IN D
	LDA	USRN		; GET CURRENT USER NUMBER
	CMP	D		; TST FOR MATCH
	RZ			;   RET W/Z SET IF MATCH
	ORA	A		; USER 0 ?
	RET			;   (Z SET IF USER 0)

	PAGE
;****************************************************************
;*								*
;*	QUEPRN		DOS # 128	(DMADOS # 48)		*
;*		QUEUE A FILE AND START PRINT IF CURRENT STATUS	*
;*		IS EMPTY.  IF QUEUE IS FULL RET PARAM IS 1	*
;*		(FILE IS NOT QUEUED)				*
;*								*
;****************************************************************

QUEPRN:	LXI	H,BPQ		; GET QUEUE START
	LXI	D,QUELEN	;
	MVI	B,MAXQUE
	INX	H
	MOV	A,M		; TEST IF QUEUE IS EMPTY
	DCX	H
	ORA	A
	JZ	INITBR		; YES, INIT PRINT
;
;  MUST BE RUNNING, OR ERROR  *****
;
	LDA	BPRFLG		; GET FLAG
	CPI	BKPRUN		; IS RUNNING?
	MVI	A,1		; SET ERROR
	STA	RETCOD
	RNZ			; IF NOT, RETURN
QUEP1:	DAD	D		; GET NEXT POSITION
	INX	H
	MOV	A,M
	DCX	H
	ORA	A		; IS EMPTY?
	JZ	QUEP2		; YES, MOVE FILE NAME
	DCR	B		; DECR ENTRY COUNT
	JNZ	QUEP1		; NOT END YET
	MVI	A,1		; NO ROOM
	STA	RETCOD		; TELL THE CALLER
	RET
;
; MUST BE RUNNING OR READY, AND HAVE ROOM FOR FILE
;   (MUST RESET RETCOD, SINCE IT IS AN ALT ENTRY PT AFTER RETCODE WAS SET)
;
QUEP2:	XCHG			; PUT QUEUE BUF ADDR INTO <DE> AS DEST
	LHLD	ARG		; PT <HL> TO USER NAME
	MVI	B,QUELEN
	CALL	MOVE  		; MOVE THE NAME ONTO QUEUE
	XRA	A
	STA	RETCOD		; NO ERRORS
	RET
;
INITBR:	LDA	BPRFLG		; GET PRINT FLAG
	ORA	A		; (CPI BKPQMT)
	MVI	A,1
	STA	RETCOD		; TELL ABOUT THE ERROR
	RNZ			; NOT EMPTY, MUST BE ERROR
	MVI	A,BPRRDY	; SET READY TO PRINT
	STA	BPRFLG
	JMP	QUEP2		; MOVE THE FILENAME

	PAGE
;****************************************************************
;*								*
;*	SUSPRN		DOS # 131	(DMADOS # 51)		*
;*		SUSPEND THE PRINT OPERATION IF RUNNING		*
;*								*
;****************************************************************

SUSPRN:	LDA	BPRFLG		; GET FLAG, SEE IF RUNNING
	CPI	BKPRUN
	MVI	A,1
	STA	RETCOD
	RNZ
	MVI	A,SUSPND	; WAS RUNNING SO STOP IT
	STA	BPRFLG
	MVI	A,FALSE
	STA	RETCOD
	RET


;****************************************************************
;*								*
;*	RESPRN		DOS # 132	(DMADOS # 52)		*
;*		RESTORE SUSPENDED PRINT TASK TO RUNNING		*
;*								*
;****************************************************************

RESPRN:	LDA	BPRFLG		; CK IF REALLY SUSPENDED
	CPI	SUSPND
	MVI	A,1		; SET ERROR
	STA	RETCOD
	RNZ
	MVI	A,BKPRUN	; O.K. TO START AGAIN
	STA	BPRFLG		; SAVE NEW FLAG
	MVI	A,FALSE
	STA	RETCOD
	RET

	PAGE
;****************************************************************
;*								*
;*	UNQPRN		DOS # 129	(DMADOS # 49)		*
;*		DEQUEUE A FILE AND STOP PRINTING IF CURRENT	*
;*		FILE IS DEQUEUED				*
;*								*
;****************************************************************

UNQPRN:	LHLD	ARG		; GET FILENAME
UNQPRX:	LXI	D,BPQ		; START OF QUEUE
	MVI	C,MAXQUE
	PUSH	H		; SAVE  FCB POINTER
	PUSH	D		; SAVE BPQ POSITION
;
DEQU2:	MVI	B,QUELEN	; SEE IF MATCH
DEQU6:	LDAX	D
	CMP	M
	JNZ	DEQU1		; NOT A MATCH, CK NEXT
	INX	D
	INX	H
	DCR	B
	JNZ	DEQU6		; NEXT CHARACTER
	POP	D		; MATCH ENTRY = DE
	POP	H		; MAKE THE STACK O.K.
	LXI	H,QUELEN
	DAD	D		; HL=MATCH+QUELEN, DE=MATCH
DEQU3:	MVI	B,QUELEN	; CRUNCH UP THE QUEUE
DEQU4:	MOV	A,C
	DCR	A		; CK IF LAST ENTRY
	JZ	DEQU7		; A ALREADY = QCLR
	;
	MOV	A,M
DEQU7:	STAX	D
	INX	H
	INX	D
	DCR	B
	JNZ	DEQU4
	DCR	C		; NEXT NAME TO CRUNCH
	JNZ	DEQU3
	XRA	A
	STA	RETCOD		; NO ERRORS
	LDA	BPQ+1		; IS EMPTY?
	ORA	A
	MVI	A,BPRRDY	; SET TO OPEN THE NEXT FILE
	STA	BPRFLG
	RNZ
	MVI	A,BKPQMT	; KILL THE PRINT OPERATION
	STA	BPRFLG
	RET
;
;
DEQU1:	POP	D		; GET NEXT ENTRY
	LXI	H,QUELEN
	DAD	D
	XCHG
	POP	H		; HL=FCB, DE=BPQ POSITION
	DCR	C
	JP	DEQU5
	;
;
NOFIND:	MVI	A,1		; TELL ABOUT THE ERROR (NOT FOUND)
	ORA	A
	STA	RETCOD
	RET
;
DEQU5:	PUSH	H
	PUSH	D		; SAVE FILENAME, AND  BPQ POSITION
	JMP	DEQU2

	PAGE
;****************************************************************
;*								*
;*	GTBPRS		DOS # 133	(DMADOS # 53)		*
;*		GET THE PRINT STATUS FLAG			*
;*								*
;****************************************************************

GTBPRS:	LDA	BPRFLG		; GET IT
	STA	RETCOD		; SAVE IT
	RET


;****************************************************************
;*								*
;*	STBPRS		DOS # 134	(DMADOS # 54)		*
;*		SET THE PRINT STATUS				*	
;*								*
;****************************************************************

STBPRS:
	LDA	ARG		;GET USER ARG.
	STA	BPRFLG		;SET THE FLAG
	RET


;****************************************************************
;*								*
;*	QUEVEC		DOS # 135	(DMADOS # 55)		*
;*		QUE VECTOR FETCH				*	
;*								*
;****************************************************************

QUEVEC:	LXI	H,BPQ		;GET THE QUEUE START ADDRESS
	SHLD	RETCOD		;RETURN THE ADDRESS
	RET

	PAGE
;****************************************************************
;*								*
;*	KILPRN		DOS # 130	(DMADOS # 50)		*
;*		KILL THE BACKGROUND PRINT FUNCTION		*
;*		DELETE THE QUEUE				*
;*								*
;****************************************************************

KILPRN:	MVI	A,BKPQMT	; SET THE QUEUE FLAG TO EMPTY
	STA	BPRFLG
	LXI	H,BPQ
	MVI	D,MAXQUE	; LENGTH OF ENTRY
KILP2:	MVI	E,QUELEN	; LENGTH OF ENTRY
KILP1:	MVI	M,QCLR		; CLEAR THE BYTE
	INX	H
	DCR	E
	JNZ	KILP1
	DCR	D
	JNZ	KILP2
	RET

	PAGE
;****************************************************************
;*								*
;*	BKPRNT	BACKGROUND PRINT ROUTINE			*
;*		THIS ROUTINE MAY CAUSE A CALL TO THE FILE	*
;*		ACCESS SUBROUTINES IN THIS MODULE.		*
;*		THE USER CALL STATUS IS PRESERVED		*
;*		ARG,RETCOD,DMAADR,DIRBUF, ETC IS PRESERVED	*
;*								*
;****************************************************************

BKPRNT:	LDA	BPRFLG		; GET THE STATUS
	ORA	A		; CK IF = QCLR
	RZ			; EMPTY, DO NOTHING
	CPI	BPRRDY		; IS READY TO OPEN?
	JZ	OPNEXT		; SO OPEN IT.
BKPRN1:	LDA	BPRFLG		; GET THE LATEST STATUS
	CPI	BKPRUN		; IS RUNNING?
	RNZ			; BYE, YOU SHOULD HAVE BEEN RUNNING!
	CALL	PRTRDY		; IS BUSY ?
	ORA	A		; SET FLAGS
	RZ			; RETURN IF SO
	LHLD	BPBUFP		; GET BUFFER POINTER
	MOV	A,M		; GET NEXT CHARACTER
	CPI	EOF		; IS EARLY END?
	JZ	NXTFIL		; OPEN THE NEXT( SET FLAG )
	MOV	C,A		; GET CHAR FOR UIOI CALL
	PUSH	H		; SAVE PTR
	CALL	LSTOUT		; PRINT THE CHARACTER
	POP	H		; RETRIEVE TEXT PTR
	INX	H		; BUMP POINTER
	SHLD	BPBUFP		; SAVE THE NEW
	MVI	A,BPBUFE AND 0FFH
	CMP	L		; AT THE END YET
	RNZ			; NO, SO, DONE
	LXI	H,BPBUF		; SET THE INIT POINTER
	SHLD	BPBUFP
	CALL	RDFIL		; 
	LDA	RETCOD		; GET RESULT
	ORA	A
	RZ
	CPI	01		; END OF FILE?
	JNZ	ERRBPR		; MUST BE ERROR IF NOT
	;
NXTFIL:	LXI	H,BPQ+QUELEN+1	; IS NEXT ENTRY EMPTY (CK FILENAME)
	MOV	A,M
	ORA	A
	JZ	KILPRN		; MUST KILL THE PRINT FLAG
	MVI	A,BPRRDY	; SET READY FOR NEXT CALL
	STA	BPRFLG
	LXI	H,BPQ		; FOOL THE UNQUEUE INTO A MATCH
	JMP	UNQPRX		; TO DELETE THE TOP FILE
;
ERRBPR:	MVI	A,FILSUS	; SET THE FLAG TO ERROR
	STA	BPRFLG
	RET
;
; OPEN THE FILE ON TOP OF THE QUEUE
;
OPNEXT:
	XRA	A		;CLEAR THE NEXT RECORD FLAG
	STA	BPNR
	STA	BPEXT		;CLEAR EXTENT ALSO
	LXI	H,BPBUF		;RESET THE BUFFER POINTER
	SHLD	BPBUFP
	LXI	H,BPQ		;SET THE FILENAME INTO THE FCB
	LXI	D,BPRFCB
	PUSH	D		;SAVE HIM
	MVI	B,QUELEN
	CALL	MOVE		;GET NEXT DRIVE/FILE NAME INTO BPR FCB AREA
	CALL	BPSAV		;SAVE THE DOS STATUS
	POP	D		;RESTORE BPR FCB ADDRESS
	CALL	DCHKIN		;CHECK IN DISK IF NECESSARY
	CALL	FNOPEN		; OPEN THE FILE
	CALL	EXCLNP		;USE THE DOS ROUTINE TO RESTORE IT
	XRA	A
	STA	DSKIN
	CALL	BPRES		;RESTORE THE DOS STATUS
	LDA	RETCOD
	INR	A		;TEST IF ERROR
	JZ	ERRBPR		;YES
	CALL	RDFIL		;READ THE FIRST SECTOR
	LDA	RETCOD
	CPI	01		;EOF?
	JZ	NXTFIL		;OPEN THE NEXT FILE
	ORA	A
	JNZ	ERRBPR
	MVI	A,BKPRUN	;SET THE FLAG TO RUN
	STA	BPRFLG
	RET
;
RDFIL:	CALL	BPSAV		;SAVE DOS STATUS
	LXI	D,BPRFCB	;GET ADDRESS OF BPR FCB
	CALL	DCHKIN		;CHECK IN THE DISK
	CALL	FNREAD
	CALL	EXCLNP		;RESET THE DOS PARAMETERS
	XRA	A
	STA	DSKIN		;RESET SO WE DON'T RESTORE AGAIN
	JMP	BPRES		;RESTORE IT
;
BPSAV:
	LHLD	DMAADR		;DMA ADDRESS
	SHLD	DMATEM
	LHLD	DIRBUF		;DMA FOR DIR
	SHLD	DIRTEM
	LHLD	ARG		;GET USER PARAMETER
	SHLD	TEMP1
	LXI	H,BPRFCB	;SET TO BPRINT FCB
	SHLD	ARG
	LXI	H,BPBUF		;GET START OF BPR BUFFER AREA
	SHLD	DMAADR		;SET DMA ADDRESS THERE
	RET			;AND EXIT
;
BPRES:
	LHLD	TEMP1
	SHLD	ARG
	LHLD	DMATEM
	SHLD	DMAADR
	RET

	PAGE
;****************************************************************
;*								*
;*	LSTOUT	(USED BY BKPRNT SUBROUT ONLY)			*
;*		OUTPUT CHARACTER TO LIST DEVICE;		*
;*		TABS ARE EXPANDED				*
;*								*
;*		ENTRY:	CHARACTER IN [C]			*
;*								*
;****************************************************************

LSTOUT:	MOV	A,C		; CHAR TO [A]
	CPI	TAB		; CHECK FOR TAB CHARACTER
	JNZ	PUTLST		; NO, OUTPUT TO CONSOLE
LSTAB0:	MVI	C,' '		; PAD TO NEXT COLUMNAR POSITION
	CALL	PUTLST		; PUT CHARACTER, BUMP COUNTER
	LDA	LCOLMN		; GET COLUMN NUMBER
	ANI	7		; MOD 8
	JNZ	LSTAB0		; SEND UNTIL AT MOD 8 POSITION
	RET


;****************************************************************
;*								*
;*	PUTLST	SEND CHARACTER TO LIST DEVICE			*
;*		CONTROL COLUMNAR POSITION			*
;*								*
;****************************************************************

PUTLST:	PUSH	B		; SAVE CHARACTER
	CALL	LIST		; TO PUT THE CHARACTER
	POP	B		; RECALL IT AGAIN
	MOV	A,C		; GRAPHIC (ASCII CTL)?
	LXI	H,LCOLMN
	INR	M		; INCREMENT COLUMN COUNT
	CPI	' '
	RNC			; NO CARRY GEN'ED IF GRAPHIC (ASCII CTL)
	DCR	M		; NO COLUMN MOVEMENT
	CPI	CR		; END OF LINE?
	RNZ			; DONE IF NOT
	MVI	M,0		; CLEAR COLUMN COUNTER
	RET

	PAGE
;****************************************************************
;*								*
;*	INIBPR		DOS # 136	(DMADOS 56)		*
;*		INITIALIZE BACKGROUND PRINT			*
;*								*
;****************************************************************

INIBPR:
	LDA	BPRFLG		;GET B.P. FLAG
	INR	A		;BUMP TO CHECK FOR ZERO
	RNZ			;RETURN IF ALREADY ON
	CALL	KILPRN		;KILL AND INIT THE QUEUE & FLAG
	LHLD	CONRDY+1	;DO THE BAD DEED (MODIFY THE UIOI)
	SHLD	CRDTEM		;OUCH!!!
	LXI	H,BPENT		;
	SHLD	CONRDY+1	;AND OUCH AGAIN...
	LHLD	CONIN+1		;MODIFY THE CONSOLE INPUT, TOO
	SHLD	CONNEW
	LXI	H,BPRCI		;SET THE BYPASS ADDRESS
	SHLD	CONIN+1
	RET
;
; ACTUAL CONIN BYPASS:
;
BPRCI:	CALL	BPENT		;IS ANYTHING TO PRINT?
	ORA	A		;IS CHARACTER READY?-TEST CONSTAT RETURN
	JZ	BPRCI		;CONTINUE PRINTING IF NO CHAR
;
CONLOP:	DB	0C3H		;JUMP INSTRUCTION
CONNEW:	DW	CONLOP		;SET TO LOOP AS DEFAULT
;
; THE ACTUAL CONRDY BYPASS:
;
BPENT:
	PUSH H! PUSH D! PUSH B
	CALL	BKPRNT	;PRINT IT
	POP B!  POP D!  POP H
CRDLOP:	DB	0C3H	;HERE IS THE SCENE.
CRDTEM:	DW	CONRDY	;IF NOT INIT, USE REAL CONSOLE READY

	PAGE
;****************************************************************
;*								*
;*	LDCLI		DOS # 137	(DMADOS # 57)		*
;*		READ SYSTEM.CLI, RESET DOS, AND BRANCH		*
;*								*
;****************************************************************

LDCLI:
	PUSH	B		; SAVE DRV ORIG SPEC'D BY UIOI (IN <C>)
	CALL	RSTSYS		; INITIALIZE THE DOS
	LXI	H,USRN		; GET USR NUMBER
	MOV	A,M
	PUSH	PSW		;   & SAVE IT
	MVI	M,0		; SET USR TO ZERO TO FIND CLI
	LXI	H,CLI		; GET MEM ADDR OF CLI,
	SHLD	LDADDR		;   & SAVE AS LD ADDR FOR LDPGM SUBROUT
	MVI	M,0FBH		; (EI) - INIT CLI IN CASE FILE NOT FND
	INX	H
	MVI	M,76H		; (HLT)
	LXI	H,CLIFCB	; PUT ADDR OF CLIFCB IN <HL>,
	SHLD	ARG		;   & STORE AS ENTRY PARM
	XCHG			;   (PUT IN <DE> FOR DCHKIN)
	CALL	DCHKIN		; THEN, CHECK IN DRV, IF NECESSARY
;
	CALL	LDPGM		; THEN, GO LOAD IT
;
	LDA	CLIRC		; GET RETCODE
	DCR	A		; 1 = CLI NOT FND
	JZ	NOCLI
	DCR	A		; 2 = CLI READ ERROR
	JZ	CRDERR
				; NO MSG DSPLY IF RETCODE = 3 (OVERFLOW)
RDONE:
	POP	PSW		; RETRIEVE ORIG USER NUMBER
	STA	USRN		; AND SAVE IT
	LXI	H,CLIDB		; RESET CLIFCB TO <'1,SYSTEM.CLI'>
	LXI	D,CLIFCB
	MVI	B,12
	CALL	MOVE
	POP	B		; RESTORE ORIG DRV SPEC'D BY UIOI (IN <C>)
	POP	D		; CLNUP STACK (TAKE RET TO EXCLNP OFF)
	PUSH	B		; SAVE ORIG DRV AGAIN,
	MOV	E,C		;   & PUT IN <E> FOR DCHKNW
	CALL	DCHKNW
	POP	B		; RESTORE ORIG DRV,
	RET			;   & RETURN TO CALLER
;
;
CLIFCB:	DB	1		; DRIVE
	DB	'SYSTEM  CLI'	; FILENAME
CLIEXT:	DB	0,0,0,0		; EXT1-2, ATTR/USER, RCCNT
	DS	16		; DSK ALLOC MAP
CLIFBN:	DB	0		; NEXT RECORD TO READ
CLIRC:	DB	0		; LD RETCD
CLIDB:	DB	1,'SYSTEM  CLI'	; DEFAULT CLI <DRV:FILENAME.TYP>
;
;
;
NOCMSG:	DB	CR,LF
NOCNAM:
	DB	'SYSTEM  CLI'
	DB	' not on '
NOCDRV:	DB	'A'
	DB	CR,LF,'$'
;
NOCLI:
	LDA	LOGDSK		; GET DRV WE'RE LOOKING ON,
	ADI	'A'		;   ADD ASCII BIAS,
	STA	NOCDRV		;   & STORE IN MSG
	INX	H		; PT <HL> TO CLI NAME
	LXI	H,CLIFCB+1	; PT <HL> TO SRC  (CLI NAME)
	LXI	D,NOCNAM	; PT <DE> TO DEST (MSG)
	MVI	B,11		; MOVE 11 BYTES
	CALL	MOVE
	LXI	B,NOCMSG	; PT TO THE MSG
;
ERRE:	CALL	PRINT		; PRINT THE OOPS MESSAGE
	JMP	RDONE
;
CRDERR:	LXI	B,CLDMSG	; CLI LOAD ERROR
	JMP	ERRE
;
CLDMSG:	DB	'cli rd err',CR,LF,'$'

	PAGE
;****************************************************************
;*								*
;*	SETCMP		DOS # 139				*
;*		GET/SET FCB COMPATIBILITY			*
;*								*
;*	ENTRY:	-1	GET COMPATIBILITY FLAG			*
;*		 0	SET CPM  COMPATIBILITY			*
;*		 1	SET SB80 COMPATIBILITY (actually, any	*
;*			  other value than 0 or -1 sets cpm)	*
;*								*
;****************************************************************

STCMPT:
	MOV	A,E		; GET OR SET?
	INR	A		;   ( -1 IS GET)
	JNZ	STCPT1		; NZ ==> SET
	LDA	CPMFLG		; ELSE, GET FLAG
	STA	RETCOD
	RET
STCPT1:
	MOV	A,E		; GET ENTRY PARM AGAIN
	STA	CPMFLG
	RET


;****************************************************************
;*								*
;*	BIOSFNC		DOS # 140				*
;*		PROVIDE ACCES TO BIOS VECTOR THRU DOS FN CALL	*
;*								*
;****************************************************************

BIOSFNC:
	LHLD	ARG2		; get entry parm2 (offset to bios vctr)
	MVI	H,0		; offset in <l> on entry
	LXI	D,BIOS
	DAD	D
	PCHL


;****************************************************************
;*								*
;*	STCLIF		DOS # 141				*
;*		SET USER PROVIDED FILENAME TO REPLACE SYSTEM.CLI*
;*								*
;****************************************************************

STCLIF:			
	XCHG			; PT <HL> TO ENTRY PARM (DRV:FILENAME.TYP)
	LXI	D,CLIFCB	; DEST IS CLI FCB
	MVI	B,12		; LENGTH IS 12 BYTES (DRV + FILENAME.TYP)
	CALL	MOVE
	RET

	PAGE
;****************************************************************
;*								*
;*	STLDAD		DOS # 142				*
;*		SET CURRENT LD PGM ADDR TO ADDR SPECIFIED	*
;*								*
;****************************************************************

STLDAD:			
	XCHG			; PUT ENTRY PARM ADDR IN <HL>,
	SHLD	LDADDR		;   & STORE
	RET


;****************************************************************
;*								*
;*	STEXAD		DOS # 143				*
;*		SET CURRENT EXECUTION ADDR			*
;*								*
;****************************************************************

STEXAD:			
	XCHG			; PUT ENTRY PARM ADDR IN <HL>,
	SHLD	EXADDR		;   & STORE
	RET


;****************************************************************
;*								*
;*	LDPGM		DOS # 144				*
;*		LOAD SPECIFIED PGM AT CURRENT LD PGM ADDR	*
;*								*
;*	EXIT:	RETCODE IS STORED IN THE 34th BYTE (R0 BYTE)	*
;*		OF THE FCB; RETCODES ARE:			*
;*			1	FILE NOT FOUND			*
;*			2	READ ERROR			*
;*			3	MEMORY OVERFLOW (OVER DOS)	*
;*		CALLER'S STACK FRAME IS SAVED & RESTORED BEFORE	*
;*		THE INDIRECT JUMP TO EXECUTION ADDR IS DONE.	*
;*		(IF THE FN IS LDCLI, EXIT IS VIA RET RATHER	*
;*		 THAN INDIRECT JUMP.)				*
;*								*
;****************************************************************

LDPGM:			
	CALL	FNOPEN		; OPEN THE REQUESTED FCB
	LDA	RETCOD		; TEST RESULT
	INR	A		; RETCODE = -1 ==> FILE NOT FND
	JNZ	LDPGM1		; JMP IF FILE FND
	INR	A		; ELSE, SET FOR RETCODE = 1
	JMP	LDERR
LDPGM1:
	LHLD	LDADDR		; SET DMA ADDR TO CUR LD ADDR
	SHLD	DMAADR
	LHLD	ARG		; GET ADDRESSED FCB,
	LXI	D,FCBNS		;   & THE OFFSET TO THE NEXT RCD
	DAD	D
	XRA	A		; INIT 1ST RCD #
	MOV	M,A
;
LDPGM2:
	CALL	FNREAD		; READ A SECTOR
	LDA	RETCOD		; GET THE RESULT
	DCR	A		; RETCODE = 1 ==> EOF
	JZ	PGMLDED		; JMP IF EOF
	INR	A		; ELSE TEST FOR OTHER (READ) ERROR
	JZ	LDPGM3		; JMP IF READ OK (MORE TO READ)
	MVI	A,2		; ELSE, SET FOR RETCODE = 2
	JMP	LDERR
LDPGM3:
	LHLD	DMAADR		; BUMP THE DMA ADDR,
	LXI	D,128		;   BY LOGICAL SECTOR SIZE
	DAD	D
	SHLD	DMAADR
	LXI	D,DOS		;   & TEST FOR OVERFLOW
	MOV	A,L
	SUB	E
	MOV	A,H
	SBB	D
	JC	LDPGM2		; NO OVERFLOW, CONTINUE
	MVI	A,3		; ELSE, SET FOR RETCODE = 3
	JMP	LDERR

PGMLDED:
	CALL	SETLDRC		; SET THE LD RETCD (0 IS IN <A>)
	CALL	RSSYS1		; RESTORE DMA ADDR, SELD
	LDA	FUNC		; GET THE FN #,
	CPI	137		;   & TEST FOR LDCLI FN
	RZ			; IF LDCLI, RETURN
	CALL	EXCLNP		; ELSE, RESTORE ENTRY LOGGED DRV,
	LHLD	ENTSP		;   RESTORE CALLER'S STACK FRAME,
	SPHL
	LHLD	EXADDR		;   & DO INDIRECT JMP TO CUR EXEC ADDR
	PCHL


LDERR:
	STA	RETCOD		; RETCODE IS IN <A>
	CALL	SETLDRC
	CALL	RSSYS1		; RESTORE DMA ADDR, SELD
	RET

SETLDRC:
	LHLD	ARG		; GET ADDRESSED FCB,
	LXI	D,FCBRR0	;   & OFFSET TO R0 BYTE (LD RETCD)
	DAD	D
	MOV	M,A		; STORE RETCD
	RET

	PAGE
;****************************************************************
;*								*
;*	ERPERM	DOS ERROR HANDLING ROUTINE			*	
;*								*
;****************************************************************

ERPERM:			
	LXI	H,MSPERM	; REPORT HARD ERROR
ERPERM1:
	CALL	ERPRNT	 	;TO REPORT THE ERROR
	CPI	CTLC
	JZ	WBOOT
	RET			; RETURN, IGNORE ERROR


;****************************************************************
;*								*
;*	ERWPRT	FILE PROTECTED ERROR				*	
;*								*
;****************************************************************

ERWPRT:
	LXI	H,MSWPRT	; PT TO ERROR MSG
ERWPT1:
	CALL	ERPERM1		; PRINT IT & GET INPUT (DOESN'T RET ON ^C)
	MVI	A,255		; IF NOT ^C, REPORT ERROR
	STA	RETCOD
	RET

ERRUSR:
	LXI	H,MSUSR		; PT TO ERROR MSG
	JMP	ERWPT1

;****************************************************************
;*								*
;*	ERSLCT	DISK SELECT ERROR				*	
;*								*
;****************************************************************

ERSLCT:
	LXI	H,MSSLCT		; ADDRESS OF SELECT MESSAGE
	JMP	ERWAIT			; WAIT FOR CONSOLE CHAR BEFORE BOOT


;****************************************************************
;*								*
;*	ERRDON	DISK READ ONLY ERROR				*	
;*								*
;****************************************************************

ERRDON:
	LXI	H,MSRDON		; DISK READ ONLY ERROR
ERWAIT:
	CALL	ERPRNT			; PRINT MESSAGE AND WAIT FOR INPUT
	JMP	WBOOT			; AND REBOOT

	PAGE
;****************************************************************
;*								*
;*	ERPRNT	REPORT DOS ERROR AND WAIT FOR CONSOLE INPUT	*
;*		SPECIAL HANDLING IF ERROR WAS CAUSED BY		* 
;*		BACKGROUND PRINT FUNCTION.			*
;*								*
;****************************************************************

ERPRNT:
	LDA	FUNC		; GET THE DOS FUNCTION
	CPI	12		; IS DISK FUNCTION?
	JNC	ERRF1		; JUMP IF SO=> NOT BACKGROUND PRINT
	PUSH	H
	LXI	H,BPQ		; SET THE NEXT FILE
	CALL	UNQPRX
	CALL	PCRLF		; NEW LINE TO PRINTER
	LDA	LOGDSK		; GET THE DISK NAME
	ADI	'A'
	STA	DSKERR		; SET IN ERROR MESSAGE
	LXI	B,MSDSK
	CALL	LPRINT		; SEND TO LIST DEVICE
	POP	B		; GET THE MESSAGE
	CALL	LPRINT
	JMP	PCRLF		; NOW MAKE IT PRINT
;
ERRF1:				; REPORT ERROR TO CONSOLE, ADDRESS IN HL
	PUSH	H		; SAVE IT
	CALL	CRLF		; CLEAR TO NEW LINE
	LDA	LOGDSK
	ADI	'A'		; CURRENT DISK NAME
	STA	DSKERR		; STORE IN MESSAGE AREA
	LXI	B,MSDSK
	CALL	PRINT		; PRINT DISK ERROR MESSAGE
	POP	B		; GET MESSAGE
	CALL	PRINT		; SEND TO CONSOLE
	JMP	CONIN		; READ CONSOLE CHARACTER
;
LPRINT:
	LDAX	B		; GET THE CHARACTER
	CPI	'$'		; DONE
	RZ			; YUP
	INX	B
	PUSH	B		; PRINT THE CHARACTER
	MOV	C,A
	CALL	LIST
	POP	B
	JMP	LPRINT		; LOOP
;
PCRLF:				; SEND CRLF TO PRINTER
	MVI	C,CR
	CALL	LIST
	MVI	C,LF
	JMP	LIST

	PAGE
;
;
;	ERROR MESSAGES
;
MSDSK:
	DB	'DISK ERR ON '
DSKERR:	DB	' : $'		;FILLED IN BY ERRFLG
MSPERM:
	DB	'BAD SECTOR$'
MSSLCT:
	DB	'SELECT$'
MSRDON:	DB	'R/O$'
BS2MSG:	DB	08,20H,08	;DUAL CHARACTER BSDEL
BSSMSG:	DB	08,20H		;SNGL CHARACTER BSDEL
BSMSG:	DB	08,'$'		;SNGL BS
MSWPRT:
	DB	'FILE PROTECTED$'
MSUSR:
	DB	'INVALID USER$'

	PAGE
;****************************************************************
;*								*
;*	DIRIO		DOS # 6					*
;*		DIRECT CONSOLE INPUT/OUTPUT			*
;*								*
;****************************************************************

DIRIO:
	MOV	A,C		; INPUT OR OUTPUT?
	INR	A		; TEST FOR WHICH(FF MEANS INPUT)
	JNZ	CONOUT		; OUTPUT - SO GO DO IT!
	CALL	GETBFC		; GET BUFFERED CHAR IF AVAILABLE
	JNZ	DIRIO1		; YES - GOT IT!
	CALL	CONRDY		; ELSE TEST PHYSICAL
	ORA	A		; 
	JZ	DIRIO1		; NO, TELL THEM NOTHING'S THERE
	CALL	CONIN		; YES, GO GET IT!
DIRIO1:	STA	RETCOD		; STUFF THE RESULT
	RET			; AND EXIT


;****************************************************************
;*								*
;*	CONGET		READ CONSOLE CHAR INTO <a>		*
;*								*
;****************************************************************

CONGET:	CALL	GETBFC		; GET BUFFERED CHAR IF AVAILABLE
	RNZ			; IF NON ZERO, THEN RETURN OLDCHR
	JMP	CONIN 		; ELSE GET CHAR FROM BIOS

	PAGE
;****************************************************************
;*								*
;*	CONECH	READ CHAR AND ECHO TO CONSOLE			*
;*								*
;****************************************************************

CONECH:	CALL	CONGET		; GET CHAR
	CALL	CHKCTL		; CHECK FOR DISPLAYABLE CHARACTERS
	RC			; CARRY IF NOT GRAPHIC OR CONTROL
	PUSH	PSW		; SAVE THE CHARACTER
	MOV	C,A		; INTO <c>
	CALL	OUTCHR		; AND ECHO
	POP	PSW		; GET CHAR BACK
	RET			; WITH CHAR IN <a>


;****************************************************************
;*								*
;*	CHKCTL	TEST FOR DISPLAYABLE CONTROL CHARACTER		*
;*		SET CARRY IF UNDISPLAYABLE			*
;*								*
;****************************************************************

CHKCTL:
	CPI	BS		; BACKSPACE IS OK
	RZ
	CPI	TAB		; TAB IS OK
	RZ
	CPI	LF		; LF IS OK
	RZ
	CPI	CR		; AND CR IS OK
	RZ
	CPI	' '
	RET			; CARRY SET IF UNDISPLAYABLE

	PAGE
;****************************************************************
;*								*
;*	CONBRK	CHECK FOR CHARACTER WAITING AT CONSOLE		*
;*		RETURNS 0 IN [A] AND Z SET IF NO CHAR		*
;*			1 IN [A] AND NZ SET IF CHAR READY	*
;*								*
;****************************************************************

CONBRK:	LDA	OLDCHR		; IS A CHARACTER WAITING ?
	ORA	A		; SET FLAGS
	JNZ	CONBK3		; YES, SET CHAR READY
	CALL	CONRDY		; CHECK FOR CHARACTER READY
	ORA	A
	RZ			; RETURN IF ZERO, OTHERWISE READ IT
	CALL	CONIN 		; GET CHARACTER TO [A]
	CALL	TSTCTLP		; TEST FOR PRINTER TOGGLE
	JZ	CONBK1		;   YES, RETURN NO CHAR RDY
				;   NO, FALL THRU TO TEST FOR SCRN BREAK
;
CONBK0:	CPI	CTLS		; MAY BE SCREEN STOP FUNCTION
	JNZ	CONBK2		; IF NOT THEN PUT CHARACTER BACK
	CALL	CONWAT		; WAIT FOR OPERATOR INPUT
CONBK1:	XRA	A		; CLEAR CHARACTER AND RETURN
	RET
;
CONBK2:	STA	OLDCHR		; CHARACTER IN ACCUM, SAVE IT
CONBK3:	MVI	A,1		; RETURN WITH 1 FOR CONSOLE BREAK
	RET


;****************************************************************
;*								*
;*	CONWAT	WAIT FOR CONTROL Q AT CONSOLE			*
;*								*
;****************************************************************

CONWAT:
	CALL	GETBFC			; SEE IF CHARACTER WAITING
	CNZ	CONW1			;   YES, TEST IT
	CALL	CONIN			;   ELSE, GET A CHARACTER,
	CALL	CONW1			;     & TEST IT
	JZ	CONWAT			;       LOOP IF PRINTER TOGGLE
	RET				;       ELSE, RETURN
CONW1:
	CPI	CTLC			; TEST FOR CTL C
	JZ	WBOOT			;   YES, ABORT
	CALL	TSTCTLP			;   ELSE, TEST FOR PRINTER TOGGLE
	RET				;     & RETURN

	PAGE
;****************************************************************
;*								*
;*	GETBFC	GET BUFFERED CHARACTER				*
;*								*
;****************************************************************

GETBFC:	LXI	H,OLDCHR		; POINT TO OLD CHARACTER
	MOV	A,M			; GET IT
	MVI	M,0			; CLEAR IT
	ORA	A			; SET FLAGS
	RET


;****************************************************************
;*								*
;*	TSTCTLP		TEST FOR PRINTER TOGGLE REQUEST		*
;*	TOGGLEP		TOGGLE PRINTER FLAG			*
;*								*
;****************************************************************

TSTCTLP:
	CPI	CTLP			; TEST FOR PRINTER TOGGLE
	RNZ				;   NO, RETURN
					;   ELSE, FALL THRU TO TOGGLE
TOGGLEP:
	PUSH	H			; SAVE [HL]
	LXI	H,LISTCP		; POINT TO PRINTER TOGGLE
	MOV	A,M			; GET CURRENT TOGGLE
	CMA				; COMPLIMENT IT
	MOV	M,A			; BACK TO MEMORY
	POP	H			; RESTORE [HL]
	XRA	A			; CLR <A> & SET Z FLAG
	RET

	PAGE
;****************************************************************
;*								*
;*	CONPUT	SEND CHARACTER TO CONSOLE			*
;*		CONTROL PRINTER ECHO AND COLUMNAR POSITION	*
;*								*
;****************************************************************

CONPUT:	PUSH	B		; SAVE CHARACTER
	CALL	CONBRK		; CHECK FOR SCREEN STOP FUNCTION
	POP	B		; GET CHARACTER
	PUSH	B		; AND RESAVE
	CALL	CONOUT		; TO WRITE THE CHARACTER
	POP	B		; RECALL IT AGAIN
	PUSH	B		; SAVE IT FOR LATER TESTS
	LDA	LISTCP		; LIST COPY TOGGLE
	ORA	A		; SET?
	CNZ	LIST		; TO PRINTER
	POP	B		; RECALL CHARACTER
	MOV	A,C		; GRAPHIC (ASCII CTL)?
	LXI	H,COLUMN
	INR	M		; INCREMENT COLUMN COUNT
	CPI	' '
	RNC			; NO CARRY GEN'ED IF GRAPHIC (ASCII CTL)
	DCR	M		; NO COLUMN MOVEMENT
	CPI	BS		; BACKSPACE ?
	JNZ	CONPT1
	DCR	M		; DECREMENT COLUMN COUNT 1 MORE FOR BS
	RET
CONPT1:	CPI	CR		; END OF LINE?
	RNZ			; DONE IF NOT
	MVI	M,0		; CLEAR COLUMN COUNTER
	RET


;****************************************************************
;*								*
;*	CTLOUT	SEND CONTROL CHARACTER REPRESENTATION		*
;*								*
;****************************************************************

CTLOUT:	MOV	A,C		; GET CHARACTER
	CALL	CHKCTL		; TAB, CR, OR LF?
	JNC	OUTCHR		; DISPLAYABLE CONTROL CHARACTER
	PUSH	PSW		; ELSE SEND UP ARROW
	MVI	C,CTL		; GET AN UP-ARROW
	CALL	CONPUT		; SEND IT
	POP	PSW		; GET CHARACTER BACK
	ORI	40H		; BECOMES GRAPHIC
	MOV	C,A		; PUT IN [C]
	JMP	OUTCHR		; AND SEND CHARACTER

	PAGE
;****************************************************************
;*								*
;*	OUTCHR		DOS #2					*
;*		OUTPUT CHARACTER TO CONSOLE			*
;*		TABS ARE EXPANDED				*
;*		ENTRY:	CHARACTER IN [C]			*
;*								*
;****************************************************************

OUTCHR:	MOV	A,C		; CHAR TO [A]
	CPI	TAB		; CHECK FOR TAB CHARACTER
	JNZ	CONPUT		; NO, OUTPUT TO CONSOLE
TAB0:	MVI	C,' '		; PAD TO NEXT COLUMNAR POSITION
	CALL	CONPUT		; PUT CHARACTER, BUMP COUNTER
	LDA	COLUMN		; GET COLUMN NUMBER
	ANI	7		; MOD 8
	JNZ	TAB0		; SEND UNTIL AT MOD 8 POSITION
	RET


;****************************************************************
;*								*
;*	CRLF	SEND CARRIAGE RETURN LINE FEED SEQUENCE		*
;*								*
;****************************************************************

CRLF:	MVI	C,CR		; GET A CR
	CALL	CONPUT		; SEND IT
	MVI	C,LF		; GET A LF
	JMP	CONPUT		; SEND IT

	PAGE
;****************************************************************
;*								*
;*	PRINT		DOS # 9					*
;*		OUTPUT BUFFER TO CONSOLE			*
;*		PRINT MESSAGE POINTED TO BY [BC] UNTIL $	*
;*								*
;****************************************************************


PRINT:	LDAX	B	; GET CHARACTER
	CPI	'$'	; END OF MESSAGE?
	RZ		; RETURN IF SO
	PUSH	B	; SAVE POINTER
	MOV	C,A	; CHAR TO [C]
	CALL	OUTCHR	; SEND THE CHARACTER
	POP	B	; RESTORE POINTER
	INX	B	; AND BUMP IT
	JMP	PRINT	; LOOP TILL DONE


;****************************************************************
;*								*
;*	READBF		DOS # 10				*
;*		BUFFERED CONSOLE INPUT	-			*
;*		BUFFER LOOKS LIKE THIS:				*
;*			[L] LENGTH OF BUFFER			*
;*			[C] CHARACTER COUNT			*
;*			[B.....] L BYTES OF CHARACTER		*
;*								*
;****************************************************************

READBF:
	LDA	COLUMN		; SET BEG COLUMN TO CUR COLUMN
	STA	BEGCOL
	LHLD	ARG		; POINT TO MAX LENGTH
	MOV	C,M		; SAVE IN C
	INX	H		; PT TO BEG OF ACTUAL BUF
	PUSH	H		; SAVE FOR LATER FILL
	MVI	B,0		; CURRENT ACTIVE LENGTH
READNX:
	PUSH	B		; SAVE CURRENT/MAX LENGTHS
	PUSH	H		; SAVE NEXT TO FILL-1
READN0:				; GET NEXT CHARACTER IN
	CALL	CONGET		; THEN GET THE CHAR
	ANI	7FH		; CLEAR PARITY
	POP	H		; RECALL NEXT TO FILL-1
	POP	B		; RECALL LENGTHS
	CPI	RUBOUT		; RUBOUT?
	JZ	RDRUB		; ECHO AND DELETE LAST CHAR
	CPI	CR		; END OF LINE?
	JZ	READEN		; SKIP TO END IF SO
	CPI	LF		; LINE FEED (ALSO ENDS LINE)
	JZ	READEN		; SKIP TO END IF SO
	CPI	BS		; BACKSPACE ?
	JZ	RDBACK		; JUMP IF SO
	CPI	CTLP		; PRINT TOGGLE ?
	JZ	RDTOG		; SKIP IF SO
	CPI	CTLX		; ERASE LINE ?
	JZ	RDKILL		; JUMP IF SO
	CPI	CTLU		; CONTROL-U?
	JZ	RDKILU		; DELETE LINE
	CPI	CTLR		; CONTROL-R?
	JZ	RDTYPE		; RETYPE
	CPI	CTLE		; CONTROL-E?
	JZ	RDEOL		; PHYSICAL END OF LINE
	JMP	RDECHO		; ACCEPT THE CHARACTER

	PAGE
;****************************************************************
;*								*
;*	READBF SUPPORT ROUTINES					*
;*								*
;****************************************************************

RDTOG:	CALL	TOGGLEP		; TOGGLE PRINTER LINE
	JMP	READNX		; AND GET NEXT CHARACTER
;
;	ERASE LINE (CONTROL-X)
;
RDKILL:				;ERASE LINE
	POP	D		;CLEAN UP STACK
	LDA	COLUMN
	LXI	H,BEGCOL
	SUB	M		;GET ACTUAL LENGTH
	MOV	B,A		;PUT IN B AS CNTR
KILLN1:
	DCR	B		;DECREMENT CURRENT BUFFER COUNT
	JM	READBF		;JUMP IF DONE
	PUSH	B		;SAVE COUNT
	CALL	DEL1CH		;BSDEL
	POP	B		;RESTORE COUNT LEFT TO BLANK OUT
	JMP	KILLN1
;
;	BACKSPACE (CONTROL-H)
;
RDBACK:			
     	MOV	A,B		;RECALL BUFFER LENGTH
	ORA	A	
	JZ	READNX		;DO NOTHING IF BEG OF BUFFER
	DCR	B		;FIX LENGTH
	DCX	H
	PUSH	B
	PUSH	H
	CALL	DELCHR		;DELETE WHAT YOU SEE
	JMP	READN0
;
DELCHR:
	PUSH	H		; SAVE BUF PTR
	LDA	BEGCOL		; IF BEGCOL IS SAME AS CUR COLUMN (BUF IS
	LXI	H,COLUMN	;   NON-0), THEN ATTEMPT IS BEING MADE TO
	CMP	M		;   BS THRU BEGCOL...
	POP	H		; RESTORE BUF PTR
	JNZ	DELCH1
	POP	D		;   ...TAKE RET ADDR OFF THE STACK,...
	JMP	RDTYP1		;   ...& FORCE RETYPE (JMP PAST PUSH B,H)
;
DELCH1:
	INX	H		; PT TO CHAR TO BE DEL'D
	MOV	A,M
	CPI	' '		; TEST FOR CTL CHAR
	JNC	DEL1CH		; NOT CTL, NORMAL BSDEL
	CPI	TAB
	JZ	TABDEL		; TO CALC # OF SCRN CHARS TO BACK UP
;DEL2CH:
	LXI	B,BS2MSG
	JMP	PRINT
;
DEL1CH:	LXI	B,BSSMSG	;NORMAL MESSAGE
	JMP	PRINT
;
;
;	TABDEL		DELETE TAB & CLR SCRN SPACES FOR READBF
;
;	ALGORITHM:	Starting from cur col pos, scan forward counting
;			the # of chars until tab or beg of line;
;			- make the cnt mod 8
;			- if char is ctl-char other than tab, dcr the cntr 1
;
;	ENTRY	:	<B> cntns actual buf cnt (not incl'ng the tab)
;			<HL> pts to the tab char
;
TABDEL:	
	MVI	C,0		; <B> has buf cnt, set <C> as cntr
	DCX	H		; get <HL> ptd to char before tab
TBDLP1:
	DCR	B
	JP	TBDL1A		; DO until,(numchars,eq,0),or,
	INR	C		;	[if we do get to beg of buf,
	INR	C
	MOV	A,C		;	 we must add 2 more to cntr,
	ANI	7		;	 & make it mod 8]
	MOV	C,A
	JMP	TABDL2
TBDL1A:	MOV	A,M
	CPI	TAB		;    (char,eq,tabchar)
	JZ	TABDL2
	DCX	H		; pt to nxt char forward
	INR	C		; bump cntr
	CPI	' '		; test for ctl-char
	JNC	TABDL1
	INR	C		; any ctl char but tab, inr cntr 1 more
TABDL1:
	MOV	A,C
	ANI	7		; make cntr mod 8
	MOV	C,A
	JMP	TBDLP1
TABDL2:
	MVI	A,8		; sub cntr from 8 to get # of chars
	SUB	C		;   to actually back up
	MOV	B,A		; & put in <B> as cntr
	MVI	C,BS		; bs to dsply in <C>
TBDLP2:
	DCR	B
	RM			; do until cntr = 0 (goes neg)
	PUSH	B
	CALL	OUTCHR
	POP	B
	JMP	TBDLP2
;
;
;	RUBOUT
;
RDRUB:
	MOV	A,B		;DO NOTHING IF BUFFER IS EMPTY
	ORA	A
	JZ	READNX
	DCR	B		;OTHERWISE, ADJUST LENGTH
	PUSH	B		;SAVE FOR LOOP
	MOV	C,M		;FETCH LAST CHAR
	DCX	H		;DECREMENT POINTER
	PUSH	H		;SAVE IT, TOO
	CALL	CTLOUT		;ECHO LAST CHAR
	JMP	READN0		;AND CONTINUE INPUT LOOP
;
;	KILL LINE AND START ON NEW LINE (CONTROL-U)
;
RDKILU:
	POP	D		;CLEAN UP STACK
	LXI	B,HUH		;AND START ALL OVER ON A
	CALL	PRINT		;FRESH LINE
	JMP	READBF

HUH:	DB	'#',CR,LF,'  $'

;
;	PHYSICAL END OF LINE (CONTROL-E)
;
RDEOL:
	PUSH	B		;SET STACK AS READN0 NEEDS
	PUSH	H
	CALL	CRLF		;GO TO A NEW LINE ON THE CONSOLE
	XRA	A
	STA	BEGCOL
	JMP	READN0		;BUT DON'T CHANGE THE BUFFER
;
;	RETYPE THE LINE (CONTROL-R)
;
RDTYPE:
	PUSH	B		;SAVE BUFFER CONTROL INFO
	PUSH	H
RDTYP1:				;ALT ENTRY FOR DELCHR
	LXI	B,HUH		;START ON A FRESH LINE
	CALL	PRINT
	LDA	COLUMN		;RESTORE BEGCOL
	STA	BEGCOL
	POP	H
	POP	B
	MOV	A,B		;NOTHING TO DO IF
	ORA	A		;BUFFER IS EMPTY
	JZ	READNX
	PUSH	B		;SET STACK AS READN0 NEEDS
	PUSH	H
	LHLD	ARG		;GET BASE OF USER BUFFER
	INX	H		;ADVANCE TO FIRST CHARACTER POSITION
	INX	H
RDTYP2:
	MOV	C,M		;FETCH CHARACTER
	PUSH	H
	PUSH	B
	CALL	CTLOUT		;ECHO IT
	POP	B
	POP	H
	INX	H
	DCR	B
	JNZ	RDTYP2		;REPEAT TILL ENTIRE BUFFER IS TYPED
	JMP	READN0
;
;	ECHO THE CHARACTER IF ECHOABLE
;
RDECHO:
	INX	H	;NEXT TO FILL
	MOV	M,A	;STORE THE CHARACTER IN THE BUFFER
	INR	B	;INCREMENT THE LENGTH
RDECH1:			;LOOK FOR CONTROL CHARACTERS
	PUSH	B
	PUSH	H	;SAVE THE PARAMETERS
	MOV	C,A	;READY TO PRINT
	CALL	CTLOUT	;MAY BE ^CHAR
	POP	H
	POP	B	;PARAMETERS READY FOR CHECKS
	MOV	A,M	;RECALL CHARACTER
	CPI	CTLC	;SET FLAGS FOR REBOOT CHECK
	MOV	A,B	;CHECK THE LENGTH
	JNZ	RDECH2	;SKIP IF NOT CTLC
;
;	CTLC FOUND, MUST BE LENGTH = 1
;
	CPI	1	;LENGTH ONE
	JZ	WBOOT	;BOOT THE SYSTEM IF FOUND
RDECH2:
	CMP	C	;UP TO THE END OF THE BUFFER?
	JC	READNX	;FOR ANOTHER CHARACTER
;
READEN:			;END OF READ, FILL CURRENT LENGTH
	POP	H	;.CURRENT LENGTH
	MOV	M,B	;FILLED TO MEMORY
	MVI	C,CR	;RETURN CARRIAGE
	JMP	CONPUT	;RETURN THROUGH CONPUT

	PAGE
;****************************************************************
;*								*
;*	SETCPM		SUPERDOS #139				*
;*	SETSB80		SUPERDOS #140				*
;*		SET/RESET COMPATIBILITY W/CPM			*
;*		(FOR NOW, USED FOR S1/S2 BYTES IN FCB -		*
;*				   (BYTES AT FCB + 13,14))	*
;*								*
;****************************************************************

SETCPM:
	MVI	A,1
	JMP	STCPMX
SETSB80:
	XRA	A
STCPMX:	STA	CPMFLG
	RET

	PAGE
;*****************************************************************
;*****************************************************************
;**								**
;**								**
;**			DOS SUPPORT ROUTINES			**
;**								**
;**								**
;*****************************************************************
;*****************************************************************

HOMEHD:	CALL	HOME		; CALL UIOI ROUTINE
	MVI	A,OOSTRK	; OFFSET TO OS TRACKS
	CALL	GTDPBA		; GET OS TRACKS FROM DISK PARM BLOCK
	MOV	B,H		;
	MOV	C,L		; 
	JMP	SETTRK		; SELECT FIRST NON OS TRACK


;****************************************************************
;*								*
;*	SEEK	SEEK TRACK GIVEN BY LOGICAL RECORD IN [HL]	*
;*		[B] CONTAINS HI ORDER BYTE OF RECORD TO SEEK	*
;*								*
;****************************************************************

SEEK:
	XCHG			; GET LOG REC BOTTOM TO DE
	LXI	H,0
	PUSH	H		; HL WILL COUNT TRACK TO SEEK (W/O OFFSET)
	MVI	A,OSPTRK
	PUSH	B		; SAVE HIGH BYTE OF LOG RCD ON STACK (IN B)
	CALL	GTDPBA		; GET SECTORS/TRACK
	XCHG			; PLACE LOW 16 BITS OF LOG REC TO HL
	MOV	B,D		; GET SEC/TRK TO BC
	MOV	C,E
	POP	D		; GET HIGH(LOG RCD) TO D
	MOV	A,D		; SEE IF IT IS ZERO (STD ADDRESSING)
	ORA	A
	JZ	SEEK0		;SKIP NEXT LOOP IF SO
;
;	LOOP TO SUBTRACT S/T UNTIL EXTENDED ADDRESS BYTE IS ZERO
;
SKLOOP:
	CALL	DSUB		;SUBTRACT SEC/TRK FROM LOG RCD
	XTHL			;GET TRACK # TO HL
	INX	H		;BUMP BY ONE
	XTHL
	JNC	SKLOOP		;JUMP IF HAVE NOT BROUGHT HL PASSED 0000
	DCR	D		;DECREASE EXTENDED ADDRESS BYTE
	JNZ	SKLOOP		;IF NOT ZERO, KEEP GOING
;
;	LOOP TO SUBTRACT S/T UNTIL BELOW ZERO, THEN WE HAVE TRACK TO USE
;
SEEK0:
	CALL	DSUB		;SUBTRACT SEC/TRK FROM LOG RCD
	XTHL			;GET TRACK # TO HL
	INX	H		;BUMP BY ONE
	XTHL
	JNC	SEEK0		;JUMP IF NOT DONE YET
	DAD	B		;ADD BACK SEC/TRK TO MAKE HL ZERO OR ABOVE
	XTHL			;GET BACK TRACK TO USE
	DCX	H		;BACK UP ONE (SINCE WE OVERSHOT)
	XCHG			;TRACK TO DE
	MVI	A,OOSTRK
	CALL	GTDPBA		;GET OS TRACKS
	DAD	D		;COMPUTE ACTUAL TRACK TO USE
	MOV	B,H		; PLACE IN BC
	MOV	C,L
	CALL	SETTRK		;SET TRACK IN UIOI
	POP	B		;GET BACK SECTOR TO USE (XTHL PUT IT ON STACK)
;
;	TRANSLATE LOGICAL TO PHYSICAL SECTOR--BC HAS SECTOR NUMBER
;
	MVI	A,OTRTBL	;GET ADDRESS OF SECTOR TRANSLATION TABLE
	CALL	GTDPH		;INTO HL FROM DISK PARAMETER HEADER
;	MOV	A,H		;SEE IF TR TABLE ADDRESS IS ZERO
;	ORA	L
;	JZ	SELSEC		;GO DIRECT TO UIOI, NO TRTBL (ASSUME LOG=PHYS)
	XCHG			;TRANSLATE TABLE ADDR MUST BE IN DE
	CALL	SECTRAN		;TRANSLATE LOGICAL TO PHYSICAL SECTOR
	MOV	B,H		;"REAL" SECTOR NUMBER INTO BC
	MOV	C,L		;TELL UIOI TO GO GET
	JMP	SELSEC		;THAT SECTOR!

	PAGE
;****************************************************************
;*								*
;*	GTDPH	GET A 2 BYTE VALUE FROM THE CURRENT DPH		*
;*		ENTER WITH OFFSET IN [A]			*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************

GTDPH:	LHLD	CURDPH		; POINT TO CURRENT D.P. HEADER
GTDPH1:	CALL	ADDVAL		; COMPUTE ADDRESS OF DESIRED ITEM
	MOV	A,M		; GET LOW BYTE
	INX	H
	MOV	H,M		; GET HIGH BYTE
	MOV	L,A		; PUT LOW BYTE IN
	RET			; ALL DONE


;****************************************************************
;*								*
;*	GTDPBA	GET 2 BYTE VALUE FROM CURRENT DISK PARAMETER BLK*
;*		ENTRY	OFFSET IN [A]				*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************

GTDPBA:
	LHLD	CURDPB	;POINT TO CURRENT D.P. BLOCK
	JMP	GTDPH1


;****************************************************************
;*								*
;*	GTDPBB	GET 1 BYTE VALUE FROM CURRENT DISK PARAMETER BLK*
;*		ENTRY	OFFSET IN [A]				*
;*		RETURNS RESULT IN [A]				*
;*								*
;****************************************************************

GTDPBB:
	PUSH	H		; SAVE [HL]
	CALL	GTDPBA		; GET ADDRESS, LOW BYTE WILL BE IN A
	POP	H		; RESTORE [HL]
	RET			; ALL DONE

	PAGE
;****************************************************************
;*								*
;*	WRDISK	WRITE BUFFER TO DISK				*
;*								*
;****************************************************************

WRDISK:	LDA	UNAFLG		; GET UNALLOCATED FLAG
	MOV	C,A		; INTO C REGISTER FOR UIOI
	CALL	WRITE		; UIOI WRITE ROUTINE
	LXI	H,UNAFLG	; POINT TO UNALLOCATED FLAG
	MVI	M,0		; AND CLEAR IT
WRDSK1:	PUSH	PSW		; SAVE RESULT OF OPERATION
	CALL	DATDMA		; REESTABLIS DATA DMA
	POP	PSW
	ORA	A		; SET FLAGS
	RZ			; RETURN IF NO ERROR
	JMP	ERPERM		; ELSE, PERMANENT ERROR


;****************************************************************
;*								*
;*	RDDISK	READ BUFFER TO DISK				*
;*								*
;****************************************************************

RDDISK:	CALL	READ		; CALL UIOI ROUTINE
	JMP	WRDSK1		; ERROR RETURN

	PAGE
;****************************************************************
;*								*
;*	FNDBLK	COMPUTE DISK BLOCK NUMBER FROM CURRENT FCB	*
;*		FCB IS POINTED TO BY ARGUMENT			*
;*								*
;****************************************************************

FNDBLK:	LHLD	ARG		; GET FCB ADDRESS
	LXI	D,FCBMP		; START OF DISK MAP WITHIN FCB
	LDA	RELREC		; GET RELATIVE RECORD=BLK THIS EXTENT*?+REC#
	CALL	GTBLKN		; GET RELATIVE BLOCK NUMBER (0-15) W/I MAP
	MVI	B,0
	MOV	C,A		; <BC>=BLOCK
	DAD	D		; ADD DISPLACEMENT TO DISK MAP
	DAD	B		; PLUS DISPLACEMENT TO CURRENT BLOCK
	MOV	C,M		; GET LOW BYTE OF BLOCK
	INX	H
	MOV	B,M		; GET HIGH BYTE (IF USED)
	MVI	H,0		; CLEAR HIGH BYTE IN CASE ONE BYTE BLOCK NUMBER
	MOV	L,C		; PUT LOW BYTE/SINGLE BYTE IN L
	LDA	TWOFLG		; GET TWO BYTE BLK NUM FLAG
	ORA	A
	RZ			; RETURN IN ONE BYTE BLOCK NUMBERS
	MOV	H,B		; GET HIGH BYTE TO H
	RET			; ALL DONE


;****************************************************************
;*								*
;*	GTBLKN	COMPUTE RELATIVE BLOCK NUMBER WITHIN THE CURRENT*
;*		DISK MAP					*
;*		ENTRY	REL RECORD IN [A]			*
;*								*
;****************************************************************

GTBLKN:
	PUSH	B		; MAKE SURE WE DONT DESTROY ANYTHING
	MOV	C,A 		; SAVE REL RECORD
	MVI	A,OBSH		; FETCH THE BLOCK SHIFT FACTOR FROM
	CALL	GTDPBB		; THE DISK PARAMETER BLOCK INTO A
	MOV	B,A		; COPY TO B
	MOV	A,C		; REL RECORD TO A
GTBLN1:	ORA	A		; CLEAR CARRY
	RAR			; AND SHIFT THE RECORD NUMBER
	DCR	B		; COUNT DOWN
	JNZ	GTBLN1		; CONTINUE SHIFTING AS NECESSARY
	MOV	B,A		; GET REL BLOCK NUMBER BYTE TO B
	LDA 	TWOFLG		; GET TWO BYTE BLOCK FLAG
	ORA	A		; TEST IT
	MOV	A,B		; GET REL BLOCK NUMBER BACK
	POP	B		; GET HIM BACK
	RZ			; RETURN IF ONE BYTE BLOCK NUMBERS
	RAL			; DOUBLE POS FOR TWO BYTE NUMBERS
	RET

	PAGE
;****************************************************************
;*								*
;*	FNDREC	COMPUTE LOGICAL SECTOR NUMBER FROM THE BLOCK	*
;*		IN [HL] AND THE RELATIVE RECORD IN RELREC	*
;*		[B] WILL CONTAIN EXTENDED ADDRESS BYTE		*
;*								*
;****************************************************************

FNDREC:	XCHG			; BLOCK INTO DE
	MVI	A,OBSH		; FETCH THE BLOCK SHIFT FACTOR AND THE
	CALL	GTDPBA		; BLOCK MASK FROM THE DISK PARAMETER BLOCK
	XCHG			; BLOCK IN HL, BSH IN E, BLM IN D
	MVI	B,0		; SET EXT ADDR BYTE TO ZERO
FNDRC1:	DAD	H		; SHIFT BLOCK NUMBER LEFT
	MVI	A,0
	ADC	B		; IF ANY CARRY, BUMP EXT ADDR BYTE
	MOV	B,A
	DCR	E		; AS MANY TIMES AS INDICATED BY BSH
	JNZ	FNDRC1
	LDA	RELREC		; GET RELATIVE RECORD AGAIN
	ANA	D		; MASK OUT BLOCK BITS
	MOV	E,A
	MVI	D,0		; D-E HAS RELATIVE RECORD NUMBER
	DAD	D		; ADD TO PHYSICAL BLOCK NUMBER
	RET


;****************************************************************
;*								*
;*	GTCNTS	SET VARIABLES FROM CURRENT FCB			*
;*								*
;****************************************************************

GTCNTS:	LHLD	ARG		; GET FCB ADDRESS
	XCHG
	LXI	H,FCBRC		; SET UP FOR RECORD COUNT RETRIEVAL
	DAD	D
	MOV	A,M		; GET RECORD COUNT
	STA	RECCNT		; STORE IT
	LXI	H,FCBNS		; GET NEXT R/W RCD NUMBER
	DAD	D
	MOV	A,M
	STA	RELREC		; SAVE IN RELATIVE RECORD
	RET

	PAGE
;****************************************************************
;*								*
;*	PTCNTS	PLACE VALUES BACK INTO CURRENT FCB AND BUMP	*
;*		RECORD COUNT					*
;*								*
;****************************************************************

PTCNTS:	LHLD	ARG		; GET FCB ADDRESS
	XCHG			; SAVE IN <DE> FOR LATER USE
	LXI	H,FCBNS
	DAD	D
	LDA	RELREC		; GET RELATIVE RECORD
	INR	A		; INCREMENT IT
	MOV	M,A		; SAVE IN FCB
	LXI	H,FCBRC		; SET FOR RECORD COUNT
	DAD	D
	LDA	RECCNT
	MOV	M,A		; SAVE NEW RECORD COUNT
	RET


;****************************************************************
;*								*
;*	SEEKDR	SEEK RECORD CONTAINING CURRENT DIRECTORY ENTRY	*
;*								*
;****************************************************************

SEEKDR:	CALL	DIRDMA		; SET DIRECTORY DMA
	LHLD	DIRNUM		; GET DIR NUMBER
	CALL	ROTHLR		; SHIFT RIGHT(DIVIDE BY 2)
	CALL	ROTHLR		; MAKE THAT DIVIDE BY FOUR 
	SHLD	DIRREC		; SAVE DIRECTORY RECORD NUMBER
	MVI	B,0		; ASSUME EXT ADDR BYTE ZERO IN DIRECTORY SRCH
	JMP	SEEK

	PAGE
;****************************************************************
;*								*
;*	CMCKSM	COMPUTE CHECKSUM FOR CURRENT DIR BUFFER		*
;*								*
;****************************************************************

CMCKSM:	PUSH	H
	PUSH	B
	MVI	B,80H
	LHLD	DIRBUF		; SET H-L TO DMA ADDRESS
	XRA	A
CMCK01: MOV	C,M		; GET NEXT BYTE FROM BUFFER
	ADD	C		; ADD TO CHECK TOTAL
	INX	H		; SET FOR NEXT BYTE
	DCR	B		; LOWER COUNT
	JNZ	CMCK01		; DONE?
	POP	B
	POP	H
	RET


;****************************************************************
;*								*
;*	SETCDK	MARK DISK WITH 1 IN MASK IN [HL]		*
;*								*
;****************************************************************

SETCDK:	LDA	LOGDSK		; FETCH CURRENT LOGGED-IN DISK
SETCD0:	MOV	B,A		; COPY DISK NUMBER TO B
	PUSH	D		; SAVE DE REG.
	XCHG			; MASK INTO DE
	LXI	H,1		; START WITH MASK FOR DISK 'A'
	INR	B
SETCD1:	DCR	B		; SHIFT BIT INTO APPROPRIATE POSITION
	JZ	SETCD2		; FOR THE DISK NUMBER
	DAD	H
	JMP	SETCD1
SETCD2:	CALL	ORDEHL		;'OR' IN THE TWO MASKS, WITH RESULT IN HL
	POP	D		;RESTORE DE
	RET

	PAGE
;****************************************************************
;*								*
;*	CHKRO	RETURN TRUE IF DIR CHECKSUM DIFFERENCE		*
;*		DISK IS READ ONLY				*
;*								*
;****************************************************************

CHKRO:	PUSH	H		; SAVE HL REG. PAIR
	LXI	H,0		; SET UP A MASK IN HL WITH BIT SET
	CALL	SETCDK		; FOR CURRENT DISK
	XCHG			; SWAP MASK INTO DE
	LHLD	RODSK		; FETCH READ-ONLY VECTOR
	CALL	ANDEHL		; MASK OUT BIT FOR CURRENT DISK
	MOV	A,H		; IS RESULT = 0?
	ORA	L
	JZ	CHKR1		; YES, DISK IS READ-WRITE
	MVI	A,1		; NO, DISK IS READ-ONLY
CHKR1:	POP	H		; RESTORE HL
	RET			; AND EXIT


;****************************************************************
;*								*
;*	SETRO	DOS # 28					*
;*		SET CURRENT DISK TO READ ONLY			*
;*								*
;****************************************************************

SETRO:	PUSH	H		; SAVE HL REG. PAIR
	LHLD	RODSK		; FETCH READ-ONLY VECTOR
	CALL	SETCDK		; PUT CURDSK BIT IN MASK
	SHLD	RODSK		; PUT VECTOR BACK
	POP	H		; RESTORE HL
	RET			; AND EXIT


;****************************************************************
;*								*
;*	CHKWRT	CHECK FOR WRITE PROTECTED DISK			*
;*								*
;****************************************************************

CHKWRT:	CALL	CHKRO		; CHECKSUM ERROR?
	ORA	A
	RZ			; OK
	JMP	ERRDON		; BOO-HOO, CAN'T WRITE TO THIS DISK

	PAGE
;****************************************************************
;*								*
;*	CHKSUM	COMPUTE CURRENT CHECKSUM RECORD AND UPDATE	*
;*		DIRECTORY ELEMENT IF C<>0			*
;*		JUST CHECK FOR EQUALITY IF C=0			*
;*								*
;****************************************************************

CHKSUM:	LXI	H,CSTBL		; GET SIZE OF CHECKSUM VECTOR FROM TABLE
	LDA	LOGDSK
	ORA	A
	RAL
	CALL	ADDVAL
	MOV	E,M		; INTO DE
	INX	H
	MOV	D,M
	LHLD	DIRREC		; GET REL SECTOR OF DIRECTORY BUFFER
	XCHG			; SWAP
	CALL	COMPDE		; SEE IF OUT OF RANGE
	RNC			; RETURN IF SO
	LHLD	CHECK		; BASE OF CURRENT DISK CHECKSUM VECTOR
	MOV	A,H		; TEST FOR ZERO==> NO CHECKSUM DESIRED
	ORA	L
	RZ			; RETURN IF NO CHECKSUM TO BE DONE
	DAD	D		; CALC ADDRESS OF CHECKSUM BYTE TO TEST
	CALL	CMCKSM		; COMPUTE CHECKSUM FOR BUFFER
	MOV	B,A		; SAVE CHECKSUM IN B
	MOV	A,C
	ORA	A		; TEST IF SET OR TEST
	JZ	CKSUM1		; JUMP IF TEST ONLY
	MOV	M,B		; SAVE NEW CHECKSUM
	RET
CKSUM1:	MOV	A,M		; GET SAVED CHECKSUM
	CMP	B
	JNZ	SETRO		; SET READ ONLY IF DIFFERENT
	RET

	PAGE
;****************************************************************
;*								*
;*	WRDIR	WRITE THE CURRENT DIRECTORY ENTRY		*
;*								*
;****************************************************************

WRDIR:	MVI	C,1		; SET INPUT PARAMATER TO INIT
	CALL	CHKSUM		; GET CHECKSUM
	MVI	A,1
	STA	UNAFLG		; SET UNALLOCATED FLAG TO SAY "DIRECTORY WRITE"
	CALL	DIRDMA		; USE DIRECTORY BUFFER
	JMP	WRDISK


;****************************************************************
;*								*
;*	RDDIR	READ NEXT DIRECTORY ENTRY			*
;*								*
;*								*
;*	ENTRY:	<C> CONTAINS FLAG FOR CHKSUM CALCULATION:	*
;*		   0  = TEST ONLY;				*
;*		   NZ = TEST AND SET				*
;*								*
;****************************************************************

RDDIR:	PUSH	B
	PUSH	D
	MVI	A,ODRM		; FETCH # DIR ENTRIES LESS 1 FROM CURRENT
	CALL	GTDPBA		; DISK PARAMETER BLOCK INTO HL
	XCHG			; SWAP INTO DE
	LHLD	DIRNUM		; GET CURRENT DIR NUMBER
	CALL	COMPDE		; COMPARE FOR EQUALITY
	INX	H		; BUMP ONE TO POINT TO NEXT
	SHLD	DIRNUM		; SAVE NEW DIR NUM
	POP	D		; GET BACK REGISTERS
	POP	B
	JNZ	REDDR1		; JUMP IF NOT END
	XRA	A
	CMA			; RETURN 255 OTHERWISE
	STA	DIRNUM		;  SAVE HERE ALSO YOU DUMMY
	STA	DIRNUM+1	; SET DIRNUM TO 0FFFFH
	RET
REDDR1:	PUSH	B		; JUST SAVE FOR NONDESTRUCTION
	MOV	A,L		; GET LOW BYTE TO A
	ANI	DMK		; MASK OUT LOW TWO BITS
	RRC
	RRC
	RRC			; A NOW HAS ABS RECORD OF DIR ENTRY
	ORA	A
	STA	DIRDSP		; SAVE
	JNZ	REDDR2		; NO NEED TO READ FROM DISK
	CALL	SEEKDR		; READ NEXT DIRECTORY FROM DISK
	CALL	RDDISK
	POP	B		; RESTORE INPUT PARAMETER FOR CHKSUM
	JMP	CHKSUM
REDDR2:	POP	B		; RESTORE STACK
	RET

	PAGE
;****************************************************************
;*								*
;*	GTABIT	RETURN BIT FROM ALLOCATION MAP			*
;*		ENTER WITH LOCATION SPECIFIED IN [BC]		*
;*								*
;****************************************************************

GTABIT:	CALL	IDXALL		; GET BYTE FROM VECTOR
	MOV	A,C	
	ANI	7		; MASK OFF ALL BUT DISP INTO BYTE
	INR	A		; SET FOR ROTATE TO LSB
	MOV	D,A
	MOV	E,A
	MOV	A,M		; GET BYTE FROM ALLOCATION
GTABT1:	RLC			; START TO TO ROTATE BYTE
	DCR	E		; COUNTDOWN
	JNZ	GTABT1		; DONE?
	RET

;
;	INDEX H-L TO ALLOCATION BYTE AS SPECIFIED BY
;	LOGICAL RECORD IN REGISTER BC
;
IDXALL:
	MOV	H,B	;GET LOGICAL BLOCK TO BC
	MOV	L,C
	CALL	ROTHLR	;SHIFT RIGHT 3 TIMES (DIVIDE BY 8)
	CALL	ROTHLR
	CALL	ROTHLR
	XCHG		;PUT IN DE
	LHLD	ALLOC	;BASE OF CURRENT ALLOC VECTOR
	DAD	D	;COMPUTE POS OF DESIRED BYTE
	RET
;
;	SET BIT CORRESPONDING TO SECTOR W/I BLOCK AS
;	SPECIFIED IN REGISTER BC TO THE LEAST SIGNIFICANT
;	BIT IN REGISTER E
;
STABIT:	
	PUSH	B
	PUSH	H	;SAVE REG'S
	PUSH	D
	CALL	GTABIT	;GETS ROTATED BYTE FROM ALLOCATION VECTOR
	MOV	B,D	;GET COUNT FOR ROTATE INTO B
	POP	D	;RET
	ANI	0FEH	;CLEAR LOW ORDER BIT FIRST
	ORA	E	;OR IN THE NEW STATUS OF THIS SECTOR
STABT1:
	RRC		;D ON RETURN FROM GTABIT HAS REL SECTOR +1
	DCR	B
	JNZ	STABT1	;JUMP IF NOT DONE
	MOV	M,A	;PUT ALLOCATION BYTE BACK IN VECTOR
	POP	H
	POP	B
	RET
;
;	SEARCH THROUGH THE DISK MAP REGION OF THE CURRENTLY POINTED TO
;	DIRECTORY FCB ENTRY. SET OR RESET THE CORRESPONDING BITS IN THE
;	ALLOCATION MAP ACCORDING TO THE VALUE OF REGISTER C ON INPUT
;	
MAPALL:
	LDA	DIRDSP	;GET DIRECTORY BUFFER DISPLACEMENT
	ADI	FCBMP	;SET FOR FIRST FILE DISK MAP BYTE
	MOV	E,A	;SAVE IN E
	MVI	D,16	;NUMBER OF BYTES TO SEARCH
	MOV	B,C	;PUT VALUE IN B FOR PARAMETER TO STABIT
MAPAL1:	MOV	A,E
	CALL	GETBF	;SET H-L TO BUFFER BYTE
	PUSH	B
	PUSH	D
	MOV	E,B	;GET BIT FOR STABIT TO E
	MVI	B,0	;HIGH BYTE OF BLOCK NUMBER WILL BE 0 IF ONE BYTE NUMS
	MOV	C,A	;GET LOW BLOCK NUMBER BYTE TO C
	LDA	TWOFLG	;GET 2-BYTE BLK # FLAG
	ORA	A
	PUSH	PSW	;SAVE STATUS OF THIS FLAG
	JZ	MAPAL2	;JUMP IF ONE BYTE BLK NUMBERS
	INX	H
	MOV	B,M	;GET HIGH BYTE
MAPAL2:
	MOV	A,B	;CHECK FOR ZERO
	ORA	C
	CNZ	STABIT	;SET THE BIT IF NOT ZERO
	POP	PSW	;RESTORE FLAG (Z=TWOFLG ON)
	POP	D	;GET BACK OTHER REGS
	POP	B
	JZ	MAPAL3	;JUMP IF SINGLE BYTE BLOCK NUMBERS
	INR	E	;DO AN EXTRA INR E AND DCR D
	DCR	D
MAPAL3:
	INR	E
	DCR	D	;DONE?
	JNZ	MAPAL1	;JUMP IF NOT
	RET

	PAGE
;
;	INITIALIZE DISK SYSTEM
;
SYSINI:
	LXI	H,0
	SHLD	RODSK		;NO READ ONLY DISKS NOW
	SHLD	RETCOD		;SET RETURN PARAMETER
	DCX	H
	SHLD	DIRNUM		;INITIALIZE DIRNUM TO -1
	MVI	A,OAL0		;FETCH DIRECTORY BLOCK ALLOCATION MAP
	CALL	GTDPBA		;INFORMATION FROM DISK PARAMTER BLOCK
	XCHG			;INTO DE
	LHLD	ALLOC		;FETCH ADDRESS OF CURRENT DISK ALLOC VECTOR
	MOV	M,E		;FILL IN FIRST TWO BYTES OF MAP,
	INX	H		;I.E., THE DIRECTORY BLOCK ALLOCATIONS
	PUSH	H		;SAVE ADDR OF ALLOC + 1 FOR LATER
	MOV	M,D
	MVI	A,ODSM		;FETCH THE NUMBER OF USER BLOCKS (LESS 1)
	CALL	GTDPBA		;INTO HL
	INX	H		;BUMP TO GET ACTUAL # OF BLOCKS
	MOV	E,L		;SAVE LOW BYTE IN E
	CALL	ROTHLR		;DIVIDE BLOCKS BY 8 TO GET # OF ALLOC BYTES
	CALL	ROTHLR
	CALL	ROTHLR
	DCX	H		;DOWN ONE (INIT ALLOC IS NOW 2 BYTES LONG)
	MOV	A,E	;GET LOW BYTE OF NUMBER OF BLOCKS
	ANI	7	;MASK LOW BITS TO SEE IF EVEN GROUP OF 8
	JNZ	SYSI2	;JUMP IF NOT-HL IS NUMBER OF BYTES TO ZERO
	DCX	H	;NEED TO ZERO ONE LESS SINCE EVEN AND DONT COUNT DIR
SYSI2:
	XCHG		;PUT NUMBER OF BYTES TO ZERO IN DE
	POP	H	;GET BACK ADDR OF ALLOC VECTOR + 1
SYSIN1:
	INX	H	;NEXT BYTE
	MVI	M,0
	DCX	D
	MOV	A,D
	ORA	E	;TEST IF AT END
	JNZ	SYSIN1
	CALL	HOMEHD	;HOME HEAD
SYSIN2:
	MVI	C,1
	CALL	RDDIR	;READ DIRECTORY WITH SET FLAG ON
	LDA	DIRNUM+1 ;CHECK HI BYTE; DONE IF 255
	INR	A
	RZ
	LDA	DIRDSP	;POINTER TO DISPLACEMENT IN BUFFER
	MOV	B,A	;SAVE IT
	CALL	GETBF	;SET H-L TO BUFFER LOCATION
	CPI	EMP	;EMPTY?
	JZ	SYSIN2	;DONT SET ALLOCATION IF DIR ENTRY NOT USED
SYSIN3:
	MVI	C,1  ;PARAMETER FOR SCANDM
	CALL	MAPALL	;SET ALLOCATION BITS
	JMP	SYSIN2
;****************************************************************
;*								*
;*	CMPRND	Routine to compute the extent and next rcd #	*
;*		  for the FCB at ARG, given the r0, r1, & r2	*
;*		  bytes.					*
;*								*
;****************************************************************

CMPRND:
	PUSH H! PUSH D! PUSH B
	LHLD	ARG		;GET FCB ADDR
	XCHG			; TO DE
	LXI	H,FCBRR1	;DISP TO r1
	DAD	D
	MOV	A,M		;GET R1
	MOV	B,A		;SAVE IN B
	RAL			;GET HIGH BIT TO Cy (BECOMES LOW OF LOW(EXT)
	INX	H		;POINT TO r2
	MOV	A,M		;GET r2
	RAL			;FORM HIGH(EXTENT)
	STA	RNDEXT+1	; AND SAVE
	DCX	H		;POINT TO r1
	DCX	H		;POINT TO r0
	MOV	A,M		;GET r0
	RAL			;GET HIGH BIT TO Cy TO BECOME LOW BIT OF EXT 
	MOV	A,B		;GET ORIG r1 TO A
	RAL			;FORM LOW(EXTENT)
	STA	RNDEXT		; AND SAVE
	MOV	A,M		;GET r0 AGAIN
	ANI	7FH		;FORM NEXT RECORD VALUE TO USE
	STA	RNDNXR		; SAVE THERE
	POP  B! POP  D! POP  H
	RET

	PAGE
;****************************************************************
;*								*
;*	SETUSR	Routine to set user # in attr byte		*
;*								*
;****************************************************************

SETUSR:
	PUSH H! PUSH D
	CALL	GTFCBAT		; PT <HL> TO ADDRESSED FCB ATTR BYTE
	LDA	USRN		; CURRENT USER
	ORA	A		; SET FLAGS
	JZ	STUSR1  	; USER 0 DOES NOT CHANGE ADDRESSED FCB
	MOV	D,A		; SAVE HERE TEMPORARILY
	MVI	A,NOT UMK	; MASK OUT INPUTTED USER NUMBER
	ANA	M	 	;   IN ADDRESSED FCB
	ORA	D		; OR-IN LOGGED USER NUMBER
	MOV	M,A		; SAVE IN FCB
STUSR1:
	POP  D! POP  H
	RET



;
;	FILE WRITE PROTECTION TEST
;
FILPRT:
	PUSH	B		; SAVE <BC>
	MVI	B,PMK		; FETCH WRITE-PROTECT MASK INTO <B>
FILPR1:
	CALL	GTDCBAT		; GET DCB ATTR BYTE
	ANA	B		; MASK OFF ALL BUT THE APPROPRIATE BIT
	POP	B
	RET


;
;	INVISIBLE FILE TEST
;
FILINV:
	PUSH	B
	MVI	B,IMK		;FETCH INVISIBLE MASK INTO B
	JMP	FILPR1

	PAGE
;****************************************************************
;*								*
;*	CPYFCB	COPY FCB FROM DIR BUFFER TO CURRENTLY ADDRESSED	*
;*		FCB						*
;*								*
;****************************************************************

CPYFCB:
	MVI	C,FCBLEN
	LHLD	ARG		; GET CURRENT FCB,
	XCHG			;   & PUT IN <DE> AS SRC FCB ADDR
	LDA	DIRDSP		; DIRECTORY BUF POINTER
	MOV	B,A		; SAVE
	CALL	GETBF		; GET ACTUAL BUF PTR & 1ST CHAR
	CALL	CMPFCBS		; SEE IF FCB HAS CHANGED (FLGS SET ON RET)
	JNZ	CPYFCB1		;   YES, PERFORM MOVE & PHYSICAL CLOSE (WRDIR)
	XRA	A		;   NO, CLEAR <A> & RET THRU WRDSK1 (RESETS
	JMP	WRDSK1		;     DATDMA & SUCCESSFUL RETCODE
CPYFCB1:
	LDAX	D		; GET CHAR FROM ADDRESSED FCB,
	MOV	M,A		;   & STORE IN DIR BUF ENTRY
	INX	D
	INX	H
	DCR	C		; DONE?
	JNZ	CPYFCB1
	CALL	SEEKDR		; POSITION DISK FOR RESTORE TO DISK
	JMP	WRDIR		; WRITE DIRECTORY


CMPFCBS:			; PERFORM STRNG CMP ON 2 FCBS
	PUSH B! PUSH D! PUSH H
	CALL	CMPSTR
	POP  H! POP  D! POP  B
	RET

	PAGE
;****************************************************************
;*
;*	OPEXT	CLOSE THE CURRENT EXTENT (WHICH PERFORMS
;*		PHYSICAL CLOSE ONLY IF FCB HAS CHANGED); THEN
;*		OPEN THE NEXT EXTENT, IF POSSIBLE.  IF RAFLAG
;*		IS ON, NEXT EXTENT TO OPEN IS IN RNDEXT.
;*
;****************************************************************

OPEXT:
OPEXT1:
	CALL	CLOSE		; CLOSE THIS EXTENT
	LDA	RETCOD		; CHECK FOR SUCCESS
	INR	A
	RZ
OPEXT2:
	LHLD	ARG		; FCB ADDRESS
	LXI	D,FCBEX
	DAD	D
	LDA	RAFLAG		; GET RANDOM R/W FLAG
	ORA	A
	JZ	OPEXT3		; JUMP IF REGULAR
;
;	RANDOM ACCESS R/W
;
	XCHG			; GET PTR TO LOW(EXTENT) TO <DE>
	LHLD	RNDEXT		; GET RANDOM EXTENT TO OPEN NEXT
	XCHG
	MOV	M,E		; PLACE IN LOW(EXTENT)
	INX	H
	MOV	M,D		; AND IN HIGH(EXTENT)
	JMP	OPEXT4
;
;	NORMAL (SEQUENTIAL) R/W
;
OPEXT3:
	INR	M		; SET FCB TO SEARCH FOR NEXT EXTENT
	JNZ	OPEXT4		; JUMP IF NOT JUST MADE 0
	INX	H		; SET <HL> TO POINT TO HIGH(EXTENT)
	INR	M		; BUMP HIGH(EXTENT)
OPEXT4:
	MVI	C,SEXTLN 	; SRCH LEN INCLUDES EXT
	CALL	SEARCH
	LDA	RETCOD		; SEE IF NEXT ONE FOUND
	INR	A
	JNZ	OPEXT5		; JUMP IF NEXT EXTENT FOUND
	LDA	RDFLAG		; SEE IF IN READ MODE
	ORA	A
	JNZ	OPEXT8		; IN READ MODE, SORRY CHARLIE
	CALL	MAKE		; IN WRITE MODE, TRY TO FIND A DIR ENTRY FREE
	JMP	OPEXT6
OPEXT5:
	CALL	OPEN
OPEXT6:
	LDA	RETCOD
	INR	A
	JNZ	OPEXT7		; CAN'T OPEN IF -1 (255)
	MVI	A,ERDIRF	; MUST RETURN A '2' FOR DIRECTORY FULL
	STA	RETCOD		; ERROR
	RET
OPEXT7:
	XRA	A
	STA	RETCOD
	JMP	GTCNTS		; ALL IS COOL, GET COUNTS FROM FCB
;
;	IN READ MODE, AND NEXT EXTENT TO OPEN IS N.F.
;
OPEXT8:
	LDA	RAFLAG		; SEE IF RANDOM MODE
	ORA	A
	RZ			; RETURN IF NOT
	MVI	A,ERSKUE	; UNWRITTEN EXTENT ERROR IF SO
	STA	RETCOD		; SAVE RETURN CODE
	RET

	PAGE
;****************************************************************
;*
;*	SELECT DATA DMA ADDRESS
;*
;****************************************************************

DATDMA:
	LHLD	DMAADR
DATDM1:
	MOV	B,H	;SET PARAM. IN B-C FOR UIOI ROUTINE
	MOV	C,L
	JMP	SETDMA	;UIOI ROUTINE
;
;	SELECT DIRECTORY DMA ADDRESS
;
DIRDMA:
	LHLD	DIRBUF	;DIR BUFFER TO USE
	JMP	DATDM1	;CONTINUE THERE
;
;
PAGE
;
;	SELECT DISK 'INFO' FOR SUBSEQUENT I/O
;
SELECT:
	LDA	LOGDSK	;GET CURRENT DISK
	CPI	MAXDSK+1 ;IN RANGE
	JNC	ERSLCT	;SELECT ERROR IF NOT
	MOV	C,A	;PREPARE TO SELECT DISK
	CALL	SELDSK	;SELECT DISK IN UIOI
	SHLD	CURDPH	;SAVE ADDRESS OF CURRENT DISK PARAMETER HEADER
	MVI	A,ODPB	;GET ADDR OF CURRENT DISK PARAMETER BLOCK
	CALL	GTDPH	;WHICH IS IN THE HEADER
	SHLD	CURDPB	;AND SAVE IT
	MVI	A,ODRBUF	;FETCH ADDR OF DIRECTORY BUFFER
	CALL	GTDPH	;WHICH IS ALSO IN THE HEADER
	SHLD	DIRBUF	;AND SAVE IT	
	MVI	A,OALVEC ;OFFSET ALLOC VECTOR
	CALL	GTDPH	;GET ALLOC VECTOR ADDRESS
	SHLD	ALLOC	;SAVE THERE
	MVI	A,OCSVEC ;OFFSET TO CHECK SUM VECTOR ADDRESS
	CALL	GTDPH	;GET CS VECTOR ADDR
	SHLD	CHECK	;SAVE THERE
	MVI	A,ODSM	;GET OFFSET TO NUMBER OF BLOCKS (LESS 1)
	CALL	GTDPBA	;GET THE VALUE
	INX	H	;BUMP TO GET ACTUAL # OF BLOCKS
	MOV	A,H	;IF HIGH BYTE ON, USE TWO BYTE BLOCK NUMBERS
	STA	TWOFLG	;SAVE AS TWO BYTE FLAG
	LXI	H,0	;SET UP A MASK WITH LOGGED-ON DISK BIT SET
	CALL	SETCDK
	XCHG		;PUT IT INTO DE
	LHLD	LOGGED	;PICK UP LOGGED DISK VECTOR
	CALL	ANDEHL	;IS THE DISK ALREADY LOGGED ON?
	MOV	A,H
	ORA	L
	RNZ		;IT IS, RETURN
	LHLD	LOGGED	;NO, SO MARK IT AS LOGGED
	CALL	SETCDK
	SHLD	LOGGED
	LDA	LOGDSK	;FETCH THE POINTER TO THE
	ADD	A	;SIZE OF THE CHECKSUM VECTOR FOR THIS DRIVE
	LXI	H,CSTBL
	CALL	ADDVAL
	XCHG		;INTO DE
	MVI	A,OCKS	;FETCH THE CHECKSUM VECTOR SIZE
	CALL	GTDPBA	;FROM DISK PARAMETER BLOCK INTO HL
	XCHG		;SWAP	
	MOV	M,E	;COPY CHECKSUM VECTOR SIZE
	INX	H	;INTO TABLE
	MOV	M,D
	JMP	SYSINI	;AND INITIALIZE THE DISK SYSTEM



	PAGE
;****************************************************************
;*								*
;*	DCHKIN	CHECK CURRENT FCB FOR DISK OTHER THAN LOGGED	*
;*		ENTRY	POINTER TO FCB IN [DE]			*
;*								*
;****************************************************************

DCHKIN:	XCHG			; PUT FCB ADDRESS INTO HL
	MOV	A,M		; GET DISK STATED IN FCB
	STA	DSKIN		; SAVE AS DISK ON INPUT (DSKIN)
	ANI	0FH		; ALLOW ONLY 16 DISKS, MASK UNNECESSARY JUNK
	DCR	A		; DOWN ONE (SO 0=A, 1=B ETC)
	RM			; NOTHING TO DO IF LOGGED DRIVE CALLED FOR
	PUSH	PSW		; SAVE NEW DRIVE
	LDA	LOGDSK		; GET CURRENTLY LOGGED DISK
	STA	DSKTMP		; SAVE IN TEMP LOCATION
	MVI	M,0		; SET DISK BYTE TO ZIP IN FCB
	POP	PSW		; RESTORE DISK AS STATED IN FCB
	MOV	E,A		; COMPATIBILITY WITH DIRECT CALL TO SELECT DISK


;****************************************************************
;*								*
;*	DCHKNW	DOS # 14					*
;*		SELECT DISK FUNCTION				*
;*								*
;****************************************************************

DCHKNW:	MOV	A,E		; GET DISK INTO A
	LXI	H,LOGDSK	; POINT TO CURRENTLY LOGGED DISK
	CMP	M		; COMPARE
	RZ			; RETURN IF SAME, NOTHING TO DO
	MOV	M,A		; STORE NEW DISK
	JMP	SELECT		; REALLY SELECT IT

	PAGE
;****************************************************************
;*								*
;*	MOVE	MOVE <B> BYTES FROM <HL> TO <DE>		*
;*								*
;****************************************************************

MOVE:
	MOV	A,M
	STAX	D
	INX	D
	INX	H
	DCR	B
	JNZ	MOVE
	RET


;****************************************************************
;*								*
;*	ZROBUF	CLEAR 128 BYTES PTED TO BY HL TO ZEROS		*
;*	CLRBUF	MOVE 128 BYTES FROM <A> TO <HL>			*
;*	CLEAR	MOVE <B> BYTES FROM <A> TO <HL>			*
;*								*
;****************************************************************

ZROBUF:
	XRA	A
CLRBUF:
	MVI	B,128
CLEAR:
	MOV	M,A
	INX	H
	DCR	B
	JNZ	CLEAR
	RET


;****************************************************************
;*								*
;*	COMPDE	COMPARE <DE> AND <HL>  (<de> - <hl>)		*
;*		RETURNS FLAGS SET AS RESULT OF CARRY		*
;*								*
;****************************************************************

COMPDE:
	MOV	A,D
	CMP	H
	RNZ
	MOV	A,E
	CMP	L
	RET

	PAGE
;****************************************************************
;*								*
;*	CMPSTR	COMPARE 2 STRINGS PTD TO BY <DE> & <HL> FOR	*
;*		LENGTH IN <C>					*
;*								*
;*		RETURN  NZ IF STRINGS NOT THE SAME,		*
;*			Z IF THEY ARE				*
;*								*
;****************************************************************

CMPSTR:
	LDAX	D		; GET CHAR FROM 1ST STRING
	CMP	M		;   CMP W/2ND STRING
	RNZ
	INX	D		; BUMP PTRS,
	INX	H
	DCR	C		;   & DCR COUNTER
	JNZ	CMPSTR		; LOOP TIL COUNT IS ZERO
	RET


;****************************************************************
;*								*
;*	DSUB	SUBTRACT [BC] FROM [HL]				*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************

DSUB:
	MOV	A,L		; SUBTRACT OFF LOW BYTE
	SUB	C		; DO SUBTRACT
	MOV	L,A		; RESTORE LOW BYTE
	MOV	A,H		; THEN SUBTRACT OFF HIGH BYTE
	SBB	B		; WITH BORROW, IF ANY
	MOV	H,A		; PUT HIGH BYTE BACK
	RET


;****************************************************************
;*								*
;*	ANDEHL	AND [DE] WITH [HL]				*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************

ANDEHL:
	MOV	A,H
	ANA	D
	MOV	H,A
	MOV	A,L
	ANA	E
	MOV	L,A
	RET


;****************************************************************
;*								*
;*	ORDEHL	OR [DE] AND [HL]				*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************

ORDEHL:
	MOV	A,H
	ORA	D
	MOV	H,A
	MOV	A,L
	ORA	E
	MOV	L,A
	RET

	PAGE
;****************************************************************
;*								*
;*	COMPBC	COMPARE [BC] AND [HL]				*
;*		RETURN  CARRY SET IF [HL] > [BC]		*
;*								*
;****************************************************************

COMPBC:	MOV	A,B
	CMP	H
	RNZ
	MOV	A,C
	CMP	L
	RET


;****************************************************************
;*								*
;*	ROTHLR	SHIFT [HL] RIGHT 1 BIT				*
;*		RETURN:	RESULT IN [HL]				*
;*								*
;****************************************************************

ROTHLR:	MOV	A,H		; GET HIGH BYTE
	ORA	A		; CLEAR CARRY
	RAR			; ROTATE IT FIRST, GET LOW BIT TO CARRY
	MOV	H,A		; PUT BYTE BACK
	MOV	A,L		; GET LOW BYTE
	RAR			; GET CARRY TO HIGH BIT AND DIVIDE BY 2
	MOV	L,A		; PUT BYTE BACK
	RET


;****************************************************************
;*								*
;*	GETBF	GET Ath CHARACTER IN DIRBUF			*
;*		ENTRY:	DISPLACEMENT IN [A]			*
;*		RETURN:	CHARACTER IN [A]			*
;*								*
;****************************************************************

GETBF:	LHLD	DIRBUF
GETBF1:	CALL	ADDVAL
	MOV	A,M
	RET

	PAGE
;****************************************************************
;*								*
;*	ADDVLE	ADD [A] SHR 3 TO [HL]				*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************

ADDVLE:
	RRC
	RRC
	RRC		; ROTATE THREE TIMES
			; AND FALL THRU TO ADDVAL

;****************************************************************
;*								*
;*	ADDVAL	ADD [A] TO [HL]					*
;*		RETURNS RESULT IN [HL]				*
;*								*
;****************************************************************


ADDVAL:	ADD	L		; ADD A TO [HL]
	MOV	L,A
	RNC			; NO CARRY, DIDNT OVERFLOW
	INR	H
	RET


;****************************************************************
;*								*
;*	GTDCBAT		GET DCB (DIR BUF) ATTR BYTE		*
;*			RETURNS ADDR(ATTR BYTE) IN <HL>,	*
;*				ATTR BYTE IN <A>		*
;*								*
;****************************************************************

GTDCBAT:
	LDA	DIRDSP		; BUF PTR FOR CUR DIR ENTRY
	ADI	FCBAT		; ADD OFFSET TO ATTR BYTE
	JMP	GETBF		; RETURN THRU GETBF


;****************************************************************
;*								*
;*	GTFCBAT		GET ADDRESSED FCB ATTR BYTE		*
;*			PRESERVES <DE>;				*
;*			RETURNS ADDR(ATTR BYTE) IN <HL>,	*
;*				ATTR BYTE IN <A>		*
;*								*
;****************************************************************

GTFCBAT:
	LHLD	ARG		; GET ADDRESSED FCB
	PUSH	D
	LXI	D,FCBAT		; OFFSET TO ATTR BYTE
	DAD	D
	POP	D
	MOV	A,M		; GET ATTR BYTE INTO <A>
	RET

	PAGE
;****************************************************************
;*								*
;*		WORKING STORAGE		(DATA AREA)		*
;*								*
;****************************************************************

WS	EQU	$



BEGCOL:	DB	0		; BEG CONSOLE COLUMN POS FOR READBF
SAVCOL:	DB	0		; SAVE BYTE FOR CONSOLE COLUMN POS
COLUMN:	DB	0		; COLUMN POSITION FOR CONSOLE
LCOLMN:	DB	0		; COLUMN POSITION FOR LIST DEVICE
LISTCP:	DB	0		; LISTING TOGGLE
OLDCHR:	DB	0		; INITIAL KEY CHAR = 00
CPMFLG:	DB	0		; INITIALIZED TO CPM COMPATIBLE
ZEROFG:	DB	0		; ON = FN 40 CALL
LDADDR:	DW	100H
EXADDR:	DW	100H
LOGDSK:	DB	0FFH		; CURRENT DISK NUMBER
;
FUNC:	DS	1		; FUNCTION NUMBER
ARG:	DS	2		; INFORMATION ADDRESS (entry parm)
ARG2:	DS	2		; ENTRY PARM2 (for biosfnc)
ENTSP:	DS	2		; ENTRY STACK POINTER
	DS	SSIZE*2		; STACK SIZE
LSTACK:
;
;
WBOOT	EQU	0		; JUMP TO WARM BOOT
IOBYTE	EQU	3		; IO BYTE LOCATION
DOSA	EQU	6		; ADDRESS OF JUMP TO DOS
DFCB	EQU	5CH		; DEFAULT FCB
DBUFF	EQU	80H		; DEFAULT DMA ADDR 
TPA	EQU	100H
;
;
MAXDSK	EQU	15		; MAX DISK NUMBER
NDISK	EQU	MAXDSK+1	; NUMBER OF DISKS ON SYSTEM
;
;	DATA ABOUT DIRECTORY POSITIONING
;
DIRDSP:	DS	1	;POINTER TO DIRECTORY ELEMENT IN BUFFER
DIRNUM:	DW	0FFFFH	;DIRECTORY NUMBER RELATIVE TO 0
DIRREC:	DW	0	;DIRECTORY RECORD NUMBER
;
;	DISK READ BUFFER ADDRESSES
;
DMAADR:	DW	DBUFF	;DMA ADDRESS
DIRBUF:	DW	DBUFF	;DMA ADDRESS FOR DIRECTORY
;
;	DIRECTORY CHECKSUM AND ALLOCATION VECTOR DATA
;
ALLOC:	DW	0	;POINTER TO CURRENT ALLOCATION VECOTR
CHECK:	DW	0 	;POINTER TO CURRENT CHECKSUM VECTOR
RODSK:	DW	0	;READ ONLY DISK VECTOR
CSTBL:	DS	2*NDISK	;CHECK SUM VECTOR SIZE TABLE (2 BYTES PER DISK)
;
;	DISK PARAMETER INFORMATION
;
;
;	DISK PARAMETER HEADER
;
OTRTBL	EQU	0		;OFFSET TO TRACK TRANSLATION TABLE
OSPAR1	EQU	OTRTBL+2	;SPARE 1
OSPAR2	EQU	OSPAR1+2	;SPARE 2
OSPAR3	EQU	OSPAR2+2	;SPARE 3
ODRBUF	EQU	OSPAR3+2	;OFFSET TO DIRECTORY DMA ADDRESS
ODPB	EQU	ODRBUF+2	;OFFSET TO DISK PARM BLOCK ADDRESS
OCSVEC	EQU	ODPB+2		;OFFSET TO CHECKSUM VECTOR ADDRESS
OALVEC	EQU	OCSVEC+2	;OFFSET TO ALLOC VECTOR ADDRESS

CURDPH:	DW	0		;ADDRESS OF CURRENT DISK PARAMETER HEADER
;
;	DISK PARAMETER BLOCK
;
OSPTRK	EQU	0		;OFFSET TO # SECTORS PER TRACK
OBSH	EQU	OSPTRK+2	;OFFSET TO BLOCK SHIFT FACTOR
OBLM	EQU	OBSH+1		;OFFSET TO BLOCK MASK
OEXM	EQU	OBLM+1		;OFFSET TO EXTENT MASK
ODSM	EQU	OEXM+1		;OFFSET TO NUMBER OF BLOCKS LESS 1
ODRM	EQU	ODSM+2		;OFFSET TO NUMBER OF DIRECTORY ENTRIES LESS 1
OAL0	EQU	ODRM+2		;OFFSET TO DIRECTORY ALLOCATION MAP (BYTE 1)
OAL1	EQU	OAL0+1		;OFFSET TO DIRECTORY ALLOCATION MAP (BYTE 2)
OCKS	EQU	OAL1+1		;OFFSET TO NUMBER OF DIRECTORY ENTRIES TO CHECK
OOSTRK	EQU	OCKS+2		;OFFSET TO NUMBER OF OPERATING SYSTEM TRACKS

CURDPB:	DW	0		;ADDRESS OF CURRENT DISK PARAMETER BLOCK
TWOFLG:	DB	0		;0 IF ONE BYTE BLOCK #, NON ZERO OTHERWISE
;
;
EMP	EQU	0E5H	;EMPTY SIGNAL
EMPTY:	DB	0E5H	;SAME-USED ONLY WHEN SPECIFICALLY LOOKING FOR FREE FCB
MXBLK:	DW	0  	;HIGHEST AVAILABLE BLOCK NUMBER-TEMP VARIABLE
MRC	EQU	127	;MAX RCD CNT (LARGEST RCD NUMBER)

DMK	EQU	3	;MASK OF LOW TWO BITS OF DIRECTORY 
FCBEX	EQU	12	;POSITION IN FCB OF EXTENT NUMBER
FCBNE	EQU	13	;NEXT EXTENT NUMBER
FCBS1	EQU	13	;POSITION IN FCB OF S1 BYTE
FCBS2	EQU	14	;   "     "   "  "  S2  "
FCBAT	EQU	14	;FILE ATTRIBUTES
FCBRC	EQU	15	;LOCATION IN FCB OF RECORD COUNT
FCBMP	EQU	16	;BEGINNING OF DISK MAP
FCBNS	EQU	32	;LOCATION OF RCD NUMBER NEXT FOR R/W
FCBRR0	EQU	33	;POSITION OF r0 IN FCB
FCBRR1	EQU	34	;POSITION OF r1 IN FCB
FCBRR2	EQU	35	;POSITION OF r2 IN FCB
SNAMLN	EQU	12	;LEN OF DRV+FILE NAME (FOR SRCH)
SEXTLN	EQU	14	;LEN OF DRV+FILE NAME+EXT (FOR SRCH)
FCBLEN	EQU	32	;FCB LENGTH
;
; ATTR BYTE MASKS:
;
; x000 0000	write-protected file
; 0x00 0000	public (dmados system) file
; 00x0 0000	system (dmados invisible) file
; 000x 0000	not used
;
; 0000 xxxx	user # nibble
;
PMK	EQU	80H	;MASK FOR WRITE-PROTECTED FILE
SYS	EQU	40H	;MASK FOR PUBLIC (SYSTEM) FILE
IMK	EQU	20H	;MASK FOR SYSTEM (INVISIBLE) FILE
UMK	EQU	0FH	;USER NUMBER MASK
;
DSKTMP: DS	1	;DISK ON ENTRY TO DOS
DSKIN: DS	1	;DISK NAMED IN FCB
LOGGED:	DW	0	;BIT VECTOR GIVING LOGGED IN DISKS
;
RECCNT:	DS	1	;RECORD COUNT IN CURRENT FCB
RELREC:	DS	1	;CURRENT VIRTUAL RECORD
RECNUM:	DS	2	;CURRENT ACTUAL RECORD
;
SRCH:	DS	2	;SEARCH ADDRESS WHEN LOOKING IN DIRECTORY
SRCHL:	DS	1	;LENGTH OF CHARACTER STRING TO MATCH
SRCHO:	DS	2	;SEARCH ADDRESS IF CAME FROM OUTSIDE
SRCHLO:	DB	1	;SEARCH LENGTH IF CAME FROM OUTSIDE
DIRNMO:	DW	0	;DIRECTORY NUMBER AFTER LAST SRNX IF FROM OUTSIDE
SRCFLG:	DB	0	;FLAG TO SAY OUTSIDE SEARCH OR SEARCH NEXT
RETCOD:	DS	2	;DOUBLE BYTE RETURN VALUE FOR USE BY DOS
SAVRC:	DS	1	;SINGLE BYTE FOR USE W/FILE DELETE
USRN:	DB	0	;USER NUMBER (IF SET INIT TO 0, WONT LOOKUP PASSWORDS)
RDFLAG:	DS	1	;READ FLAG FOR SEARCH ROUTINES
UNAFLG:	DB	0	;FLAG INDICATING SECTOR AS UNALLOCATED (IF NON ZERO)
LTEMP:	DS	1	;TEMPORARY DOS STORAGE LOCATION
;
;	RANDOM ACCESS TEMPS
;
RAFLAG:	DB	0		;FLAG TO SAY IF RANDOM R/W OR REGULAR
RNDEXT:	DW	0		;TEMP FOR RANDOM EXTENT TO READ/WRITE
RNDNXR:	DB	0		;TEMP FOR RANDOM NEXT RECORD TO R/W
;
; BACKGROUND PRINT DEFINITIONS AND DATA AREA
;
;
QUELEN	EQU	11+1		;QUEUE ENTRY LENGTH + DRIVE
MAXQUE	EQU	6		;NUMBER OF ENTRIES IN QUEUE, MAX
QCLR	EQU	00		;QUEUE ENTRY EMPTY FLAG (FILL CHAR)
BPQ:	DS	QUELEN*MAXQUE	;QUEUE
BPRFLG:	DB	0FFH		;STATUS FLAG: STARTS AT 0FFH =OFF
;
BKPQMT	EQU	00		;QUEUE EMPTY CODE
BKPRUN	EQU	01		;PRINTING TOP FILE IN QUEUE
SUSPND	EQU	02		;TOP FILE PRINT SUSPENDED
PRTSUS	EQU	03		;PRINT SUSPENDED DUE TO PRINTER ERROR
BPRRDY	EQU	04		;BKGND PRINT READY TO OPEN NEXT FILE(TOP)
FILSUS	EQU	05		;FILE ERROR CAUSED SUSPENTION
;
EOF	EQU	1AH		;END OF FILE MARK
;
;
BPRFCB:	DB	0		;FILETYPE
	DS	8		;PRINT FCB FILENAME
	DB	'PRN'		;EXTENTION NAME
BPEXT:	DB	0,0,0,0
	DS	16
BPNR:	DB	0		;NEXT RECORD
;
;
TEMP1:	DW	0		;TEMP FOR INFO
DMATEM:	DW	BPBUF		;TEMP FOR DMAADR
DIRTEM:	DW	BPBUF		;TEMP FOR DIR DMA (BUFFA)
BPBUFP:	DW	BPBUF		;POINTER
;
BPBUF:	DS	128		;PRINT BUFFER
BPBUFE	EQU	$		;END OF BUFFER
;
;
;
LSTBYT	EQU	$		!=;
ACTSIZ	EQU	$-DOS		!=; ACTUAL SIZE OF CODE
;
;
;	NOW MUST MAKE SURE WE FILL UP TO MAKE RELOCATION
;	SCHEME WORK PROPERLY
;
DOSFILL	EQU	(DOSSIZ-($-DOS))-1 !=; FILL FOR RELOCATION

	DS	DOSFILL
DOSEND:	DB	0		!=; ENSURE HEX FILE HAS BYT HERE
;
	END
